Phantom image along border while dragging object in fabric.js - javascript

I have a group of objects in fabric.js, everything is non evented and not selectable except a single object which I will call the selector. They are grouped together because they all need to move as one group. When this selector moves with in the bounds of the group everything works as expected. However when I moved the object outside of the bounds (even though I programmatically have it stop before that point it draws phantom objects along the edge of the main group.
I have gone through the code and commented things out and tried placing .renderAll() and .setCoords() on objects I think may be the issue but so far no luck.
Here is a short clip showing what is happening - https://i.imgur.com/bnIJWY7.mp4

Related

A scatterplot with links between points using d3?

I am trying to make a visualization using d3 which is basically a scatter plot with links between the points. (I have attached a .gif of the existing java based visualization)
The points can be added by double clicking other points. On hovering over a point, I wish to have links drawn between the point and all its partners on screen.
I have the part where on double clicking a node, its partners are added. What I need help with is drawing the links (primarily I am not able to understand how can I get the x1,y1,x2,y2 values required to draw the links).
This is what my DOM looks like:
I have seen a lot of examples online but somehow not able to figure the solution - if anyone could link me to a similar visualization or share a fiddle/ give some pointers on how this can be achieved I would be really grateful.
First the simple stuff: here are 2 mechanisms for drawing the lines.
Next, in terms of the data representation of the lines, check out how links are typically drawn when working with the force directed layout.
Important: Do not get distracted by the existence of the force layout in this example and by the fact that the force layout works with these links (which are passed into it by calling force.links(links)). That aspect of the example probably doesn't have an equivalent in what you're trying to achieve.
However, do notice how the links array is constructed —— with each element of the array being an object with pointers to source and target datums. In your case, you'll want to work with a similar links array, where source is the node under the mouse and target is a node that's connected to it. So you'll end up with an array of links who all have the same source datum but unique target datums.
You can then bind the links array (via the usual .data() method) to a d3 selection of line or path elements. Once you bind, you can use the usual enter, update, exit pattern to append, update and remove (on mouse out) the drawn lines.
Given a source and target datums, you can calculate the x and y of the endpoints in the same way you currently calculate the translation of each <g> element, presumably using a d3 scale.

Finding the minimum translation vector using intersection points

I'm building an application based on Paper.js.
I have a list of items, each composed from a top level group and a bunch of paths as children.
I need to implement collision detection, which currently works like so:
When an item is dragged, its components (the paths it's comprised of) are checked against any other path in the same layer using the
Path#getIntersections(path) method.
If the method returns a non empty array (of CurveLocations, which describe the points of intersection) I know there's a collision. I
stop dragging and combine the items.
If the returned array is empty, there's no collision to handle so no need to interrupt the drag. I translate (move) the dragged item by
the distance it was dragged.
And now, here's what I need to do in step 2:
Upon detecting a collision, I need to move the item to the nearest
"legal" position (the closest to the current mouse position without
overlapping any other shape/border).
Now I can go about implementing SAT or GJK and solving it without the getIntersections method, but the only thing I'm lacking here is the MTV (if I'm not mistaken).
Can someone please confirm if this is either possible or not, and if it is, then how?
Update
After some fiddling with the various mouse events, I've come to a current (imperfect) solution:
onMouseDown: Save the mouse offset (item position minus mouse position)
onMouseDrag: Check for intersections. If so, translate the dragged object by event.delta.negate() while the check returns true. When done, update the offset.
If no intersection is detected, just move the dragged item to the mouse position minus offset.
onMouseUp: The same as in the drag event, except if no collision is detected then do nothing.
This is more or less working, except it's jittery and it doesn't deal with containment.
Will update with an example as time permits.
If you only have two shapes and they are all quite close to circles and boxes and have similar sizes you could get the center of the bounding box of the shapes and use those center points as a direction vector. Then you move it incrementally away until there is no intersection anymore. But if you have shapes like a U or O that surround another smaller shape it is likely that this method will not give the shortest distance. The same if the moving away will hit other objects.
So I think what you really need is a numerical solution that moves the shape away from its center point in a circular fashion with growing diameter until there wont be any intersections anymore.
Another problem could be when your shape is enclosed in another shape and you will not even have any intersections. So I guess it would be better to use hittest.
Edit:
Here is a very easy not very well optimized example of what I tried to explain with the middle points. Reload it if you do not see any overlays. For the circular way the checking just gets more complicated because you would move the shape not only away but also in all other kind of directions.
Edit2: Second example that checks for intersection and moves the shape outside. As you can see intersection alone is not enough to check for if the obstacle gets bigger than the dragged item.

KineticJS - Draw free with mouse

I'm building a canvas paint tool where the use simply drags his mouse to draw on the canvas. As I understand it lines is the best way for the job. So on mouse down I create a KineticJS Line object and when the user drags I add a point between the last mouse position and the current. Note, I only have one line object that has multiple points.
When the user releases his mouse the Line is finished and whenever you click again to draw more, I create a new line object.
Problem with this is that if you are going to draw a text, say "My name is x" That would result in many line objects, 1 for each character (and 2 for "x" and "i").
Is there a better way to do this? My idea was to have only one line object, and onmousedown you simply not add a line from the previous position, and then when u drag you do. But I don't think KineticJS Line supports that.
So basically, can I improve the way I let the user draw?
Your current design of having 1-2 polylines that define one letter is fine.
Both canvas and Kinetic can support a whole paragraph of characters before lagging in performance.
If you want 1 single definition for a whole sentence, you can use a custom Kinetic.Shape.
With Shape, you get full access to a wrapped canvas context. You could use that context to do your second idea--a single context.path drawing a sentence through a saved set of moveTo and lineTo commands.
Personally I would go with your current design (1-2 polylines per character) because the performance is fine and you get more flexibility. (For example, if you want to draw the person's name in a different color is easier in your current design).

HTML Canvas: mouse click hit test by using ghost canvas - anti-aliasing troubles

I'm writing an JavaScript application that is drawing arbitrarily shaped objects on a HTML canvas. The user should be able to select any of the objects by clicking on them.
To make this an O(1) operation I'm using a shadow canvas, i.e. a not displayed canvas that has exactly the same size, where each object drawn on the normal canvas is also drawn there - but with a color that represents it's ID.
So a simple ghostContex.getImageData() together with the mouse click coordinates gives me the color at that pixel and thus the ID of the clicked object.
All of that is working fine - except when I click on the exact border of an object.
As it's drawn with anti-aliasing on the ghost canvas I get a wrong color (as that color is a mixture between the correct ID and the ID of the object under it that was drawn before...). This wrong color is representing a wrong ID and thus I'm selecting a totally different object :(
How can I solve that problem?
Note #1: I'm already using the translate(0.5, 0.5) trick to prevent most anti-aliasing
Note #2: I was trying to write this application with SVG before, but especially this object selection was extremely slow as I guess it's been too many objects for the collision detection. That's the main reason why I want a O(1) approach now... Oh, and this way I can easily draw a much bigger line on the ghost canvas than the line is drawn on the normal canvas to make picking much easier.
Note #3: Relevant browsers are Firefox, Chrome, Android 2.3+ native and iOS native
The reason why I couldn't accept any answer here is quite easy and quite sad: it doesn't exist... :(
The antialiasing can not be switched of, the standard has no method for that. But the standard does have a hit test function (http://www.w3.org/html/wg/drafts/2dcontext/html5_canvas_CR/#hit-regions) that would do exactly what is needed here. Even in a nice way that would hide the nasty details for the developer - but it's not implemented in any of the browsers right now.
And implementation was looking to be far away till impossible (see e.g. comment #6 at https://code.google.com/p/chromium/issues/detail?id=328961). But apparently it gained momentum during the last month...
So what can be done in the mean time? What did I do?
In my code I could implement for each shape a isPointInShape() method. So I use the ghost canvas trick to get a shape and verify with the isPointInShape() that I really selected the correct shape. This helps in the anti aliased pixels not to pick a wrong shape (just think of clicking on the border of shape #2 where we had a 50% antialias transparency - this would tell you wrongly a selection of shape #1...).
If implementing a generic isPointInShape() is quite hard for your shape you could try a trick that I was reading of somewhere else (I didn't try it tough, so I haven't tested it...):
Create an additional ghost canvas of size 1x1 pixel that is positioned exactly on the mouse position. Then draw the shape of interest - when the A of the RGBA is changed, this shape does belong to that pixel.
I know this is an old post, but recently I had a similar issue. The way I solved the "seam of two colors" problem was doing a 10x10 pixel sampling of the secondary canvas instead of a single pixel. I then stringified the RGB values and used these as keys in a map that mapped to the object that color represents. So initially with the 1 pixel sampling I used the map immediately to determine the associated object but antialiasing created halfway colors that didn't exist in the map. The 10x10 method solves this problem by looping through the 100 RGB values returned and creating a "counting map." This map uses the stringified colors and maps them to a count, but only includes valid colors from the first map in the count. So you end up with a map saying you counted 65 red pixels and 23 blue pixels (where the remaining 12 pixels were some weird anti-alias hybrid). In the same loop where I was counting the colors I also maintained a variable for current max count and current color associated with that max count (to avoid looping through this new map again). Now at the end you have the color that was counted the most in that 10x10 sampling and can use that to map back to the object associated with it. You will only get an undefined result if no valid colors were found in the 10x10 sample which you can reasonably assume means the "background" was clicked.
I made up the name ghost context! Are you using my old tutorial? :)
In that old tutorial I do not clear the ghost context after each object is drawn to it. In your case, to fix your issue, you may need to clear after testing each object on the ghost context.
Make sure of course that you are translating the ghost context and normal context by precisely the same amounts. (and translating them back, or resetting the transformation, afterwards).

on click get all <area> elements mouse is within based on coords

I'm using the jquery maphilight plugin and have a large number (hundreds) of overlapping elements on my image map. I've noticed that when hovering over the image map, maphilight will highlight the first element it finds for those coordinates, so overlapping can become an issue.
I'm looking to be able to click the image map somewhere and have maphilight (or an external function) return me an array of all the elements not just the first one.
Open to any ideas on how to go about this.
EDIT: To simplify, when I click a point I'm looking for maphilight to get the area (as it already does), but then add that to an array and continue looking for other areas from the same coordinates. Not just return me the first area it finds and stop.
You may need to look into vectors. Using normal elements/divs/images is to complicated. Here a great example of this, Using jQuery, they created a word map http://jvectormap.com/ they make a fully interactive map. Another great example is svg but this can be quite complex http://keith-wood.name/svg.html
Hope this help's you go in the right direction.

Categories

Resources