现在的位置: 首页 > 综合 > 正文

使用SVG内置API计算图形或点经过transform之后的新坐标

2013年08月24日 ⁄ 综合 ⁄ 共 4160字 ⁄ 字号 评论关闭

一个应用场景是,点击一条路径,显示该路径的控制点。因为有transform变形( 平移、缩放、倾斜、旋转等变换),所以获取变形后的新坐标需要计算。

纯数学的方法,就是用2D变换矩阵的一些公式去运算,过程稍微有点复杂。

不过好在SVG已经提供了丰富的API将一些矩阵运算封装了,非常实用,下面是Demo.svg代码.

知识点:getScreenCTM()   matrixTransform()

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 1000 1000" version="1.1" xmlns="http://www.w3.org/2000/svg">
<title>ctm</title>

<text x="100" y="100">点击线条</text>

<line id="l1" x1="200" y1="100" x2="600" y2="100" stroke="red" stroke-width="8" />
<line id="l2" x1="200" y1="100" x2="600" y2="100" stroke="orange" stroke-width="8" transform="rotate(30)" />
<line id="l3" x1="200" y1="100" x2="600" y2="100" stroke="yellow" stroke-width="8" transform="rotate(60)" />
<line id="l4" x1="200" y1="100" x2="600" y2="100" stroke="green" stroke-width="8" transform="rotate(90)" />
<line id="l5" x1="200" y1="100" x2="600" y2="100" stroke="blue" stroke-width="8" transform="rotate(120)" />
<line id="l6" x1="200" y1="100" x2="600" y2="100" stroke="purple" stroke-width="8" transform="rotate(150)" />

<g transform="translate(100,100)">
    <line id="l7" x1="200" y1="100" x2="600" y2="100" stroke="purple" stroke-width="20" transform="rotate(30)" />
</g>

<circle id="c1" cx="123" cy="186" r="28" stroke="green" stroke-width="10" fill="none" />
<circle id="c2" cx="469.6" cy="386.6" r="28" stroke="green" stroke-width="10" fill="none" />

<script type="text/javascript"><![CDATA[
var root = document.documentElement;
var ls=document.getElementsByTagName("line");
var cs=document.getElementsByTagName("circle");

document.addEventListener('click',showCs,false);

function showCs(e){
    var t=e.target;
    if(t.tagName!=='line')return;
    var ctm = t.getScreenCTM();
    var rootCTM = root.getScreenCTM();
    showCircle(cs[0], t.x1.baseVal.value, t.y1.baseVal.value, ctm, rootCTM);
    showCircle(cs[1], t.x2.baseVal.value, t.y2.baseVal.value, ctm, rootCTM);
}

function showCircle(c,x,y,ctm,rootCTM){
    var pt1 = root.createSVGPoint();
    pt1.x = x;
    pt1.y = y;
    var pt2 = pt1.matrixTransform(rootCTM.inverse().multiply(ctm));
    //pt2 = pt1.matrixTransform(ctm).matrixTransform(rootCTM);
    c.cx.baseVal.value = pt2.x;
    c.cy.baseVal.value = pt2.y;
}

]]>
</script>
</svg>

一个应用场景是,点击一条路径,显示该路径的控制点。因为有transform变形( 平移、缩放、倾斜、旋转等变换),所以获取变形后的新坐标需要计算。

纯数学的方法,就是用2D变换矩阵的一些公式去运算,过程稍微有点复杂。

不过好在SVG已经提供了丰富的API将一些矩阵运算封装了,非常实用,下面是Demo.svg代码.

知识点:getScreenCTM()   matrixTransform()

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 1000 1000" version="1.1" xmlns="http://www.w3.org/2000/svg">
<title>ctm</title>

<text x="100" y="100">点击线条</text>

<line id="l1" x1="200" y1="100" x2="600" y2="100" stroke="red" stroke-width="8" />
<line id="l2" x1="200" y1="100" x2="600" y2="100" stroke="orange" stroke-width="8" transform="rotate(30)" />
<line id="l3" x1="200" y1="100" x2="600" y2="100" stroke="yellow" stroke-width="8" transform="rotate(60)" />
<line id="l4" x1="200" y1="100" x2="600" y2="100" stroke="green" stroke-width="8" transform="rotate(90)" />
<line id="l5" x1="200" y1="100" x2="600" y2="100" stroke="blue" stroke-width="8" transform="rotate(120)" />
<line id="l6" x1="200" y1="100" x2="600" y2="100" stroke="purple" stroke-width="8" transform="rotate(150)" />

<g transform="translate(100,100)">
    <line id="l7" x1="200" y1="100" x2="600" y2="100" stroke="purple" stroke-width="20" transform="rotate(30)" />
</g>

<circle id="c1" cx="123" cy="186" r="28" stroke="green" stroke-width="10" fill="none" />
<circle id="c2" cx="469.6" cy="386.6" r="28" stroke="green" stroke-width="10" fill="none" />

<script type="text/javascript"><![CDATA[
var root = document.documentElement;
var ls=document.getElementsByTagName("line");
var cs=document.getElementsByTagName("circle");

document.addEventListener('click',showCs,false);

function showCs(e){
    var t=e.target;
    if(t.tagName!=='line')return;
    var ctm = t.getScreenCTM();
    var rootCTM = root.getScreenCTM();
    showCircle(cs[0], t.x1.baseVal.value, t.y1.baseVal.value, ctm, rootCTM);
    showCircle(cs[1], t.x2.baseVal.value, t.y2.baseVal.value, ctm, rootCTM);
}

function showCircle(c,x,y,ctm,rootCTM){
    var pt1 = root.createSVGPoint();
    pt1.x = x;
    pt1.y = y;
    var pt2 = pt1.matrixTransform(rootCTM.inverse().multiply(ctm));
    //pt2 = pt1.matrixTransform(ctm).matrixTransform(rootCTM);
    c.cx.baseVal.value = pt2.x;
    c.cy.baseVal.value = pt2.y;
}

]]>
</script>
</svg>

抱歉!评论已关闭.