Render javascript in svg - javascript
Adding js snippets to an svg file does render in the browser (Firefox), but when i convert the same file to some output formats (like png or pdf etc.) the javascript parts aren't rendered and don't show in the output files. Below is what i am trying to do (drawing a filled rectangle around a path shape):
<svg width="793.70081" height="1122.51965" version="1.1" id="toplevel"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<rect id="rectG" x="0" y="0" width="50" height="50" fill="yellow" transform="translate(100 200) scale(0.1 -0.1) "/>
<path id="pathG" d="M390.01 151l73 -366c43.3333 10 78.1667 31.3333 104.5 64c26.3333 32.6667 39.5 70.3333 39.5 113c0 52 -18.3333 96.8333 -55 134.5c-36.6667 37.6667 -81.3333 56.5 -134 56.5c-9.33333 0 -18.6667 -0.666667 -28 -2zM472.01 861c-5.33333 32 -10 53 -14 63
c-9.33333 20 -25 30.6667 -47 32s-45 -22.6667 -69 -72c-22.6667 -44.6667 -38.6667 -93.6667 -48 -147c-0.666667 -4 -1 -10 -1 -18c0 -22 2.5 -52 7.5 -90s9.16667 -62.3333 12.5 -73l36 33c13.3333 5.33333 35.3333 30.3333 66 75c39.3333 58 59 113.333 59 166
c0 10.6667 -0.666667 21 -2 31zM351.01 251l-27 141c-10.6667 -8 -31.6667 -29 -63 -63c-31.3333 -34 -55.3333 -61.6667 -72 -83c-66.6667 -86 -100 -164 -100 -234c0 -23.3333 3.33333 -46.6667 10 -70c10 -32.6667 34.6667 -68 74 -106
c57.3333 -54.6667 121.667 -80.6667 193 -78c23.3333 0.666667 48.6667 5.66667 76 15l-76 378c-49.3333 -6.66667 -87.3333 -30.6667 -114 -72c-20 -31.3333 -30.6667 -65.3333 -32 -102c-1.33333 -40 21 -78.3333 67 -115c39.3333 -31.3333 70.3333 -47.3333 93 -48v-10
c-29.3333 3.33333 -63.6667 19 -103 47c-52.6667 37.3333 -84 81.3333 -94 132c-3.33333 15.3333 -5 31 -5 47c0 52 16 98.6667 48 140s73.6667 68.3333 125 81zM401.01 1077c26 0.666667 51.3333 -32.6667 76 -100c21.3333 -58.6667 33.6667 -115.333 37 -170
c4 -64.6667 -5.33333 -129 -28 -193c-29.3333 -82.6667 -77.3333 -150.667 -144 -204l30 -155c18 2.66667 35.3333 4 52 4c82 0 145.667 -31 191 -93c40 -54 58.3333 -117.333 55 -190c-2.66667 -58.6667 -22 -108.167 -58 -148.5s-83.3333 -67.5 -142 -81.5l41 -229
c2 -9.33333 3 -18.6667 3 -28c0 -46 -19.8333 -86.5 -59.5 -121.5s-82.8333 -52.5 -129.5 -52.5c-43.3333 0 -82.6667 18 -118 54c-32.6667 34 -49 69 -49 105c0 30.6667 11.5 57.3333 34.5 80s49.8333 33.6667 80.5 33c28.6667 -0.666667 53.3333 -10.5 74 -29.5
s31.3333 -42.5 32 -70.5c0.666667 -29.3333 -9 -54.8333 -29 -76.5s-45 -32.5 -75 -32.5c-5.33333 0 -10.6667 0.333333 -16 1c32.6667 -30 64.6667 -43.3333 96 -40c20 2 44.6667 13.3333 74 34c42.6667 30.6667 64 70 64 118c0 9.33333 -1 19 -3 29l-39 218
c-18 -4 -51.3333 -6.66667 -100 -8c-94 -2.66667 -176.167 31.5 -246.5 102.5c-70.3333 71 -105.167 155.167 -104.5 252.5c0 53.3333 25 119.333 75 198c36 56.6667 82.3333 116 139 178c46 50.6667 72.3333 77.3333 79 80c-12.6667 30.6667 -25.6667 96.6667 -39 198
c-1.33333 10.6667 -2 22 -2 34c0 65.3333 14.6667 131 44 197c31.3333 70.6667 66.3333 106.333 105 107z" transform="translate(100 200) scale(0.1 -0.1) "/>
<script type="text/javascript"><![CDATA[
var x = document.getElementById("pathG");
bb=x.getBBox();
var rect = document.getElementById("rectG");
rect.setAttribute('x', bb.x);
rect.setAttribute('y', bb.y);
rect.setAttribute('width', bb.width);
rect.setAttribute('height', bb.height);
]]></script>
</svg>
This shows in Firefox:
but in Inkscape, or converting the svg file to pdf or png using commandline tools like rsvg-convert or cairosvg doesn't show the rectangle. Is there a way to achieve this?
Most SVG editors, viewers and convertors presumably do not execute JavaScript in SVG documents; they expect static XML text files. (This applies even for browser if you load such SVG as image or CSS background-image.)
If you have your SVG document displayed in browser (as document, so JS is interpreted and runs), you can then obtain resulting source code from web console using
copy(document.documentElement.outerHTML)
command: it should place SVGs source even with elements and attributes generated by JS. (It will include <script> tags as well, but since they are not needed anymore because their outcome is already present, you can safely remove them. Or you can remove them prior copying with while(x=document.querySelector('script'))x.remove();copy(document.documentElement))
Related
Any downsides to copying svg of React Icons instead of importing the element?
Using React Icons, I imported about 15 icon elements. Then I realized in DevTools that I can simply copy the SVG that the React Icon element produces. I'm mainly concerned about performance and I'm using Webpack to build my React App. With that in mind, I'm wondering what costs the least computing and/or data between the two. I figured using the SVG element is less importing work which may lower the size of the payload a little bit? If it helps to visualize this, I'm wondering if using a React icon like this... <svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 512 512" height="28" width="28" xmlns="http://www.w3.org/2000/svg"><path d="M418.2 177.2c-5.4-1.8-10.8-3.5-16.2-5.1.9-3.7 1.7-7.4 2.5-11.1 12.3-59.6 4.2-107.5-23.1-123.3-26.3-15.1-69.2.6-112.6 38.4-4.3 3.7-8.5 7.6-12.5 11.5-2.7-2.6-5.5-5.2-8.3-7.7-45.5-40.4-91.1-57.4-118.4-41.5-26.2 15.2-34 60.3-23 116.7 1.1 5.6 2.3 11.1 3.7 16.7-6.4 1.8-12.7 3.8-18.6 5.9C38.3 196.2 0 225.4 0 255.6c0 31.2 40.8 62.5 96.3 81.5 4.5 1.5 9 3 13.6 4.3-1.5 6-2.8 11.9-4 18-10.5 55.5-2.3 99.5 23.9 114.6 27 15.6 72.4-.4 116.6-39.1 3.5-3.1 7-6.3 10.5-9.7 4.4 4.3 9 8.4 13.6 12.4 42.8 36.8 85.1 51.7 111.2 36.6 27-15.6 35.8-62.9 24.4-120.5-.9-4.4-1.9-8.9-3-13.5 3.2-.9 6.3-1.9 9.4-2.9 57.7-19.1 99.5-50 99.5-81.7 0-30.3-39.4-59.7-93.8-78.4zM282.9 92.3c37.2-32.4 71.9-45.1 87.7-36 16.9 9.7 23.4 48.9 12.8 100.4-.7 3.4-1.4 6.7-2.3 10-22.2-5-44.7-8.6-67.3-10.6-13-18.6-27.2-36.4-42.6-53.1 3.9-3.7 7.7-7.2 11.7-10.7zM167.2 307.5c5.1 8.7 10.3 17.4 15.8 25.9-15.6-1.7-31.1-4.2-46.4-7.5 4.4-14.4 9.9-29.3 16.3-44.5 4.6 8.8 9.3 17.5 14.3 26.1zm-30.3-120.3c14.4-3.2 29.7-5.8 45.6-7.8-5.3 8.3-10.5 16.8-15.4 25.4-4.9 8.5-9.7 17.2-14.2 26-6.3-14.9-11.6-29.5-16-43.6zm27.4 68.9c6.6-13.8 13.8-27.3 21.4-40.6s15.8-26.2 24.4-38.9c15-1.1 30.3-1.7 45.9-1.7s31 .6 45.9 1.7c8.5 12.6 16.6 25.5 24.3 38.7s14.9 26.7 21.7 40.4c-6.7 13.8-13.9 27.4-21.6 40.8-7.6 13.3-15.7 26.2-24.2 39-14.9 1.1-30.4 1.6-46.1 1.6s-30.9-.5-45.6-1.4c-8.7-12.7-16.9-25.7-24.6-39s-14.8-26.8-21.5-40.6zm180.6 51.2c5.1-8.8 9.9-17.7 14.6-26.7 6.4 14.5 12 29.2 16.9 44.3-15.5 3.5-31.2 6.2-47 8 5.4-8.4 10.5-17 15.5-25.6zm14.4-76.5c-4.7-8.8-9.5-17.6-14.5-26.2-4.9-8.5-10-16.9-15.3-25.2 16.1 2 31.5 4.7 45.9 8-4.6 14.8-10 29.2-16.1 43.4zM256.2 118.3c10.5 11.4 20.4 23.4 29.6 35.8-19.8-.9-39.7-.9-59.5 0 9.8-12.9 19.9-24.9 29.9-35.8zM140.2 57c16.8-9.8 54.1 4.2 93.4 39 2.5 2.2 5 4.6 7.6 7-15.5 16.7-29.8 34.5-42.9 53.1-22.6 2-45 5.5-67.2 10.4-1.3-5.1-2.4-10.3-3.5-15.5-9.4-48.4-3.2-84.9 12.6-94zm-24.5 263.6c-4.2-1.2-8.3-2.5-12.4-3.9-21.3-6.7-45.5-17.3-63-31.2-10.1-7-16.9-17.8-18.8-29.9 0-18.3 31.6-41.7 77.2-57.6 5.7-2 11.5-3.8 17.3-5.5 6.8 21.7 15 43 24.5 63.6-9.6 20.9-17.9 42.5-24.8 64.5zm116.6 98c-16.5 15.1-35.6 27.1-56.4 35.3-11.1 5.3-23.9 5.8-35.3 1.3-15.9-9.2-22.5-44.5-13.5-92 1.1-5.6 2.3-11.2 3.7-16.7 22.4 4.8 45 8.1 67.9 9.8 13.2 18.7 27.7 36.6 43.2 53.4-3.2 3.1-6.4 6.1-9.6 8.9zm24.5-24.3c-10.2-11-20.4-23.2-30.3-36.3 9.6.4 19.5.6 29.5.6 10.3 0 20.4-.2 30.4-.7-9.2 12.7-19.1 24.8-29.6 36.4zm130.7 30c-.9 12.2-6.9 23.6-16.5 31.3-15.9 9.2-49.8-2.8-86.4-34.2-4.2-3.6-8.4-7.5-12.7-11.5 15.3-16.9 29.4-34.8 42.2-53.6 22.9-1.9 45.7-5.4 68.2-10.5 1 4.1 1.9 8.2 2.7 12.2 4.9 21.6 5.7 44.1 2.5 66.3zm18.2-107.5c-2.8.9-5.6 1.8-8.5 2.6-7-21.8-15.6-43.1-25.5-63.8 9.6-20.4 17.7-41.4 24.5-62.9 5.2 1.5 10.2 3.1 15 4.7 46.6 16 79.3 39.8 79.3 58 0 19.6-34.9 44.9-84.8 61.4zm-149.7-15c25.3 0 45.8-20.5 45.8-45.8s-20.5-45.8-45.8-45.8c-25.3 0-45.8 20.5-45.8 45.8s20.5 45.8 45.8 45.8z"></path></svg> will load faster than importing the same icon like this: import {FaReact} from 'react-icons/fa'; const Example = () => { return <FaReact/> }
How to alter SVG-element on a web-page with contebnt from a new file?
I use SVGInject to load svg-images inline: <img src="image1.svg" id="changeme" onload="SVGInject(this)" /> This works like a charm, and the image can be moved, rotated etc. But is it possible to later "change" the image maybe? document.getElementById('changeme').src = 'image2.svg'; SVGInject(document.getElementById('changeme')); This does NOT work. Should the object be reloaded? Or the original destroyed and a new created... cheers
Replacing the svg won't work as svg-inject.js removes the original img element. Thus, document.getElementById('changeme') can't select or replace anything. You might wrap the original SVGInject(el) function in a helper function that's cloning the img element before inlining svg. This way you can replace the img src, remove the previously inlined svg and finally re-inject the changed svg url. /// find and replace all svgs with class name "svg-replace" var svgInjects = document.querySelectorAll('.svg-replace'); if(svgInjects.length){ for(var i=0; i<svgInjects.length; i++){ var svgEl = svgInjects[i]; // modified inject function SVGInjectCloned(svgEl); } } function SVGInjectCloned(svgEl){ var svgCloned = svgEl.cloneNode(true); svgEl.parentNode.appendChild(svgCloned); /// hide original svgEl.setAttribute('style', 'display:none'); // inline svg SVGInject(svgCloned); //console.log('svg inlined'); } function replaceSvg(previousSvgEl, newSvgUrl){ var svgEl = document.querySelector(previousSvgEl); // find and delete previously inlined svg var inlinedSvg = svgEl.nextElementSibling; if(inlinedSvg){ inlinedSvg.remove(); /// make original visible again svgEl.removeAttribute('style'); // update svg src svgEl.src = newSvgUrl; // reclone svg element for inlining var svgCloned = svgEl.cloneNode(true); svgEl.parentNode.appendChild(svgCloned); /// hide original svgEl.setAttribute('style', 'display:none'); SVGInject(svgCloned); } } // example button var newSvgUrl = "data:image/svg+xml,%3Csvg aria-hidden='true' focusable='false' data-prefix='fas' data-icon='user-friends' class='svg-inline--fa fa-user-friends fa-w-20' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 512'%3E%3Cpath fill='currentColor' d='M192 256c61.9 0 112-50.1 112-112S253.9 32 192 32 80 82.1 80 144s50.1 112 112 112zm76.8 32h-8.3c-20.8 10-43.9 16-68.5 16s-47.6-6-68.5-16h-8.3C51.6 288 0 339.6 0 403.2V432c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48v-28.8c0-63.6-51.6-115.2-115.2-115.2zM480 256c53 0 96-43 96-96s-43-96-96-96-96 43-96 96 43 96 96 96zm48 32h-3.8c-13.9 4.8-28.6 8-44.2 8s-30.3-3.2-44.2-8H432c-20.4 0-39.2 5.9-55.7 15.4 24.4 26.3 39.7 61.2 39.7 99.8v38.4c0 2.2-.5 4.3-.6 6.4H592c26.5 0 48-21.5 48-48 0-61.9-50.1-112-112-112z'%3E%3C/path%3E%3C/svg%3E"; var btnSvgReplace = document.querySelector('.btnSvgReplace'); if(btnSvgReplace){ btnSvgReplace.addEventListener('click', function(){ replaceSvg('#firstSvg', newSvgUrl ); }); } img, svg { width:100px; height:100px; } <script src="https://cdn.jsdelivr.net/npm/#iconfu/svg-inject#1.2.3/dist/svg-inject.min.js"></script> <div class="svg-wrp"> <img src="data:image/svg+xml,%0A%3Csvg aria-hidden='true' focusable='false' data-prefix='fas' data-icon='users' class='svg-inline--fa fa-users fa-w-20' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 640 512'%3E%3Cpath fill='currentColor' d='M96 224c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm448 0c35.3 0 64-28.7 64-64s-28.7-64-64-64-64 28.7-64 64 28.7 64 64 64zm32 32h-64c-17.6 0-33.5 7.1-45.1 18.6 40.3 22.1 68.9 62 75.1 109.4h66c17.7 0 32-14.3 32-32v-32c0-35.3-28.7-64-64-64zm-256 0c61.9 0 112-50.1 112-112S381.9 32 320 32 208 82.1 208 144s50.1 112 112 112zm76.8 32h-8.3c-20.8 10-43.9 16-68.5 16s-47.6-6-68.5-16h-8.3C179.6 288 128 339.6 128 403.2V432c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48v-28.8c0-63.6-51.6-115.2-115.2-115.2zm-223.7-13.4C161.5 263.1 145.6 256 128 256H64c-35.3 0-64 28.7-64 64v32c0 17.7 14.3 32 32 32h65.9c6.3-47.4 34.9-87.3 75.2-109.4z'%3E%3C/path%3E%3C/svg%3E" class="svg-replace" id="firstSvg" /> </div> <p><button class="btnSvgReplace">Replace svg</button></p>
Is it possible to create single path SVG for below image?
I was able to create this(however it has the transparent part at the center - want it solid white) "M62,31c0,17.1-13.9,31-31,31S0,48.1,0,31S13.9,0,31,0S62,13.9,62,31z M48.5,43.9L46,44l-7.3-11.3 c-0.5-0.8-1.4-1.2-2.3-1.2L26.7,32l-0.2-2.8l9.6-2.7c0.9-0.3,1.4-1.2,1.2-2.1c-0.2-0.9-1.2-1.4-2.1-1.2l-8.9,2.5L25.9,19 c-0.1-1.4-1.3-2.5-2.7-2.4c-1.4,0.1-2.5,1.3-2.4,2.7l0.9,15.6c0.1,1.4,1.3,2.5,2.7,2.4l10.7-0.6L42.5,48c0.5,0.7,1.3,1.2,2.1,1.2 c0,0,0.1,0,0.1,0l4-0.1c1.4-0.1,2.5-1.2,2.5-2.6C51.1,44.9,49.9,43.8,48.5,43.9z M23.4,6c-2.8,0-5.1,2.3-5.1,5.1s2.3,5.1,5.1,5.1 s5.1-2.3,5.1-5.1S26.2,6,23.4,6z M35.2,42.4c-0.2,5.7-4.8,10.2-10.5,10.2c-5.8,0-10.5-4.7-10.5-10.5c0-3.5,1.8-6.7,4.5-8.6v-3.9 c-4.6,2.3-7.9,7-7.9,12.5c0,7.7,6.2,13.9,13.9,13.9c6.1,0,11.3-4,13.2-9.5L35.2,42.4z" Path 1 result : Later, I was able to extract another path for the center figure, which is: "M40.3,40.3c0.1,1.4-1,2.6-2.5,2.6l-4,0.1c0,0-0.1,0-0.1,0c-0.9,0-1.7-0.4-2.1-1.2l-7.3-11.3l-10.7,0.6 c-1.4,0.1-2.6-1-2.7-2.4L10,13.3c-0.1-1.4,1-2.6,2.4-2.7c1.4-0.1,2.6,1,2.7,2.4l0.4,6.8l8.9-2.5c0.9-0.2,1.8,0.3,2.1,1.2 c0.3,0.9-0.3,1.8-1.2,2.1l-9.6,2.7l0.2,2.8l9.6-0.5c0.9,0,1.8,0.4,2.3,1.2L35.1,38l2.5-0.1C39.1,37.8,40.3,38.9,40.3,40.3z M12.5,10.2c2.8,0,5.1-2.3,5.1-5.1S15.4,0,12.5,0C9.7,0,7.4,2.3,7.4,5.1S9.7,10.2,12.5,10.2z M13.9,46.6c-5.8,0-10.5-4.7-10.5-10.5 c0-3.5,1.8-6.7,4.5-8.6v-3.9C3.2,25.9,0,30.6,0,36.1C0,43.8,6.2,50,13.9,50c6.1,0,11.3-4,13.2-9.5l-2.7-4.1 C24.2,42,19.6,46.6,13.9,46.6z" Path 2 result : Looking for a single path SVG, which creates an exact image like . Thank you in advance.
Haters will say I'm cheating. And they will be absolutely right. <svg width="60" height="60" style="background-color: LightSalmon; border-radius: 100%" viewBox="1 1 60 60" > <path d="M62 31c0 17.1-13.9 31-31 31S0 48.1 0 31 13.9 0 31 0s31 13.9 31 31zM48.5 43.9L46 44l-7.3-11.3c-.5-.8-1.4-1.2-2.3-1.2l-9.7.5-.2-2.8 9.6-2.7c.9-.3 1.4-1.2 1.2-2.1-.2-.9-1.2-1.4-2.1-1.2l-8.9 2.5-.4-6.7c-.1-1.4-1.3-2.5-2.7-2.4-1.4.1-2.5 1.3-2.4 2.7l.9 15.6c.1 1.4 1.3 2.5 2.7 2.4l10.7-.6L42.5 48c.5.7 1.3 1.2 2.1 1.2h.1l4-.1c1.4-.1 2.5-1.2 2.5-2.6-.1-1.6-1.3-2.7-2.7-2.6zM23.4 6c-2.8 0-5.1 2.3-5.1 5.1s2.3 5.1 5.1 5.1 5.1-2.3 5.1-5.1S26.2 6 23.4 6zm11.8 36.4c-.2 5.7-4.8 10.2-10.5 10.2-5.8 0-10.5-4.7-10.5-10.5 0-3.5 1.8-6.7 4.5-8.6v-3.9c-4.6 2.3-7.9 7-7.9 12.5C10.8 49.8 17 56 24.7 56c6.1 0 11.3-4 13.2-9.5l-2.7-4.1z"/> </svg> The real answer is that compound paths in a single <path/> element can only have one style (as the style is defined by the said path).
Not able to click an svg path element using selenium webdriver
I am working on automating charts data and below is how the data is represented. <g style="cursor:pointer;" clip-path="url(#highcharts-2)" transform="translate(62,10) scale(1 1)" class="highcharts-markers highcharts-series-0 highcharts-tracker"> <path d="M 811 367.23566666666665 L 816 372.23566666666665 811 377.23566666666665 806 372.23566666666665 Z" fill="#18abc9"></path> <path d="M 731 400.91344444444445 L 736 405.91344444444445 731 410.91344444444445 726 405.91344444444445 Z" fill="#18abc9"></path> <path d="M 651 386.432 L 656 391.432 651 396.432 646 391.432 Z" fill="#18abc9"></path> <path d="M 570 390.61766666666665 L 575 395.61766666666665 570 400.61766666666665 565 395.61766666666665 Z" fill="#18abc9"></path> <path d="M 490 381.09166666666664 L 495 386.09166666666664 490 391.09166666666664 485 386.09166666666664 Z" fill="#18abc9"> </path><path d="M 410 334.905 L 415 339.905 410 344.905 405 339.905 Z" fill="#18abc9"></path></g> I have written the following Selenium code to click on the first path element. List<WebElement> a = driver.findElements(By.xpath("(//*[name()='svg']//*[name()='path' and contains(#fill, '#090')])[1]")); Actions actionBuilder = new Actions(driver); actionBuilder.click(a.get(0)).build().perform(); The list a has just one webelement received. The program throws error when trying to click. org.openqa.selenium.WebDriverException: Element is not clickable at point (904, 556.86669921875). Other element would receive the click: <path d="M 801 341.00352 L 806 346.00352 801 351.00352 796 346.00352 Z" fill="#090"></path> The path I provided in the error is not exactly the same as the DOM I provided.
The error is due to the fact that another path element is overlapping the path you want to click. I'm guessing that the path is oddly shaped and Selenium is trying to click the middle of it and ends up clicking the other path. You can try moveToElement() in Actions and play with the offsets until you get it right.
Manipulate a path in Snap.svg or redraw it?
For a metaball animation like this one: http://paperjs.org/examples/meta-balls/ I am creating a path in snap.svg that connects two circles. It looks like this: <path d="M171 370 C207, 335, 493 335, 529 370 C493, 335, 493 264, 529 229 C493, 264, 207 264, 171 229 z"></path> What would be better: to redraw the path on each frame or to manipulate it? How can I manipulate the path? (i.e. move the points and control points around) If it were more than two circles, I suppose redrawing would be the way to go.
Just update the d attribute of the path. <path id="p" d="M171 370 C207, 335, 493 335, 529 370 C493, 335, 493 264, 529 229 C493, 264, 207 264, 171 229 z"></path> First Select the path if it is not already stored in a variable: var path = Snap("#p"); Then update: path.attr({ d: newD });