Loading...

Translate from DOM to SVG Coordinates and Back Again

View: 661    Dowload: 0   Comment: 0   Post by: hanhga   Category: HTML-CSS template   Fields: Other

All the cool kids are using Scalable Vector Graphics. SVGs are great until you want to mix DOM and vector interactions — then life becomes more complicated.

SVGs have their own coordinate system. It is defined via the viewbox attribute, e.g. viewbox="0 0 800 600"which sets a width of 800 units and a height of 600 units starting at (0, 0). If you position this SVG in an 800×600 pixel area, each SVG unit maps directly to a screen pixel.

However, the beauty of vector images is they can be scaled to any size. Your SVG could be scaled in a 400×300 space or even stretched beyond recognition in a 100×1200 space. Adding further elements to an SVG becomes difficult if you don’t know where to put them.

(SVG coordinate systems can be confusing – Sara Soueidan’sviewport, viewBox and preserveAspectRatio article describes the options.)

Simple Separated SVG Synergy

You may be able to avoid translating between coordinate systems entirely.

SVGs embedded in the page (rather than an image or CSS background) become part of the DOM and can be manipulated in a similar way to other elements. For example, given a basic SVG with a single circle:

<svg id="mysvg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 600" preserveAspectRatio="xMidYMid meet">
  <circle id="mycircle" cx="400" cy="300" r="50" />
<svg>

we can apply CSS effects:

circle {
  stroke-width: 5;
  stroke: #f00;
  fill: #ff0;
}

circle:hover {
  stroke: #090;
  fill: #fff;
}

and attach event handlers to modify their attributes:

var mycircle = document.getElementById('mycircle');

mycircle.addEventListener('click', function(e) {
  console.log('circle clicked - enlarging');
  mycircle.setAttributeNS(null, 'r', 60);
}, false)

SVG to DOM Coordinate Translation

What if we want to overlay a DOM element on top of an SVG item, e.g. a menu or information box on a map? Again, because our HTML-embedded SVG elements form part of the DOM we can use the fabulous getBoundingClientRect() method to return all dimensions in a single call. Open the console in the example above to reveal the clicked circle’s new attributes following a radius increase.

Element.getBoundingClientRect() is supported in all browsers and returns an DOMrect object with the following properties in pixel dimensions:

  • .x and .left – x-coordinate, relative to the viewport origin, of the left side of the element
  • .right – x-coordinate, relative to the viewport origin, of the right side of the element
  • .y and .top – y-coordinate, relative to the viewport origin, of the top side of the element
  • .bottom – y-coordinate, relative to the viewport origin, of the bottom side of the element
  • .width – width of the element (not supported in IE8 and below but is identical to .right minus .left)
  • .height – height of the element (not supported in IE8 and below but is identical to .bottom minus .top)

All coordinates are relative to the browser viewport and will therefore change as the page is scrolled. The absolute location on the page can be calculated by adding window.scrollX to .left and window.scrollY to .top.

DOM to SVG Coordinate Translation

This is the tricky part. Presume you click an SVG and want to create or position an SVG element at that point. The event handler object will give you the DOM .clientX and .clientY pixel coordinates but these must be translated to SVG units.

It’s tempting to think you can calculate the x and y coordinates of an SVG point by applying a multiplication factor to the pixel location. For example, if a 1000 unit-width SVG is placed in a 500px width container, you can multiply any cursor x coordinate by two to get the SVG location. It rarely works!…

  • There is no guarantee the SVG will fit exactly into your container.
  • If the page or element dimensions change – perhaps in response to the user resizing the browser – the x and y factors must be re-calculated.
  • The SVG could be transformed in either 2D or 3D space.
  • Even if you overcome these hurdles, it never quite works as you expect. There’s often a margin of error.

Fortunately, SVGs provide their own matrix factoring mechanisms to translate coordinates. The first step is to create a point on the SVG using the createSVGPoint() method and pass in our screen x and y coordinates:

var svg = document.getElementById('mysvg'),
    pt = svg.createSVGPoint();

pt.x = 100;
pt.y = 200;

We can then apply a matrix transformation. That matrix is created from an inverse of the SVG’s (under-documented!).getScreenCTM() method which maps SVG units to screen coordinates:

var svgP = pt.matrixTransform(svg.getScreenCTM().inverse());

svgP now has .x and .y properties which provide the SVG coordinate location.

We can therefore place a circle at a point clicked on an SVG canvas:

var svg = document.getElementById('mysvg'),
    NS = svg.getAttribute('xmlns');

svg.addEventListener('click', function(e) {
  var pt = svg.createSVGPoint(), svgP, circle;
  
  pt.x = e.clientX;
  pt.y = e.clientY;
  svgP = pt.matrixTransform(svg.getScreenCTM().inverse());

  circle = document.createElementNS(NS, 'circle');
  circle.setAttributeNS(null, 'cx', svgP.x);
  circle.setAttributeNS(null, 'cy', svgP.y);
  circle.setAttributeNS(null, 'r', 10);
  svg.appendChild(circle);
}, false);

The createElementNS() and setAttributeNS() methods are identical to the standard DOM createElement()and setAttribute() methods except they specify an XML namespace URI. In other words, they act on the SVG rather than the HTML. setAttributeNS() can be passed a null namespace URI because it is directly manipulating an SVG element.

DOM to Transformed SVG Element Coordinates

There’s a further complication. What if we click on an SVG element which has been transformed in some way? It could be scaled, rotated or skewed which would affect our resulting SVG coordinate. For example, this <g> layer is 4x larger than the standard unit so coordinates will be one quarter those of the containing SVG:

<g id="local" transform="scale(4)">
  <rect x="50" y="50" width="100" height="100" />
</g>

The resulting rectangle appears to be 400 units in size at position 200, 200.

Fortunately, the .getScreenCTM() can be used on any SVG element and the resulting matrix considers all transformations. We can therefore create a simple svgPoint translation function:

var svg = document.getElementById('mysvg'),
    local = svg.getElementById('local');

console.log( svgPoint(svg, 10, 10) ); // returns x, y
console.log( svgPoint(local, 10, 10) ); // = x/4, y/4

// translate page to SVG co-ordinate
function svgPoint(element, x, y) {
  var pt = svg.createSVGPoint();

  pt.x = x;
  pt.y = y;

  return pt.matrixTransform(element.getScreenCTM().inverse());
}

 

Translate from DOM to SVG Coordinates and Back Again

All the cool kids are using Scalable Vector Graphics. SVGs are great until you want to mix DOM and vector interactions — then life becomes more complicated.

Posted on 01-09-2016 

Comment:

To comment you must be logged in members.

Files with category

  • Business/Consulting HTML & CSS Template

    Business/Consulting HTML & CSS Template

    View: 24    Download: 1   Comment: 0

    Category: HTML-CSS template     Fields: none

    It's elegant Business HTML Template. You can use it for creating Business, Finance, Corporate, Consulting websites or promoting your services. Looks perfect in all major browsers, tablets, and phones. Clean and commented code lets you customize it...

  • Photography Portfolio HTML/CSS Template

    Photography Portfolio HTML/CSS Template

    View: 28    Download: 0   Comment: 0

    Category: HTML-CSS template     Fields: none

    Portfolio and Photography HTML5/CSS template build with latest bootstrap framework , best suited for photographers. Features 3 HTML5/CSS3 Templates Video background for the homepage (YouTube Only) Supersized slideshow for the homepage Built on...

  • Creative Login Form with Validation

    Creative Login Form with Validation

    View: 40    Download: 0   Comment: 0

    Category: HTML-CSS template     Fields: none

    Upturn customized LOGIN FORM & INPUT STYLES is ready for Desktop, tablet and mobile devices. Simple to implement. Just copy the HTML and link to the CSS,JS file. You can easily edit, change and customize them for yourself. For students or anyone else...

  • Login Form Like Facebook

    Login Form Like Facebook

    View: 36    Download: 0   Comment: 0

    Category: HTML-CSS template     Fields: none

    This is a simple Facebook form that can be imported to your site with ease. Please don't forget to give credit to original developer because I really worked hard to develop this project and please don't forget to like and share it if you found it...

  • Custom-able Invoice: Easy to Use

    Custom-able Invoice: Easy to Use

    View: 33    Download: 1   Comment: 0

    Category: HTML-CSS template     Fields: none

    Make billing easy with Free Invoice Template. Professional invoices for your business: Proforma, Service, Sales, Freelance. Please don't forget to give credit to original developer because I really worked hard to develop this project and please don't...

  • Awsome Responsive HTML Pages

    Awsome Responsive HTML Pages

    View: 24    Download: 0   Comment: 0

    Category: HTML-CSS template     Fields: none

    A responsive html pages. The site have self sliding images on the index page. There are drop down menu with icons on them. The site have bootstrap that makes it responsive to different devices .

  • How To Create an Animated Search Form

    How To Create an Animated Search Form

    View: 273    Download: 0   Comment: 0

    Category: HTML-CSS template     Fields: none

    How To Create an Animated Search Form, Learn how to create an animated search form with CSS.

  • How to reset / remove chrome's input highlighting / focus border? used CSS

    How to reset / remove chrome's input highlighting / focus border? used CSS

    View: 224    Download: 0   Comment: 0

    Category: HTML-CSS template     Fields: none

    You have seen that chrome puts a thicker border on :focus but it kind of looks off in my case where I've used border-radius also. Is there anyway to remove that?

 
File suggestion for you
Loading...
File top downloads
Loading...
Loading...
Codetitle - library source code to share, download the file to the community
Copyright © 2018. All rights reserved. codetitle Develope by Vinagon .Ltd