请帮助我理解使用普通javascript操作svg元素及其变换的最佳实践。
我理解坐标系是在节点和链接等下传递的。
我想要实现的是在旋转后继续对元素进行原始翻译。在应用旋转后不沿轴。
我是否必须克隆复制第一个translate-transform并将其添加到转换列表的末尾?
非常感谢,如果有人能够以雄辩的方式阐明。
答案 0 :(得分:3)
实现这一目标的方法是嵌套转换。例如,请查看以下示例SVG。
<svg width="600" height="200">
<g>
<rect x="0" y="50" width="100" height="100" fill="blue"/>
</g>
</svg>
&#13;
您可以将一个转换应用于<g>
,将另一个转换应用于<rect>
。它们将是独立的,但将结合起来以实现整体效果。
因此,例如,如果我想将所有内容都移动,我可以将转换变换应用于该组。
<svg width="600" height="200">
<g transform="translate(200,0)">
<rect x="0" y="50" width="100" height="100" fill="blue"/>
</g>
</svg>
&#13;
然后,如果我想将矩形旋转到位,我可以通过对其应用旋转变换来实现。
<svg width="600" height="200">
<g transform="translate(200,0)">
<rect x="0" y="50" width="100" height="100" fill="blue"
transform="rotate(45,50,100)"/>
</g>
</svg>
&#13;
然后,如果我想,我可以通过更新组的转换来进一步向右移动矩形。
<svg width="600" height="200">
<g transform="translate(400,0)">
<rect x="0" y="50" width="100" height="100" fill="blue"
transform="rotate(45,50,100)"/>
</g>
</svg>
&#13;
考虑这一点的方法是<rect>
在其自己的小世界中(&#34;坐标空间&#34;是官方术语:)并且幸福地没有意识到什么是继续在其父元素。
因此,如果我们使用上面学到的东西,我们可以轻松创建您所追求的动画类型。以下动画包含三个阶段。首先我们向右移动矩形,然后我们旋转它,然后我们继续向右移动。中间的旋转不会影响我们再次向右移动的第三阶段。
var outer = document.getElementById("outer");
var inner = document.getElementById("inner");
var tx = 0; // the animated X position
var angle = 0; // the animated angle
/*
* The first phase of the animation.
* Function to step to the right until we hit tx=200.
*/
var stepRightTo200 = function() {
setTimeout(function() {
tx += 4;
outer.setAttribute('transform', 'translate('+tx+',0)');
if (tx < 200) // schedule another step in this phase
stepRightTo200();
else // start next phase of animation
rotateTo45();
}, 32);
};
/*
* The second phase of the animation.
* Step the angle around until we hit 45 degrees.
*/
var rotateTo45 = function() {
setTimeout(function() {
angle += 1;
inner.setAttribute('transform', 'rotate('+angle+',50,100)');
if (angle < 45)
rotateTo45()
else
stepRightTo400(); // start third phase of animation
}, 32);
};
/*
* The third phase of the animation.
* Step to the right until we hit tx=400.
*/
var stepRightTo400 = function() {
setTimeout(function() {
tx += 4;
outer.setAttribute('transform', 'translate('+tx+',0)');
if (tx < 400)
stepRightTo400();
}, 32);
};
// Kick off first phase of animation
stepRightTo200();
&#13;
<svg width="600" height="200">
<g id="outer">
<rect id="inner" x="0" y="50" width="100" height="100" fill="blue"/>
</g>
</svg>
&#13;
在上面的示例中,我将&#34;外部&#34;转变为父母群体,但我们并非真的必须这样做。我们可以将变换操作嵌套到单个变换中。
因此我们可以将上面的第三个SVG示例简化为:
<svg width="600" height="200">
<rect x="0" y="50" width="100" height="100" fill="blue"
transform="translate(400,0) rotate(45,50,100)"/>
</svg>
&#13;
&#34;外部&#34;变换成为变换列表中的第一个变换。如果您需要创建多部分转换,这是构建多部分转换的好方法。首先创建(或想象)嵌套的组结构,然后将转换应用于来自&#34;外部&#34; (左)到&#34;里面&#34; (右)。
最后,我们可以使用这种非嵌套形式重写动画脚本。
var inner = document.getElementById("inner");
var tx = 0; // the animated X position
var angle = 0; // the animated angle
/*
* The first phase of the animation.
* Function to step to the right until we hit tx=200.
*/
var stepRightTo200 = function() {
setTimeout(function() {
tx += 4;
inner.setAttribute('transform',
'translate('+tx+',0) rotate('+angle+',50,100)');
if (tx < 200) // schedule another step in this phase
stepRightTo200();
else // start next phase of animation
rotateTo45();
}, 32);
};
/*
* The second phase of the animation.
* Step the angle around until we hit 45 degrees.
*/
var rotateTo45 = function() {
setTimeout(function() {
angle += 1;
inner.setAttribute('transform',
'translate('+tx+',0) rotate('+angle+',50,100)');
if (angle < 45)
rotateTo45()
else
stepRightTo400(); // start third phase of animation
}, 32);
};
/*
* The third phase of the animation.
* Step to the right until we hit tx=400.
*/
var stepRightTo400 = function() {
setTimeout(function() {
tx += 4;
inner.setAttribute('transform',
'translate('+tx+',0) rotate('+angle+',50,100)');
if (tx < 400)
stepRightTo400();
}, 32);
};
// Kick off first phase of animation
stepRightTo200();
&#13;
<svg width="600" height="200">
<rect id="inner" x="0" y="50" width="100" height="100" fill="blue"/>
</svg>
&#13;
希望这可以帮助您了解转换的工作原理。
答案 1 :(得分:1)
最好的方法是创建矩阵变换,然后请求各种变换并使用consolidate()方法。以下是一个例子
SELECT
tkoh.ticketid,
tkoh.ownergroup,
tkoh.owndate,
tck.ACTUALFINISH,
coalesce(datediff(day, tkoh.owndate, lead(tkoh.owndate) over(order by tkoh.ticketid, tkoh.owndate)),
datediff(day, tkoh.owndate, tck.ACTUALFINISH)) As Diff
FROM tkownerhistory tkoh
LEFT JOIN ticket tck on tck.ticketid = tkoh.ticketid
WHERE tkoh.ticketid IN ('О1253565', 'О1253578') and tkoh.ownergroup is not null
ORDER BY tkoh.ticketid, tkoh.owndate;
&#13;