Get X,Y position of element in Javascript - javascript
I want to find X,Y position of mouse click relative to SVG element. The SVG element will be embedded in HTML.
var svg = document.getElementById("svg1");
svg.addEventListener('click', event => {
let x = event.clientX;
let y = event.clientY;
console.log(x, y);
});
html {
height: 100%
}
body {
height: 100%;
display: flex;
justify-content: center;
background-color: #fff;
}
svg {
height: 100%;
background: grey;
}
<svg id="svg1" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="40" fill="#52c927" />
<circle cx="50" cy="50" r="25" fill="white" />
<circle cx="50" cy="50" r="15" fill="red" />
</svg>
Want to subract offsetLeft and offsetTop of SVG before printing X and Y in console. But not able to get those value
To get an element coordinates or size use Element.getBoundingClientRect
event.target.getBoundingClientRect() or event.currentTarget.getBoundingClientRect() (for the element bound to the listener, rather than the one who propagated the event). Or directly with your cached Element reference constant svg.getBoundingClientRect()
const bcr = event.target.getBoundingClientRect();
console.log(bcr.left, bcr.top)
https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect
In your specific case, to get the relative mouse coordinates:
var svg = document.getElementById("svg1");
svg.addEventListener('click', event => {
const bcr = event.target.getBoundingClientRect();
const relative_x = event.clientX - bcr.left;
const relative_y = event.clientY - bcr.top;
console.log(relative_x, relative_y);
});
You can get the coordinates relative to the element like this:
var svg = document.getElementById("svg1");
svg.addEventListener('click', event => {
const rect = svg.getBoundingClientRect();
let x = event.clientX - rect.left;
let y = event.clientY - rect.top;
console.log(x, y);
});
html {
height: 100%
}
body {
height: 100%;
display: flex;
justify-content: center;
background-color: #fff;
}
svg {
height: 100%;
background: grey;
}
<svg id="svg1" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="40" fill="#52c927" />
<circle cx="50" cy="50" r="25" fill="white" />
<circle cx="50" cy="50" r="15" fill="red" />
</svg>
Related
Javascript function does not work for multiple circular progress bar
This querySelectorAll does not work for multiple circular progress bar. When I use querySelector it works for only one circle. How can i use this function for multiple circular progress bar. Again, why this error -> "Uncaught TypeError: circle.getAttribute is not a function" ? const circle = document.querySelectorAll(".progress"); const number = document.querySelectorAll(".progress-percent"); const val = circle.getAttribute("data-value"); let counter = 0; let cir = 377; setInterval(() => { if (counter == val) { clearInterval(); } else { counter += 1; circle.style.strokeDashoffset = (cir - (cir / 100) * val); number.innerHTML = counter; } }, 25); body { background-color: #f50057; display: flex; justify-content: center; align-items: center; } .progress { stroke: #fff; stroke-width: 2; stroke-dasharray: 377; stroke-dashoffset: 377; transition: 2.5s ease-out; } .progress-percent { color: #fff; } <section> <div> <svg> <circle r="60" cx="60" cy="60"></circle> <circle r="60" cx="60" cy="60" class="progress" data-value="80"></circle> </svg> <p><span class="progress-percent"></span>%</p> </div> <div> <svg> <circle r="60" cx="60" cy="60"></circle> <circle r="60" cx="60" cy="60" class="progress" data-value="90"></circle> </svg> <p><span class="progress-percent"></span>%</p> </div> <div> <svg> <circle r="60" cx="60" cy="60"></circle> <circle r="60" cx="60" cy="60" class="progress" data-value="70"></circle> </svg> <p><span class="progress-percent"></span>%</p> </div> </section>
unlike .querySelector, .querySelectorAll returns many results. The previous actions that you would call on a single circle will not automatically apply to each of your circles. However, you can use the .forEach method and pass a function with each item as an argument. you can read more about .forEach here If you have any questions, please ask. Hopefully this helps point you in the right direction 👋 const circles = document.querySelectorAll(".progress"); const numbers = document.querySelectorAll(".progress-percent"); const cir = 377; circles.forEach((circle, index) => { let counter = 0; const val = circle.getAttribute("data-value"); setInterval(() => { if (counter == val) { clearInterval(); } else { counter += 1; circle.style.strokeDashoffset = (cir - (cir / 100) * val); numbers[index].innerHTML = counter; } }, 25); }); body { background-color: #f50057; display: flex; justify-content: center; align-items: center; } .progress { stroke: #fff; stroke-width: 2; stroke-dasharray: 377; stroke-dashoffset: 377; transition: 2.5s ease-out; } .progress-percent { color: #fff; } <section> <div> <svg> <circle r="60" cx="60" cy="60"></circle> <circle r="60" cx="60" cy="60" class="progress" data-value="80"></circle> </svg> <p><span class="progress-percent"></span>%</p> </div> <div> <svg> <circle r="60" cx="60" cy="60"></circle> <circle r="60" cx="60" cy="60" class="progress" data-value="90"></circle> </svg> <p><span class="progress-percent"></span>%</p> </div> <div> <svg> <circle r="60" cx="60" cy="60"></circle> <circle r="60" cx="60" cy="60" class="progress" data-value="70"></circle> </svg> <p><span class="progress-percent"></span>%</p> </div> </section>
how to make svg curve at one end
im using svg for circular progress bar , i want to make one end curve not the both end . how is this possible ? how can i implement one end curve in svg? svg { height: 80vh; margin: 10vh auto; border: 1px solid red; display: block; transform: rotate(-90deg); } svg circle { stroke-width: 10; fill: transparent; } #outer { stroke: lightgrey; } #inner { stroke: blue; animation: value 2.5s linear forwards; stroke-linecap: round; } #keyframes value { 0% { stroke-dasharray: 0 100; } 100% { stroke-dasharray: 90 100; } } <svg viewbox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <circle id="outer" cx="50" cy="50" r="40" /> <circle id="inner" pathLength="100" cx="50" cy="50" r="40" /> </svg>
The easiest way would be to mask the starting point of the blue circle. For this you will need a <mask> like so: <mask id="m"> <rect width="100" height="100" fill="white"/> <rect x="85" y="40" width="10" height="10" /> </mask> Please observe that the first rectangle is white and it covers the whole chart. (Everything under a white pixel will be visible). The smaller rectangle is black and covers the starting point of the blue circle. Everything under a black pixel will be invisible. svg { height: 80vh; margin: 10vh auto; border: 1px solid red; display: block; transform: rotate(-90deg); } svg circle { stroke-width: 10; fill: transparent; } #outer { stroke: lightgrey; } #inner { stroke: blue; animation: value 2.5s linear forwards; stroke-linecap: round; } #keyframes value { 0% { stroke-dasharray: 0 100; } 100% { stroke-dasharray: 90 100; } } <svg viewbox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <mask id="m"> <rect width="100" height="100" fill="white"/> <rect x="85" y="40" width="10" height="10" /> </mask> <circle id="outer" cx="50" cy="50" r="40" /> <circle id="inner" pathLength="100" cx="50" cy="50" r="40" mask="url(#m)" /> </svg>
Try this code: svg { height: 80vh; margin: 10vh auto; border: 1px solid red; display: block; transform: rotate(-90deg); border-top-right-radius: 20px; } svg circle { stroke-width: 10; fill: transparent; } #outer { stroke: lightgrey; } #inner { stroke: blue; animation: value 2.5s linear forwards; stroke-linecap: round; } #keyframes value { 0% { stroke-dasharray: 0 100; } 100% { stroke-dasharray: 90 100; } } <svg viewbox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <circle id="outer" cx="50" cy="50" r="40" /> <circle id="inner" pathLength="100" cx="50" cy="50" r="40" /> </svg>
I came up with an alternative solution than enxaneta suggested. The problem with using a mask is that when your value goes over 96% or so, the circle isn't completely filled and the mask is revealed. Instead, you can set a rounded progress line on top of another progress line that has flat endcaps. By rotating the rounded progress line by roughly 5 degrees, the flat end is revealed. Here's how to do that in React Native with react-native-svg: const radius = 60; let myPercentage = 40; const circleCircumference = 2 * Math.PI * radius; const valueOffset = circleCircumference - (circleCircumference * myPercentage * 0.98) / 100; <Svg height={radius * 2 + 30} width={radius * 2 + 30}> <G rotation={-90} originX={radius + 15} originY={radius + 15}> // Background gray circle <Circle cx="50%" cy="50%" r={radius} stroke="rgb(60, 60, 60)" fill="transparent" strokeWidth="10" strokeDasharray={circleCircumference} strokeLinecap="butt" /> // Background progress circle with flat ends <Circle cx="50%" cy="50%" r={radius} stroke={"rgb(0, 51, 204)"} fill="transparent" strokeWidth="10" strokeDasharray={circleCircumference} strokeDashoffset={valueOffset} strokeLinecap="butt" /> // Progress circle with round ends rotated by 5 degrees <Circle cx="50%" cy="50%" r={radius} stroke={rgb(0, 51, 204)} fill="transparent" rotation={5} originX={radius + 15} originY={radius + 15} strokeWidth="10" strokeDasharray={circleCircumference} strokeDashoffset={valueOffset} strokeLinecap="round" /> </G> </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"
I want to place boxes of text and images on the corners of the path. How to do that?
I have defined a path over which a red dot moves on scrolling up and down. I want to place boxes of text and images on the corners of the path. So how do I go about doing that? function positionTheDot() { // What percentage down the page are we? var scrollPercentage = (document.documentElement.scrollTop + document.body.scrollTop) / (document.documentElement.scrollHeight - document.documentElement.clientHeight); // Get path length var path = document.getElementById("theMotionPath"); var pathLen = path.getTotalLength(); // Get the position of a point at <scrollPercentage> along the path. var pt = path.getPointAtLength(scrollPercentage * pathLen); // Position the red dot at this point var dot = document.getElementById("dot"); dot.setAttribute("transform", "translate(" + pt.x + "," + pt.y + ")"); }; // Update dot position when we get a scroll event. window.addEventListener("scroll", positionTheDot); // Set the initial position of the dot. positionTheDot(); .verylong { height: 2000px; } svg { width: 1000px; height: 1000px; align: center; } body { background-color: #333333; } h1 { color: red; font-size: 50px; text-align: center; } <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="/scripts/snippet-javascript-console.min.js?v=1"></script> <svg viewBox="0 0 820 820" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink"> <path d="M10 10 H 600 V 500 H 10 L 10 10" stroke="#d3d3d3" stroke-width="5" fill="none" id="theMotionPath"/> <!--<circle cx="10" cy="110" r="3" fill="#000"/> <!--The bottom grey dot--> <!-- <circle cx="110" cy="10" r="3" fill="#000"/> <!--The top grey dot--> <!-- Red circle which will be moved along the motion path. --> <circle cx="0" cy="0" r="5" fill="red" id="dot"/> </svg> <div class="verylong"> </div> This is what I tried to do by adding div, I had added cx and cy in div but that didn't help. div { width: 320px; padding: 10px; border: 5px solid gray; margin: 0; } </style> </head> <body> <svg viewBox="0 0 120 120"> <svg viewBox="0 0 820 820" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink"> <path d="M10 10 H 600 V 500 H 10 L 10 10" stroke="#d3d3d3" stroke- width="5" fill="none" id="theMotionPath"/> <!-- Red circle which will be moved along the motion path. --> <circle cx="0" cy="0" r="5" fill="red" id="dot"/> <div>This text is the actual content of the box.</div> </svg>