Mousemove and Hover Jquery effect to Pure Javascript or VueJS event - javascript
I have a VueJS component which is a svg map image of the united states. I previously used jquery to create hover effects to display the information bubble. I am trying to convert this to a pure Javascript solution. It seems a click event is the easiest to implement given vuejs mousemove seems to be less reliable. I have added the click event in method and I am trying to capture the SVG path location and steal the top and left position to enable the info box there. I have tried this.offsettop and this.offsetleft but they return undefined.
Jquery code I am trying to convert:
$("path, circle").hover(function(e) {
$('#info-box').css('display','block');
$('#info-box').html($(this).data('info'));
});
$("path, circle").mouseleave(function(e) {
$('#info-box').css('display','none');
});
$(document).mousemove(function(e) {
$('#info-box').css('top',e.pageY-$('#info-box').height()-30);
$('#info-box').css('left',e.pageX-($('#info-box').width())/2);
}).mouseover();
var ios = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
if(ios) {
$('a').on('click touchend', function() {
var link = $(this).attr('href');
window.open(link,'_blank');
return false;
});
}
VueJS Component
<template id="geomap-assignments">
<v-card class="pa-4 ma-3 rounded-lg" min-height="500px">
<div class="card-title-docs">
<h4 class="card-header">Assignments</h4>
<h5 class="card-sub-header"></h5>
</div>
<div class="map-container">
<div id="info-box"></div>
<?xml version="1.0" encoding="utf-8" ?>
<svg xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="us-map" preserveAspectRatio="xMinYMin meet" sodipodi:docname="Republican_Party_presidential_primaries_results,_2016.svg" inkscape:version="0.91 r13725" x="0px" y="0px" width="959px" height="593px" viewBox="174 100 959 593" enable-background="new 174 100 959 593" xml:space="preserve">
<sodipodi:namedview bordercolor="#666666" objecttolerance="10" pagecolor="#ffffff" borderopacity="1" gridtolerance="10" guidetolerance="10" inkscape:cx="509.19152" inkscape:cy="282.2353" inkscape:zoom="1.2137643" showgrid="false" id="namedview71" inkscape:current-layer="g5" inkscape:window-maximized="1" inkscape:window-y="-8" inkscape:window-x="-8" inkscape:pageopacity="0" inkscape:window-height="1017" inkscape:window-width="1920" inkscape:pageshadow="2">
</sodipodi:namedview>
<g id="g5">
<path id="HI" data-info="<div>State: Hawaii</div><div>Capital: Honolulu</div>" fill="#D3D3D3" d="M407.1,619.3l1.9-3.6l2.3-0.3l0.3,0.8l-2.1,3.1H407.1z M417.3,615.6l6.1,2.6l2.1-0.3l1.6-3.9 l-0.6-3.4l-4.2-0.5l-4,1.8L417.3,615.6z M448,625.6l3.7,5.5l2.4-0.3l1.1-0.5l1.5,1.3l3.7-0.2l1-1.5l-2.9-1.8l-1.9-3.7l-2.1-3.6 l-5.8,2.9L448,625.6z M468.2,634.5l1.3-1.9l4.7,1l0.6-0.5l6.1,0.6l-0.3,1.3l-2.6,1.5l-4.4-0.3L468.2,634.5z M473.5,639.7l1.9,3.9 l3.1-1.1l0.3-1.6l-1.6-2.1l-3.7-0.3V639.7z M480.5,638.5l2.3-2.9l4.7,2.4l4.4,1.1l4.4,2.7v1.9l-3.6,1.8l-4.8,1l-2.4-1.5 L480.5,638.5z M497.1,654.1l1.6-1.3l3.4,1.6l7.6,3.6l3.4,2.1l1.6,2.4l1.9,4.4l4,2.6l-0.3,1.3l-3.9,3.2l-4.2,1.5l-1.5-0.6l-3.1,1.8 l-2.4,3.2l-2.3,2.9l-1.8-0.2l-3.6-2.6l-0.3-4.5l0.6-2.4l-1.6-5.7l-2.1-1.8l-0.2-2.6l2.3-1l2.1-3.1l0.5-1l-1.6-1.8L497.1,654.1z" />
<path id="OK" data-info="<div>State: Oklahoma</div><div>Capital: Oklahoma City</div>" fill="#D3D3D3" d="M549.3,422.6l-10.7-0.5l-6.4-0.5l0.3,0.2l-0.7,10.4l22,1.4l32.1,1.3l-2.3,24.4l-0.5,17.8l0.2,1.6 l4.3,3.7l2.1,1.1l0.7-0.2l0.7-2.1l1.4,1.8h2.1v-1.4l2.7,1.4l-0.5,3.9l4.1,0.2l2.5,1.1l4.1,0.7l2.5,1.8l2.3-2.1l3.4,0.7l2.5,3.4h0.9 v2.3l2.3,0.7l2.3-2.3l1.8,0.7h2.5l0.9,2.5l4.8,1.8l1.4-0.7l1.8-4.1h1.1l1.1,2.1l4.1,0.7l3.7,1.4l3,0.9l1.8-0.9l0.7-2.5h4.3l2.1,0.9 l2.7-2.1h1.1l0.7,1.6h4.1l1.6-2.1l1.8,0.5l2.1,2.5l3.2,1.8l3.2,0.9l1.9,1.1l-0.4-37.2l-1.4-11l-0.2-8.9l-1.4-6.5l-0.8-7.2l-0.1-3.8 l-12.1,0.3l-46.4-0.5l-45-2.1L549.3,422.6z" />
<path id="KS" data-info="<div>State: Kansas</div><div>Capital: Topeka</div>" fill="#D3D3D3" d="M677.4,425.1l-12.6,0.2l-46.1-0.5l-44.6-2.1l-24.6-1.3l4.1-64.7l21.8,0.8l40.5,1.4l44.1,0.5h5.1 l3.2,3.2l2.8,0.2l0.9,1.1v2l-1.8,1.6l-0.5,2.6l2.2,3.6l2.5,3.1l2.5,2l1.1,11.2L677.4,425.1z" />
<path id="LA" data-info="<div>State: Louisiana</div><div>Capital: Baton Rouge</div>" fill="#D3D3D3" d="M776.2,573l-1-2.6l-1.1-3.1l-3.3-3.5l0.9-6.8l-0.1-1.1l-1.3,0.3l-8.2,0.9l-25,0.5l-0.7-2.4l0.9-8.5 l3.3-5.9l5-8.7l-0.6-2.4l1.3-0.7l0.5-2l-2.3-2.1l-0.1-1.9l-1.8-4.3l-0.5-5.9l-9.7,0.1l-19.2,0.9l-22.2,0l0,9.6l0.7,9.4l0.7,3.9 l2.5,4.1l0.9,5l4.3,5.5l0.2,3.2l0.7,0.7l-0.7,8.5l-3,5l1.6,2.1l-0.7,2.5l-0.7,7.3l-1.4,3.2l0.1,3.6l4.7-1.5l8.1-0.3l10.3,3.6 l6.5,1.1l3.7-1.5l3.2,1.1l3.2,1l0.8-2.1l-3.2-1.1l-2.6,0.5l-2.7-1.6c0,0,0.2-1.3,0.8-1.5c0.6-0.2,3.1-1,3.1-1l1.8,1.5l1.8-1 l3.2,0.6l1.5,2.4l0.3,2.3l4.5,0.3l1.8,1.8l-0.8,1.6l-1.3,0.8l1.6,1.6l8.4,3.6l3.6-1.3l1-2.4l2.6-0.6l1.8-1.5l1.3,1l0.8,2.9 l-2.3,0.8l0.6,0.6l3.4-1.3l2.3-3.4l0.8-0.5l-2.1-0.3l0.8-1.6l-0.2-1.5l2.1-0.5l1.1-1.3l0.6,0.8c0,0-0.2,3.1,0.6,3.1 c0.8,0,4.2,0.6,4.2,0.6l4,1.9l1,1.5h2.9l1.1,1l2.3-3.1v-1.5h-1.3l-3.4-2.7l-5.8-0.8l-3.2-2.3l1.1-2.7l2.3,0.3l0.2-0.6l-1.8-1v-0.5 h3.2l1.8-3.1l-1.3-1.9l-0.3-2.7l-1.5,0.2l-1.9,2.1l-0.6,2.6l-3.1-0.6l-1-1.8l1.8-1.9l2-1.8L776.2,573z" />
<path id="VA" data-info="<div>State: Virginia</div><div>Capital: Richmond</div>" fill="#D3D3D3" d="M1002.9,369.2l-0.1-1.9l6.5-2.5l-0.8,3.2l-2.9,3.8l-0.4,4.6l0.5,3.4l-1.8,5l-2.2,1.9l-1.5-4.6 l0.4-5.4l1.6-4.2L1002.9,369.2z M1005.2,397.5L947,410.1l-37.4,5.3l-6.7-0.4l-2.6,1.9l-7.3,0.2l-8.4,1l-8.9,1l8.5-4.9l0-2.1 l1.5-2.1l10.6-11.5l3.9,4.5l3.8,1l2.5-1.1l2.2-1.3l2.5,1.3l3.9-1.4l1.9-4.6l2.6,0.5l2.9-2.1l1.8,0.5l2.8-3.7l0.3-2.1l-1-1.3l1-1.9 l5.3-12.3l0.6-5.7l1.2-0.5l2.2,2.4l3.9-0.3l1.9-7.6l2.8-0.6l1-2.7l2.6-2.3l1.3-2.3l1.5-3.4l0.1-5.1l9.8,3.8 c0.7,0.3,0.7-4.8,0.7-4.8l4.1,1.4l-0.5,2.6l8.2,2.9l1.3,1.8l-0.9,3.7l-1.3,1.3l-0.5,1.7l0.5,2.4l2,1.3l3.9,1.4l2.9,1l4.9,0.9 l2.2,2.1l3.2,0.4l0.9,1.2l-0.4,4.7l1.4,1.1l-0.5,1.9l1.2,0.8l-0.2,1.4l-2.7-0.1l0.1,1.6l2.3,1.5l0.1,1.4l1.8,1.8l0.5,2.5l-2.6,1.4 l1.6,1.5l5.8-1.7L1005.2,397.5z" />
<g id="DC">
<path id="path58" fill="#D3D3D3" d="M975.8,353.8l-1.1-1.6l-1-0.8l1.1-1.6l2.2,1.5L975.8,353.8z" />
<circle id="circle60" data-info="<div>Washington DC</div>" fill="#D3D3D3" stroke="#FFFFFF" stroke-width="1.5" cx="975.3" cy="351.8" r="5" />
</g>
</g>
<path id="path67" fill="none" stroke="#A9A9A9" stroke-width="2" d="M385,593v55l36,45 M174,525h144l67,68h86l53,54v46" />
</svg>
</div>
</v-card>
</template>
<script>
Vue.component('geomap-assignments', {
template: '#geomap-assignments',
methods: {
activateCaption: function (event) {
// `event` is the native DOM event
if (event) {
const left = this.offsetTop
const top = this.offsetTop
alert("LEFT" + left + "RIGHT" + top);
}
}
},
data() {
return {
documents: [
]
}
}
})
</script>
<style scoped>
.card-title-docs {
margin: 20px 20px;
}
.card-header {
font-size: 1rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1px;
color: #515151;
}
.card-sub-header {
font-size: .8rem;
font-weight: 500;
text-transform: uppercase;
letter-spacing: .7px;
color: #7f818d;
}
.map-container{
position:relative;
width: 100%;
height: 100%;
}
#us-map {
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
path:hover, circle:hover {
stroke: #002868 !important;
stroke-width: 2px;
stroke-linejoin: round;
fill: #002868 !important;
cursor: pointer;
}
#path67 {
fill: none !important;
stroke: #A9A9A9 !important;
cursor: default;
}
#info-box {
display: none;
position: absolute;
top: 0px;
left: 0px;
z-index: 1;
background-color: #ffffff;
border: 2px solid #BF0A30;
border-radius: 5px;
padding: 5px;
font-family: arial;
}
</style>
'''
The solution was found in the comments on the question.
In summary, the issue was understanding how to position the #info-box element. Using the getBoundingClientRect() function, we can get the position of any element relative to the entire document. To get the position of the clicked path element, simply subtract the top and left of the #us-map from the top and left of the path. This will give the position for the top left corner of the path, relative to the containing element. We can then use that to position the #info-box.
Related
Click svg path and change option value on a select component
Currently I have some code that when selecting a value from a dropdown list will paint a specific path of a svg image. var paths1 = { "https://www.google.com": { color: "#eb8c00", selector: "#path1" }, "https://www.yahoo.com": { color: "#eb8c00", selector: "#path2" }, } $('#path').on("change", function() { $('#path1, #path2').css({ fill: "#FFFFFF" }); var value = $(this).val() if (!value) { return; } var { color, selector } = paths1[value] $(selector).css({ fill: color }); }); <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div name="svg"> <svg id="Layer_1" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="500px" height="500px" viewBox="0 0 500 500" enable-background="new 0 0 500 500" xml:space="preserve"> <path id="path1" fill="#FFFFFF" stroke="#231F20" stroke-miterlimit="10" d="M291.451,51.919v202.54c0,0,164.521,119.846,140.146,0 C407.227,134.613,291.451,51.919,291.451,51.919z"/> <path id="path2" fill="#FFFFFF" stroke="#231F20" stroke-miterlimit="10" d="M169.595,150.844c0,0-76.24,69.615-40.606,128.309 c35.634,58.695,155.798-51.867,151.654-85.993C276.498,159.034,177.054,89.42,169.595,150.844z"/> </svg> </div> <select id="path" name="path" class="pathSelector"> <option value="">Select Path</option> <option value="https://www.google.com">Google</option> <option value="https://www.yahoo.com">Yahoo</option> </select> <div> <input type="button" class="selectbutton" value="Select" onClick="window.open(path.value,'newtab'+path.value)"> </div> It works fine, as the button will also redirect to a different page.Now I need to be able to the reverse. I want to click on a path and the dropdown selector will also change. Clicking on path1 will select Google and clicking on path2 will select Yahoo from my dropdown list. How can I achieve this?
To achieve this, you could define a click event handler: $('#Layer_1 path').on("click", function() {...}); and use a for in loop to compare the selector values in the paths1 array with the ID of the clicked path: for (key in paths1) { if (paths1[key].selector == '#' + this.id) {...} } If you found a match, you can use the key to select the option tag and assign the selected property to it: $('option[value="' + key + '"]').prop('selected', true); All together: $('#Layer_1 path').on("click", function() { for (key in paths1) { if (paths1[key].selector == '#' + this.id) { $('option[value="' + key + '"]').prop('selected', true); } } }); You could also change the colors similar to the other event handler: $('#Layer_1 path').on("click", function() { for (key in paths1) { if (paths1[key].selector == '#' + this.id) { $('option[value="' + key + '"]').prop('selected', true); $('#path1, #path2').css({ fill: "#FFFFFF" }); $(this).css({fill: paths1[key].color}); } } }); Working example: var paths1 = { "https://www.google.com": { color: "#eb8c00", selector: "#path1" }, "https://www.yahoo.com": { color: "#eb8c00", selector: "#path2" }, } $('#path').on("change", function() { $('#path1, #path2').css({ fill: "#FFFFFF" }); var value = $(this).val() if (!value) { return; } var { color, selector } = paths1[value] $(selector).css({ fill: color }); }); $('#Layer_1 path').on("click", function() { for (key in paths1) { if (paths1[key].selector == '#' + this.id) { $('option[value="' + key + '"]').prop('selected', true); $('#path1, #path2').css({ fill: "#FFFFFF" }); $(this).css({fill: paths1[key].color}); } } }); <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div name="svg"> <svg id="Layer_1" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="500px" height="500px" viewBox="0 0 500 500" enable-background="new 0 0 500 500" xml:space="preserve"> <path id="path1" fill="#FFFFFF" stroke="#231F20" stroke-miterlimit="10" d="M291.451,51.919v202.54c0,0,164.521,119.846,140.146,0 C407.227,134.613,291.451,51.919,291.451,51.919z"/> <path id="path2" fill="#FFFFFF" stroke="#231F20" stroke-miterlimit="10" d="M169.595,150.844c0,0-76.24,69.615-40.606,128.309 c35.634,58.695,155.798-51.867,151.654-85.993C276.498,159.034,177.054,89.42,169.595,150.844z"/> </svg> </div> <select id="path" name="path" class="pathSelector"> <option value="">Select Path</option> <option value="https://www.google.com">Google</option> <option value="https://www.yahoo.com">Yahoo</option> </select> <div> <input type="button" class="selectbutton" value="Select" onClick="window.open(path.value,'newtab'+path.value)"> </div>
here is a code that you can check out as an example. It must help. Good luck. function SelectADropdownItem(id, val) { var d = document.getElementById(id); for (var i = 0; i < d.length; i++) { if (d[i].value == val) { d[i].selected = true; } else { d[i].selected = false; } } } <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <img onclick="SelectADropdownItem('design-dropdown','Fleur')" src="//www.willmaster.com/library/images/ImageClickSelects/flower.jpg" style=" border: none; height: 120px; width: 94px; cursor: pointer; margin: 0 5px 0 5px; " alt="Flower design" /> <img onclick="SelectADropdownItem('design-dropdown','Nine Patch')" src="//www.willmaster.com/library/images/ImageClickSelects/ninepatch.jpg" style=" border: none; height: 120px; width: 94px; cursor: pointer; margin: 0 5px 0 5px; " alt="Nine patch design" /> <img onclick="SelectADropdownItem('design-dropdown','Pink Gate')" src="//www.willmaster.com/library/images/ImageClickSelects/pinkgate.jpg" style=" border: none; height: 120px; width: 94px; cursor: pointer; margin: 0 5px 0 5px; " alt="Pink gate design" /> <br /> <img onclick="SelectADropdownItem('design-dropdown','Sand Dollar')" src="//www.willmaster.com/library/images/ImageClickSelects/sanddollar.jpg" style=" border: none; height: 120px; width: 94px; cursor: pointer; margin: 0 5px 0 5px; " alt="Sand dollar design" /> <img onclick="SelectADropdownItem('design-dropdown','Sandria')" src="//www.willmaster.com/library/images/ImageClickSelects/sandria.jpg" style=" border: none; height: 120px; width: 94px; cursor: pointer; margin: 0 5px 0 5px; " alt="Sandria design" /> <img onclick="SelectADropdownItem('design-dropdown','Blue Wheel')" src="//www.willmaster.com/library/images/ImageClickSelects/wheel.jpg" style=" border: none; height: 120px; width: 94px; cursor: pointer; margin: 0 5px 0 5px; " alt="Blue wheel design" /> <select id="design-dropdown"> <option>Select here or click a pattern above.</option> <option value="Fleur">Fleur</option> <option value="Nine Patch">Nine Patch</option> <option value="Pink Gate">Pink Gate</option> <option value="Sand Dollar">Sand Dollar</option> <option value="Sandria">Sandria</option> <option value="Blue Wheel">Blue Wheel</option> </select> </body> </html>
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"
Can't get hamburger menu to animate on click
I targeted the SVG rect using :nth-chid(1), 2 and 3 and made a -> that I'm trying to trigger on click. Don't know what I'm doing wrong here. Any Help would be great thank you! (function() { var burger; buger = document.getElementById('burger'); burger.addEventListener('click', function() { console.log('you cliked the burger'); return burger.classList.toggle('st0-active'); }); }).call(this); body { max-width: 900px; margin: 0 auto; } .st0-active:nth-child(1) { -webkit-transform: rotate(27deg) translate(23px, -51px); transform: rotate(27deg) translate(23px, -51px); fill: #000; } .st0-active:nth-child(2) { fill: #000; } .st0-active:nth-child(3) { -webkit-transform: rotate(-21deg) translate(-48px, 15px); transform: rotate(-21deg) translate(-48px, 15px); fill: #000; } <body> <svg class="mo-icon__svg" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 200 200" style="enable-background:new 0 0 200 200;" xml:space="preserve" id="burger"> <g id="icon_x5F_hamburger"> <rect x="0.11206" y="46.3329" class="st0" width="200" height="8"/> <rect x="0.11206" y="96.22083" class="st0" width="200" height="8"/> <rect x="0.11206" y="146.10876" class="st0" width="200" height="8"/> </g> </svg> </body> Here is a picture of my designed end goal Which is the reason I'm using CSS Transforms and targeting the rect using nth-child Here is a link to the codepen that I'm currently working on enter link description here
(function() { var burger; burger = document.getElementById('burger'); burger.addEventListener('click', function() { console.log('you cliked the burger'); return burger.classList.toggle('st0-active'); }); }).call(this); body { max-width: 900px; margin: 0 auto; } #burger > g > rect{ transition: transform 1s; } .st0-active > g > rect:nth-child(1) { -webkit-transform: rotate(27deg) translate(23px, -51px); transform: rotate(27deg) translate(23px, -51px); fill: #000; } .st0-active > g > rect:nth-child(2) { fill: #000; } .st0-active > g > rect:nth-child(3) { -webkit-transform: rotate(-21deg) translate(-48px, 15px); transform: rotate(-21deg) translate(-48px, 15px); fill: #000; } <body> <svg class="mo-icon__svg" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 200 200" style="enable-background:new 0 0 200 200;" xml:space="preserve" id="burger"> <g id="icon_x5F_hamburger"> <rect x="0.11206" y="46.3329" class="st0" width="200" height="8"/> <rect x="0.11206" y="96.22083" class="st0" width="200" height="8"/> <rect x="0.11206" y="146.10876" class="st0" width="200" height="8"/> </g> </svg> </body> Try to add this code. #burger{ transition: transform 1s; } Additionally CSS3 transitions allows you to change property values smoothly (from one value to another), over a given duration.
Vertically centering part of svg content
I've been trying to center a collection of svg paths/text vertically in CSS / JS for quite a while with no luck. None of the solutions I've found here have worked so far. I have multiple < text > , < circle >, < rect >, although I don't think the type of content really matters. The height is variable, so I have thought of 2 methods: 1) Transform via 50%. This is not working because you cannot transform a sub-set of content from a svg, from what I have found so far. The < g > tag was promising but I had no luck. 2) My second idea was to adjust the mask down via javascript once content is loaded. This, likewise, is not working. All code is on code-pen and copied here as well: https://codepen.io/anon/pen/MmdWXB HTML: <div class="mask_group" id="mask_container"> <div class="text"> <svg> <defs> <mask id="mask" x="0" y="0" width="100%" height="100%" > <rect class="cutout label" x="0" y="0" width="100%" height="100%"/> <text class="label normal_font_weight" y="1em" dy="0em" x="50%">A</text> <text class="label normal_font_weight" y="3em" dy="0em" x="50%">B</text> <line class="label" x1="47%" y1="4.6em" x2="53%" y2="4.6em" style="stroke:rgb(255,0,0);stroke-width:1.5" /> <text class="label" y="7em" dy="0em" x="50%">C</text> <text class="label" y="9em" id="final_text" dy="0em" x="50%">D</text> </mask> </defs> <rect id="base" x="0" y="0" width="100%" height="100%"/> </svg> </div> </div> <div style="background-color:blue; width: 100%; height: 100%"> </div> CSS: html,body { height: 100%; } .text { position: relative; /*top: 0; left: 0;*/ width: 100%; height: 100%; margin-left: 0%; /*z-index: 11; */ } .mask_group { position: fixed; width: 100%; height: 100%; z-index: 10; } svg { position: absolute; width: 100%; height: inherit; } svg text { text-anchor: middle; } .cutout { fill: white; } svg #base { fill: #051E2A; /*#1F5773;*/ -webkit-mask: url(#mask); mask: url(#mask); } /*Unused*/ .vert_center { position: relative; margin-top: 50%; transform: translateY(-50%); } JS: function body_loaded() { var final_text = document.getElementById("final_text"); var position = final_text.getBoundingClientRect(); var bottom = position.bottom; var mask_container = document.getElementById("mask_container"); var mask_position = mask_container.getBoundingClientRect(); var mask_height = mask_position.height; var origin_y = (mask_height - bottom) / 2; alert(origin_y); var mask = document.getElementById("mask"); mask.style.y = origin_y; } Thanks ahead of time!
I'm not sure what you are attempting to do with the <mask>, so I am going to ignore it for now. To vertically centre the SVG, just give it a fixed height and use the standard translate(-50%) trick. The only wrinkle is that you can't put the CSS transform on the <svg> element because transform has a different behavior in SVGs than it does in CSS. SVG transforms pre-date CSS transforms. So you just need to wrap the SVG in an HTML container and apply the transform to that instead. I've set the height of the <svg> to 10em. Obviously you'll need to adjust that if you have more text. You could do that with JS using svgElem.setAttribute("height", "10em"); But take it out of the CSS first obviously :) html,body { height: 100%; } .svg-wrapper { position: absolute; width: 100%; top: 50%; transform: translate(0, -50%); } .mask_group { position: fixed; width: 100%; height: 100%; z-index: 10; } svg { width: 100%; height: 10em; fill: blue; /* default fill colour for contents */ } svg text { text-anchor: middle; } svg #base { fill: #051E2A; /*#1F5773;*/ } <div class="mask_group" id="mask_container"> <div class="svg-wrapper"> <svg> <rect id="base" x="0" y="0" width="100%" height="100%"/> <text class="label normal_font_weight" y="1em" dy="0em" x="50%">A</text> <text class="label normal_font_weight" y="3em" dy="0em" x="50%">B</text> <line class="label" x1="47%" y1="4.6em" x2="53%" y2="4.6em" style="stroke:rgb(255,0,0);stroke-width:1.5" /> <text class="label" y="7em" dy="0em" x="50%">C</text> <text class="label" y="9em" id="final_text" dy="0em" x="50%">D</text> </svg> </div> </div> <div style="background-color:blue; width: 100%; height: 100%"> </div>