I have A SVG with two eyes where each pupil tracks the mouse position.
The issue is, the two eyes acts individually and not as a group. For example if you position the cursor between both eyes, the pupil from the left goes in the right direction and the pupil from the right goes to the left direction.
What I would like to achieve is, when the cursor is positioned between (or close to) both eyes, the pupils stay in the center of the eye.
let l1 = document.querySelector("#l1");
let l2 = document.querySelector("#l2");
let svg1 = document.querySelector("#svg1");
const toSVGPoint = (svg, x, y) => {
let p = new DOMPoint(x, y);
return p.matrixTransform(svg.getScreenCTM().inverse());
};
document.addEventListener('mousemove', e => {
let p = toSVGPoint(svg1, e.clientX, e.clientY);
l1.setAttribute('x2', p.x);
l1.setAttribute('y2', p.y);
l2.setAttribute('x2', p.x);
l2.setAttribute('y2', p.y);
});
.container{
width: 20em;
height: 20em;
margin: 200px auto;
}
<div class="container">
<svg id="svg1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200">
<ellipse cx="80" cy="45" rx="20" ry="22" stroke-width="10" stroke="#fdd176"/>
<ellipse cx="120" cy="45" rx="20" ry="22" stroke-width="10" stroke="#fdd176"/>
<line marker-start="url(#pupil)" id="l1" x1="80" y1="45" />
<line marker-start="url(#pupil)" id="l2" x1="120" y1="45" />
<defs>
<marker id="pupil" viewBox="0 0 18 18" refX="10" refY="5" markerWidth="37" markerHeight="37" orient="auto-start-reverse">
<circle fill="#fdd176" r="4" cy="5" cx="5" />
</marker>
</defs>
</svg>
</div>
Here is my codepen where you can see it live.
And another codepen where you can see the wanted result.
Thank you.
3
Answers
The following solution initially places the pupils in the center of the eye and then translates them by one tenth of the distance that the mouse pointer has from the center of the SVG viewBox (which I chose to be (0, 0) for simplicity). The factor of one tenth is chosen so that when the mouse reaches the edge of the viewBox, the pupils reach the edge of the eye.
Both pupils always move in parallel, like in the "wanted result" codepen.
With the technique, using the a marker, you can adjust the
refX
of the marker element. As a default value it is 10, but when you point in between the eyes the value need to be smaller.So, here I try to do a calculation based on the position on the x axis. I think it could be done better somehow, but this is all for now.
Enhancement of Heiko his answer