MXGraph: edges are not redrawn when they are moved - javascript

this might be a stupid question and I know it is hard to tell without a look at the code... However I have an issue and maybe somebody can point me toward the right direction.
I am developing a javascript mxGraph application integrated with Angular7. I'm using a modified version of the ports.html example.
If I add two nodes and connect them, then I export it in XML with this code:
var enc = new mx.mxCodec(mx.mxUtils.createXmlDocument());
var node = enc.encode(editor.graph.getModel());
xml = mx.mxUtils.getPrettyXml(node);
I am able to save it correctly and then reload it.
However if I move the connection as shown in the image here:
the connection is not redrawn in the graph, although it is present in the model as cell:
Here a screenshot of the model, as you can see, both connections are present but just the one that I didn't move is drawn:

I found the solution... It is somehow related to this past issue that I had: MxCodec decode function not working with XML
As when an edge is moved it creates an Array of mxPoints, which are not decoded properly because of missing ctor in window. The solution was adding to the window:
window['mxPoint'] = mx.mxPoint;

Related

dojox gfx make a node moveable after getting sgv from json

I have a surface with some shapes. I use
dojox.gfx.utils.toJson(surface)
to generate a json from it, and then
dojox.gfx.utils.fromJson(surface, json)
to get the data and append it to the surface.
The problem comes when I create a moveable node. After saving it to json and then appending it to the surface, the node is no longer moveable. I found no way of making the node moveable again. Is there a way to do this?
I want to be able to save and load svg data in my page and after load, move the elements around. Using dojo seemed easy enough before i stumbled on this problem. If I can't do this easy, is there a better library I can use, to achieve my goal?
Edit: here is the actual code: http://pastebin.com/2qLCTw8B
I found the answer to my problem.
First of all, when you require a dojo module it is good to assign it to a variable, which i didn't know. This way when assigning the on module, you can use the on function, used to add event listener, anywhere in the code. From there it is easy to create a moveable node, when you click on it.
It seemed though that this is a useless operation, as you could just iterate over the surface - children array, and make every node moveable.
Here is the improved code: http://pastebin.com/wAvSnZpN
The code needed, if you decide to use events anyway:
function HandleMouseDown(e) {
var foo = new dojox.gfx.Moveable(e.gfxTarget);
}
on(surface, 'mousedown', HandleMouseDown);

ThreeJS geometry data from Json not rendering

Firstly, I'm a big fan of the site and have used it countless time to help me when stuck on a problem, but this is the first time I have come across something that has required me to write a question because I simply cannot find a situation like this.
I have a Json file which I am loading a bunch of data from that I then run through with my code to put the right data in the right places so it can be rendered by ThreeJS (quick side note, big thanks to mrdoob, westLangley and the rest of the ThreeJS team for what they've done and their continued engagement with helping people here).
So at that point the mesh is able to be rendered and have orbit controls and so on. Then I made just a simple exporter in a similar style to that of ThreeJS.org/editor. The big difference being that I simple use JSON.stringify on a number of objects (the one I will focus on here is called "geo") and write their data to a new Json (json2). The goal being that now I can simply load json2 into the new program which will populate "geo" with the data of the json2's geo thus circumventing all of the processing that goes into putting the data in the right places.
Now here is the issue. All the data seems to be the same between the two "geo"s, but when going to color a face in the code by using:
for ( var i = 0; i < sD.geo.faces.length; i ++ ) {
var face = sD.geo.faces[ i ];
face.color.setStyle("#0066FF");
}
the error that "face.color does not have a function called setStyle" (rough quote from memory) appears. And again, this works perfectly fine in the first program.
So I looked into it further and it seems that when digging into the "face" variable in the code above via firebug, it doesn't have a constructor or prototype in its drop down menu, as it does have the first program. I'll upload screenshots of the two dropdowns to show more visually in a little while. )Update: Nevermind, I don't have enough rep to post them. Forgot about that haha)
So the data I have doesn't have the constructor/methods, so could it be that the data I'm setting the sD.geo equal to? (even did it so that it just sets the vertices from the json2 to the sD.geo.vertices so as to avoid that but didn't work, obviously). Any other ideas as to what my issue could be? Should I add the methods to the json2 and how because I looked into that a lot and couldn't find any good examples on it.
I apologize if I jumped all over the place throughout this, I tried to keep it as linear as possible as to cause as little confusion as possible.
Any and all help is appreciated, and I am more than willing to answer any questions anyone has that I am able to.
Thanks!
After tinkering with this more, I found a solution for adding the json2's geometry data to the new program's geo.
function loadGeo(json) {
var loader = new THREE.ObjectLoader();
var object = loader.parse( json );
var pushed = false;
object.traverse(function(child) {
if (child.geometry !== undefined && pushed !== true) {
addGeometry(child.geometry);
$.each(child.material.materials, function(cm, cMat) {
sD.geo.materials.push(cMat);
});
pushed = true;
}
});
}
Now this works, but it is far from flawless. For example, in object.traverse I put in a check to only add the first geometry and material it finds and ignore the rest. Both because I am only adding a single geometry and I haven't used/looked into traverse enough to know of any proper exit. Also in the json, the materials (there are ~24 for the single geometry) are very deep in the object tree, which is okay but probably not optimal.
The one big issue that I have come across with this is that for some reason, the materialIndexes I assigned to the faces in the geometry aren't assigned properly; they all are just set to 0(from the ones I looked at, there are ~11,000 faces so couldn't look through them all). An odd issue, and will edit my answer if and when I find solutions to this or others give solutions on here.
I figured this out by going back to the three.org/editor and seeing how their importer worked and making a rough attempt at something that uses the threejs loaders in the same way, but really make it less tied into the actual Editor and make it very "bare-bones" so that it serves my purposes alone. That being said, I'm curious if there is any ThreeJS importer which uses the loaders that can just populate variables in the way like I am doing here.

How can I fix the Scaling and Rotating of an Inkscape SVG in FabricJS?

I am having some trouble with scaling and rotation of SVG images with FabricJS.
I've been working on an icon builder for my website. A user can add layers, select a shape for that layer, then set a number of options such as coloring and stroke width. I populate the possible "shapes" and, for maximum flexibility in the shape's complexity, I am using SVG files that I have created with Inkscape. I use the loadSVGFromURL functionality in FabricJS to handle loading the file onto my canvas.
The problem is when I load some (seems to be most) of these SVGs to the canvas then try to use the handles to scale and rotate the image, the rendered result is not appearing as expected: Octagon SVG Image and Action Results.
On that image, don't worry about the "sliced" edges, that's just the editor's boundaries. After loading my octogon.svg to the canvas, it looks right. When I rotate, it gets messed up. I rotated to the right and downward and the image moved to the left and upward. Then, when I scale, it moves vertically the opposite direction.
I have tried programmatically changing these settings and it behaves the same way. I've read several posted questions here and on newsgroup discussions, but nothing got me a solid solution.
One very close solution was using an optimization tool to remove some transformation data that is apparently not liked much by fabric (that tool being found here http://petercollingridge.appspot.com/). It seemed to work, but not for every image, this one included. In fact, regardless of the optimization options I chose, the tool altered the octagon so much, it wasn't really usable as an octogon. That tool is also reference in this existing question: 10470508 (issue-with-svg-display-rendering-in-fabric-js)
I have saved the SVG out of Inkscape in various formats: Inkscape SVG, plain SVG, and Optimized SVG - none made any difference. I also tried Simplifying the Path prior to exporting in all of these formats - again, no difference (though for some shapes, this did seem to work).
I have read many bugs and the related discussions on GitHub with Kangax involved and tried things like the centeredRotation property and origin points on the objects.
I noticed that Inkscape's x,y of 0,0 is the bottom left corner which I thought was a little odd and thought maybe that had something to do with the scaling at least. To attempt fixing it from that point of view, I set flipY on the object, but that didn't work at all. It appeared very far above the editor panel. It almost feels like the transform point is somewhere way above the bounding box. But I cannot verify that. All the settings I check seem like they are set correctly.
I did try a hexagon made in Illustrator and it seemed to work, but I do not have Illustrator at my disposal and to say that is a "solution" is somewhat undesirable. Perhaps this is better logged as a bug, but with all the related chatter, I am somewhat hoping that it is resolved and I just have not found the right combination of settings or processes to follow. I really need to be able to use Inkscape for these. Kangax has pointed out that Inkscape SVGs are more troublesome for FabricJS, but he goes on to say they are getting better. So perhaps this can help with another step forward.
I have also reviewed the code itself on GitHub, but cannot seem to pin point what exactly I would need to change to fix this; though, I am not really sure where the point of failure is - fabric, my settings, or my SVG file.
UPDATE 2/21/2014 10:27PM EST
I began digging into the SVG file structure, comparing the ones giving me trouble with the ones that are working. It definitely does seem like the problem is due to a "transform" attribute being present on a path, container, or other object tag. The optimization processes I've tried should have removed them, but I still have not found a solid solution that just works in all cases. I'll keep you updated.
I don't know much about fabricjs and Inkscape, but using the svg DOM the following will apply for rotation and scale transformations applied individually to an element: Maybe you can apply this. If you want to rotate+scale an element your can append the transformation strings or use transformation matrix. Hope this helps
var bb=elem.getBBox()
var bbx=bb.x
var bby=bb.y
var bbw=bb.width
var bbh=bb.height
var cx=bbx+.5*bbw
var cy=bby+.5*bbh
//----rotate from center of elem---
elem.setAttribute("transform","rotate(angle "+cx+" "+cy+")")
//---scale: translate center to(0,0)+scale+translate back---
elem.setAttribute("transform","translate("+cx+" "+cy+")scale(myScale)translate("+(-cx)+" "+(-cy+")")
Would it be advantageous to load your svg files as xml using XMLHttpRequest? You could then treat them as xml, work on them, then insert them as SVG by cloning them.
pretty seamless, I think. You can extract elements from XMLdoc and insert them as svg by merely cloning them. Also you can include a DIV in your html and dump the entire xml response text into it as its innerHTML. Then everything is available for DOM workings.
var XMLdoc
function loadSVGasXML()
{
var SVGFile="my.svg"
var loadXML = new XMLHttpRequest;
function handler()
{
if(loadXML.readyState == 4 && loadXML.status == 200)
{
//---responseText---
var xmlString=loadXML.responseText
//---mySVGDiv.innerHTML=xmlString ---
//---DOMParser---
var parser = new DOMParser();
XMLdoc=parser.parseFromString(xmlString,"text/xml").documentElement ;
}
}
if (loadXML != null)
{
loadXML.open("GET", SVGFile, true);
loadXML.onreadystatechange = handler;
loadXML.send();
}
}
Like the other issues posted about this, the problem was still in the individual transformations on the paths. The online solutions I found never worked as well as I needed them to; at least not with SVGs from InkScape. Saving the SVG in a different type right out of InkScape also did not impact the end result. Some shapes, when "simplified", were fine; however, it was not consistent enough. So, I set out to develop a solution.
After reading SVG file structure documentation, I created this specifically to handle InkScape SVGs. Some SVG commands are not handled, but so far, I have not noticed an issue with the few missing commands (which were excluded simply due to time).
EvilEye Games - InkScape SVG Transform Remover
In the end though, I just decided to use some free SVGs from another website. So it was all for not for me. However, I was able to figure it out and fix the problem. So figured maybe this would come in handy for someone else. Its not perfect, but it does what it needs to.

How do I make a dygraph not lose its y-axis when I update it while panning?

This may be a bit obscure, but I'm developing a viewer app that chunks up a large dataset and then allows it to be viewed using dygraphs, where new data chunks are loaded on either side as you pan through it.
The trouble is, when you update the graph as it's being panned, it seems to lose its y-axis range. You can see this on the dynamic update demo on the official site:
http://dygraphs.com/tests/dynamic-update.html
If you shift-drag to pan, you'll see the plot (and y-axis) disappear as new data is added. To prove the error, run this in the Chrome console, and you'll see [ NaN, NaN ] output as the plot disappears:
window.setInterval(function() { console.log(window.g.yAxisRange()); }, 200);
Now, there would be various workarounds involving timers, but ultimately this seems like a bug in the dygraphs library itself. Is there an easy way to patch in a fix? Alternatively, if there's a way to tell when a pan is in progress, I could simply avoid altering the data set until I know that the user is not in the middle of a pan—but there's no official callback or flag for this, and it looks like the internal isPanning flag has been carefully hidden on a local-scope context object, where it's safe from my prying eyes.
What's the quickest way to patch or monkey-patch this problem?
This was a bug in dygraphs which is now fixed. If you download the latest version (either from github or dygraphs.com), you'll no longer have this issue.
If you want the gory details, here's the fix:
https://github.com/danvk/dygraphs/commit/97583b90be3e80c95654d010db8a4b3f8813bb7a
The panning code was storing data in objects that didn't belong to it, and when updateOptions() got called, those objects were destroyed and chaos ensued.

Capture website screenshot using javascript

I've seen similar questions asked and the answers were not quite what I'm after. Since this question is slightly different, I'm asking again - Hopefully you'll agree this isn't a duplicate.
What I want to do: Generate an image showing the contents of my own website as seen by the user (actually, each specific user).
Why I want to do it: I've got some code that identifies places on the page where the user's mouse hovers for a significant length of time (ppl tend to move the mouse to areas of interest). I also record click locations. These are recorded as X/Y co-ords. relative to the top-left of the page
NB: This is only done for users who are doing usability testing.
I'd ideally like to be able to capture a screenshot and then use something server-side to overlay the mouse data on the image (hotspots, mouse path, etc.)
The problem I have is that page content is very dynamic (not so much during display but during server-side generation) - depending on the type of user, assigned roles, etc... whole boxes can be missing - and the rest of the layout readjusts accordingly - consequently there's no single "right" screenshot for a page.
Option 1 (which feels a little nasty): would be to walk the DOM and serialize it and send that back to the server. I'd then open up the appropriate browser and de-serialize the DOM. This should work but sounds difficult to automate. I suspect there'd also be some issues around relative URLs, etc.
Option 2: Once the page has finished loading, capture an image of the client area (I'd ideally like to capture the whole length of the page but suspect this will be even harder). Most pages don't require scrolling so this shouldn't be a major issue - something to improve for version 2. I'd then upload this image to the server via AJAX.
NB: I don't want to see anything outside the contents of my own page (chrome, address bar, anything)
I'd prefer to be able to do this without installing anything on the end-user pc (hence javascript). If the only possibility is a client-side app, we can do that but it will mean more hassle when getting random users to usability test (currently, we just email friends/family/guinea pigs a different URL)
One alternative solution would be to "record" the positions and dimensions of the main structural elements on the page:
(using jQuery)
var pageStructure = {};
$("#header, #navigation, #sidebar, #article, #ad, #footer").each(function() {
var elem = $(this);
var offset = elem.offset();
var width = elem.outerWidth();
var height = elem.outerHeight();
pageStructure[this.id] = [offset.left, offset.top, width, height];
});
Then you send the serialized pageStructure along with the mouse-data, and based on that data you can reconstruct the layout of the given page.
One thing we always talk about where I work is the value of ownership vs the cost required to make something from scratch. With the group I have, we could build just about anything...however, at a per-hour rate in the $100 range, it would need to be a pretty marketable tool or replace a very expensive product for it to be worth our time. So, when it comes to things like this that are already done, I'd consider looking elsewhere first. Think of what you could do with all that extra time....
A simple, quick google search found this: http://www.trymyui.com/ It's likely not perfect, but it points to the fact that solutions like this are out there and already working/tested. Or, you could download a script such as this heatmap Obviously, you'd need to add a bit to allow you to re-create what was on the screen while the map was created.
Good Luck.
IMO, it's not worth reinventing the wheel. Just buy an existing solution like ClickTale.
http://www.clicktale.com/

Categories

Resources