最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - stacking transforms in D3 - Stack Overflow

programmeradmin0浏览0评论

I have an SVG element with a transform already applied to it (this could be a single translate, or a bination of multiple transforms). I'm trying to apply additional transform to it. Problem is that this transform could be applied repeatedly and needs to stack with the existing transform state (so appending additional transforms to the end is not practical). Looking through d3 API, I didn't notice anything that lets me apply a relative transform (although I must admit, I'm not that familiar with advanced features of d3). Manually parsing the current transform string and then puting the same transformation matrix that SVG already does behind the scenes for free seems silly, is there a better way?

For example, if existing element already has the following attribute:

transform="translate(30) rotate(45 50 50)"

And I invoke this transformation logic twice, wanting to offset the element by 1 pixel in each dimension each time, I would need to parse and process both, the translate and rotate calls, because the new translations cannot be applied prior to rotation.

I have an SVG element with a transform already applied to it (this could be a single translate, or a bination of multiple transforms). I'm trying to apply additional transform to it. Problem is that this transform could be applied repeatedly and needs to stack with the existing transform state (so appending additional transforms to the end is not practical). Looking through d3 API, I didn't notice anything that lets me apply a relative transform (although I must admit, I'm not that familiar with advanced features of d3). Manually parsing the current transform string and then puting the same transformation matrix that SVG already does behind the scenes for free seems silly, is there a better way?

For example, if existing element already has the following attribute:

transform="translate(30) rotate(45 50 50)"

And I invoke this transformation logic twice, wanting to offset the element by 1 pixel in each dimension each time, I would need to parse and process both, the translate and rotate calls, because the new translations cannot be applied prior to rotation.

Share Improve this question asked Jan 14, 2014 at 23:19 Alexander TsepkovAlexander Tsepkov 4,1864 gold badges38 silver badges65 bronze badges 10
  • Okay, I answered quickly without reading carefully. Can you explain why concatenating multiple transformation strings doesn't achieve your objective? Maybe with pictures showing what you're trying to acplish? SVG transforms are by default relative and cumulative. – AmeliaBR Commented Jan 15, 2014 at 0:02
  • Imagine I call the logic that performs translate(1,1) 100 times (as in, let's say it gets invoked on every mousemove event), I will end up with transform="translate(30) rotate(45 50 50) translate(1,1) translate(1,1) translate(1,1) ... translate(1,1) translate(1,1)". Now image if I call it 1000 times, now imagine I'm manipulating several elements at once. This is a lot of unnecessary memory and putational overhead for the DOM. – Alexander Tsepkov Commented Jan 15, 2014 at 0:21
  • 1 I did some fiddling around. In Firefox, you can get the current transformation matrix by setting transforms as styles instead of attributes, and then use getComputedStyle(this)["transform"]. However, you have to use CSS transformations (with units) instead of SVG transformations (bare numbers). And since Chrome doesn't fully support CSS transformations, that means you have to use "-webkit-transform" to apply the style. And even though the style gets applied I get "none" back from getComputedStyle(this)["-webkit-transform"] or getComputedStyle(this)["webkitTransform"]. – AmeliaBR Commented Jan 15, 2014 at 1:10
  • 1 Have you seen d3.transform? This should do exactly what you want. – Lars Kotthoff Commented Jan 15, 2014 at 9:25
  • 1 @LarsKotthoff Great tip. Also, I discovered there are a number of Javascript functions to access current transformations and the puted matrix: Element.transform.baseVal.consolidate().matrix will get you the current matrix on this element; Element.getTransformToElement() will get you a matrix representing all transforms, including transformations on parent elements. But using d3 ready-made functions is probably easier. – AmeliaBR Commented Jan 16, 2014 at 7:02
 |  Show 5 more ments

2 Answers 2

Reset to default 5

I've actually been thinking that there should be a special function for this, similar to the way the classed() function handles adding and remove certain classes without messing up the other ones.

However, until that happens, just access the existing attribute and then concatenate strings:

selection.attr("transform", function(d){
        return this.getAttribute("transform") +
                     " translate(30) rotate(45 50 50)";
    });

You could also use d3.select(this).attr("transform") but the raw javascript should work and saves a function call.

Just be careful not to mix up attribute transforms with style transforms.

As Lars pointed out in a ment, d3.transform will generate the transform from the string. Applying that to my original problem, I can do the following:

element.attr('transform', d3.transform('translate(30) rotate(45 50 50) translate(1,1) translate(1,1)').toString())
发布评论

评论列表(0)

  1. 暂无评论