Drawing SVGs on canvas and managing drawn elements using their identifiers

I have an SVG file loaded in an <object> . I use javascript to control some elements in this svg. For instance:

 var theSvgXml = document.getElementById('theObject').contentDocument; theSvgXml.getElementById('theElementId').style.display = 'inline'; theSvgXml.getElementById('theElementId').style.fill = 'red'; theSvgXml.getElementById('anotherElement').style.display = 'none'; 

It works fine and everything was fine. But I wonder if the same can be done with the canvas. I read about kinetic js, java js, canvg js, and I saw various methods for loading an SVG file into the canvas with either the file directory, or xml, or through the image.

But after drawing this svg file on canvas, can I manipulate elements by their identifiers?

SVG is created using Adove Illustrator, and each layer or group is assigned an identifier that can be accessed using css selectors. Again, is it possible to do this in the canvas after drawing the SVG on it. (Note that SVG is HUGE, and the only reason I think of a canvas solution is because svg does not show the effect of illustrator multiplication to create a shadow)

Any help would be greatly appreciated. Thanks.

Code snippet:

 <g id="Pockets"> <g id="Pen__x26__Radio_Arm_Pocket" class="st791"> … </g> <g id="Pen_Pocket_Arm" class="st791"> … </g> <g id="Card_Zipper_Arm_Pocket" class="st791"> … </g> <g id="Radio_Pocket_Arm_Pocket" class="st791"> … </g> <g id="Angled_Chest_Pocket_Right" class="st791"> … </g> <g id="Angled_Chest_Pocket_Left" class="st791"> … </g> <g id="Angled_Chest_Pocket_left_and_Right" class="st791"> … </g> <g id="Chest_Pocket_Right" class="st791"> … </g> <g id="Chest_Pocket_Left" class="st791"> … </g> <g id="Chest_Pocket_left_and_Right" class="st791"> … </g> <g id="Tool_Pocket" class="st791"> … </g> <g id="Cargo_x2F_Mobile_Pocket_Velcro" class="st791"> … </g> <g id="Cargo_x2F_Mobile_Pocket_Zip" class="st791"> … </g> <g id="Cargo_x2F_Mobile_Pocket_Button" class="st791"> … </g> <g id="Cargo_Pocket_Velcro" class="st791"> … </g> <g id="Cargo_Pocket_Button" class="st791"> … </g> <g id="Cargo_Pocket_Zip" class="st791"> … </g> <g id="Back_Pocket_Right_Velcro" class="st791"> … </g> <g id="Back_Pocket_left_Velcro" class="st791"> … </g> <g id="Back_Pocket_left_and_Right_Velcro" class="st791"> … </g> <g id="Back_Pocket_Right_Velcro_Button" class="st791"> … </g> <g id="Back_Pocket_left_Velcro_Button" class="st791"> … </g> <g id="Back_Pocket_left_and_Right_Button" class="st791"> … </g> <g id="Back_Pocket_Right_Zip" class="st791"> … </g> <g id="Back_Pocket_left_Zip" class="st791"> … </g> <g id="Back_Pocket_left_and_Right_Zip" class="st791"> … </g> </g> 

As you can see the form of the xml fragment after exporting the file from Adobe Illustrator, each group is configured with an identifier. How to save them to canvas as objects (as Fabrics.js suggests using the getObjects () method)? Is there any way to achieve this? If so, how can I refer to these groups? Also, shadow is a key issue, and I don't want to use flash. Thanks

+6
source share
4 answers

Here's how to do it with Fabric:

 fabric.loadSVGFromURL('/assets/72.svg', function(objects, options){ var group = fabric.util.groupSVGElements(objects, options); group .set({ left: 300, top: 200 }) .scaleToWidth(500) .setCoords(); canvas.add(group); }, reviver); function reviver(element, object) { object.id = element.getAttribute('id'); } 

The code should be pretty straightforward. We load SVG; The fabric analyzes it internally, spitting out a multitude of objects representing each element. Then we group these elements and add them to the canvas in one piece. Reviver is responsible for reading the id from each SVG element and assigning it to the corresponding instance.

Run this snippet at http://fabricjs.com/kitchensink/ and you will get:

loaded svg

Inspect this grouped object:

 canvas.item(0) + ''; "#<fabric.PathGroup (29303): { top: 200, left: 300 }>" 

And his children:

 canvas.item(0).getObjects(); // Array[2287] 

Lets get one by id:

 var greenland = canvas.item(0).getObjects().filter(function(obj) { return obj.id === 'path4206'; })[0]; 

This is all plain old Javascript, as you can see. Now change the color of this particular object / form:

 greenland.fill = 'red'; 

greenland in red

+8
source

<canvas> works with pixels, it has no concept of objects / elements such as SVG. Thus, to change the image that you need, to manipulate the underlying SVG and re-display it on the canvas after each change.

You can place an SVG image on <canvas> using the .drawImage method.

 var cvs = document.createElement('canvas'), ctx = cvs.getContext('2d'); cvs.width = 600; cvs.height = 300; document.body.appendChild(cvs); var img = new Image(); img.width = '600'; img.height = '300'; img.onload = function(){ ctx.drawImage(img,0,0); } img.src = 'file.svg'; 

But you cannot manipulate the SVG created in this way. To do this, you should try to convert the <svg> DOM do base46 element to an encoding, set it as the image source, and then display it on the canvas.

So, in the above example, instead of img.src = 'file.svg' you will need

 img.src = 'data:image/svg+xml;base64,' + btoa( document.getElementById('mySvgElement').outerHTML ); 
+1
source

Just some random thoughts about your situation.

While html canvas has several layout modes, the canvas does not have a mixed image.

However, Firefox does! This is a multiplication extension for the layout:

 ctx.globalCompositeOperation = 'multiply'; 

The main canvas libraries that have SVG β†’ Canvas translators have FabricJS and KineticJS, but not one of them has implemented this multiplier filter yet. Of the two, FabricJS is larger than SVG capable at this point, and I see that Kangax (creator of FabricJS) commented on your post. You could ask him really nicely if he added a multiple filter;)

Since you have access to Adobe Illustrator, you can try Mike Swanson's impressive SVG β†’ Canvas translator. I don’t know if it handles image filters, but it does an impressive job of accepting standard Adobe Illustrator SVG files and creating Canvas drawings (a very impressive application if you ask me!): Http://blog.mikeswanson.com/post/29634279264 / ai2canvas

Thinking inside SVG - you should check out the SVGJS library:

SVGJS is an SVG library that allows you to manage SVG elements by identifier.

https://svgdotjs.imtqy.com/

There is also an extension that imports from Illustrator:

https://svgdotjs.imtqy.com/importing-exporting/

And finally, SVGJS also has an extension that performs a dark image filter (not multiplying, but closing)

https://svgdotjs.imtqy.com/plugins/svg-filter-js/

If you despair ... (you are unlikely to get despair!)

You can "roll up your own" multiple filter by capturing canvas pixels with context.getImageData and then run this function for each of the r, g, b pixels you want to propagate.

 function multiply(top, bottom){ return(top*bottom/255; } 

Good luck

+1
source

If you use a framework such as kinetics, you can access and manage layers and objects by their identifier or names.

0
source

Source: https://habr.com/ru/post/953620/


All Articles