将 dom 转换svg_如何从DOM转换为SVG坐标并再次返回

将 dom 转换svg

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.

所有很酷的孩子都在使用可伸缩矢量图形。 SVG很棒,除非您想将DOM和矢量交互混合在一起-然后生活变得更加复杂。

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.

SVG具有自己的坐标系。 它是通过viewbox属性定义的,例如viewbox="0 0 800 600" ,其设置从(0,0)开始的800单位的宽度和600单位的高度。 如果将此SVG放置在800×600像素区域中,则每个SVG单元将直接映射到屏幕像素。

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可以在400×300的空间中缩放,甚至可以超出100×1200的空间。 如果您不知道将它们添加到SVG的位置,则很难。

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

(SVG坐标系可能会令人困惑-Sara Soueidan的视口,viewBox和preserveAspectRatio文章介绍了这些选项。)

简单分离的SVG协同 (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:

嵌入页面(而不是图像或CSS背景)中的SVG成为DOM的一部分,并且可以通过与其他元素类似的方式进行操作。 例如,给定一个基本的SVG和一个圆圈:

<svg id="mysvg" xmlns="https://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:

我们可以应用CSS效果:

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);

The following example adds thirty random circles to an SVG image, applies a hover effect in CSS and uses JavaScript to increase the radius by ten units when a circle is clicked:

下面的示例将30个随机圆添加到SVG图像,在CSS中应用悬停效果,并在单击圆时使用JavaScript将半径增加10个单位:

See the Pen SVG interaction by SitePoint (@SitePoint) on CodePen.

请参阅CodePenSitePoint ( @SitePoint )的Pen SVG交互

SVG到DOM坐标转换 (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.

如果我们想将DOM元素覆盖在SVG项的顶部,例如地图上的菜单或信息框,该怎么办? 同样,因为我们HTML嵌入SVG元素构成了DOM的一部分,所以我们可以使用神话般的getBoundingClientRect()方法在单个调用中返回所有尺寸。 在上面的示例中打开控制台,以显示半径增加后单击的圆的新属性。

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

所有浏览器均支持Element.getBoundingClientRect()并返回一个具有以下像素尺寸属性的DOMrect对象:

  • .x and .left – x-coordinate, relative to the viewport origin, of the left side of the element

    .x.left –元素左侧相对于视口原点的x坐标

  • .right – x-coordinate, relative to the viewport origin, of the right side of the element

    .right –元素右侧相对于视口原点的x坐标

  • .y and .top – y-coordinate, relative to the viewport origin, of the top side of the element

    .y.top –元素顶.top对于视口原点的y坐标

  • .bottom – y-coordinate, relative to the viewport origin, of the bottom side of the element

    .bottom元素底侧相对于视口原点的y坐标

  • .width – width of the element (not supported in IE8 and below but is identical to .right minus .left)

    .width –元素的宽度(IE8及更低版本不支持,但与.right减去.left相同)

  • .height – height of the element (not supported in IE8 and below but is identical to .bottom minus .top)

    .height -元素的高度(不支持在IE8和下方,但是相同的.bottom减去.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.

所有坐标都是相对于浏览器视口的,因此将在滚动页面时更改。 页面上的绝对位置可以通过添加计算window.scrollX.leftwindow.scrollY.top

DOM到SVG坐标转换 (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.

这是棘手的部分。 假设您单击了SVG,并且想要在该点创建或放置SVG元素。 事件处理程序对象将为您提供DOM .clientX.clientY像素坐标,但必须将它们转换为SVG单位。

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!…

极具诱惑力的是,您可以通过将乘法因子应用于像素位置来计算SVG点的x和y坐标。 例如,如果将1000单位宽度的SVG放置在500px宽度的容器中,则可以将任何光标x坐标乘以2以获得SVG位置。 它很少起作用!…

  • There is no guarantee the SVG will fit exactly into your container.

    不能保证SVG完全适合您的容器。
  • 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.

    如果页面或元素的尺寸发生变化(可能是由于用户调整了浏览器的大小),则必须重新计算x和y因子。
  • The SVG could be transformed in either 2D or 3D space.

    SVG可以在2D或3D空间中转换。
  • 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:

幸运的是,SVG提供了自己的矩阵分解机制来转换坐标。 第一步是使用createSVGPoint()方法在SVG上创建一个点,并传入屏幕的x和y坐标:

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:

然后,我们可以应用矩阵变换。 该矩阵是根据SVG的逆方法创建的(未 .getScreenCTM() 说明!)。 .getScreenCTM()方法,该方法将SVG单位映射到屏幕坐标:

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

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

svgP现在具有.x.y属性,可提供SVG坐标位置。

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

因此,我们可以在SVG画布上单击的点处放置一个圆圈:

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.

除了它们指定XML名称空间URI之外, createElementNS()setAttributeNS()方法与标准DOM createElement()setAttribute()方法相同。 换句话说,它们作用于SVG而不是HTML。 可以将setAttributeNS()传递给空名称空间URI,因为它直接操作SVG元素。

DOM转换为SVG元素坐标 (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:

还有进一步的复杂化。 如果我们单击经过某种方式转换的SVG元素怎么办? 它可能会缩放,旋转或倾斜,这会影响我们生成的SVG坐标。 例如,此<g>层比标准单位大4倍,因此坐标将是包含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.

所得的矩形在位置200、200处看起来为400个单位。

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:

幸运的是, .getScreenCTM()可以在任何SVG元素上使用,并且生成的矩阵考虑所有转换。 因此,我们可以创建一个简单的svgPoint转换函数:

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());
}

The following demonstration works in all browsers. A circle is added to the cursor point when the grey SVG area is clicked. A circle is also added when the green box is clicked, but that layer has been scaled 4x so the circle appears four times larger.

以下演示适用于所有浏览器。 单击灰色SVG区域时,会在光标点添加一个圆圈。 单击绿色框时,还会添加一个圆,但是该图层已缩放4倍,因此该圆显得大了四倍。

See the Pen translate SVG co-ordinates by SitePoint (@SitePoint) on CodePen.

见笔翻译SVG坐标由SitePoint( @SitePoint上) CodePen

You could keep life simple by ensuring all SVG units map directly to page coordinates but, at some point, your client will ask for that image to be “just a few pixels larger” and your system will break. Translate between coordinate systems now and you’ll never need worry again!

您可以通过确保所有SVG单元直接映射到页面坐标来简化生活,但是在某些时候,您的客户会要求该图像“仅大几个像素”,并且系统会崩溃。 现在在坐标系之间转换,您将不再需要担心!

翻译自: https://www.sitepoint.com/how-to-translate-from-dom-to-svg-coordinates-and-back-again/

将 dom 转换svg

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值