How can I draw a "transparent stroke" with Raphael.js - javascript

I am attempting to draw the path of a graph so that the path is transparent and the rest of the canvas is not. This way I can use the canvas as a mask and fill the path with different colors using html elements. Kind of like this:

There's no way to achieve this natively through Raphael, but it could be accomplished by some selective modification of the SVG produced by Raphael. Consider the use of a mask applied to the path. This technique is used to absolutely delicious visual effect here.
Don't forget that you can access the DOM node associated with a Raphael paper object through that paper object's canvas property (I don't know why Baranovskiy chose such a misleading name!). You could use this to interact directly with the SVG in the DOM, though I can't vouch for interactions between Raphael and custom modifications =)

To fill only the outer part of a path, you will have to draw what is often called a "donut" made of two path strings.
You will find a good example here : How to achieve 'donut holes' with paths in Raphael .
The idea is:
* give the outer path string as a large counter clockwise closed rectangle, telling the browser that what has to be filled is what is inside
* concat the inner path string as the clockwise closed path you want, telling the browser what has to be filled is what is outside.
Thus resulting in a filled shape with a hole which is the intersection of both filled shapes.

Related

Triangulate path data from OpenType.js using Earcut

I have a use case where I need to render a significant amount (~50,000 glyphs) of crisp, scalable text strings on a canvas element. The best solution I've tried so far involves triangulating text drawn on a canvas element (Text was drawn using fillText method), uploading matrix uniforms and the Float32Array of triangles representing that string to the GPU via WebGL. Using this method, I was able to render 100,000 glyphs at about 30fps. Glyphs become blocky at very high zoom levels, but that is fine for my use case.
However, this method has overhead of about ~250ms per string, since I first draw the string to a canvas element in memory, read pixel data, turn the bitmap image into a vector and then triangulate the vector data. Searching the web for solutions, I came across two interesting open-source projects:
OpenType.js: https://opentype.js.org/
Earcut: https://github.com/mapbox/earcut
So now I want to re-write my initial proof of concept to use OpenType and Earcut. OpenType for feeding curve data into Earcut, and Earcut for triangulating that data and returning an array representing the point for each triangle.
My problem is, I can't figure out how to get the data OpenType provides and convert it into the format that Earcut accepts. Can anyone provide assistance for this?
More Info:
This StackOverflow question had some great information, but lacks some of the implementation details: Better Quality Text in WebGL. I suppose what I am trying to accomplish is the "Font as Geometry" approach described in the first answer.
You can create a path using Font.getPath. Path consists of move-to, line-to, curve-to, quad-to and close instructions, accessed via path.commands. You will need to convert bezier curve instructions into small segments first, of course.
Once you have a set of closed paths, you need to determine which ones are holes. Inner outlines will be oriented in an opposite direction to outer ones, and you can assign them to the smallest outer outline containing them. Once you have groups of <outer outline and a set of holes> you should be able to feed it to earcut library.
This is a simple implementation that assumes there are no intersections. For me it worked very well for most fonts, except for very few "fancy" fonts that have intersecting paths.
Here's a working example: https://jsbin.com/gecakub/edit?html,js,output
Instead of creating meshes for each string, you could also create them for individual characters, and then position them yourself using kerning data from the library.
Edit: this solution will only work for TTF fonts, though it can be easily adjusted for CCF (.otf) by ignoring path orientation and using a better "path A is inside path B" check, unless the font has intersecting paths.

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.

clip-path in Raphaël.js

How can I use clip-path with Raphaël.js like this example. It seams that Raphael.js has only clip-rect in it.
You can cut a hole through a path drawn shape.
This is a technique known as donut holes and you can see an example on my index page
If this looks difficult it is not
See the information database and the technique labelled donut holes
My site index is
http://www.irunmywebsite.com/
Err it used to be.
Now you can find a multiple clip path (Imagine seeing a view through several holes}
The carousel and the thumbnail holder are just one path...
See the Raphael Crousel
A much better example I include below. The central blue region has several holes cut into it. This has multi purpose usage.
It is part of what I call a DOM / SVG hybrid solution.
Cut multi purpose holes for a variety of reasons
I don't think you can do it via Raphael. You can do it by manipulating the DOM directly, but you will loose the ability to call Raphael methods for that element.
I find Raphael a bit obsolete, now that IE supports SVG. You can do much more with plain javascript and and the SVG specification.
If, like in the example image, it's a raster image (png, gif, jpg... bitmap pixel images) you are trying to clip, it's actually really easy. In Raphael 2, you just set the fill to point at the image file. It uses it as a background image.
If you want to crop an image or photograph with a Raphael path or shape like a clipping mask or clip-path for image files, just set the image as the path's fill.
somepath.attr({fill: 'someimage.png'});
Limitations (AFAIK):
Only one image per path
Only one path per image (use compound paths for complex masks)
Things like background position aren't easy - see this question for more
I think it's impossible to stop the image repeating

VML alternative to SVG pattern (possibly using Raphael JS)

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.

Choosing right technology (SVG vs Canvas)

I'm writing an app for shape manipulation, such that after creating simple shapes the user can create more complex ones by clipping the shapes against each other (i.e. combining two circles together into a figure 8 stored using a single path rather than a group, or performing intersection of two circles to create a "bite" mark), and am trying to decide on a graphics library to use.
SVG seems to handle 80% of the functionality I need out of the box (shape storage, movement, rotation, scaling). The problem is that the other 20% (using clipping to create a new set of complex polygons) seems impossible to achieve without recreating SVG functionality in my own modules (I'd have to store the shape once for drawing inside SVG, and once for processing clipping myself). I could be wrong about SVG, but by reading about Raphael library (based on SVG), it seems like it only handles clipping using a rectangle, and even that clipping is temporary (it only renders part of the shape, but still stores entire shape to be rerendered once the clipping rectangle is moved). Perhaps I'm just confused about SVG standard, but even retrieving/parsing the paths to compute a new path using subsets of previous paths seems non-obvious in SVG (there is a Subpath() function, but I don't see anything to find the points of intersection of two polygon perimeters, or combine several subpaths into a single path).
As a result, Canvas seems like a better alternative since it doesn't introduce the extra overhead by keeping track of shapes I'd already have to keep track of to make my own clipping implementation work. Not only that, I've already implemented the polygon class that can be moved, rotated, and scaled. Canvas has some other issues, however (I'd have to implement my own redraw method, which I'm sure will not be as efficient as SVG one that takes advantage of browser-specific frameworks in Chrome and Firefox; and I'd have to accept IE incompatibility which is handled for free with libraries like Raphael).
Thanks
This may address what you're mentioning.
Clipping can be done using non-rectangular objects using the 'clipPath' element.
For example, I have element with id of 'clipper' that defines what to clip out, and a path that is subject to the clipping. Not sure if they intersect in this snippet.
<g clip-rule="nonzero">
<clipPath id="clipper">
<ellipse rx="70" ry="95" clip-rule="evenodd"/>
</clipPath>
<!-- stuff to be clipped -->
<path clip-path="url(#clipper)" d="M-100 0 a100 50"/>
</g>
This is just a snippet from something I have. Hope it helps.
Seems to me that you are trying to do 2D constructive geometry. Since SVG runs in retained mode, the objects you draw are stored and then the various operations performed. With Canvas you are running against a bit map so the changes are effected immediately. Since your users will in turn perform more operations on your simpler shapes to create ever more complex ones Canvas should in the long term be a better fit.
The only outstanding question is what will be done with those objects once your users are finished with them. If you zoom the image it will get the jaggies. SVG will avoid that problem but you trade-off with greater complexity and performance impact.
Both svg and canvas are a vector graphical technology.Each one having some different functionality.
Canvas
Canvas is a bitmap with an immediate modegraphics application programming interface (API) for drawing on it. Canvas is a “fire and forget” model that renders its graphics directly to its bitmap and then subsequently has no sense of the shapes that were drawn; only the resulting bitmap stays around.
More Information about canvas - http://www.queryhome.com/51054/about-html5-canvas
SVG
SVG is used to describe Scalable Vector Graphics
SVG is known as a retained mode graphics model persisting in an in-memory model. Analogous to HTML, SVG builds an object model of elements, attributes, and styles. When the element appears in an HTML5 document, it behaves like an inline block and is part of the HTML document tree.
More Information about SVG - http://www.queryhome.com/50869/about-svg-part-1
See here for more information about canvas vs svg in detail - Comparing svg vs canvas
You're right - you'll have to mathematically perform the clipping and creation of new shapes regardless of whether you use SVG or Canvas. I'm biased, it seems like it would be more useful to use SVG since you also get things like DOM events on the shapes (mouse, dragging) and serialization into a graphical format for free.

Categories

Resources