Drawing SVG element on top with smooth transitions - javascript
I have a page with different SVG elements that react when hovering over them. When hovering, the element increases in size, covering neighbouring elements. My trouble is that some of the neighbours have been drawn later and won't be covered. [Example]
I tried to fix the issue by using appendChild() when hovering over to make it the last drawn element, but this removes the smooth transition effect I set with CSS.
Example:
for (var i = 0; i < 20; i++) {
for (var n = 0; n < 5; n++) {
var new_rect = document.getElementById("0").cloneNode(true);
new_rect.setAttributeNS(null, "cx", i * 20 + 10);
new_rect.setAttributeNS(null, "cy", n * 20 + 10);
new_rect.setAttributeNS(null, "id", i + n);
document.getElementById("mainG").appendChild(new_rect);
}
}
function expand(evt) {
//evt.target.parentNode.appendChild(evt.target);
evt.target.setAttributeNS(null, "r", "25");
}
function shrink(evt) {
evt.target.setAttributeNS(null, "r", "10");
}
.circle {
fill: hsl(100, 30%, 80%);
-webkit-transition: .1s ease-in-out;
}
.circle:hover {
fill: hsl(0, 50%, 70%);
}
<svg version="1.1" baseProfile="full" width="440" height="150" xmlns="http://www.w3.org/2000/svg">
<g id="mainG">
<circle id="0" cx="10" cy="10" r="10" stroke="none" fill="white" class="circle" onmouseover="expand(evt)" onmouseout="shrink(evt)"></circle>
</g>
<g id="cloneG"></g>
</svg>
How can I both get the element to be drawn on top while still having smooth transitions between states?
You can force a reflow with the following..
var test = evt.target.offsetHeight;
Do this just before changing the radius
for (var i = 0; i < 20; i++) {
for (var n = 0; n < 5; n++) {
var new_rect = document.getElementById("0").cloneNode(true);
new_rect.setAttributeNS(null, "cx", i * 20 + 10);
new_rect.setAttributeNS(null, "cy", n * 20 + 10);
new_rect.setAttributeNS(null, "id", i + n);
document.getElementById("mainG").appendChild(new_rect);
}
}
function expand(evt) {
evt.target.parentNode.appendChild(evt.target);
var test = evt.target.offsetHeight;
evt.target.setAttributeNS(null, "r", "25");
}
function shrink(evt) {
evt.target.setAttributeNS(null, "r", "10");
}
.circle {
fill: hsl(100, 30%, 80%);
-webkit-transition: 1s ease-in-out;
}
.circle:hover {
fill: hsl(0, 50%, 70%);
}
<svg version="1.1" baseProfile="full" width="440" height="150" xmlns="http://www.w3.org/2000/svg">
<g id="mainG">
<circle id="0" cx="10" cy="10" r="10" stroke="none" fill="white" class="circle" onmouseover="expand(evt)" onmouseout="shrink(evt)"></circle>
</g>
<g id="cloneG"></g>
</svg>
in this way you preserve the CSS transition :
for (var i = 0; i < 20; i++) {
for (var n = 0; n < 5; n++) {
var new_rect = document.getElementById("0").cloneNode(true);
new_rect.setAttributeNS(null, "cx", i * 20 + 10);
new_rect.setAttributeNS(null, "cy", n * 20 + 10);
new_rect.setAttributeNS(null, "id", i + n);
document.getElementById("mainG").appendChild(new_rect);
}
}
function expand(evt) {
evt.target.parentNode.appendChild(evt.target);
evt.target.setAttributeNS(null, "r", "25");
evt.target.style.fill='hsl(0, 50%, 70%)';
}
function shrink(evt) {
evt.target.setAttributeNS(null, "r", "10");
evt.target.style.fill='hsl(100, 30%, 80%)';
}
.circle {
fill: hsl(100, 30%, 80%);
-webkit-transition: .4s ease-in-out;
}
<svg version="1.1" baseProfile="full" width="440" height="150" xmlns="http://www.w3.org/2000/svg">
<g id="mainG">
<circle id="0" cx="10" cy="10" r="10" stroke="none" fill="white" class="circle" onmouseover="expand(evt)" onmouseout="shrink(evt)"></circle>
</g>
<g id="cloneG"></g>
</svg>
or (same thing with CSS added through JS)
for (var i = 0; i < 20; i++) {
for (var n = 0; n < 5; n++) {
var new_rect = document.getElementById("0").cloneNode(true);
new_rect.setAttributeNS(null, "cx", i * 20 + 10);
new_rect.setAttributeNS(null, "cy", n * 20 + 10);
new_rect.style.fill='hsl(100, 30%, 80%)';
new_rect.setAttributeNS(null, "id", i + n);
document.getElementById("mainG").appendChild(new_rect);
}
}
function expand(evt) {
evt.target.parentNode.appendChild(evt.target);
evt.target.setAttributeNS(null, "r", "25");
evt.target.style.fill='hsl(0, 50%, 70%)';
evt.target.style.transition= '.4s ease-in-out';
}
function shrink(evt) {
evt.target.setAttributeNS(null, "r", "10");
evt.target.style.fill='hsl(100, 30%, 80%)';
}
<svg version="1.1" baseProfile="full" width="440" height="150" xmlns="http://www.w3.org/2000/svg">
<g id="mainG">
<circle id="0" cx="10" cy="10" r="10" stroke="none" fill="white" class="circle" onmouseover="expand(evt)" onmouseout="shrink(evt)"></circle>
</g>
<g id="cloneG"></g>
</svg>
Related
How do I get a style property value from an SVG element that is animated using transform?
If I have an SVG element that is animated using transform, either using SMIL or CSS, how do I get the computed style of the property that is animated? Here I have a <rect> that rotates, but as you can see the rotate property just returns none: var rect1 = document.getElementById('rect1'); setTimeout(function(){ let rectStyle = getComputedStyle(rect1); console.log(rectStyle.rotate); }, 200); <svg id="svg" width="200" viewBox="0 0 4 4" xmlns="http://www.w3.org/2000/svg"> <rect id="rect1" x="1" y="1" width="2" height="2" fill="red"> <animateTransform attributeName="transform" attributeType="XML" type="rotate" values="0 2 2; 360 2 2" dur="10s" repeatCount="indefinite"/> </rect> </svg> var rect1 = document.getElementById('rect1'); setTimeout(function(){ let rectStyle = getComputedStyle(rect1); console.log(rectStyle.rotate); }, 200); #rect1 { transform-origin: center; animation-name: rotate; animation-duration: 10s; animation-timing-function: linear; animation-iteration-count: infinite; } #keyframes rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } <svg id="svg" width="200" viewBox="0 0 4 4" xmlns="http://www.w3.org/2000/svg"> <rect id="rect1" x="1" y="1" width="2" height="2" fill="red" /> </svg>
In the case of a SMIL animation just read off the SMIL values if you want to. var rect1 = document.getElementById('rect1'); setTimeout(function(){ let a = rect1.transform.animVal[0].matrix.a; let b = rect1.transform.animVal[0].matrix.b; let angle = Math.atan2(b, a) * (180/Math.PI); console.log(angle); }, 200); <svg id="svg" width="200" viewBox="0 0 4 4" xmlns="http://www.w3.org/2000/svg"> <rect id="rect1" x="1" y="1" width="2" height="2" fill="red"> <animateTransform attributeName="transform" attributeType="XML" type="rotate" values="0 2 2; 360 2 2" dur="10s" repeatCount="indefinite"/> </rect> </svg>
In the case of a CSS animation you can use transform instead of rotate but you get something like matrix(....). to get the exact value you need similar to this article . var rect1 = document.getElementById('rect1'); setTimeout(function(){ let rectStyle = getComputedStyle(rect1); let values = rectStyle.transform.split('(')[1]; values = values.split(')')[0]; values = values.split(','); let a = values[0]; let b = values[1]; let c = values[2]; let d = values[3]; var angle = Math.atan2(b, a) * (180/Math.PI); console.log(angle); }, 200); #rect1 { transform-origin: center; animation-name: rotate; animation-duration: 10s; animation-timing-function: linear; animation-iteration-count: infinite; } #keyframes rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } <svg id="svg" width="200" viewBox="0 0 4 4" xmlns="http://www.w3.org/2000/svg"> <rect id="rect1" x="1" y="1" width="2" height="2" fill="red" /> </svg>
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"
Using CSS transitions to animate dynamic SVG Attributes
I'm trying to animate the attributes of various SVG shapes using JavaScript and CSS transitions. For example: HTML: <svg width="400" height="400"> <circle id="circle" cx="200" cy="200" r="15" stroke="none" fill="blue" /> <rect id="rect" x="100" y="100" height="30" width="30" stroke="none" fill="red" /> </svg> <button id="button">Animate</button> JavaScript: document.getElementById("button").addEventListener("click", function () { var circle = document.getElementById("circle"); var cx = 50 + Math.round(Math.random() * 300); var cy = 50 + Math.round(Math.random() * 300); // using 'setAttribute' circle.setAttribute("cx", cx); circle.setAttribute("cy", cy); var rect = document.getElementById("rect"); var x = 50 + Math.round(Math.random() * 300); var y = 50 + Math.round(Math.random() * 300); // using 'setAttributeNS' rect.setAttributeNS(null, "x", x); rect.setAttributeNS(null, "y", y); }, false); CSS: circle, rect { -webkit-transition: all 0.7s ease-in-out; -moz-transition: all 0.7s ease-in-out; transition: all 0.7s ease-in-out; } Here's a complete JSFiddle: http://jsfiddle.net/kkhvzyjq/ In Chrome, this works beautifully. However, in Safari and Firefox, while the new attributes are applied (the shapes move), there's no transition/animation. Is there a way to do this that works in these browsers?
Safari and Firefox do not transition changes in the position attributes. The CSS property transform works better for that: http://jsfiddle.net/kkhvzyjq/7/ document.getElementById("button").addEventListener("click", function() { var circle = document.getElementById("circle"); var cx = 50 + Math.round(Math.random() * 300); var cy = 50 + Math.round(Math.random() * 300); circle.style.transform = "translate(" + cx + "px," + cy + "px)"; var rect = document.getElementById("rect"); var x = 50 + Math.round(Math.random() * 300); var y = 50 + Math.round(Math.random() * 300); rect.style.transform = "translate(" + x + "px," + y + "px)"; }, false); circle, rect { -webkit-transition: all 0.7s ease-in-out; -moz-transition: all 0.7s ease-in-out; transition: all 0.7s ease-in-out; } <svg width="400" height="400"> <circle id="circle" r="10" stroke="none" fill="blue" style="transform:translate(200px,200px);" /> <rect id="rect" height="10" width="10" stroke="none" fill="red" style="transform:translate(100px,100px);" /> </svg> <button id="button">Animate</button>