Chushanxiaocao
Chushanxiaocao

Reputation: 11

change of SVG cannot reflected onto PNG

This page displays a SVG having three strokes. Clicking on Save as PNG button will convert the SVG to PNG. This works well.

http://www.holisticedu.us/wechat/three.htm

Clicking on the strokes of the SVG will change the stroke color from back to red. Then clicking on Save as PNG button , the stoke color of the PNG does not change. I have no idea about this. I want that the stroke color of the PNG can also be changed when the stroke color of the SGV was changed.

The following is my code, thank you for any suggestions.

<!DOCTYPE html><html xmlns="http://www.w3.org/2000/svg"     xmlns:xlink="http://www.w3.org/1999/xlink"><head><meta charset="utf-8"/>
<title>three</title>

<script type="text/javascript">

function changeRectColor(evt) {  
evt.target.setAttributeNS(null,"fill","red");
}

</script>

</head><body>



<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="250" height="250" viewBox="0 0 2052 2052">

<def>
<g id="g1" onclick="changeRectColor(evt)" name="三" transform="translate(514 718) matrix(1 0 0 -1 0 616)">
<path name="1.1" onclick="changeRectColor(evt)" d="M677 619Q699 619 733 602Q756 592 756 577Q756 566 726 559Q691 548 572 530Q390 505 335 505Q284 505 264 517Q244 531 244 541Q244 550 288 552Q390 561 513 583Q599 597 652 613Q671 619 677 619Z"/>
<path name="1.2" onclick="changeRectColor(evt)" d="M645 343Q667 343 701 326Q724 316 724 301Q724 293 700 288Q672 280 575 267Q428 249 383 249Q332 249 312 261Q292 275 292 285Q292 292 328 293Q411 300 512 316Q582 327 625 338Q640 343 645 343Z"/>
<path name="1.3" onclick="changeRectColor(evt)" d="M852 104Q860 104 914 84Q960 59 960 39Q960 21 897 21Q816 23 722 23Q623 23 465 12Q351 7 222 -19Q185 -27 177 -27Q156 -27 115 -9Q72 10 72 21Q72 36 100 38Q244 39 311 51Q438 65 591 73Q735 85 811 99Q844 104 852 104Z"/>
</g>
</def>


<g id="bg" transform="translate(514 718)">
<rect id="sq" style="fill:none;stroke:lightgray;stroke-width:4" x="-512" y="-716" width="0" height="0"/>
<g id="box"><rect style="fill:none;stroke:black;stroke-width:4" x="0" y="-204" width="1024" height="1024"/>
<line style="stroke:black;stroke-width:2;stroke-dasharray:60 60;" x1="0" y1="308" x2="1024" y2="308"/>
<line style="stroke:black;stroke-width:2;stroke-dasharray:60 60;" x1="512" y1="-204" x2="512" y2="820"/>
</g></g>
<use id="u1" xlink:href="#g1" x="0" y="0"/>

</svg>


<button><font size = 4>Save as PNG</font></button>

<canvas id="he_canvas" width="250" height="250"></canvas>


<script type="text/javascript">

var btn = document.querySelector('button');
var svg = document.querySelector('svg');
var canvas = document.querySelector('he_canvas');


function triggerDownload (imgURI) {


  var evt = new MouseEvent('click', {
    view: window,
    bubbles: false,
    cancelable: true
  });
var a = document.createElement('a');  
a.setAttribute('download', 'mypng.png');
a.setAttribute('href', imgURI);
a.setAttribute('target', '_blank');

a.dispatchEvent(evt);
}




btn.addEventListener('click', function () {
var canvas_browser = document.getElementById('he_canvas');
var ctx = canvas_browser.getContext('2d');

var data = (new XMLSerializer()).serializeToString(svg);
var DOMURL = window.URL || window.webkitURL || window;

var img = new Image();
var svgBlob = new Blob([data], {type: 'image/svg+xml;charset=utf-8'});
var url = DOMURL.createObjectURL(svgBlob);


img.onload = function () {
ctx.drawImage(img, 0, 0);
DOMURL.revokeObjectURL(url);

var imgURI = canvas_browser
.toDataURL('image/png')
.replace('image/png', 'image/octet-stream');

triggerDownload(imgURI);
};

img.src = url;
});

</script>

</body></html>

Upvotes: 1

Views: 77

Answers (1)

Kaiido
Kaiido

Reputation: 136707

Important note :

This question is raised by a behavior which is only implemented in Firefox, so the first part of this answer will assume to be seen from Firefox.


This one is an interesting case...

So what you are doing is to handle click events on cloned nodes through an <use> element.

evt.target.setAttributeNS(null,"fill","red");

Here, evt.target will be the cloned node, not the original one, you can check it by cloning twice your elements :

<script>
function changeRectColor(evt) {
     evt.target.setAttributeNS(null,"fill","red");
    }
</script>
<svg width="500" height="250" viewBox="0 0 4104 2052">

<def>
<g id="g1" onclick="changeRectColor(evt)" name="三" transform="translate(514 718) matrix(1 0 0 -1 0 616)">
<path name="1.1" onclick="changeRectColor(evt)" d="M677 619Q699 619 733 602Q756 592 756 577Q756 566 726 559Q691 548 572 530Q390 505 335 505Q284 505 264 517Q244 531 244 541Q244 550 288 552Q390 561 513 583Q599 597 652 613Q671 619 677 619Z"></path>
<path name="1.2" onclick="changeRectColor(evt)" d="M645 343Q667 343 701 326Q724 316 724 301Q724 293 700 288Q672 280 575 267Q428 249 383 249Q332 249 312 261Q292 275 292 285Q292 292 328 293Q411 300 512 316Q582 327 625 338Q640 343 645 343Z"></path>
<path name="1.3" onclick="changeRectColor(evt)" d="M852 104Q860 104 914 84Q960 59 960 39Q960 21 897 21Q816 23 722 23Q623 23 465 12Q351 7 222 -19Q185 -27 177 -27Q156 -27 115 -9Q72 10 72 21Q72 36 100 38Q244 39 311 51Q438 65 591 73Q735 85 811 99Q844 104 852 104Z"></path>
</g>
</def>

<g id="bg" transform="translate(514 718)">

<rect id="sq" style="fill:none;stroke:lightgray;stroke-width:4" x="-512" y="-716" width="0" height="0"></rect>
<g id="box"><rect style="fill:none;stroke:black;stroke-width:4" x="0" y="-204" width="1024" height="1024"></rect>
<line style="stroke:black;stroke-width:2;stroke-dasharray:60 60;" x1="0" y1="308" x2="1024" y2="308"></line>
<line style="stroke:black;stroke-width:2;stroke-dasharray:60 60;" x1="512" y1="-204" x2="512" y2="820"></line>
</g></g>
<use id="u1" xlink:href="#g1" x="0" y="0"></use>
<use id="u2" xlink:href="#g1" x="1026" y="0"></use>

</svg>

As you can see, only the cloned one gets modified, but this cloned one is not accessible from the DOM (it is only in some shadow-DOM), hence, when you parse your SVG element to create a new image from it, you won't be able to parse the changes made to these cloned nodes.

Solution

Don't use a <use> element... Instead, display directly the original nodes.
Anyway, as said previously, only Firefox does handle click events on cloned nodes inside a <use> element.

var btn = document.querySelector('button');
var svg = document.querySelector('svg');

btn.addEventListener('click', function () {
var canvas_browser = document.createElement('canvas');
var ctx = canvas_browser.getContext('2d');

var data = (new XMLSerializer()).serializeToString(svg);
var DOMURL = window.URL || window.webkitURL || window;

var img = new Image();
var svgBlob = new Blob([data], {type: 'image/svg+xml;charset=utf-8'});
var url = DOMURL.createObjectURL(svgBlob);

img.onload = function () {
canvas_browser.width = img.width;
canvas_browser.height = img.height;
ctx.drawImage(img, 0, 0);
DOMURL.revokeObjectURL(url);
document.body.appendChild(canvas_browser)
};

img.src = url;
});
<button>download</button><br>
<script>
function changeRectColor(evt) {   
     evt.target.setAttributeNS(null,"fill","red");
    }
</script>
<svg width="250" height="250" viewBox="0 0 2052 2052">

<g id="bg" transform="translate(514 718)">

<rect id="sq" style="fill:none;stroke:lightgray;stroke-width:4" x="-512" y="-716" width="0" height="0"></rect>
<g id="box"><rect style="fill:none;stroke:black;stroke-width:4" x="0" y="-204" width="1024" height="1024"></rect>
<line style="stroke:black;stroke-width:2;stroke-dasharray:60 60;" x1="0" y1="308" x2="1024" y2="308"></line>
<line style="stroke:black;stroke-width:2;stroke-dasharray:60 60;" x1="512" y1="-204" x2="512" y2="820"></line>
</g></g>
<g id="g1" onclick="changeRectColor(evt)" name="三" transform="translate(514 718) matrix(1 0 0 -1 0 616)">
<path name="1.1" onclick="changeRectColor(evt)" d="M677 619Q699 619 733 602Q756 592 756 577Q756 566 726 559Q691 548 572 530Q390 505 335 505Q284 505 264 517Q244 531 244 541Q244 550 288 552Q390 561 513 583Q599 597 652 613Q671 619 677 619Z"></path>
<path name="1.2" onclick="changeRectColor(evt)" d="M645 343Q667 343 701 326Q724 316 724 301Q724 293 700 288Q672 280 575 267Q428 249 383 249Q332 249 312 261Q292 275 292 285Q292 292 328 293Q411 300 512 316Q582 327 625 338Q640 343 645 343Z"></path>
<path name="1.3" onclick="changeRectColor(evt)" d="M852 104Q860 104 914 84Q960 59 960 39Q960 21 897 21Q816 23 722 23Q623 23 465 12Q351 7 222 -19Q185 -27 177 -27Q156 -27 115 -9Q72 10 72 21Q72 36 100 38Q244 39 311 51Q438 65 591 73Q735 85 811 99Q844 104 852 104Z"></path>
</g>
</svg>

Upvotes: 1

Related Questions