Skip to content

Commit 8806fee

Browse files
committed
support dx, dy on all marks
On all marks except text, dx, dy are rendered as a transform(translate) property, possibly with the 0.5px offset on high-density screens. On text marks, the dx and dy properties are used. closes #379
1 parent 5670bbf commit 8806fee

File tree

13 files changed

+43
-34
lines changed

13 files changed

+43
-34
lines changed

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,10 @@ All marks support the following style options:
467467
* **strokeDasharray** - a comma-separated list of dash lengths (in pixels)
468468
* **mixBlendMode** - the [blend mode](https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode) (*e.g.*, *multiply*)
469469
* **shapeRendering** - the [shape-rendering mode](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering) (*e.g.*, *crispEdges*)
470+
* **dx** - horizontal offset; defaults to 0
471+
* **dy** - vertical offset; defaults to 0
472+
473+
For all marks except [text](#plottextdata-options), the **dx** and **dy** options are rendered as a translate(dx, dy) transform property, possibly including a 0.5 offset on high-density screens.
470474

471475
All marks support the following optional channels:
472476

@@ -846,11 +850,9 @@ The following text-specific constant options are also supported:
846850
* **fontStyle** - the [font style](https://developer.mozilla.org/en-US/docs/Web/CSS/font-style); defaults to normal
847851
* **fontVariant** - the [font variant](https://developer.mozilla.org/en-US/docs/Web/CSS/font-variant); defaults to normal
848852
* **fontWeight** - the [font weight](https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight); defaults to normal
849-
* **dx** - the horizontal offset; defaults to 0
850-
* **dy** - the vertical offset; defaults to 0
851853
* **rotate** - the rotation in degrees clockwise; defaults to 0
852854

853-
The **dx** and **dy** options can be specified either as numbers representing pixels or as a string including units. For example, `"1em"` shifts the text by one [em](https://en.wikipedia.org/wiki/Em_(typography)), which is proportional to the **fontSize**. The **fontSize** and **rotate** options can be specified as either channels or constants. When fontSize or rotate is specified as a number, it is interpreted as a constant; otherwise it is interpreted as a channel.
855+
For text marks, the **dx** and **dy** options can be specified either as numbers representing pixels or as a string including units. For example, `"1em"` shifts the text by one [em](https://en.wikipedia.org/wiki/Em_(typography)), which is proportional to the **fontSize**. The **fontSize** and **rotate** options can be specified as either channels or constants. When fontSize or rotate is specified as a number, it is interpreted as a constant; otherwise it is interpreted as a channel.
854856

855857
#### Plot.text(*data*, *options*)
856858

src/mark.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const TypedArray = Object.getPrototypeOf(Uint8Array);
77
const objectToString = Object.prototype.toString;
88

99
export class Mark {
10-
constructor(data, channels = [], {facet = "auto", ...options} = {}) {
10+
constructor(data, channels = [], {facet = "auto", dx, dy, ...options} = {}) {
1111
const names = new Set();
1212
this.data = data;
1313
this.facet = facet ? keyword(facet === true ? "include" : facet, "facet", ["auto", "include", "exclude"]) : null;
@@ -27,6 +27,8 @@ export class Mark {
2727
}
2828
return true;
2929
});
30+
this.dx = +dx || 0;
31+
this.dy = +dy || 0;
3032
}
3133
initialize(facets) {
3234
let data = arrayify(this.data);

src/marks/area.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,10 @@ export class Area extends Mark {
5959
});
6060
}
6161
render(I, {x, y}, {x1: X1, y1: Y1, x2: X2 = X1, y2: Y2 = Y1, z: Z, title: L, fill: F, fillOpacity: FO, stroke: S, strokeOpacity: SO}) {
62+
const {dx, dy} = this;
6263
return create("svg:g")
6364
.call(applyIndirectStyles, this)
64-
.call(applyTransform, x, y)
65+
.call(applyTransform, x, y, dx, dy)
6566
.call(g => g.selectAll()
6667
.data(Z ? group(I, i => Z[i]).values() : [I])
6768
.join("path")

src/marks/bar.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,12 @@ export class AbstractBar extends Mark {
5555
this.ry = impliedString(ry, "auto");
5656
}
5757
render(I, scales, channels, dimensions) {
58-
const {rx, ry} = this;
58+
const {dx, dy, rx, ry} = this;
5959
const {title: L, fill: F, fillOpacity: FO, stroke: S, strokeOpacity: SO} = channels;
6060
const index = filter(I, ...this._positions(channels), F, FO, S, SO);
6161
return create("svg:g")
6262
.call(applyIndirectStyles, this)
63-
.call(this._transform, scales)
63+
.call(this._transform, scales, dx, dy)
6464
.call(g => g.selectAll()
6565
.data(index)
6666
.join("rect")
@@ -110,8 +110,8 @@ export class BarX extends AbstractBar {
110110
options
111111
);
112112
}
113-
_transform(selection, {x}) {
114-
selection.call(applyTransform, x, null);
113+
_transform(selection, {x}, dx, dy) {
114+
selection.call(applyTransform, x, null, dx, dy);
115115
}
116116
_positions({x1: X1, x2: X2, y: Y}) {
117117
return [X1, X2, Y];
@@ -138,8 +138,8 @@ export class BarY extends AbstractBar {
138138
options
139139
);
140140
}
141-
_transform(selection, {y}) {
142-
selection.call(applyTransform, null, y);
141+
_transform(selection, {y}, dx, dy) {
142+
selection.call(applyTransform, null, y, dx, dy);
143143
}
144144
_positions({y1: Y1, y2: Y2, x: X}) {
145145
return [Y1, Y2, X];

src/marks/dot.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {create} from "d3";
22
import {filter, positive} from "../defined.js";
33
import {Mark, identity, maybeColor, maybeNumber, maybeTuple, title} from "../mark.js";
4-
import {Style, applyDirectStyles, applyIndirectStyles, applyTransform, applyAttr} from "../style.js";
4+
import {Style, applyDirectStyles, applyIndirectStyles, applyTransform, applyAttr, offset} from "../style.js";
55

66
export class Dot extends Mark {
77
constructor(
@@ -55,9 +55,10 @@ export class Dot extends Mark {
5555
) {
5656
let index = filter(I, X, Y, F, FO, S, SO);
5757
if (R) index = index.filter(i => positive(R[i]));
58+
const {dx, dy} = this;
5859
return create("svg:g")
5960
.call(applyIndirectStyles, this)
60-
.call(applyTransform, x, y, 0.5, 0.5)
61+
.call(applyTransform, x, y, offset + dx, offset + dy)
6162
.call(g => g.selectAll()
6263
.data(index)
6364
.join("circle")

src/marks/frame.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {create} from "d3";
22
import {Mark, number} from "../mark.js";
3-
import {Style, applyDirectStyles, applyIndirectStyles, applyTransform} from "../style.js";
3+
import {Style, applyDirectStyles, applyIndirectStyles, applyTransform, offset} from "../style.js";
44

55
export class Frame extends Mark {
66
constructor({
@@ -26,10 +26,11 @@ export class Frame extends Mark {
2626
channels,
2727
{marginTop, marginRight, marginBottom, marginLeft, width, height}
2828
) {
29+
const {dx, dy} = this;
2930
return create("svg:rect")
3031
.call(applyIndirectStyles, this)
3132
.call(applyDirectStyles, this)
32-
.call(applyTransform, null, null, 0.5, 0.5)
33+
.call(applyTransform, null, null, offset + dx, offset + dy)
3334
.attr("x", marginLeft + this.insetLeft)
3435
.attr("y", marginTop + this.insetTop)
3536
.attr("width", width - marginLeft - marginRight - this.insetLeft - this.insetRight)

src/marks/line.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {line as shapeLine} from "d3";
44
import {Curve} from "../curve.js";
55
import {defined} from "../defined.js";
66
import {Mark, indexOf, identity, maybeColor, maybeTuple, titleGroup, maybeNumber} from "../mark.js";
7-
import {Style, applyDirectStyles, applyIndirectStyles, applyTransform, applyAttr} from "../style.js";
7+
import {Style, applyDirectStyles, applyIndirectStyles, applyTransform, applyAttr, offset} from "../style.js";
88

99
export class Line extends Mark {
1010
constructor(
@@ -55,9 +55,10 @@ export class Line extends Mark {
5555
});
5656
}
5757
render(I, {x, y}, {x: X, y: Y, z: Z, title: L, fill: F, fillOpacity: FO, stroke: S, strokeOpacity: SO}) {
58+
const {dx, dy} = this;
5859
return create("svg:g")
5960
.call(applyIndirectStyles, this)
60-
.call(applyTransform, x, y, 0.5, 0.5)
61+
.call(applyTransform, x, y, offset + dx, offset + dy)
6162
.call(g => g.selectAll()
6263
.data(Z ? group(I, i => Z[i]).values() : [I])
6364
.join("path")

src/marks/link.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {create, path} from "d3";
22
import {filter} from "../defined.js";
33
import {Mark, maybeColor, maybeNumber, title} from "../mark.js";
44
import {Curve} from "../curve.js";
5-
import {Style, applyDirectStyles, applyIndirectStyles, applyTransform, applyAttr} from "../style.js";
5+
import {Style, applyDirectStyles, applyIndirectStyles, applyTransform, applyAttr, offset} from "../style.js";
66

77
export class Link extends Mark {
88
constructor(
@@ -56,9 +56,10 @@ export class Link extends Mark {
5656
{x1: X1, y1: Y1, x2: X2 = X1, y2: Y2 = Y1, title: L, stroke: S, strokeOpacity: SO}
5757
) {
5858
const index = filter(I, X1, Y1, X2, Y2, S, SO);
59+
const {dx, dy} = this;
5960
return create("svg:g")
6061
.call(applyIndirectStyles, this)
61-
.call(applyTransform, x, y, 0.5, 0.5)
62+
.call(applyTransform, x, y, offset + dx, offset + dy)
6263
.call(g => g.selectAll()
6364
.data(index)
6465
.join("path")

src/marks/rect.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,11 @@ export class Rect extends Mark {
6565
{x, y},
6666
{x1: X1, y1: Y1, x2: X2, y2: Y2, title: L, fill: F, fillOpacity: FO, stroke: S, strokeOpacity: SO}
6767
) {
68-
const {rx, ry} = this;
68+
const {dx, dy, rx, ry} = this;
6969
const index = filter(I, X1, Y2, X2, Y2, F, FO, S, SO);
7070
return create("svg:g")
7171
.call(applyIndirectStyles, this)
72-
.call(applyTransform, x, y)
72+
.call(applyTransform, x, y, dx, dy)
7373
.call(g => g.selectAll()
7474
.data(index)
7575
.join("rect")

src/marks/rule.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {create} from "d3";
22
import {filter} from "../defined.js";
33
import {Mark, identity, maybeColor, title, number, maybeNumber} from "../mark.js";
4-
import {Style, applyDirectStyles, applyIndirectStyles, applyTransform, applyAttr} from "../style.js";
4+
import {Style, applyDirectStyles, applyIndirectStyles, applyTransform, applyAttr, offset} from "../style.js";
55

66
export class RuleX extends Mark {
77
constructor(
@@ -46,7 +46,7 @@ export class RuleX extends Mark {
4646
const index = filter(I, X, Y1, Y2, S);
4747
return create("svg:g")
4848
.call(applyIndirectStyles, this)
49-
.call(applyTransform, X && x, null, 0.5, 0)
49+
.call(applyTransform, X && x, null, offset, 0)
5050
.call(g => g.selectAll("line")
5151
.data(index)
5252
.join("line")
@@ -103,9 +103,10 @@ export class RuleY extends Mark {
103103
{width, height, marginTop, marginRight, marginLeft, marginBottom}
104104
) {
105105
const index = filter(I, Y, X1, X2);
106+
const {dx, dy} = this;
106107
return create("svg:g")
107108
.call(applyIndirectStyles, this)
108-
.call(applyTransform, null, Y && y, 0, 0.5)
109+
.call(applyTransform, null, Y && y, dx, offset + dy)
109110
.call(g => g.selectAll("line")
110111
.data(index)
111112
.join("line")

0 commit comments

Comments
 (0)