How to draw a bezier line between two DOM elements - javascript

How can I draw a Bezier Line between two non-static DOM elements, like this:
The two lines should be drawn between the
<div class="brick small">Line starts here</div>
and the
<div class="brick small">Line ends here</div>
of this CodePen: https://codepen.io/anon/pen/XeamWe
Note that the boxes can be dragged. If one of the elements changes its position, the line should be updated accordingly.
If I'm not wrong I can't use a canvas, right? What can I use instead?

Let me point you toward the answer I beleve you're looking for, it's a dom element type called 'SVG' which is supported by most if not all web browsers of today (so you won't need to plug in anything external), in which you can draw lines, shapes, apply graphical filters much like in Photoshop and many other useful things, but the one to be pointed out here is the so called 'path', a shape that can consist of both straight lines with sharp corners, or curved lines (bezier) or both combined.
The easiest way to create such paths is to first draw them in for example Illustrator, save the shape in the SVG format, open that file in a text editor and pretty much just copy the generated markup code and paste it into your html, as it is supported there. This will result in the drawn shape to be displayed on your site. But in your case, you won't come around the a little bit complex structuring of the paths, because you wish to have control of it using javascript, so I would suggest first making a few simple paths in this way by exporting from Illustrator, study these in code, then manipulate their bezier values in javascript until you get the hang of how they work, once you've done that you will be able to create the accurate bezier shape you have in mind and (knowing the positions of the elements you want to connect) position them so that they connect your boxes.
Paths can even be decorated with markers, like an arrowhead in the end or beginning of the path, you can even design your own markers as you like them to look and much more if you would dig deeper into it.
Good luck! :)

Related

D3 map SVG performance

I've been struggling the past few days to optimize performance on a D3 map, especially on mobile. I am using SVG transforms for zooming and panning but made the following observation: the overkill comes from path strokes used to fake spacing between countries.
I have uploaded a pair of sample maps for comparison:
http://www.nicksotiriadis.gr/d3/d3-map-1.html
http://www.nicksotiriadis.gr/d3/d3-map-2.html
The only difference between the two maps is the stroke path along the country paths, and the difference in performance is even noticeable on desktop devices - but more obvious on mobile. Removing the path strokes makes mobile performance a breeze..
I tried all kinds of svg stroke shape-rendering options without significant results.
Now to the question. Is there any way to remove a thin border from each country to fake the spacing between countries instead of using a stroke?
If anyone else has a different suggestion I'd love to hear it!
Update: Attaching explanation photo.
What I have drawn is this. The red arrow points to the country joints. When adding a stroke in a color same as the background to the country paths (here depicted in dark grey color) it creates the sense that the countries are seprated - however this adds a serious performance hit on mobile devices. What I am looking for is somehow re-shape the countries paths so that their borderlines are where the blue arrow points, but without having a stroke.
Update 2: People seem not to be able to understand what I am looking for, so I am updating this in order to make the question even clearer.
Let's assume that the original countries paths are shown on the left of this image. What I am looking for is a way that I can somehow 'contract' the paths inwards so that the newly created paths shown in red, leave enough empty space between them that will 'emulate' a stroke between them.
Doing this, will leave no use to having an extra layer of strokes, thus gain performance from only using paths instead of paths+strokes.
Update 2: Hello again, I seem to have found a half-solution to my problem. I managed to extract the topojson to shapefile, edit the shapefile the way I want (used a program named OpenJump), but the conversion takes away all the topojson properties I need - id, country name, so I can't convert back to the original topojson.
Does anyone have any suggestions?
D3 has a thing just for that: topojson.mesh() (see documentation). The idea is that since most countries share borders, there's no need to draw the shared borders twice. If you can draw each border only once, you get as much as 80% reduction in the number of strokes you have to draw. The mesh method does the javascript processing to turn a bunch of closed shapes (countries) into the multiline path of just the borders between them. You can then draw that multiline path into a single <path> object that you position on top of the fills.
The mesh looks like this.
Here's another example.
Finally found the answer. This radically improves d3 map performance!
1) I got my topojson file and extracted to shapefile using mapshaper.org. This gives 3 files: .shp, .shx, .dbf . From what I realized the .dbf file holds all the TopoJSON properties/attributes.
2) Opened the .shp shape file to OpenJUMP http://www.openjump.org/ - Which automatically imports the .dbf file as well.
3) I selected the countries layer and went to Tools > Analysis > Buffer.
4) Checked the Update geometry in source layer box so that the geometry is edited without losing the rest of the attributes/properties and added a negative Fixed Distance -0.1. This shrinked all the country geometries to the result I was looking for.
5) Saved Dataset as ESRI Shapefile
6) Reimported BOTH .shp and .dbf that were produced from OpenJUMP back to mapshaper.org - careful, BOTH files.
7) Exported as TopoJSON. Contains new shape and all original properties/attributes!
The following link has been updated with the new produced map; we have a 'bordered' look without the need of strokes.
http://v7.nicksotiriadis.gr/d3/d3-map-1.html
Compare the performance to this link that has the original shapes + stroke. Please try on mobile to see the performance difference!
http://v7.nicksotiriadis.gr/d3/d3-map-2.html
Also, here is the updated world map TopoJSON file in case someone wants some extra performance! :D
http://v7.nicksotiriadis.gr/d3/js/world-topo-bordered.json
There might be a couple of reasons of this behaviour (on my computer, everything is working fine at the same speed ):
Browser
Which browser do you use ? On Chrome, your exemples are working perfectly.
TopoJson
eg. previous answer.
Animation
You are launching the animation when the page is loading. You might want to add a delay (animation().delay(in ms)). There is also a function in D3: queue(), https://github.com/mbostock/queue which load the data before launching a function.
--
If none of this change your problem, and if you want it to work fine on mobile, you can try to mix D3 and Leaflet (map for mobiles), which is great in term of performance by loading tiles.
One example:
http://bl.ocks.org/zross/6a31f4ef9e778d94c204
Hope it helps

How do I adjust the "depth" of graphics in d3?

I am writing an animation using d3, and I cannot seem to find a way to easily ensure that a graphic always appears "behind" other graphics.
Specifically, I am dealing with lines and circles (imagine a directed graph), and it sort of looks bad to have some of the lines on top of the circles, and others underneath. Is there a way to set the z/depth of certain graphics, in this case my lines, manually? I apologize if this seems google-able, but I attempted typing "graphic depth d3" and other variations and got nothing.
EDIT : Accepted answer works, a more detailed description of the problem can be found here.
SVG doesn't have a z-index property or similar, the elements are drawn in the order in which they appear in the DOM -- elements higher up are drawn behind elements that have been added afterwards.
The easiest way to group elements into layers is to use g elements. So in your example, I would use two g groups, one for the lines and one for the circles. Add the g for the lines first and then all of the lines underneath it. If you then add the circles to the second g that you added afterwards, all circles will always be on top of all lines.

Efficient method to check which polygon a certain located inside

In my JavaScript application I have more than 30+ polygons. They are defined like this:
polygons:[
{name:'xx',bounds:[20,20,60,20,50,40,30,10...],minzoom:0,maxzoom:5},
{name:'yy',bounds:[.....],minzoom:6,maxzoom:8},
........
]
Now given a certain point like [10,10] with zoom 4.
Which is the fast way to check which polygon this point is located inside?
My first thought is iterator the polygons, and to check if the point is inside the polygon.
Then this question came to be a point-in-polygon question which have a lot of answers at stackoverflow.
I just wonder if there is any alternative methods?
Assuming the polygons do not overlap (or that if they do, you're only interested in the top-most polygon), you can employ the "point-in-polygon" solution that involves a canvas:
Create a canvas big enough to hold all your polygons.
Draw each polygon in a different colour, one after the other
Look up what colour the pixel is where the point is located
This will tell you the polygon that's there.
Note that you don't even need them to be human-distinguishable colours, you could literally use #000000, #000001, #000002 and so on, and use the colour's hex code as the index of the polygon.

An old quesition, how to determine a point in a irregular shape?

i'm learning Html5 Canvas for some weeks, but the problem above baffle me a long time.
An irregular shape, possible is a circle, Rect, ellipse, polygon , or a path which constructed by some lines and bezier curve...
I found some algorithm for some shape, like circle, rect, and polygon,but , if i used them in canvas, it will be so complex for those many many shape.
I also view some canvas libary,such as Kinetic.js, paper.js, fabric.js,etc, they all do this work well, but the code of they is so much and blend here to there, so I can't get main point...
but i found,all of them don't use the 'isPointInPath' method to do this work. why? if use this, I can do this work too!
kinetic.js , i knew him use the getImageData to determine, but strange, the imagedata its got is no alpha(alpha is always 255), but the shape its drew is semitransparent, oh no my brain is out of thought.
so i'm here want to know how determine a point is in a irregular shape(possibly it's semitransparent) in canvas, even a think way can help me.
and , is some preblem with the 'isPointInPath' method? thus no one use it?
I see no reason why you can't use the built-in functions:
var isInPath = context.isPointInPath(x, y)
For strokes you can use - strokes are separate as a path can be an open line or you can have stroke widths that expands outside the actual polygon:
var isInStroke = context.isPointInStroke(x, y)
Note that this will only work for the last path (after using beginPath()). If you need to iterate several paths (ie. shapes) you need to re-construct the paths (no need to stroke or fill though). This is perhaps a reason why some don't use it.
Transparency is not an issue as checking paths involves the vectors, not the rendered output of those (color information is not part of the check).
In the future you will be able to use the Path object directly. Currently this is not implemented in any browser which otherwise would make iterating a breeze; so re-constructing last path is the only way for now. As you don't actually have to draw anything when checking, the performance is acceptable unless there are a zillion objects to iterate.

How to create jigsaw puzzle from an image using javascript

I googled it but didn't find a good answer. Specifically, I want to learn:
to slice an image into curved pieces
to create individual objects from those pieces (i assume that i need
this to reassemble)
thanks.
There are several pieces to this puzzle. :)
The first piece is SVG and its Canvas. That's what you'll need to draw, because otherwise you can't make a curved piece out of a picture. Only rectangles are possible with standard HTML/CSS.
The second piece is an algorithm for generating jigsaw pieces from the picture. Google should help you with that if you can't figure one out by yourself (though it doesn't seem very complicated).
The rest should be straightforward.
Added: A quick Google search gave just such a jigsaw engine in the first result. Check out the source of that.
I'll assume the image you want to saw to pieces is a raster image with a resolution that you will use for the puzzle pieces, call that /picture/. Also, I assume you have the edges along which you wish to saw in a second raster image with the same dimensions, call that /raster/. Then your problem amounts to determining all connected areas in the raster. Each pixel of the raster gets annotated with the id of the jigsaw piece it belongs to, initially 'none', -1 or whatever. Then your algorithm scans across all pixels in the raster, skipping pixels that already belong to a piece. For each unassigned piece it executes a flood fill, "coloring" the pixels with the pieces id (e.g. number). In a second scan, after allocating an image for each piece, you add the corresponding pixels of the image to the piece. As part of your first pass you can maintain for each piece id the bounding box. That allows you to allocate the the images for the pieces to their proper dimensions.
You need a suitable convention to deal with border pixels: e.g. border pixels to the right belong to the piece if they have the same x-position, but are above they also belong to the piece.

Categories

Resources