animating path segments of an imported svg in paper.js - javascript

I am trying to use paper.js to animate svgs I designed in Illustrator. Specifically what I am trying to do is import the svg, and then expand and contract the points on the path. Here is an example of moving paths in paper.js: http://paperjs.org/tutorials/paths/working-with-path-items/
What I want eventually is the path to expand based off the width of another object. It will expand if the object is touching it, and contract back to normal if the object is no longer touching it.
I know that to import the svg I use:
project.importSVG(document.getElementById('svg')[, options.expandShapes: true ]);
The option.expandShapes: true, from what I understand expands the shapes to path items.
How do I access the paths of the svg, in order to expand and contract them?
Here is my SVG path :
path fill="#FFD495" d="M456.5,1396.3c-21-31.5-47.7-90.4-45.3-135.6c3.3-62.9,21.3-997.5,15.1-1014.5
c-12.6-34.9-7.8-113.1-100.3-111.6c-107.1,1.8-132.7,6.6-159.4,6.6c-47.9,0-23-91.8-23-91.8s39.6-7.6,107.8-7.6s136.8-22.2,205,30.8
s67.6,52.5,75.2,97.9c5.7,34.3,30.3,1039.4,30.3,1075.1c0,53-22.7,98.4,7.6,98.4c0,0,103.5,134-104,58.3"

Using project.importSVG has actually inserted your SVG paths as Path items in your project.
These are stored in an array as children of the project, accessible by using project.activeLayer.children.
If you do console.log(project.activeLayer.children), you should be able to inspect them in your console.
So now you can access the Path's themselves, second step is to access the Segments of those paths, if you wish to do so.
Segments, are children of Paths so they can be acccessed by Path.segments.
You should read about Project Hierarchy and Path Items

You can't treat it as a path after you import the SVG. But here is a more simple way to achieve your goal.
Just create your SVG as a Path directly in Paper.js via pathData using SVG path syntax.
like this:
pathData = 'M456.5,1396.3c-21-31.5-47.7-90.4-45.3-135.6c3.3-62.9,21.3-997.5,15.1-1014.5c-12.6-34.9-7.8-113.1-100.3-111.6c-107.1,1.8-132.7,6.6-159.4,6.6c-47.9,0-23-91.8-23-91.8s39.6-7.6,107.8-7.6s136.8-22.2,205,30.8s67.6,52.5,75.2,97.9c5.7,34.3,30.3,1039.4,30.3,1075.1c0,53-22.7,98.4,7.6,98.4c0,0,103.5,134-104,58.3';
var path = new Path(pathData);
path.strokeColor = 'red';
path.strokeWidth = 10;
see the result in Paper.js Sketch
And then you can animate this path.

Related

Unable to programmatically create a clipping mask in Illustrator with Extendscript

I am having trouble creating a clipping mask in Illustrator using ExtendScript, the problem is that im trying to create it by using compound path item.
In adobe illustrator i can group the compound path item with the background and press "Create new mask" and every thing works, but i cant do it programatically
If i use a path item (not compound path) and the next code:
newGroup1.clipped = true;
It works, but if i sustitute the path item for a compund path item, it doesnt work.
The code:
app.activeDocument.newGroup1.selected = true;
app.executeMenuCommand("makeMask");
With simple compound path items, it work, but with complex compound path items i get a message box that said that the paths are so complex and it could affect the preview. After i press ok it works, but this message box does not allow me to do a batch process.
Is there any way to programatically create clipping mask by using complex compound path items??
If I understand you correctly, your setup basically works, the only problem are the message boxes.
However, those can be supressed in a script by setting the app's userInteractionLevel:
app.userInteractionLevel = UserInteractionLevel.DONTDISPLAYALERTS;
If you do this, it's usually good practice to save the initial userInteractionLevel at the beginning of the script and then in the end, reset it to its initial value:
myUserInteractionLevel = app.userInteractionLevel;
app.userInteractionLevel = UserInteractionLevel.DONTDISPLAYALERTS;
// then do all your stuff
// and in the end, reset:
app.userInteractionLevel = myUserInteractionLevel;

Can't properly import SVGs to canvas

I'm having problems to import SVGs to the canvas and using setZoom() with the FabricJS. I'm using version "2.0.0.rc4".
I've been trying to import them using two methods, but each one has different problems:
1- loadSVGFromURL
fabric.loadSVGFromURL(src, function(objects, options) {
let loadedObjects = new fabric.Group(group);
var obj = fabric.util.groupSVGElements(objects, options);
canvas.add(obj).renderAll();
});
With this method some SVGs load incorrectly on the canvas, but the zoom works perfectly.
loadSVGFromURL loads the SVG incorrectly
2- new fabric.Image
const image = new Image();
image.crossOrigin = "Anonymous";
image.src = src;
let imageObject;
image.onload = () => {
imageObject = new fabric.Image(image, {
scaleY: 1,
scaleX: 1,
cropX: 0,
cropY: 0,
lockUniScaling: true,
crossOrigin: 'Anonymous'
});
}
With this method every SVG is correctly imported, but when I try to use the zoom in my app, the shapes of the SVG inside the viewbox (container) adjust their size independently, like it's being masked, cropped or clipped. I guess is something related to the preserveAspectRatio property, but I can't make it work.
This is the method I'm using for setting the zoom. The method works correctly for the canvas and other objects, except the SVGs imported with the method previously described.
setCanvasZoom(value) {
// value is from 10 to 500.
// the zoomFactor will result in an integer from 0.1 to 5
let zoomFactor = parseInt(value, 10) / 100;
this.canvas.setZoom(zoomFactor);
this.canvas.setWidth(this.templateDimensions.width * zoomFactor);
this.canvas.setHeight(this.templateDimensions.height * zoomFactor);
this.canvas.renderAll();
}
The shapes are adjusted independently to the container
Am I doing something wrong using the first method to import SVGs? I tried optimizing the SVGs with svgo and also edit them in Illustrator but with no success (in fabricjs/kitchensink loads incorrectly as well).
Does exists a way to lock the SVGs inside the container, using the second method? Should I use another method to set the zoom?
I'd really appreciate any help with these issues.
there was indeed a bug in circle and ellipse parsing at the time of writing this question. circles were inheriting width and height from the svg document overriding radius value and displacing them.
The bug has been fixed here,
https://github.com/kangax/fabric.js/pull/4637/files#diff-35fc8e842fb0e1e1953d9ba21a292160R189
the bug has been introduced between rc3 and rc4 but now you can import the path normally without preprocessing the SVG, provided you download last version.
The problem was with the SVGs files, the circle tags were imported incorrectly to the FabricJS canvas, placing the objects in other places, even outside the original viewBox.
I tested both versions of the SVG in FabricJS Kitchensink:
Screenshot with the differences between SVG imported with <circle> tags and <circle> tags converted to <paths>
I used svgo to process all the SVGs files with the option of convertShapeToPath included and the parameter convertArcs set as true.
{
"plugins": [
{"convertShapeToPath": {"convertArcs": true}},
]
}
It's also possible to convert the primitive shapes to paths in Illustrator selecting the object and making a compound path of it (menu Object > Compound path > Create or just cmd ⌘ + 8).
I couldn't find an issue on GitHub or Stack Overflow about this problem, so I really hope this solution could help others facing the same problem.
Thank you very much to the developers and maintainers of FabricJS for the amazing work!
Gists of SVGs files:
SVG with <circle> tags
SVG with <circle> tags converted to <path>

Setting connector (edge) points in mxgraph

I'm trying to import a diagram in our custom format to mxgraph, but am stuck on setting the points on the connector. I've tried called the functions in mxEdgeStyle like ElbowConnector:
ElbowConnector(view.getState(edge), model.getSource(edge), model.getTarget(edge), points)
where points is the array of point I want to set. I get the feeling I'm calling entirely the wrong function, or am I using it incorrectly?
The edge styles are style like the other key/value styles. In the link you provide to the API specifications, the top example tells you how to use it:
var style = stylesheet.getDefaultEdgeStyle();
style[mxConstants.STYLE_EDGE] = mxEdgeStyle.ElbowConnector;

Using SVG path syntax in paper.js?

With the raphael.js library, paths are described using the SVG path syntax, (e.g. M98.36,214.208l2.186-1.093V210.2l-3.378,0.117l1.174,4.137L98.36,214.208z, which provides a very compact way to create a shape (especially if your shape is drawn with an external application such as Illustrator).
I'm interested in using the paper.js library (not SVG-based), but a first look at the documentation seems to show that paths are built step by step through object methods. This is a very different approach ("path building" vs "path description", one could say), not very suitable to my needs.
So: is there a way to use SVG Paths in paper.js? Or a similar "path description" solution?
Reference:
http://paperjs.org/reference/path
http://raphaeljs.com/reference.html#Paper.path
You can use SVG path syntax as described in the Paper.js reference for pathData
var pathData = 'M98.36,214.208l2.186-1.093V210.2l-3.378,0.117l1.174,4.137L98.36,214.208z';
var path = new Path(pathData);
path.strokeColor = 'black';
// Scale the copy by 1000%, so we see something
path.scale(10);
And here as an example as a Paper.js Sketch

html5 canvas - Saving paths or clip areas to reuse

I'm currently implementing a 2d deformable terrain effect in a game I'm working on and its going alright but I can envision it becoming a performance hog very fast as I start to add more layers to the effect.
Now what I'm looking for is a way to possibly save a path, or clipping mask or similar instead of having to store each point of the path in the terrain that i need to draw through each frame. And as I add more layers I will have to iterate over the path more and more which could contain thousands of points.
Some very simple code to demonstrate what I'm currently doing
for (var i = 0; i < aMousePoints.length; i++)
{
cRenderContext.save();
cRenderContext.beginPath();
var cMousePoint = aMousePoints[i];
cRenderContext.arc(cMousePoint.x, cMousePoint.y, 30, 0, 2 * Math.PI, false);
cRenderContext.clip();
cRenderContext.drawImage(cImg, 0, 0);
cRenderContext.closePath();
cRenderContext.restore();
}
Basically I'm after an effecient way to draw my clipping mask for my image over and over each frame
Notice how your clipping region stays exactly the same except for its x/y location. This is a big plus.
The clipping region is one of the things that is saved and restored with context.save() and context.restore() so it is possible to save it that way (in other words defining it only once). When you want to place it, you will use ctx.translate() instead of arc's x,y.
But it is probably more efficient to do it a second way:
Have an in-memory canvas (never added to the DOM or shown on the page) that is solely for containing the clipping region and is the size of the clipping region
Apply the clipping region to this in-memory canvas, and then draw the image onto this canvas.
Then use drawImage with the in-memory canvas onto your game context. In other words: cRenderContext.drawImage(in-memory-canvas, x, y); where x and y are the appropriate location.
So this way the clipping region always stays in the same place and is only ever drawn once. The image is moved on the clipping-canvas and then drawn to look correct, and then the in-memory canvas is drawn to your main canvas. It should be much faster that way, as calls to drawImage are far faster than creating and drawing paths.
As a separate performance consideration, don't call save and restore unless you have to. They do take time and they are unnecessary in your loop above.
If your code is open-source, let me know and I'll take a look at it performance-wise in general if you want.
Why not have one canvas for the foreground and one canvas for the background? Like the following demo
Foreground/Background Demo (I may of went a little overboard making the demo :? I love messing with JS/canvas.
But basically the foreground canvas is transparent besides the content, so it acts like a mask over the background canvas.
It looks like it is now possible with a new path2D object.
The new Path2D API (available from Firefox 31+) lets you store paths, which simplifies your canvas drawing code and makes it run faster. The constructor provides three ways to create a Path2D object:
new Path2D(); // empty path object
new Path2D(path); // copy from another path
new Path2D(d); // path from from SVG path data
The third version, which takes SVG path data to construct, is especially handy. You can now re-use your SVG paths to draw the same shapes directly on a canvas as well:
var p = new Path2D("M10 10 h 80 v 80 h -80 Z");
Information is taken from Mozilla official site.

Categories

Resources