Save SVG as PNG using javascript Unknown DOM exception - javascript
I am trying to convert an SVG to PNG through browser using javascript
I've been following the answer on this question Save inline SVG as JPEG/PNG/SVG
It works for the given XML in that answer
Unfortunately, I got Uncaught DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported. when trying to convert my SVG. Here's the snippet to my code. Can anybody tell me why it's not working?
var btn = document.querySelector('button');
var svg = document.querySelector('svg');
var canvas = document.querySelector('canvas');
function triggerDownload (imgURI) {
var evt = new MouseEvent('click', {
view: window,
bubbles: false,
cancelable: true
});
var a = document.createElement('a');
a.setAttribute('download', 'MY_COOL_IMAGE.png');
a.setAttribute('href', imgURI);
a.setAttribute('target', '_blank');
a.dispatchEvent(evt);
}
btn.addEventListener('click', function () {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var data = (new XMLSerializer()).serializeToString(svg);
var DOMURL = window.URL || window.webkitURL || window;
var img = new Image();
img.crossOrigin = 'anonymous'
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
.toDataURL('image/png')
.replace('image/png', 'image/octet-stream');
triggerDownload(imgURI);
};
img.src = url;
});
<button>svg to png</button>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="161px" height="91px" version="1.1" style="background-color: rgb(255, 255, 255);"><defs/><g transform="translate(0.5,0.5)"><rect x="0" y="0" width="160" height="90" fill="#ffffff" stroke="#000000" pointer-events="none"/><path d="M 0 26 L 0 0 L 160 0 L 160 26 Z" fill="#dae8fc" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(48.5,7.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="63" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; white-space: nowrap; font-weight: bold; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Classname</div></div></foreignObject><text x="32" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica" font-weight="bold">Classname</text></switch></g><g transform="translate(5.5,32.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="62" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; overflow: hidden; max-height: 22px; max-width: 148px; width: 63px; white-space: normal; word-wrap: normal;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">+ field: type</div></div></foreignObject><text x="31" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">+ field: type</text></switch></g><path d="M 0 56 L 160 56" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(5.5,66.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="111" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; overflow: hidden; max-height: 22px; max-width: 148px; width: 112px; white-space: normal; word-wrap: normal;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">+ method(type): type</div></div></foreignObject><text x="56" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">+ method(type): type</text></switch></g></g></svg>
<canvas id="canvas"></canvas>
You have issues in your SVG's foreignObject on removing this will solve your issue,
var btn = document.querySelector('button');
var svg = document.querySelector('svg');
var canvas = document.querySelector('canvas');
function triggerDownload (imgURI) {
var evt = new MouseEvent('click', {
view: window,
bubbles: false,
cancelable: true
});
var a = document.createElement('a');
a.setAttribute('download', 'MY_COOL_IMAGE.png');
a.setAttribute('href', imgURI);
a.setAttribute('target', '_blank');
a.dispatchEvent(evt);
}
btn.addEventListener('click', function () {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var data = (new XMLSerializer()).serializeToString(svg);
var DOMURL = window.URL || window.webkitURL || window;
var img = new Image();
img.crossOrigin = 'anonymous'
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
.toDataURL('image/png')
.replace('image/png', 'image/octet-stream');
triggerDownload(imgURI);
};
img.src = url;
});
<button>svg to png</button>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="161px" height="91px" version="1.1" style="background-color: rgb(255, 255, 255);">
<defs/>
<g transform="translate(0.5,0.5)">
<rect x="0" y="0" width="160" height="90" fill="#ffffff" stroke="#000000" pointer-events="none"/>
<path d="M 0 26 L 0 0 L 160 0 L 160 26 Z" fill="#dae8fc" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
<g transform="translate(48.5,7.5)">
<switch>
<text x="32" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica" font-weight="bold">Classname</text>
</switch>
</g>
<g transform="translate(5.5,32.5)">
<switch>
<text x="31" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">+ field: type</text>
</switch>
</g>
<path d="M 0 56 L 160 56" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(5.5,66.5)">
<switch>
<text x="56" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">+ method(type): type</text>
</switch>
</g>
</g>
</svg>
<canvas id="canvas"></canvas>
You can also try Canvas2Image plugin
Related
Re-Center text position as str length changes
I am new to javascript and am having an issue repositioning animated text as the string length varies. I have an SVG element and a string within it, where that string needs to be centered within that SVG. Using ' | ' as a center reference, the centering would look like: | | | g g g g g g If I start the animation with a str of len 3, it will be centered properly for Len 3 strs, but then other lens would be equivalent to: | | g g g Example code: function animateValue(obj, start, end, duration) { let startTimestamp = null; const step = (timestamp) => { if (!startTimestamp) startTimestamp = timestamp; const progress = Math.min((timestamp - startTimestamp) / duration, 1); const str = obj.innerHTML; // console.log(`${str.length}` ); if (`${str.length}`==="1"){ obj.style.x = '200px'; } obj.innerHTML = Math.floor(progress * (end - start) + start); if (progress < 1) { window.requestAnimationFrame(step); } }; window.requestAnimationFrame(step); } const obj = document.getElementById("heading"); animateValue(obj, 100, 0, 5000); svg { position: absolute ; width: 40%; border: 1px solid rgba(255,255,255,0.3); margin-left: 30%; border-radius: 50%; } #roseline, #majline { stroke: #eee; stroke-width: .5; } text { font-family: Montserrat, sans-serif; font-size: 10; fill: #eee; } text.heading1{ font-size:4.5em; fill: #0ee; } <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 500 500" id="compassrose"> <defs> <symbol> <line x1="40" y1="250" x2="50" y2="250" id="roseline" /> <line x1="40" y1="250" x2="60" y2="250" id="majline" /> <path d="M10,250a240,240 0 1,0 480,0a240,240 0 1,0 -480,0" id="rosecircle" transform='rotate(90 250 250)' /> </symbol> </defs> <div class="triangle-container"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 500 500" id="compassrose"> <polygon points="250,40 280,0 220,000" class="triangle" /> </svg> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 500 500" > <polygon points="0,260 0,220 40,240" /> </svg> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 500 500" > <polygon points="500,260 500,220 460,240" /> <text class="heading1" id="heading" x='190px' y='250px' fontSize="36">100 </text> </svg> </div> </svg> I have tried re-arranging the divs to allow for the absolute and relative positioning, however that was not properly maintaining size relationships as needed.
If you use dominant-baseline="middle" text-anchor="middle" on the text element and position it in the middle of the SVG (250,250) it should work. function animateValue(obj, start, end, duration) { let startTimestamp = null; const step = (timestamp) => { if (!startTimestamp) startTimestamp = timestamp; const progress = Math.min((timestamp - startTimestamp) / duration, 1); obj.innerHTML = Math.floor(progress * (end - start) + start); if (progress < 1) { window.requestAnimationFrame(step); } }; window.requestAnimationFrame(step); } const obj = document.getElementById("heading"); animateValue(obj, 200, 0, 5000); svg { display: block; position: absolute; width: 40%; border: 1px solid rgba(255, 255, 255, .3); margin-left: 30%; border-radius: 50%; } #roseline, #majline { stroke: #eee; stroke-width: .5; } text { font-family: Montserrat, sans-serif; font-size: 10; fill: #eee; } text.heading1 { fill: #0ee; } <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500" id="compassrose"> <defs> <symbol> <line x1="40" y1="250" x2="50" y2="250" id="roseline" /> <line x1="40" y1="250" x2="60" y2="250" id="majline" /> <path d="M10,250a240,240 0 1,0 480,0a240,240 0 1,0 -480,0" id="rosecircle" transform='rotate(90 250 250)' /> </symbol> </defs> <polygon points="250,40 280,0 220,000" class="triangle" /> <polygon points="0,260 0,220 40,240" /> <polygon points="500,260 500,220 460,240" /> <text class="heading1" id="heading" x="250" y="250" font-size="60" dominant-baseline="middle" text-anchor="middle">100</text> </svg>
Isolate section of SVG when mouse is hovered
I am attempting to build an interactive map from scratch. I have an SVG of the map of Canada that has separate layers for each province. I'd like to highlight a specific province/territory when the mouse is hovered over it. I have tried using a function that gets the live update of the mouse coordinates, but I am unsure as to how to figure out which section of the image it is on. I am unsure as to if this is the best method of doing it. Through some of my research, I have found a method of gathering the pointer coordinates: let x = 0; let y = 0; function showCoords() { x = event.clientX; y = event.clientY; } And I call it around the SVG using: <div onmousemove="showCoords()"> ...SVG HERE </div> I can select the different layers inside of the SVG, but the question is if I can find a way of checking which layer my mouse is currently over. Thank you! Edit: I have reached a solution that accomplishes my goal, but I am unsure as to if it is efficient. Using CSS, I fill each group upon hover: #canada { fill: hsl(0, 0%, 29%); } #canada g { transition: .3s; } #canada g:hover { fill: hsl(189, 88%, 59%); } I am also using the onClick option on each group to pull up their dialogue.
Maybe something like this? Just keep "data-name" attribute on each <g> inside svg code. let x = 0; let y = 0; let svgCountry = document.querySelector("#states svg"); let svgStates = svgCountry.querySelectorAll("[data-name]"); let resContainer = document.getElementById("state-hovered-is"); // init tooltip function showCoords(event) { let x = event.clientX; let y = event.clientY; resContainer.setAttribute("style", "left:" + (x + 15) + "px;" + "top:" + (y - 50) + "px;"); } // close tooltip function clearCoor() { resContainer.innerHTML = ""; } // clear everything function clearAllOn() { svgStates.forEach(function(el) { el.classList.remove("hover"); resContainer.innerHTML = ""; console.clear(); }); } // display current state in div function displayState(el) { var res = el.getAttribute("data-name"); el.classList.add("hover"); resContainer.innerHTML = "<p>You're at" + " " + res + "</p>"; console.log(res); } svgStates.forEach(function(el) { // mouse events el.addEventListener("mouseenter", function() { displayState(el); }); el.addEventListener("mouseleave", function() { clearAllOn(); }); // touch events el.addEventListener("touchstart", function() { clearAllOn(); displayState(el); }); }); body { background-color: #fff; font-family: Arial, Helvetica, sans-serif; color: #333; } g.hover { opacity: 0.5; } #states { margin: 0 auto; width: 600px; max-width: 100%; position: relative; } #state-hovered-is { text-align: center; min-height: 50px; position: fixed; pointer-events: none; background-color: rgba(0, 0, 0, 0.76); border-radius: 6px; } #state-hovered-is p { color: #fff; margin: 0; padding: 15px; width: 180px; } <div id="states" onmousemove="showCoords(event)" onmouseout="clearCoor()"> <!-- State name here --> <div id="state-hovered-is"></div> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 961.38 830.7"> <defs> <style> .cls-1 { fill: #fff;} .cls-2 {fill: #b8c4e6;} .cls-3 {fill: #ce8080;} .cls-4 {fill: #e99bd2;} .cls-5 {fill: #acac90;} .cls-6 {fill: #e6c0c0;} .cls-7 {fill: #4d6ac1;} .cls-8 {fill: #c9e6b8;} .cls-9 {fill: #f3f3db;} .cls-10 {fill: #cece71;} .cls-11 {fill: #7188ce;} .cls-12 {fill: #daa0a0;} .cls-13 {fill: #91916b;} .cls-14 {fill: #dada94;} .cls-15 {fill: #916b86;} </style> </defs> <title>Canada</title> <g id="Layer_1"> <ellipse class="cls-1" cx="480.69" cy="415.35" rx="679.8" ry="587.39" /> <path class="cls-1" d="M539.84,220.75c-2.45,5-6.57,8.18-10.72,11.7l2-9.56C534.53,224.17,537,221.84,539.84,220.75Z" transform="translate(-0.06 -0.26)" /> <path class="cls-1" d="M53,543.56c-1.09,2.13-2.18,4.23-3.52,6.84l-.51-10.68.56-.25Z" transform="translate(-0.06 -0.26)" /> <path class="cls-1" d="M771.19,558.14c-.32-2.18-.77-4.36-.89-6.56a3.15,3.15,0,0,1,1.31-2.05,1.76,1.76,0,0,1,1.64.49,4.19,4.19,0,0,1,.17,2.5c-.48,1.84-1.18,3.62-1.79,5.43Z" transform="translate(-0.06 -0.26)" /> <path class="cls-1" d="M40.77,527.77l-7-8.41.35-.18A76,76,0,0,1,40.4,524c.77.71.87,2.14,1.27,3.25Z" transform="translate(-0.06 -0.26)" /> <path class="cls-1" d="M493.56,95.47l3.41,6L485.7,105a30.91,30.91,0,0,1,2.81-2.42C491.7,100.51,493.64,100.2,493.56,95.47Z" transform="translate(-0.06 -0.26)" /> </g> <g id="Yukon" data-name="Yukon"> <path class="cls-3" d="M174.12,185.61c.91,1.61.88,2.8-.63,4.31-4.21,4.21-8.16,8.68-12.2,13.07-.34.38-.78,1-.72,1.39.58,3.9-2,6.08-4.31,8.53a6.48,6.48,0,0,0-1.84,3.83,5.33,5.33,0,0,0,1.79,3.5c1.85,1.68,4.07,2.94,6,4.53,3.45,2.83,3.47,5.7.33,9.15-2.19,2.39-4.41,4.77-6.37,7.34-1.76,2.3-1.12,4.05,1.42,5.49,1.4.81,2.66,1.88,4.19,3-2.18,1.51-3.35,2.81-2.33,5.22.45,1.05,0,2.31-1.73,2.4a17.09,17.09,0,0,0-3.62.83c-4.36,1.21-5.4,4.72-5.53,8.56a57.14,57.14,0,0,0,.5,10c.23,1.57,1.5,3,2.39,4.63-2.26,2.84-2.38,6.32-1.6,10.12a46.41,46.41,0,0,1,.52,7.56,1.6,1.6,0,0,1-.82,1.17c-2.55,1.24-3,3.61-3.48,6a9.38,9.38,0,0,1-1.27,3.48,10.68,10.68,0,0,0-1.7,8.87,2.39,2.39,0,0,1-.44,1.48c-.6,1-1.32,2-2,2.93-1.42,2.18-1.43,4,.77,5.24,3.32,1.83,3.1,4.7,2.57,7.41-.72,3.66-.45,6.87,2,9.78,1.47,1.77,1.39,3.3-.37,4.95a7.72,7.72,0,0,0-1.45,3.08c-.28.81-.27,1.71-.5,2.53-1.52,5.43,1,6.26,4.74,7.61,1.41.5,2.57,1.66,3.93,2.34a26.86,26.86,0,0,0,4.63,1.87c1.72.5,3.51.73,5.24,1.06.05.25.15.5.1.53-3,2.14-3,5.28-2.81,8.48.09,2,0,4,0,6.25A575.11,575.11,0,0,1,48.14,298a7.87,7.87,0,0,1,.58-.75c3.2-3.33,3.13-5.09-.71-7.55a38.29,38.29,0,0,0-6.52-3.12c-2.14-.86-3.05-5-1.32-6.73q13.23-13,26.49-26c6.81-6.67,13.65-13.31,20.46-20q13.26-13,26.5-26,10.56-10.35,21.15-20.68,11.07-10.83,22.16-21.66c1.92-1.87,3.87-3.74,6-5.43a2.44,2.44,0,0,1,2.34-.08,12.63,12.63,0,0,1,4.51,7.68c.95,5.52,2.44,10.95,3.73,16.42A5.64,5.64,0,0,0,174.12,185.61Z" transform="translate(-0.06 -0.26)" /> </g> <g id="British_Columiba" data-name="British Columiba"> <g> <path class="cls-4" d="M190.26,405.28c.27.14.53.31,1.06.62-1,1.88-2,3.69-2.9,5.53-5.64,11.14-11.24,22.3-16.9,33.43-4.43,8.73-8.92,17.42-13.38,26.13l-19.37,37.93c-.21.42-.68.84-.65,1.24.17,2.7,0,5.24-2.52,6.95.78,2,1.25,4.14,2.45,5.8.82,1.15,1.83,1.89,1.89,3.54s.46,3.46,2.33,4.55c2.39,1.41,1.92,4.19,2.3,6.41.31,1.81-.17,3.77-.35,5.66s.8,3.35,2.22,4.62a2.72,2.72,0,0,1,.81,2.17,5.54,5.54,0,0,0,1.49,5.42c.88,1,1.18,2.44,1.69,3.71.82,2,1.6,4,2.38,6,1,2.51,2,5,2.9,7.55.32.88.14,2.18.72,2.67,3.23,2.74,2.75,6.63,3,10.1a15.41,15.41,0,0,0,3.74,8.9c3.16,3.57,2.61,7,1.68,10.73-.83,3.31-1.92,6.57-3,9.84s-.35,6.2,1.21,9.74c-5.31-2.27-10.13-4.28-14.9-6.38-10.53-4.64-21.08-9.23-31.54-14-8.14-3.72-16.25-7.52-24.19-11.65-8.81-4.6-17.41-9.61-26.09-14.47a2,2,0,0,1-1-1.12,65.21,65.21,0,0,1-1-7.47c-.16-3.6-1.05-5-4.37-5.94,0-1.19,0-2.34,0-3.5a3.82,3.82,0,0,0-2.71-3.76c-1.17-.5-3.27-.93-3.32-1.53a9.88,9.88,0,0,1,.91-5.44c3.08-5.49,3.08-7.06-1-11.44-2.29-2.47-4.78-4.79-6.82-7.46a9.16,9.16,0,0,1-1.44-4.76c-.2-2.61-1.08-4.69-3.49-5.72-3.27-1.39-4.67-4.2-5.48-7.23a5.27,5.27,0,0,1,1-4.36,5.48,5.48,0,0,0,1.59-5.2c-.48-3.26,1.93-4.89,4.78-5.55a19.58,19.58,0,0,0,3.83-1c2.43-1.12,2.65-3.06.7-4.87a7.78,7.78,0,0,1-2-9.22c1.46-3.4,1.33-5.05-1-6.15-1.19-.56-2.78-.29-4.19-.39-.47,0-.93-.05-1.65-.09,1.67-3,3-5.78,6.86-6.28a4.12,4.12,0,0,0,3.2-2.73c.72-1.68,2.44-2.95,3.74-4.38,1.14-1.23,1.82-2.81.52-4a5.8,5.8,0,0,0-4-1A30.06,30.06,0,0,0,44.62,459c-1.84-6.08-.47-11.9,1.17-17.65A3.74,3.74,0,0,1,48,439.05c7.2-1.55,10.53-7,13.68-12.85a30.35,30.35,0,0,1,3.83-4.91c1.69-2,2.72-4.14,1.8-6.84s-1.71-5.51-2.66-8.23A52.51,52.51,0,0,0,62,399.51c-1.34-2.62-.9-5.19-.39-7.83q2.15-11.08,4.26-22.15c1.08-5.61,2.21-11.21,3.21-16.84a9.48,9.48,0,0,0-.36-2.74c-.16-1.32-.33-2.65-.44-4-.14-1.58-.18-3.17-.36-4.74a11.92,11.92,0,0,1,1.16-7.34c1.92-3.53,1.66-7.9-.48-9.87l1.06-1.21c7.65,6.68,15.29,13.38,23.2,19.74,8.69,7,17.59,13.76,26.79,20,13.27,9,26.71,17.88,40.42,26.24C169.85,394.8,180.18,399.83,190.26,405.28Z" transform="translate(-0.06 -0.26)" /> <path class="cls-4" d="M67.71,323.4c-4.2-2.13-8.84-4.21-13.43-1.55-2.84,1.64-5.18.87-8.06.13,2.21-2.52,1.9-5.53,1.88-8.49s0-6.08,0-9.44a8.14,8.14,0,0,1,1.68.85c5.42,4.9,10.73,9.92,16.24,14.72l3.65,3.2L68.61,324A4,4,0,0,0,67.71,323.4Z" transform="translate(-0.06 -0.26)" /> <path class="cls-1" d="M52.34,580.17c.15,1.23-.68,2.57-1.25,4.47-2.23-1.77-4.17-2.89-5.53-4.5a75.63,75.63,0,0,1-5.85-8.23,3.32,3.32,0,0,1-.2-2.75c2.52-5.09,2.08-6.95-3.06-9.61-1.82-.94-2.5-1.94-2.32-4,.32-3.52.35-4.15-4.79-9.94,2-2.92,1.55-3.82-.24-7-1.32-2.35-1.69-5.31-2.07-8.06-.29-2.13-.63-4-2.58-5.25a2.26,2.26,0,0,1-.79-1.75c.24-3.45.6-6.89.93-10.33,2-.08,2.8,1.11,3.33,2.71A29.72,29.72,0,0,0,36,529,45.65,45.65,0,0,1,43,536.54c1.16,1.66,1.53,4.06,1.7,6.17a84.4,84.4,0,0,1,0,10.06c-.17,4.12,1.42,7.63,3.38,11.07a18,18,0,0,1,2.24,4.56A109.17,109.17,0,0,1,52.34,580.17Z" transform="translate(-0.06 -0.26)" /> <path class="cls-1" d="M17.57,426.81l6.17,8.48C16.39,441.78,11.81,449.73,11,459.7,10.41,448.18,12.87,437.39,17.57,426.81Z" transform="translate(-0.06 -0.26)" /> </g> </g> <g id="Alberta" data-name="Alberta"> <path class="cls-5" d="M194.56,407.63c27.17,14.46,55.83,25.35,85,35.57L214.1,643.67c-10.88-4-21.29-7.82-31.68-11.68-3.52-1.3-6.91-3-10.51-4s-5.08-3.41-6.18-6.74c-1.26-3.84-.43-7.18,1.12-10.59A26.88,26.88,0,0,0,169.13,597a4.52,4.52,0,0,0-1-2.58c-4.16-4.42-5.32-9.88-5.71-15.66-.07-1-.13-2.32-.75-2.88-2.84-2.56-2.45-6.26-3.65-9.38-.64-1.69-1.62-3.26-2.29-4.95-.84-2.14-1.52-4.35-2.27-6.53-.05-.15-.06-.35-.17-.44a6.25,6.25,0,0,1-2-7.07c.17-.6-1.07-1.75-1.85-2.43a2.33,2.33,0,0,1-1.08-2.43,28.92,28.92,0,0,0-.52-7.52c-.36-2.17,0-4.65-2.15-6.28-1.47-1.09-1.92-2.71-2.35-4.49-.35-1.45-1.6-2.69-2.47-4-.51-.77-1.07-1.51-1.72-2.42,2.55-1.41,2.87-3.59,2.69-6a5,5,0,0,1,.5-2.5q5-9.88,10-19.7c6.78-13.11,13.63-26.19,20.37-39.32,3.84-7.45,7.51-15,11.31-22.47C187.5,421.2,191,414.48,194.56,407.63Z" transform="translate(-0.06 -0.26)" /> </g> </svg> </div> Here's how the full map looks: https://jsfiddle.net/darkosss/7umphzwn/
Javscript to dynamically build HTML/SVG for mobile view
I have a full screen SVG image/mask reveal; it works great on desktop but it doesn't scale/fit on mobile devices. So im guessing the best solution would be to dynamically build the SVG and SVG container depending on screen width and have a mobile & desktop build. So i'm looking for advice and the best solution and if someone could point me in the right direction or know of an example I can look at. // DRAW SVG MASK ///////////////////////////// var svg = document.querySelector("#svg__bg"); var tl = new gsap.timeline({ onUpdate: onUpdate }); var pt = svg.createSVGPoint(); var ratio = 0.5625; tl.to("#masker", {duration: 2, attr: {r: 2400}, ease: "power2.in" }); tl.reversed(true); function mouseHandler() { tl.reversed(!tl.reversed()); } function getPoint(evt) { pt.x = evt.clientX; pt.y = evt.clientY; return pt.matrixTransform(svg.getScreenCTM().inverse()); } function mouseMove(evt) { var newPoint = getPoint(evt); gsap.set("#dot", { cx: newPoint.x, cy: newPoint.y }); gsap.to("#ring, #masker", {duration: 0.88, attr: { cx: newPoint.x, cy: newPoint.y }, ease: "power2.out" }); } function onUpdate() { var prog = (tl.progress() * 100); } function newSize() { var w = window.innerWidth; var h = window.innerHeight; if (w > h * (16 / 9)) { gsap.set("#svg__bg", { attr: { width: w, height: w * ratio } }); } else { gsap.set("#svg__bg", { attr: { width: h / ratio, height: h } }); } var data = svg.getBoundingClientRect(); gsap.set("#svg__bg", { x: w / 2 - data.width / 2 }); gsap.set("#svg__bg", { y: h / 2 - data.height / 2 }); } window.addEventListener("mousedown", mouseHandler); window.addEventListener("mouseup", mouseHandler); window.addEventListener("mousemove", mouseMove); newSize(); window.addEventListener("resize", newSize); #import url('https://fonts.googleapis.com/css?family=Montserrat:700&display=swap'); body { min-height: 100vh; background-color: #1F242D; cursor: none; overflow: hidden; font-family: 'Montserrat', sans-serif; } .intro-svg { position: relative; padding: 0; margin: 0; width: 100%; min-height: 100vh; height: calc(var(--vh, 1vh) * 100); overflow: hidden; z-index: 1; } .svg__container { height: 100%; width: 100%; position: relative; overflow: hidden; } .svg__image { position: absolute; top: 0; left: 0; right: 0; bottom: 0; cursor: none; } .text-svg { position: absolute; top: 0; left: 0; right: 0; bottom: 0; cursor: none; z-index:2; } .impact-text { font-size: 7em; line-height: 1.2; text-transform: uppercase; } <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.2.6/gsap.min.js"></script> <div class="intro-svg"> <div class="svg__container"> <svg id="svg__bg" class="svg__image" xmlns="http://www.w3.org/2000/svg" x="0" y="0" width="1600" height="900" viewBox="0 0 1600 900"> <defs> <radialGradient id="mask-gradient"> <stop offset="80%" stop-color="#fff"/><stop offset="100%" stop-color="#000" /> </radialGradient> <mask id="the-mask"> <circle id="masker" r="250" fill="url(#mask-gradient)" cx="800" cy="450"> </circle> </mask> <mask id="mask-text" width="100" height="100" x="0" y="0"> <text id="masker" class="impact-text row-1" fill="none" stroke="#fff" stroke-width="3" x="10.1%" y="42%">A</text> <text id="masker" class="impact-text row-2" fill="white" x="10%" y="55%">Digital</text> <text id="masker" class="impact-text row-3" fill="white" x="10%" y="68%">Designer</text> </mask> </defs> <image id="lines" xlink:href="https://i.imgur.com/1TQRj56.jpg" x="0" y="0" width="1600" height="900" /> <g id="mask-reveal" mask="url(#the-mask)"> <image id="regular" xlink:href="https://i.imgur.com/7VtEKv3.jpg" x="0" y="0" width="1600" height="900" /> </g> <g mask="url(#mask-text)"> <image id="text-before" xlink:href="https://i.imgur.com/7VtEKv3.jpg" x="0" y="0" width="1600" height="900" /> </g> <circle id="ring" r="20" fill="none" stroke="#D74A53" stroke-width="2" cx="800" cy="450" /> <circle id="dot" r="4" fill="#D74A53" cx="800" cy="450"/> </svg> </div> </div>
just add #svg__bg { width: 100%; height:auto; } andchange them with media query don't forget to change <svg id="svg__bg" class="svg__image" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 1600 900"> without width="1600" height="900"
svg to canvas image in jspdf - I Get a black content
I've used jspdf to convert the svg image to canvas and then to pdf The plugins I've used are <script type="text/javascript" src="assets/js/jquery.js"></script> <script type="text/javascript" src="assets/js/jspdf.js"></script> <script type="text/javascript" src="assets/js/html2canvas.js"></script> <script type="text/javascript" src="assets/js/html2canvas.svg.js"></script> <script type="text/javascript" src="assets/js/canvg.js"></script> My HTML code for the svg is genpdf <svg class="bullet" width="416" height="50"> <g transform="translate(75,5)"> <rect class="range s0" width="301" height="25" x="0"/> <rect class="range s1" width="250.83333333333334" height="25" x="0"/> <rect class="range s2" width="200.66666666666666" height="25" x="0"/> <rect class="measure s0" width="230.76666666666668" height="8.333333333333334" x="0" y="8.333333333333334"/> <rect class="measure s1" width="210.7" height="8.333333333333334" x="0" y="8.333333333333334"/> <g class="tick" transform="translate(0,0)" style="opacity: 1;"> <line y1="25" y2="29.166666666666668"/> <text text-anchor="middle" dy="1em" y="29.166666666666668">0</text> </g> <g class="tick" transform="translate(50.16666793823242,0)" style="opacity: 1;"> <line y1="25" y2="29.166666666666668"/> <text text-anchor="middle" dy="1em" y="29.166666666666668">5</text> </g> <g class="tick" transform="translate(100.33333587646484,0)" style="opacity: 1;"> <line y1="25" y2="29.166666666666668"/> <text text-anchor="middle" dy="1em" y="29.166666666666668">10</text> </g> <g class="tick" transform="translate(150.5,0)" style="opacity: 1;"> <line y1="25" y2="29.166666666666668"/> <text text-anchor="middle" dy="1em" y="29.166666666666668">15</text> </g> <g class="tick" transform="translate(200.6666717529297,0)" style="opacity: 1;"> <line y1="25" y2="29.166666666666668"/> <text text-anchor="middle" dy="1em" y="29.166666666666668">20</text> </g> <g class="tick" transform="translate(250.8333282470703,0)" style="opacity: 1;"> <line y1="25" y2="29.166666666666668"/> <text text-anchor="middle" dy="1em" y="29.166666666666668">25</text> </g> <g class="tick" transform="translate(301,0)" style="opacity: 1;"> <line y1="25" y2="29.166666666666668"/> <text text-anchor="middle" dy="1em" y="29.166666666666668">30</text> </g> <g x="200" y="100" style="text-anchor: end;" transform="translate(-6,12.5)"> <text class="title">NOVORA</text> </g> </g> </svg> I'm unable to get the exact image that is required as an output when I generate it to pdf. I'm converting the svg to canvas but still I'm unable to get the desired output. Instead of the exact image I get a black content inside that. The css code for the above one is .bullet { font: 10 px sans-serif; } .bullet.marker { stroke: #000; stroke-width: 2px; } .bullet .tick line { stroke: # 666; stroke-width: .5px; } .bullet.range.s0 { fill: #eee; } .bullet.range.s1 { fill: #ddd; } .bullet.range.s2 { fill: #ccc; } .bullet.measure.s0 { fill: steelblue; } .bullet.measure.s1 { fill: #fff; } .bullet.measure.s2 { fill: steelblue; } .bullet.measure.s3 { fill: lightsteelblue; } .bullet.title { font-size: 10px; font-weight: bold; } .bullet.subtitle { fill: #999; } The javascript that helps me rendering the data is function genPdf(){ var svgElements = $("#page-content-wrapper").find('svg'); //replace all svgs with a temp canvas svgElements.each(function() { var canvas, xml; canvas = document.createElement("canvas"); canvas.className = "screenShotTempCanvas"; // canvas.getContext("3d"); //convert SVG into a XML string xml = (new XMLSerializer()).serializeToString(this); // Removing the name space as IE throws an error xml = xml.replace(/xmlns=\"http:\/\/www\.w3\.org\/2000\/svg\"/, ''); //draw the SVG onto a canvas canvg(canvas, xml); $(canvas).insertAfter(this); $(this).addClass('tempHide'); $(this).hide(); }); html2canvas(document.getElementById('page-content-wrapper'), { onrendered: function (canvas){ var img = canvas.toDataURL("image/jpeg",1.0); var doc = new jsPDF(); doc.addImage(img, 'JPEG' , 10, 10); doc.save('test.pdf'); } }); setTimeout(function(){ $("#page-content-wrapper").find('.screenShotTempCanvas').remove(); $("#page-content-wrapper").find('.tempHide').show().removeClass('tempHide'); $("#page-content-wrapper").find('.bullet').show(); },2000); } function getStyle(el, styleProp) { var camelize = function(str) { return str.replace(/\-(\w)/g, function(str, letter) { return letter.toUpperCase(); }); }; if (el.currentStyle) { return el.currentStyle[camelize(styleProp)]; } else if (document.defaultView && document.defaultView.getComputedStyle) { return document.defaultView.getComputedStyle(el, null) .getPropertyValue(styleProp); } else { return el.style[camelize(styleProp)]; } } Please help me out in this. Thanks
Save result from html2canvas library
I used html2canvas library to get screenshot of the html content using jvascript. That is what html2canvas library does. What I tried to do is to get a screenshot of the output from html2canvas library and save it in any image format(say jpeg). But was not able to achieve it. Here is what I've tried so far: HTML <svg width="500" height="350"> <circle id="orange-circle" r="30" cx="50" cy="50" fill="orange" /> <rect id="blue-rectangle" width="50" height="50" x="25" y="200" fill="#0099cc"></rect> <animate xlink:href="#orange-circle" attributeName="cx" from="50" to="450" dur="5s" begin="0s" repeatCount="2" fill="freeze" id="circ-anim"/> <animate xlink:href="#blue-rectangle" attributeName="x" from="50" to="425" dur="5s" begin="0s" repeatCount="indefinite" fill="freeze" id="rect-anim"/> </svg> CSS svg { border: 3px solid #eee; display: block; margin: 1em auto; } p { color: #aaa; text-align: center; margin: 2em 0; } JS(with html2canvas lib) <script type="text/javascript" src="html2canvas.js"></script> <script type="text/javascript"> html2canvas(document.body).then(function(canvas) { document.body.appendChild(canvas); }); </script>
The only thing you need to do is wrapping the function by a window.onload Here are the example window.onload = function() { $("#convert").click(function(){ html2canvas($('.svgElement')).then(function(canvas) { var imgLink = canvas.toDataURL("image/png"); var img = document.createElement('img'); img.src = imgLink; document.body.appendChild(img); }); }); } https://jsfiddle.net/t1fw7pgy/1/ In your code, the function is called before render the element, therefore it will just give you a blank canvas page.