Svg.js: Text.dy() does not perform as expected

Created on 10 Jan 2018  路  4Comments  路  Source: svgdotjs/svg.js

I've made a demo as an example.

In the example, there are two elements, a rectangle and a text, drawn on a SVG. Each of them can be moved as far as you drag them in the y-axis. In other words, the movement of the mouse in y-axis while dragging should equal to the movement of the dragged element in the y-axis. However, in the demo, the text moves in a weird way and the movement of it does not match with the mouse.

I've diggeed into the code to see what was going on.


The argument in the following codes may be numbered (which is slightly different from source) to avoid name conflicting


// text.y()
y: function (y) {
    /* skipped */

    if (y == null)
        // we get "oy - o" if the y in attr is a number
        return typeof oy === 'number' ? oy - o : oy

    /* skipped */
}

In text.dy(), first a wrapper (SVG.Number) wraps the value that we want to shift the text in y-axis. Then it call text.y() to get the original y position, which is the value that excluding the bounding box offset in y-axis and plus the wrapper with it. Finally, the shifted y position wrapping in SVG.Number is passed into text.y().

// text.dy()
dy: function(y1) {
    // equivalence to `return this.y( y1+oy-o )`
    return this.y(new SVG.Number(y1).plus(this instanceof SVG.FX ? 0 : this.y()), true)
}

Then it comes the problem.

Because the shifted y position is a value that excluding the bounding box offset, it should add the offset before it is set to the attribute. However, since y is not a number but a SVG.Number, it is directly set to the attribute without including the bounding box offset.

// text.y()
// argument y2=y1+oy-o
y: function (y2) {
    /* skipped */

    // since y2 is a SVG.Number, this is equivalance to `return this.attr(y2)`
    return this.attr('y', typeof y2 === 'number' ? y2 + o : y2)
}

We originally want to shift the text with distance y1 away from oy, the result position should be oy+y1 to make it correct. However, in current version of SVG.js, we get y1+oy-o instead, where o is the offset of the bounding box in y-axis.


You can see another demo tested with text.dy(0).
To make sense, the text should stay still; however it runs (or shifts) away instead.

bug

All 4 comments

Can you try typeof y2.valueOf() == 'number'?

typeof y2.valueOf() == 'number' // true if y2 is a SVG.Number

See Demo.
In the case that text.y() acts as a setter, changing the return line of it to the following code fixes the problem.

return this.attr('y', typeof y2.valueOf() === 'number' ? y2 + o : y2)

Finally fixed this in the current master. Thank you for digging and testing!

Glad to see this fixed. :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

imkiven picture imkiven  路  8Comments

mixn picture mixn  路  9Comments

edemaine picture edemaine  路  9Comments

Salitehkat picture Salitehkat  路  4Comments

Fuzzyma picture Fuzzyma  路  3Comments