Is there a way to convert a stroked path to a shape using javascript? Do any libraries offer this as a build in feature?
I know Illustrator has this function, so a possible solution would be to copy the SVG image on the screen and move it to Illustrator, but if you could do that, would you lose all the associated meta-data stored as attributes?
[I]s there a way to convert a stroked path to a shape using JavaScript?
Yes, there's a way to convert an SVG path stroke into an outlined shape. Unfortunately, it is not a prepackaged function built into SVG. The way to do it is called Math. You'd need to account for bézier curves, miter settings, linecaps, linejoins, and dasharrays. As #inhan noted you might use various functions to help you or to approximate it, but none of them are going to do the math for you. It is possible, but it is not by any means easy…in JavaScript.
[W]ould there be a way to copy the svg image on the screen and move it to Illustrator?
Sure, that's easy.
Open your D3.js SVG-based illustration in a web browser.
Open the Developer Tools (or Firebug).
Find the element you want, right-click and choose "Copy as HTML" or "Copy SVG".
Paste the code into a text editor and wrap it with SVG.
Open the SVG in Illustrator.
Outline the path(s) you want.
Save as SVG
Copy/paste the SVG code Illustrator exported into…wherever you want.
But what does this gain you? Certainly nothing that works with your D3.js visualization.
But if you could do that, would you lose all the associated meta-data stored as attributes?
What are you talking about? If you are talking about attributes in the source code, then you only lose it if you don't copy/paste the attributes onto the result. If you are talking about JavaScript data bound to a visualization running in the web browser, of course you are going to lose the data if you round trip through Adobe Illustrator.
Your questions make so little sense to me that I have a feeling that I must be missing what your needs/goals are. What are you really trying to accomplish?
Using Element.getTotalLength() and Element.getSubpath() functions in Raphaël along with stoke-width and stroke-dasharray attributes of that path in a function would probably give the result.
Related
Frustrated that there is no extension to do something I want I am writing my own. One of the key features I need is to be able to display graphs within vs code itself (graph refers to both a curve and nodes-edges).
In order to accomplish this I learnt about webviews, but that seems overkill. All I need is some very basic draw functionalities (straight line, bezier curve, circle, text).
The minimum I need to be able to do is:
I have code that generates a list of values over time. All the extension needs to do is read the generated txt file and plot the evolution of the values over time. Ideally this happens in the sidebar.
Any tips?
Webviews are the way to go. You can do things like this with them:
See also my antlr4-vscode extension repo
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! :)
I want to retrieve the outline information of font glyphs as bézier paths in HTML5. This would allow me to randomize the outlines:
In Cocoa, I would use appendBezierPathWithGlyph:inFont:. In Java, I would use TextLayout.getOutline(). How does this work in JavaScript?
I discovered that Mozilla has mozPathText but I can't get it to work.
Out of necessity I've created my own library called opentype.js. It parses OpenType, TrueType, PostScript and WOFF fonts.
Here's how it parses a typeface:
Load the .ttf / .otf file using a XMLHttpRequest.
Parse the glyf and loca table to extract the letter shapes (glyphs).
Parse the cmap table which contains the mapping from characters to glyphs.
Parse the head and hmtx table to get the metrics, basically the spacing between each letter.
Then it can create a bézier path:
Convert the letters of the text into glyphs.
Convert the coordinates of the glyph to quadratic curves.
Adjust the spacing using kerning information.
This results in a path that you can draw using the HTML5 canvas:
var font = opentype.parseFont(arrayBuffer);
var path = font.getPath("Hello, World!", {x:0, y:150, fontSize:72});
path.draw(ctx);
The demo website has a live example.
Low-level parsing
In JavaScript you will have to manually parse the typeface file and extract the path data you need. AFAIK there is no helper-library for this at the moment so you are left to do this yourselves.
To parse a file you will also need to upload it manually and parse it as raw data using the new File API and possible typed arrays for binary font formats (ttf).
It's possible to write a very long answer for this as this is rather low-level stuff and to broad to be covered here (IMHO). However, here are the file format specifications for the common font files:
WOFF (recommended)
Embedded OpenType
Open type
Open Font
TrueType
Type 1 (PDF)
But there is another approach you can take as an intermediate step saving you a lot of pain:
Pre-parse
Select the typefaces you want to use. Run them through Java/Cocoa/.NET (WPF) or whatever you prefer and build arrays containing the information you need (for example, WPF gives you the path data for each glyph). Convert them to JavaScript arrays or JSON objects and use those for the render and manipulation. The resulting points will be in em values which are easy to scale.
Now you can simply go through the arrays and render the path segment type (line, bezier etc.) and modify the point positions.
mozPathText is for canvas and just holds the text path (currently Path API is not exposed in any browser, but will in the future - however, it cannot be used for this as the low-level path data per glyph isn't available for many reason, legal reasons possibly being one).
Trace
The third approach is to sort of "OCR" the glyphs on the canvas by tracing each individual glyph and try to build paths from it's traced outline.
This can be done in several way - one way is to parse line by line and group pixels based on distance/connectivity and then iterate through the group/region using neural networks or fill algorithms to find the outer boundaries for the glyph.
Or - you can draw the text as outlines and just trace the connected pixels for each shape and use that as a line path.
In this case you may run into challenges that may seem simple enough but can turn out to not be.
Example: the letter O consist of an outer path and an inner path. The inner path punches a "hole" in the outer path. You cannot define this behavior directly just by defining paths in canvas so you need to add "cuts" between the two paths after you have determined they belong to each other, and then join them at the cuts.
Using different composite modes may help in creating the illusion of such but you will still need to determine which path is the solid part and which will be drawn as the "hole".
Warp/distortion
A final approach is to not use glyph paths at all but just warp the bitmap using interpolation and warp grid (typically used in connection with 3D textures):
http://davis.wpi.edu/~matt/courses/morph/2d.htm
Warping (pdf)
Morphing (pdf)
Define your own fonts/paths (manual trace)
The more obvious option perhaps: define your own font paths from scratch. A bit more work in the area of either making a font designer or by manually tracing an image, or defining the paths manually. A "font-plotter" (using a trace image) is not so complicated but require patience.
You can use a canvas in the browser to record the lines you are plotting and use smoothing algorithms (cardinal spline + knee detection) to get nice round curves and sharp corners.
It all depends on what result you want in the end and how much work you are willing to put down. There is unfortunately no free ticket in this regard as the internal data isn't exposed (and probably won't be in the future either).
With SVG it's possible in some browsers to do the reverse of what you're asking: specify custom font glyphs as bezier paths, and then lay out text using them. You could possibly import an SVG font and then perform your transformations on that. But even though SVG is now widely supported, SVG fonts are not. Only Safari, Chrome, and Opera currently have support for them.
If you want to do these types of transformations with system fonts in a vector way, that's not possible in any browser that I know of. There's simply no API in HTML or SVG to get the outline path of an installed glyph. (Maybe there's something you can use in a plugin like Flash, I haven't checked out their text API for a while.)
If you're okay doing it the raster way, you can use a hidden canvas element to lay out your text in an off screen buffer and then get a pixel map of the result. You can then perform pixel-based transformations on it and draw that into a second, visible canvas element.
In SVG it is possible to define a pattern that can be used as the fill for a path. For an example of what I mean you can check this link: SVG pattern example. Unfortunately SVG is not usable in older versions of Internet Explorer, so I'll have to work with VML there.
To make my life a little more easy I use Raphaël JS (to be more specific, I use the draw package of ExtJS 4.0, which is based on Raphaël), so I don't have to worry about the differences between SVG and VML.
Raphael JS however, does not provide a way to define patterns and use them, so I'll have to do this by hand. In SVG this is not much of a problem, but in VML I cannot find a way to create a pattern and use it as the (repeating) background of a path.
The closest thing I have found is the ability to use an image as the background of a path, as described here on MSDN. The problem is I want to fill the path with a repeating vector image, so I can scale it and still have it look nice.
Any help in pointing me in the right direction for solving this would be greatly appreciated.
Edit: For people visiting my post: I've come to the conclusion that what I describe above is not possible. The only patterning possible in VML is tiling an image, using a fill element. Patterns made of vector shapes are not possible in VML.
I'm using this method:
1- Create a bounding box with path element (not rect) of the path you want to fill.
2- Append "z" and the path string of the path you want to fill to the bounding box path string. This will create a clipped rect.
3- Use javascript for repeating pattern behind the clipped rect.
I need to choose a library for "standard" charting: pies, lines and bars.
From what I've read, it seems to me that the best format is SVG/VML, like Highcharts for example. SVG is becoming standard across all major browsers, now that IE 9 accepts it. It seems easier to rescale and export than Canvas.
Still, I see that several charting libraries rely on Canvas. Am I missing something? Is there any reason for considering Canvas over SVG for such applications?
You can generally achieve the same results with either. Both end up drawing pixels to the screen for the user. The major differentiators are that HTML5 Canvas gives you pixel-level control over the results (both reading and writing), while SVG is a retained-mode graphics API that makes it very easy to handle events or manipulate the artwork with JavaScript or SMIL Animation and have all redrawing taken care of for you.
In general, I'd suggest using HTML5 Canvas if you:
need pixel-level control over effects (e.g. blurring or blending)
have a very large number of data points that will be presented once (and perhaps panned), but are otherwise static
Use SVG if you:
want complex objects drawn on the screen to be associated with events (e.g. move over a data point to see a tooltip)
want the result to print well at high resolution
need to animate the shapes of various graph parts independently
will be including text in your output that you want to be indexed by search engines
want to use XML and/or XSLT to produce the output
Canvas isn't needed unless you want heavy manipulation/animation or are going to have 10,000+ charts. More on performance analysis here.
It is also important to make the distinction: Charting and diagramming are two different things. Displaying a few bar charts is very different from (for instance) making diagramming flowcharts with 10,000+ movable, link-able, potentially-animated objects.
Every SVG element is a DOM element, and adding 10,000 or 100,000 nodes to the DOM causes incredible slowdown. But adding that many elements to Canvas is entirely doable, and can be quite fast.
In case it may have confused you: RaphaelJS (in my opinion the best charting SVG Library) makes use of the word canvas, but that is no way related to the HTML <canvas> element.
In the past two years, my preference has been to use svg, as I mainly deal with relatively small datasets to build pies, column charts or maps.
However one advantage I have found with canvas is the ability to save the chart as an image thanks to the toDataURL method. I haven't found an equivalent for svg, and it seems that the best way to save an svg chart client side is to convert it to canvas first (using for example canvg).