main page - page initiale - hauptseite - página principal projects - projets - projekte - proyectos authors - auteurs - autoren - autores papers - exposés - berichte - papeles help - aide - hilfe - ayuda

carto:papers:svg:examples:interactivity:show_coordinates

Show coordinates on mouse-move

This example shows the use of mouse-over events to display real world coordinates.

Check symbols and mouse-over effects for reference.

Files used

Right-click, save ...

Technical Details

This example uses different javascript functions to display coordinate data. We have a group called groupShowCoords which is scaled and translated to be at a fix place while the rest of the graphics is zoom/pannable. The function initMap() initializes values for coordinate calculation and gets references to SVG objects as described in the example mouse-over effects. The function showCoords(evt) does the actual coordinate calculation and the display of the data in a svg-text-element. The function resetCoords() does reset offset and pixelSizes for the coordinate calculation. It uses global variables. The function resetCoords() is also called when a zoom and scroll event happens.

//global variables
var svgObjCity;
var svgObjX;
var svgObjY;
var svgSVGObj;
var svgDoc;
var svgCoordsGroup;
var ulXCorner;
var ulYCorner;
var origPixSize;
var pixSize;
var offsetX;
var offsetY;
var yMinusVal;
var refCoordRect;
var ratioY;
var pixHeight;

function initMap(evt) {
  // Retrieve the SVG document object:
  var directTarget = evt.getTarget();
  if( directTarget.getNodeType() != 9 ){ // if not DOCUMENT_NODE
    svgDoc = directTarget.getOwnerDocument();
  }
  else {
    svgDoc = directTarget;
  }
  //get reference to text-Element
  svgObjX = svgDoc.getElementById("coordx");
  svgObjY = svgDoc.getElementById("coordy");
  //get reference to text within text-Element
  svgObjX = svgObjX.getFirstChild();	
  svgObjY = svgObjY.getFirstChild();
  svgSVGObj = svgDoc.getDocumentElement();
  //reference to coordinate box (for later scaling and translating)
  refCoordRect = svgDoc.getElementById("groupShowCoords");
  //initialize coordinates, pixsize etc.
  var viewbox = new String(svgSVGObj.getAttribute("viewBox"));
  var viewboxes = viewbox.split(' ');
  ulXCorner = viewboxes[0];
  ulYCorner = viewboxes[1];
  var width = viewboxes[2];
  var height = viewboxes[3];
  var pixWidth = svgSVGObj.getAttribute("width");
  pixHeight = svgSVGObj.getAttribute("height");
  origPixSize = width / pixWidth;
  //a value to subtract Y-Values, because of inverted y-axis
  yMinusVal = 302000;
  
  //determine ratio for coordinate box placement along y-axis
  translateY = getTranslate("groupShowCoords","y");
  ratioY = translateY / height;
  
  //call resetCoords();
  resetCoords();
}

First we initialize some global variables that should be available throughout all functions. We get references to the SVG root-element and the two text-elements where we want to display the coordinate data. The function initMap() is called from the html-file with the event onload. To determine the starting viewBox we extract the values from the viewBox-attribute using a split function. To determine a pixel-size we divide the width of the viewBox with the number of pixels of the plugin's width, assuming that we have the same ratio for both axes. The value is stored in the variable origPixSize.

function resetCoords() {
  //get current zoom and pan values
  var scale = svgSVGObj.getCurrentScale();
  var trans = svgSVGObj.getCurrentTranslate();
  var transx = trans.getX();
  var transy = trans.getY();
  //reset values according to current scale and translate
  pixSize = origPixSize / scale;
  offsetX = parseFloat(ulXCorner) - transx * pixSize;
  offsetY = parseFloat(ulYCorner) - transy * pixSize;
  
  //to determine y-position, x-position is always the same ...
  var height = pixHeight * pixSize;
  var newScale = 1 / parseFloat(scale);
  var newTranslateX = offsetX;
           //position always relative to bottom of viewBox
  var newTranslateY = offsetY + height * ratioY;
  newtransform = "translate(" + newTranslateX + " " +
                        newTranslateY + ") " + "scale(" + newScale + ")";
  
  //reset position and scale for the showCoordsgroup
  //so it always stays at the same place
  refCoordRect.setAttribute('transform', newtransform);
}

The function resetCoords() is called from the functions initMap(), and from the onzoom and onscroll-events to reset offsetValues (.getCurrentTranslate()) and pixelSizes (.getCurrentScale()) whenever a zoom and pan-event occurs. These values are important to calculate the real-world coordinates, since the reported values by the method evt.getClientX() only represent pixel-values from the upper left corner of the viewport.

Note that .getCurrentTranslate() and .getCurrentScale() return values relative to the initial state of the loaded document. All zoom and pan results are calculated relative to this initial state. While zoomed in the values for .getCurrentTranslate() get multiplied by .getCurrentScale(). With no other transformations or scripts applied the values in the initial state are:

To actually calculate the coordinates and display them in a text-object we call the function showCoords(evt) that gets a reference to the mouse-move event as a parameter to determine the actual mouse-position. The .setData()-method displays the coordinates that are calculated using the scale- and offset-values.

function showCoords(evt) {
  //to show coordinates
  svgObjX.setData(Math.round(offsetX+evt.getClientX()*pixSize))
  svgObjY.setData(Math.round(yMinusVal-evt.getClientY()*pixSize-offsetY))
}

Finally we need to register the events onmousemove, onzoom and onscroll in order to execute the javascript-functions as described in the svg-code-snippet below. We do this in the svg-root-element.

<svg xml:space="preserve" width="450" height="325" 
                       viewBox="480000 0 360000 260000" id="svgAll"
                       onmousemove="showCoords(evt)" onzoom="zooming()" 
                       onscroll="scrolling()">

Not to forget, there is one more function we need to determine a current translate value of an object. It gets a reference to the object required, does some pattern-matching and extracts the translate part for either x or y:

function getTranslate(myElement,xOrY) {
  //get reference to element
  element = svgDoc.getElementById(myElement);
  
  //first get transform value of coordinate box
  var curTransform = element.getAttribute("transform");
  curTransform = new String(curTransform); //Wert in ein String umwandeln
  //no fear from Regular expressions, just copy it, I copied it either ...
  var translateRegExp=/translate\(([-+]?\d+)(\s*[\s,]\s*)([-+]?\d+)\)\s*/;
  //This part extracts the translation-part from the transform-string
  if (curTransform.length != 0){
    var result = curTransform.match(translateRegExp);
    if (result == null || result.index == -1){
       var oldTranslateX = 0;
       var oldTranslateY = 0;
    }
    else{
       var oldTranslateX = result[1];
       var oldTranslateY = result[3];
    }
  }
  if (xOrY == "x") {
    return oldTranslateX;
  }
  if (xOrY == "y") {
    return oldTranslateY;
  }      
}

Credits: Kevin Lindsey, for some hints on the .getCurrentTranslate-events.




Last modified: Wednesday, 02-Apr-2003 11:38:23 CEST
© carto:net (andré m. winter & andreas neumann)
original URL for reference: http://www.carto.net/papers/svg/samples/show_coordinates.shtml
del.icio.us Add this page to del.icio.us