import {create} from "../context.js"; import {identity, number} from "../options.js"; import {Mark} from "../mark.js"; import {applyMarkers, markers} from "../marker.js"; import {applyDirectStyles, applyIndirectStyles, applyTransform, applyChannelStyles, offset} from "../style.js"; const defaults = { ariaLabel: "tick", fill: null, stroke: "currentColor" }; class AbstractTick extends Mark { constructor(data, channels, options) { super(data, channels, options, defaults); markers(this, options); } render(index, scales, channels, dimensions, context) { return create("svg:g", context) .call(applyIndirectStyles, this, dimensions, context) .call(this._transform, this, scales) .call((g) => g .selectAll() .data(index) .enter() .append("line") .call(applyDirectStyles, this) .attr("x1", this._x1(scales, channels, dimensions)) .attr("x2", this._x2(scales, channels, dimensions)) .attr("y1", this._y1(scales, channels, dimensions)) .attr("y2", this._y2(scales, channels, dimensions)) .call(applyChannelStyles, this, channels) .call(applyMarkers, this, channels, context) ) .node(); } } export class TickX extends AbstractTick { constructor(data, options = {}) { const {x, y, inset = 0, insetTop = inset, insetBottom = inset} = options; super( data, { x: {value: x, scale: "x"}, y: {value: y, scale: "y", type: "band", optional: true} }, options ); this.insetTop = number(insetTop); this.insetBottom = number(insetBottom); } _transform(selection, mark, {x}) { selection.call(applyTransform, mark, {x}, offset, 0); } _x1(scales, {x: X}) { return (i) => X[i]; } _x2(scales, {x: X}) { return (i) => X[i]; } _y1({y}, {y: Y}, {marginTop}) { const {insetTop} = this; return Y && y ? (i) => Y[i] + insetTop : marginTop + insetTop; } _y2({y}, {y: Y}, {height, marginBottom}) { const {insetBottom} = this; return Y && y ? (i) => Y[i] + y.bandwidth() - insetBottom : height - marginBottom - insetBottom; } } export class TickY extends AbstractTick { constructor(data, options = {}) { const {x, y, inset = 0, insetRight = inset, insetLeft = inset} = options; super( data, { y: {value: y, scale: "y"}, x: {value: x, scale: "x", type: "band", optional: true} }, options ); this.insetRight = number(insetRight); this.insetLeft = number(insetLeft); } _transform(selection, mark, {y}) { selection.call(applyTransform, mark, {y}, 0, offset); } _x1({x}, {x: X}, {marginLeft}) { const {insetLeft} = this; return X && x ? (i) => X[i] + insetLeft : marginLeft + insetLeft; } _x2({x}, {x: X}, {width, marginRight}) { const {insetRight} = this; return X && x ? (i) => X[i] + x.bandwidth() - insetRight : width - marginRight - insetRight; } _y1(scales, {y: Y}) { return (i) => Y[i]; } _y2(scales, {y: Y}) { return (i) => Y[i]; } } export function tickX(data, {x = identity, ...options} = {}) { return new TickX(data, {...options, x}); } export function tickY(data, {y = identity, ...options} = {}) { return new TickY(data, {...options, y}); }