I just want to know if there's a way that I can synchronize the map zoom button on two different html pages?
https://i.stack.imgur.com/nrFf9.png
I want to sync all the buttons in left and right map.
Here's the code for my Left and Right Map
LEFT
var scale = 1,
panning = false,
pointX = 0,
pointY = 0,
start = { x: 0, y: 0 },
zoom1 = document.getElementById("zoom1");
zoom2 = document.getElementById("zoom2");
function setTransform() {
zoom1.style.transform = "translate(" + pointX + "px, " + pointY + "px) scale(" + scale + ")";
zoom2.style.transform = "translate(" + pointX + "px, " + pointY + "px) scale(" + scale + ")";
}
function reset(){
event.preventDefault();
scale = 1;
pointX = 0;
pointY = 0;
start = { x: 0, y: 0 };
setTransform();
}
function zoomOut(){
document.getElementById("zoomout").click();
event.preventDefault();
var xs = (event.clientX - pointX) / scale,
ys = (event.clientY - pointY) / scale,
delta = (event.wheelDelta ? event.wheelDelta : -event.deltaY);
(delta > 0) ? (scale *= 1.04) : (scale /= 1.04);
setTransform();
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>LEFT</title>
<style>
#vatican g path {
-moz-transition-property: opacity;
-o-transition-property: opacity;
-webkit-transition-property: opacity;
transition-property: opacity;
-moz-transition-duration: 0.5s;
-o-transition-duration: 0.5s;
-webkit-transition-duration: 0.5s;
transition-duration: 0.5s;
-moz-transition-timing-function: ease;
-o-transition-timing-function: ease;
-webkit-transition-timing-function: ease;
transition-timing-function: ease;
stroke: gray;
stroke-width: 0.5px;
}
</style>
</head>
<body>
<div class="btn-zoom">
<div>
<button id="zoomout" onclick="zoomOut()">-</button>
</div>
<div>
<button onclick="reset()">R</button>
</div>
</div>
<div class="zoom_outer">
<div id="zoom1">
<svg id="vatican"
xmlns:mapsvg="http://mapsvg.com"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
height="100%"
width="100%"
viewBox="0 300 2000 2100"
preserveAspectRatio="none"
mapsvg:geoViewBox="116.927573 20.834769 126.606549 4.640292">
<g>
<path id="VA" title="Vatican City (Holy See)" class="land" d="M473.758,317.509L486.073,391.484L578.644,421.415L578.099,480.789L575.735,515.828L573.327,572.038L573.872,588.098L583.461,593.693L591.868,602.697L601.457,614.133L605.684,621.92L610.455,639.683L612,659.392L611.728,665.231L611.546,670.827L609.592,681.777L602.32,697.106L587.551,713.652L573.872,721.195L566.237,723.871L553.922,724.602L539.471,721.195L527.064,715.599L521.384,709.759L515.612,704.649L500.025,709.272L480.983,716.572L448.536,728.981L417.452,736.037L406.092,740.417L402.683,745.526L403.047,752.583L403.683,767.182L409.908,773.508L410.408,781.294L407.455,788.837L402.683,792L393.186,785.674L347.014,767.912L346.56,778.618L340.379,778.131L266.94,767.182L241.219,762.802L235.993,752.583L223.541,747.474L200.683,744.797L191.685,740.417L179.733,737.983L165.963,736.037L150.194,736.523L150.785,748.203L126.335,753.313L109.249,755.016L104.931,750.637L98.75,743.094L103.931,737.983L109.703,732.874L94.479,718.762L78.21,705.379L66.803,697.106L48.625,681.777L40.582,692.727L17.224,679.101L0,672.287L55.351,638.952L75.574,625.326L79.709,622.406L86.344,610.97L91.525,593.693L95.433,584.204L102.522,575.201L112.521,566.928L124.018,554.762L134.47,546.488L140.741,536.998L144.877,524.102L149.648,494.902L154.011,471.299L161.146,466.188L171.598,461.809L184.095,455.969L199.274,441.368L212.089,422.875L221.224,398.541L227.858,380.047L273.575,374.208L298.343,375.667L305.932,374.208L339.788,361.554L353.694,357.173L360.783,369.097L390.322,360.337L388.913,345.493L409,339.166z"/>
</g>
</svg>
</div>
</div>
<script src="main.js"></script>
</body>
</html>
RIGHT
var scale = 1,
panning = false,
pointX = 0,
pointY = 0,
start = { x: 0, y: 0 },
zoom1 = document.getElementById("zoom1");
zoom2 = document.getElementById("zoom2");
function setTransform() {
zoom1.style.transform = "translate(" + pointX + "px, " + pointY + "px) scale(" + scale + ")";
zoom2.style.transform = "translate(" + pointX + "px, " + pointY + "px) scale(" + scale + ")";
}
function reset(){
event.preventDefault();
scale = 1;
pointX = 0;
pointY = 0;
start = { x: 0, y: 0 };
setTransform();
}
function zoomOut(){
document.getElementById("zoomout").click();
event.preventDefault();
var xs = (event.clientX - pointX) / scale,
ys = (event.clientY - pointY) / scale,
delta = (event.wheelDelta ? event.wheelDelta : -event.deltaY);
(delta > 0) ? (scale *= 1.04) : (scale /= 1.04);
setTransform();
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>RIGHT</title>
<style>
#vatican g path {
-moz-transition-property: opacity;
-o-transition-property: opacity;
-webkit-transition-property: opacity;
transition-property: opacity;
-moz-transition-duration: 0.5s;
-o-transition-duration: 0.5s;
-webkit-transition-duration: 0.5s;
transition-duration: 0.5s;
-moz-transition-timing-function: ease;
-o-transition-timing-function: ease;
-webkit-transition-timing-function: ease;
transition-timing-function: ease;
stroke: gray;
stroke-width: 0.5px;
}
</style>
</head>
<body>
<div class="btn-zoom">
<div>
<button id="zoomout" onclick="zoomOut()">-</button>
</div>
<div>
<button onclick="reset()">R</button>
</div>
</div>
<div class="zoom_outer">
<div id="zoom2">
<svg id="vatican"
xmlns:mapsvg="http://mapsvg.com"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
height="100%"
width="100%"
viewBox="0 300 2000 2100"
preserveAspectRatio="none"
mapsvg:geoViewBox="116.927573 20.834769 126.606549 4.640292">
<g>
<path id="VA" title="Vatican City (Holy See)" class="land" d="M473.758,317.509L486.073,391.484L578.644,421.415L578.099,480.789L575.735,515.828L573.327,572.038L573.872,588.098L583.461,593.693L591.868,602.697L601.457,614.133L605.684,621.92L610.455,639.683L612,659.392L611.728,665.231L611.546,670.827L609.592,681.777L602.32,697.106L587.551,713.652L573.872,721.195L566.237,723.871L553.922,724.602L539.471,721.195L527.064,715.599L521.384,709.759L515.612,704.649L500.025,709.272L480.983,716.572L448.536,728.981L417.452,736.037L406.092,740.417L402.683,745.526L403.047,752.583L403.683,767.182L409.908,773.508L410.408,781.294L407.455,788.837L402.683,792L393.186,785.674L347.014,767.912L346.56,778.618L340.379,778.131L266.94,767.182L241.219,762.802L235.993,752.583L223.541,747.474L200.683,744.797L191.685,740.417L179.733,737.983L165.963,736.037L150.194,736.523L150.785,748.203L126.335,753.313L109.249,755.016L104.931,750.637L98.75,743.094L103.931,737.983L109.703,732.874L94.479,718.762L78.21,705.379L66.803,697.106L48.625,681.777L40.582,692.727L17.224,679.101L0,672.287L55.351,638.952L75.574,625.326L79.709,622.406L86.344,610.97L91.525,593.693L95.433,584.204L102.522,575.201L112.521,566.928L124.018,554.762L134.47,546.488L140.741,536.998L144.877,524.102L149.648,494.902L154.011,471.299L161.146,466.188L171.598,461.809L184.095,455.969L199.274,441.368L212.089,422.875L221.224,398.541L227.858,380.047L273.575,374.208L298.343,375.667L305.932,374.208L339.788,361.554L353.694,357.173L360.783,369.097L390.322,360.337L388.913,345.493L409,339.166z"/>
</g>
</svg>
</div>
</div>
<script src="main.js"></script>
</body>
</html>
I am calling the same JS file for the 2 pages.
This will help me alot if you guys can help me with this. Thank you!
Irrespective you use the same JS file for the two different page, both pages will load the JS as a new version for their own. so, even if you do some script change on one page, it wont reflect on the other until you refresh it.
Instead you can use Database to handle this as one of the solution.
Lets say on default both zoom was set at 8, and zoom button has a class "zoom_btn", and data-zoom='8'
Create a DB table called zoom_change with a column zoom_value with default one row with value of '8'.
Create a page in PHP or any other backend you use to update zoom_value in zoom_change table
Create another page in PHP or any other backend you use to fetch zootem_value in zoom_change table
using JQuery :
on the common JS page :
Script #1 to Record zoom changes into DB:
$(".zoom_btn").on("click", function() {
var zoom_value = parseInt($(this).attr("data-zoom"))+1;
$.post('zoom_value_update.php',
{
value : zoom_value
}, function () {
// $(this).attr("data-zoom",zoom_value);
// Do something with the zoom value ----
});
});
Script #2 to update zoom_value from DB to data attribute :
function() {
setInterval(() => {
$.post('zoom_value_fetch.php',
{ }, function (result) {
$(".zoom_btn").attr("data-zoom",result);
// Do something with the zoom value ----
});
}, 5000);
}();
Please note that this one of the method i know of. Not the only one. Please consider other answers as well.
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>
I am trying to center g element having text with tspan inside svg element using d3 using below code.
var rootSVGSize = d3.select("svg.root-svg").node().getBoundingClientRect()
var dataLabelSize = d3.select("g.data-label").node().getBoundingClientRect()
var x = rootSVGSize.width / 2;
var y = rootSVGSize.height / 2;
d3.select("g.data-label").attr("transform", "translate(" + x + "," + y + ")")
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg class="root-svg" width="180" height="200" style="border: black;border-style: solid;border-width: 1px;">
<g class="data-label">
<text alignment-baseline="middle" style="font-family: Arial; font-size: 36px; font-style: normal; font-weight: normal; fill: rgb(242, 200, 15);" text-anchor="middle">
<tspan x="0" dy="0">1/1/2018</tspan>
<tspan x="0" dy="41">3:00:00</tspan>
<tspan x="0" dy="41">AM</tspan>
</text>
<title>1/1/2018 3:00:00 AM</title>
</g>
</svg>
As you can see after executing above code, the group element is not centered correctly on x and y coordinates. How can I make group element center inside svg?
I am using getBoundingClientRect becuase I want to get size of svg at initial stage after assigning width and height that is before anything is rendred inside svg.
You have to take into account the x and y position of both the SVG container and the group:
var x = (rootSVGSize.x - dataLabelSize.x) + (rootSVGSize.width - dataLabelSize.width) / 2;
var y = (rootSVGSize.y - dataLabelSize.y) + (rootSVGSize.height - dataLabelSize.height) / 2;
That way, you can have any value you want for alignment-baseline, dominant-baseline and text-anchor, it doesn't matter, the group will be always centered.
Here is your code with that change:
var rootSVGSize = d3.select("svg.root-svg").node().getBoundingClientRect()
var dataLabelSize = d3.select("g.data-label").node().getBoundingClientRect()
var x = (rootSVGSize.x - dataLabelSize.x) + (rootSVGSize.width - dataLabelSize.width) / 2;
var y = (rootSVGSize.y - dataLabelSize.y) + (rootSVGSize.height - dataLabelSize.height) / 2;
d3.select("g.data-label").attr("transform", "translate(" + x + "," + y + ")")
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg class="root-svg" width="180" height="200" style="border: black;border-style: solid;border-width: 1px;">
<g class="data-label">
<text alignment-baseline="middle" style="font-family: Arial; font-size: 36px; font-style: normal; font-weight: normal; fill: rgb(242, 200, 15);" text-anchor="middle">
<tspan x="0" dy="0">1/1/2018</tspan>
<tspan x="0" dy="41">3:00:00</tspan>
<tspan x="0" dy="41">AM</tspan>
</text>
<title>1/1/2018 3:00:00 AM</title>
</g>
</svg>
I've made a few changes in the svg, the most important: I've changed some values for the tspan's dy. Also I'm using dominant-baseline="middle" instead of alignment-baseline="middle". I hope it helps.
var rootSVGSize = d3.select("svg.root-svg").node().getBoundingClientRect()
var dataLabelSize = d3.select("g.data-label").node().getBoundingClientRect()
var x = rootSVGSize.width / 2;
var y = rootSVGSize.height / 2;
d3.select("g.data-label").attr("transform", "translate(" + x + "," + y + ")")
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg class="root-svg" width="180" height="200" style="border: black;border-style: solid;border-width: 1px;">
<g class="data-label">
<text dominant-baseline="middle" style="font-family: Arial; font-size: 36px; font-style: normal; font-weight: normal; fill: rgb(242, 200, 15);" text-anchor="middle">
<tspan x="0" dy="-41">1/1/2018</tspan>
<tspan x="0" dy="41">3:00:00</tspan>
<tspan x="0" dy="41">AM</tspan>
</text>
<title>1/1/2018 3:00:00 AM</title>
</g>
</svg>
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>