KineticJS - Draw free with mouse - javascript

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).

Related

Make line follow contour of shape

I'm working on a app that is based on vector data and using various boolean operations. For these boolean operation I'm using a library called clipper. Now I need to make a vector operation which I'm not sure how to do in Clipper. I have a straight line consisting of two points that always have to stay inside a closed polygon. What I mean by this is the following image. The green line is the closed polygon and the red line is the straight line. When the red line is outside the green polygon it needs to follow the contour of the green polygon.
I'm not sure how to archive this. Any suggestion on how to do this with clipper or maybe another library will be very helpful!
I don't know clipper, but I've seen examples of this using "dashed lines" around a vector image.
THe method is very simple, however.
Consider that your line is part of a "dashed line" around the border of the image.
To make it appear it only exists one line, the space between each dash has to be at least equal or greater than full_perimeter - dash_size.
In this example, the movement would be generated with an iteration over the offset where the dash is drawn to make it move around the picture.
I hope this helps, or points you in a way to solve this problem :D

Click event handling for draw features in Openlayers 3`

I have implemented the following example from the Openlayers 3 library where you can measure lines and areas.
http://openlayers.org/en/latest/examples/measure.html
Specifically for areas, to complete the shape you can either double click at the last vertex you want to draw, or single click back at the start of the shape when the cursor snaps to the original point.
I have an issue whereby many users are taking their cursor back to the original point and it is snapping, but they are double clicking thinking therefore completing the original shape and inadvertently starting a new one.
How am I able to code this example so that if a double click occurs at the original point, then the shape is completed but a new shape not started?
Thanks
You can set property snapTolerance into 1, it should help:
new ol.interaction.Draw( {
snapTolerance: 1,
...
You still can finish shape with single click, but you have to click exactly in the first point.
I set snapTolerance for myself some time before and people are happy now :).

Move a Box with another on colission respecting the next neighboring mesh in Three.js

Found a lot of physic engines out there but nothing that fit my needs directly.
I try to to find a simple way to push and pull boxes including collision detection which respects the next neighboring mesh hit while moving.
Some use cases to understand:
All boxes except box 1 are moveable.
Push or Pull box 4 to west:
Should move box 3 to west on collision.
Should make box 3 and 4 not able to move west when box 3 hits box 2.
Push 2, 3 or 4 to north:
Should stop when it hits box 2, because box 1 is not movable.
it should not possible to push or pull 2 colliding boxes with a box.
Maybe not the best question... I could write such a logic from scratch but this would end in fairly complex code :) and I wonder if nobody solved something like that before.
Does there exist an easy way to implement such a logic using an existing physic engine or a three.js plugin?
Hope the question is formulated well enough so that anyone can understand it.
Maybe easier If you know the famous boulder dash game.
Possible to move both rocks in both directions.
Impossible to move a rock.
In my case it should be possible to move 2 colliding rocks/cubes but not 3.
So basically you want to make certain objects immovable at various points. You can do this with physi.js. Just increase the mass of the object so it becomes so heavy relative to the other objects that it is immovable.
Pretty simple, it's more about geometry and logic than physics... if I understand your simplified world.
In the case of boulderdash (or also sokoban), where the movement is tiled-based, when you are about to move the character you first check the adjacent tile, in the direction of the movement. It could be walkable or occupied by a movable object (or also a wall). If there's a movable object, then you check the next adjacent tile. If it's walkable then means the movable object it's indeed movable. Otherwise, that movable object is currently not movable.
In a non-tiled scenario like yours seems, you check for collision with a first box and, when this happens, you check the presence of a next colliding box, adding a new colision point the size of the first box, in the direction of the movement.
I just answered a similar question here.
You should use bounding boxes of type THREE.Box3 for this purpose.
You should definitely check this example out. I think it will be very useful for you.

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.

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).

Categories

Resources