I have two SVGs with the same elements. When I click an element on SVG1 it's highlighted by toggling a CSS class. I want the same element on SGV2 to be automatically highlighted (NB: later, I'll want to be able to alter what's highlighted on SVG2 by clicking SVG2).
I've tried making a conversion table so when I use getElementById to capture the SVG1 click, that ID is translated to the corresponding ID on SVG2, then apply CSS class, but that doesn't work. Any suggestions on how I should do this?
Here's a JSfiddle - https://jsfiddle.net/scottmclaughlin/gynzou0t/21/
// changes colour of the clicked element
function highlighter () {
var ellipses = document.getElementById(this.id);
ellipses.classList.toggle("keyHighlight");
// also duplicate highlight on second svg
let duplicateEllipses = (ellipses) => translateTable[ellipses];
duplicateEllipses.classList.toggle("keyHighlight1");
}
Unrelated, the SVGs should be side by side but the column/row CSS isn't right for some reason.
ellipses is an element not an id, and your duplicateEllipses usage is weird, it's defined as a function, but used as an element. The logic way I think you suppose to do is like this:
let duplicateEllipses = document.getElementById(translateTable[this.id]);
duplicateEllipses.classList.toggle("keyHighlight1");
Not the cleaner way but you can try:
let ellipses = document.querySelectorAll('.ellipsoid')
ellipses.forEach(e => {
e.addEventListener('click', function() {
e.classList.toggle("keyHighlight")
if (e.id.slice(-2) !== '-1') {
let e1 = document.querySelector(`#${e.id}-1`)
if (e1.classList.contains('keyHighlight') && e.classList.contains('keyHighlight')) {
e1.classList.add("keyHighlight")
} else if (!e1.classList.contains('keyHighlight') && e.classList.contains('keyHighlight')){
e1.classList.add("keyHighlight")
} else {
e1.classList.remove("keyHighlight")
}
}
})
})
.keyHighlight {fill: #6CAD0E; opacity: 1;}
.keyHighlight1 {fill: #6CAD0E; opacity: 1;}
/* Create two equal columns that float next to each other */
.column {
float: left;
width: 50%;
padding: 10px;
}
/* Clear floats after the columns */
.row:after {
content: "";
display: table;
clear: both;
}
.row {
display: flex;
}
<html>
<head>
<meta charset="utf-8">
<title>duplicate test</title>
</head>
<body>
<div class="row">
<div class="column">
<p>SVG1</p>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="200" height="250" id="fingering">
<ellipse class="ellipsoid" id="LH1" cx="66" cy="45" rx="20" ry="20" fill="#ffffff" stroke="#000000" pointer-events="all"/>
<ellipse class="ellipsoid" id="LH2" cx="66" cy="95" rx="20" ry="20" fill="#ffffff" stroke="#000000" pointer-events="all"/>
<ellipse class="ellipsoid" id="LH3" cx="66" cy="145" rx="20" ry="20" fill="#ffffff" stroke="#000000" pointer-events="all"/>
</svg>
</div>
<div class="column">
<p>SVG2</p>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="200" height="250" id="fingering1">
<ellipse class="ellipsoid" id="LH1-1" cx="66" cy="45" rx="20" ry="20" fill="#ffffff" stroke="#000000" pointer-events="all"/>
<ellipse class="ellipsoid" id="LH2-1" cx="66" cy="95" rx="20" ry="20" fill="#ffffff" stroke="#000000" pointer-events="all"/>
<ellipse class="ellipsoid" id="LH3-1" cx="66" cy="145" rx="20" ry="20" fill="#ffffff" stroke="#000000" pointer-events="all"/>
</svg>
</div>
</div>
</body>
</html>
Use a W3C standard Web Component <svg-circle-stack> for each stack of Ellipsis.
(supported in all modern browsers, not in IE)
The WebComponent registers listeners on every Ellipse to handle the click;
And sends an Event, with index payload, on every click to all Ellipsis.
Ellipsis with the same index will also Toggle color.
It doesn't matter when you add more <svg-circle-stack>; Using Events make sure they always work.

When the <svg-circle-stack> is removed from the DOM, it cleans up listeners set outside its own scope on document. (the click handlers are cleaned automatically)
Positioning you do yourself with CSS Grid or flexbox.
<style type="text/css">
.highlight { fill: gold }
svg-circle-stack { width:90px; height:180px; display:inline-block; background:pink }
svg-circle-stack ellipse { fill:white; stroke:black; pointer-events:all; cursor:pointer }
svg-circle-stack ellipse:hover { stroke:lightgreen }
</style>
<svg-circle-stack></svg-circle-stack>
<svg-circle-stack></svg-circle-stack>
<svg-circle-stack></svg-circle-stack>
<svg-circle-stack></svg-circle-stack>
<script>
customElements.define("svg-circle-stack", class extends HTMLElement {
connectedCallback() {
this.innerHTML = `<svg viewBox="15 0 100 190">
<ellipse cx="66" cy="45" rx="20" ry="20" />
<ellipse cx="66" cy="95" rx="20" ry="20" />
<ellipse cx="66" cy="145" rx="20" ry="20" />
</svg>`;
this.ln = this.querySelectorAll("ellipse").forEach((ellipse, index) => {
ellipse.onclick = (evt) => {
ellipse.dispatchEvent(new CustomEvent("ellipseClick",
{ bubbles:true, detail:index }))
}
return document.addEventListener("ellipseClick", (evt) => {
if (evt.detail == index) ellipse.classList.toggle("highlight");
})
})
}
disconnectedCallback() {
this.ln.forEach(ellipse => document.removeEventLister("ellipseClick"))
}
});
</script>