Note that there are some explanatory texts on larger screens.

plurals
  1. POHow do you create an SVG cursor-tracking element?
    text
    copied!<p>I have the following XML code to create an SVG image that has a little circle that follows the user's cursor around. The area that tracks the cursor and displays the circle doesn't line up with the rest of the image. I am not sure why this is. I would love for someone to enlighten me (I just started learning about SVGs a couple days ago).</p> <p>If I change the <code>preserveAspectRatio</code> from <code>xMidYMin</code> to <code>none</code> then the circle has a different set of problems. It doesn't follow the cursor very far down and it goes farther to the right than it should.</p> <p>Also, I am not very good with JavaScript, so if you see ways that the code can be simplified or if you can figure out how to switch this over to jQuery, I would greatly appreciate that.</p> <pre class="lang-xml prettyprint-override"><code>&lt;?xml version="1.0" encoding="utf-8" standalone="no" ?&gt; &lt;!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd" [ &lt;!ATTLIST svg xmlns:a3 CDATA #IMPLIED a3:scriptImplementation CDATA #IMPLIED&gt; &lt;!ATTLIST script a3:scriptImplementation CDATA #IMPLIED&gt; ]&gt; &lt;svg viewBox="0 0 720 1278" preserveAspectRatio="xMidYMin" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a3="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/" a3:scriptImplementation="Adobe" onload="init(evt)" onzoom="updateTracker(evt)" onscroll="updateTracker(evt)" onresize="updateTracker(evt)"&gt; &lt;script type="text/ecmascript" a3:scriptImplementation="Adobe"&gt; &lt;![CDATA[ var elems = { tracker: false, cursor: false, trans: true, scale: true, mx: true, my: true, ux: true, uy: true }; var frame = { x_trans: 0, y_trans: 0, zoom: 1, x_scale: 1, y_scale: 1 }; function init(e) { if (window.svgDocument == null) svgDocument = e.target.ownerDocument; // Find nodes by id and store in elems object for (var id in elems) getElement(id, elems[id]); } function getElement(id, useFirstChild) { // Find the node with the specified id var node = svgDocument.getElementById(id); if (useFirstChild) { // Grab first child of node // This is used to get the text node of tspan and text elements elems[id] = node.firstChild; } else { // Do not need first child so use the node we just found elems[id] = node; } } function updateTracker(e) { // Get the top-most SVG element var SVGRoot = svgDocument.documentElement; // Get the current zoom and pan settings var trans = SVGRoot.currentTranslate; var scale = SVGRoot.currentScale; // Determine the translation needed to move the upper-left // corner of our tracking rectangle to the upper-left of the // current view. // The zeros are used to reinforce that we are translating // the origin of the rectangle to the upper-left corner of the // current view. frame.x_trans = (0.0 - trans.x) / scale; frame.y_trans = (0.0 - trans.y) / scale; // Now that we have moved the rectangles corner to the // upper-left position, let us scale the rectangle to fit // the current view. X and Y scales are maintained seperately // to handle possible anamorphic scaling from the viewBox frame.zoom = scale; frame.x_scale = 1 / scale; frame.y_scale = 1 / scale; // Get the current viewBox var vbox = SVGRoot.getAttributeNS(null, "viewBox"); if (vbox) { // We have a viewBox so, update our translation and scale // to take the viewBox into account // Break the viewBox parameters into an array to make life easier var params = vbox.split(/\s+/); // Determine the scaling from the viewBox // Note that these calculations assume that the outermost // SVG element has height and width attributes set to 100%. var h_scale = window.innerWidth / params[2]; var v_scale = window.innerHeight / params[3]; // Update our previously calculated transform frame.x_trans = frame.x_trans / h_scale + parseFloat(params[0]); frame.y_trans = frame.y_trans / v_scale + parseFloat(params[0]); frame.x_scale = frame.x_scale / h_scale; frame.y_scale = frame.y_scale / v_scale; } // Apply changes to the tracking rectangle updateTrackerTransform(); } function updateCursor(e) { // Get the mouse x and y coordinates var x = e.clientX; var y = e.clientY; // Calculate the user-coordinate using the scaling and // translation values we calculated for the tracking // rectangle var nx = x * frame.x_scale + frame.x_trans; var ny = y * frame.y_scale + frame.y_trans; // Update the cursor position elems.cursor.setAttributeNS(null, "cx", nx); elems.cursor.setAttributeNS(null, "cy", ny); // Update our text fields elems.mx.data = x; elems.my.data = y; elems.ux.data = nx; elems.uy.data = ny; } function updateTrackerTransform() { // Build the text versions of the translate and scale transformation var trans = "translate(" + frame.x_trans + "," + frame.y_trans + ")" var scale = "scale(" + 1 / frame.zoom + "," + 1 / frame.zoom + ")"; // Apply the transformation to our tracking rectangle elems.tracker.setAttributeNS(null, "transform", trans + " " + scale); // Update our text fields elems.trans.data = trans; elems.scale.data = scale; }]]&gt; &lt;/script&gt; &lt;!-- Create the cursor element --&gt; &lt;circle id="cursor" cx="100" cy="100" r="10" fill="orange" /&gt; &lt;!-- A group of elements collectively refered to as the tracker --&gt; &lt;g id="tracker"&gt; &lt;!-- Draw a visible rectangle to show the tracking area --&gt; &lt;rect x="0" y="0" width="100%" height="100%" fill="blue" opacity="0.25" /&gt; &lt;!-- - This is the actual tracking rectangle. This is all that is needed - to track the cursor. Just place the "tracker" id here and remove this group - and all of the other elements in this group --&gt; &lt;rect x="0" y="0" width="100%" height="100%" opacity="0" onmousemove="updateCursor(evt)" /&gt; &lt;/g&gt; &lt;/svg&gt; </code></pre> <p><strong><a href="http://jsfiddle.net/UEZ2D/" rel="nofollow">Live demo on jsFiddle</a></strong></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload