Dibujar SVG en Canvas y manipular elementos dibujados usando sus ID

Tengo un file SVG cargado en una label <object> . Estoy usando javascript para manipular algunos elementos dentro de esta svg. Por ejemplo:

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

Esto funciona a la perfección y todo estaba bien. Pero me pregunto si se puede hacer lo mismo con el canvas. También he leído sobre cinética js, fabric js, canvg js, y vi los diversos methods para cargar el file svg en el canvas, ya sea por el directory de files, el xml o mediante una image.

Pero después de dibujar este file svg en el canvas, ¿puedo manipular los elementos por sus ID?

El SVG se crea con Adove Illustrator, y cada capa o grupo recibe una identificación con acceso a ella mediante selectores CSS. De nuevo, ¿puede hacerse esto en canvas después de dibujar el SVG en él? (Tenga en count que el SVG es enorme y la única razón por la que estoy pensando en la solución de canvas es porque el svg no muestra el efecto multiplicador del ilustrador para crear una sombra)

Cualquier ayuda será muy apreciada. Gracias.

Fragmento de código:

 <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> 

Como puede ver en el fragment xml después de exportar el file desde adobe illustrator, cada grupo se configura con una ID. ¿Cómo se pueden conservar estos en canvas como objects (como sugiere Fabrics.js utilizando el método getObjects ())? ¿Hay una manera de lograr esto? En caso afirmativo, ¿cómo puedo hacer reference a estos grupos? Además, la sombra es una cuestión key y no quiero usar flash. Gracias

He aquí cómo hacer esto con 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'); } 

El código debería ser bastante autoexplicativo. Cargamos SVG; La tela lo analiza internamente, escupiendo un set de objects que representan cada elemento. Luego agrupamos esos elementos y los agregamos al canvas en un solo trozo. Reviver es responsable de leer id de cada elemento SVG y asignarlo a la instancia de fabric correspondiente.

Ejecute este fragment en http://fabricjs.com/kitchensink/ y obtendrá:

svg cargado

Examinemos este object agrupado:

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

Y sus hijos:

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

Vamos a recuperar uno por id:

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

Esto es todo un viejo Javascript, como puedes ver. Cambiemos el color de ese object / forma particular ahora:

 greenland.fill = 'networking'; 

Groenlandia en rojo

<canvas> opera en píxeles, no tiene el concepto de objects / elementos como SVG. Así que para manupular la image necesitaría manipular el SVG subyacente y volver a renderizarlo en el canvas después de cada cambio.

Puedes poner una image SVG en <canvas> usando el método .drawImage .

 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'; 

Pero no puedes manipular el SVG creado de esta manera. Para ello, intente convertir un elemento <svg> DOM en una cadena codificada en base46, configúrelo como una fuente de una image y luego renderice en el canvas.

Entonces, en el ejemplo anterior en lugar de img.src = 'file.svg' necesitarías

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

Solo algunos pensamientos random sobre su situación

Si bien el canvas html tiene algunos modos de composition, el canvas no tiene una combinación de imágenes múltiples.

Sin embargo, ¡Firefox sí! Es una extensión de mezcla múltiple para composition:

 ctx.globalCompositeOperation = 'multiply'; 

Las principales bibliotecas de canvass que tienen traductores de SVG -> Canvas son FabricJS y KineticJS, pero ninguno de ellos ha implementado este filter de multiplicación todavía. De los dos, FabricJS es más capaz de SVG en este momento y veo que Kangax (el creador de FabricJS) ha comentado tu publicación. Puede preguntarle muy amablemente si agregará un filter múltiple;)

Como parece que tiene acceso a Adobe Illustrator, puede probar el impresionante SVG -> Canvas traductor de Mike Swanson. No sé si maneja los filters de image, pero hace un trabajo impresionante al tomar SVG de Adobe Illustrator estándar y crear dibujos de Canvas (aplicación muy impresionante, si me preguntas): http://blog.mikeswanson.com/post / 29634279264 / ai2canvas

Pensando dentro de SVG, debería verificar la biblioteca de SVGJS:

SVGJS es una biblioteca SVG que le permite manipular elementos SVG por ID.

https://svgdotjs.github.io/

También hay una extensión que importa desde Illustrator:

https://svgdotjs.github.io/importing-exporting/

Y, finalmente, SVGJS también tiene una extensión que hace un filter de image oscura (no multiplicado, pero cerrado)

https://svgdotjs.github.io/plugins/svg-filter-js/

Si te desesperas … (¡Es poco probable que te desesperes!)

Puede "hacer rodar su propio" filter múltiple al tomar los píxeles del canvas con context.getImageData y luego ejecutar esta function en cada uno de los elementos r, g, b de los píxeles que desea multiplicar.

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

¡Buena suerte!

Si usa un marco como cinético, entonces puede acceder y manipular capas y objects por sus identificadores o nombres.