UNPKG

@react-financial-charts/axes

Version:
244 lines 9.81 kB
var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; import { first, GenericChartComponent, getAxisCanvas, getStrokeDasharrayCanvas, last, } from "@react-financial-charts/core"; import { range as d3Range, zip } from "d3-array"; import { forceCollide, forceSimulation, forceX } from "d3-force"; import * as React from "react"; import { AxisZoomCapture } from "./AxisZoomCapture"; export class Axis extends React.Component { constructor() { super(...arguments); this.chartRef = React.createRef(); this.getMoreProps = () => { return this.chartRef.current.getMoreProps(); }; this.drawOnCanvas = (ctx, moreProps) => { const { showDomain, showGridLines, showTickLabel, showTicks, transform, range, getScale, tickLabelFill } = this.props; ctx.save(); ctx.translate(transform[0], transform[1]); const scale = getScale(moreProps); const tickProps = tickHelper(this.props, scale); if (showTicks) { drawTicks(ctx, tickProps); } if (showGridLines) { tickProps.ticks.forEach((tick) => { drawGridLine(ctx, tick, tickProps, moreProps); }); } if (showTickLabel) { const { fontFamily, fontSize, fontWeight, textAnchor } = tickProps; ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`; if (tickLabelFill !== undefined) { ctx.fillStyle = tickLabelFill; } ctx.textAlign = textAnchor === "middle" ? "center" : textAnchor; tickProps.ticks.forEach((tick) => { drawEachTickLabel(ctx, tick, tickProps); }); } if (showDomain) { drawAxisLine(ctx, this.props, range); } ctx.restore(); }; } render() { const { bg, axisZoomCallback, className, zoomCursorClassName, zoomEnabled, getScale, inverted, transform, getMouseDelta, edgeClip, onContextMenu, onDoubleClick, } = this.props; const zoomCapture = zoomEnabled ? (React.createElement(AxisZoomCapture, { bg: bg, getScale: getScale, getMoreProps: this.getMoreProps, getMouseDelta: getMouseDelta, axisZoomCallback: axisZoomCallback, className: className, zoomCursorClassName: zoomCursorClassName, inverted: inverted, onContextMenu: onContextMenu, onDoubleClick: onDoubleClick })) : null; return (React.createElement("g", { transform: `translate(${transform[0]}, ${transform[1]})` }, zoomCapture, React.createElement(GenericChartComponent, { ref: this.chartRef, canvasToDraw: getAxisCanvas, clip: false, edgeClip: edgeClip, canvasDraw: this.drawOnCanvas, drawOn: ["pan"] }))); } } Axis.defaultProps = { edgeClip: false, zoomEnabled: false, zoomCursorClassName: "", }; const tickHelper = (props, scale) => { const { orient, innerTickSize = 4, tickFormat, tickPadding = 4, tickLabelFill, tickStrokeWidth, tickStrokeDasharray, fontSize = 12, fontFamily, fontWeight, showTicks, showTickLabel, ticks: tickArguments, tickValues: tickValuesProp, tickStrokeStyle, tickInterval, tickIntervalFunction } = props, rest = __rest(props, ["orient", "innerTickSize", "tickFormat", "tickPadding", "tickLabelFill", "tickStrokeWidth", "tickStrokeDasharray", "fontSize", "fontFamily", "fontWeight", "showTicks", "showTickLabel", "ticks", "tickValues", "tickStrokeStyle", "tickInterval", "tickIntervalFunction"]); let tickValues; if (tickValuesProp !== undefined) { if (typeof tickValuesProp === "function") { tickValues = tickValuesProp(scale.domain()); } else { tickValues = tickValuesProp; } } else if (tickInterval !== undefined) { const [min, max] = scale.domain(); const baseTickValues = d3Range(min, max, (max - min) / tickInterval); tickValues = tickIntervalFunction ? tickIntervalFunction(min, max, tickInterval) : baseTickValues; } else if (scale.ticks !== undefined) { tickValues = scale.ticks(tickArguments); } else { tickValues = scale.domain(); } const format = tickFormat === undefined ? scale.tickFormat(tickArguments) : (d) => tickFormat(d) || ""; const sign = orient === "top" || orient === "left" ? -1 : 1; const tickSpacing = Math.max(innerTickSize, 0) + tickPadding; let ticks; let dy; // tslint:disable-next-line: variable-name let canvas_dy; let textAnchor; if (orient === "bottom" || orient === "top") { dy = sign < 0 ? "0em" : ".71em"; canvas_dy = sign < 0 ? 0 : fontSize * 0.71; textAnchor = "middle"; const y2 = sign * innerTickSize; const labelY = sign * tickSpacing; ticks = tickValues.map((d) => { const x = Math.round(scale(d)); return { value: d, x1: x, y1: 0, x2: x, y2, labelX: x, labelY, }; }); if (showTicks) { const nodes = ticks.map((d) => ({ id: d.value, value: d.value, fy: d.y2, origX: d.x1 })); const simulation = forceSimulation(nodes) .force("x", forceX((d) => d.origX).strength(1)) .force("collide", forceCollide(22)) .stop(); for (let i = 0; i < 100; ++i) { simulation.tick(); } // @ts-ignore ticks = zip(ticks, nodes).map((d) => { const a = d[0]; const b = d[1]; if (Math.abs(b.x - b.origX) > 0.01) { return Object.assign(Object.assign({}, a), { x2: b.x, labelX: b.x }); } return a; }); } } else { ticks = tickValues.map((d) => { const y = Math.round(scale(d)); const x2 = sign * innerTickSize; const labelX = sign * tickSpacing; return { value: d, x1: 0, y1: y, x2, y2: y, labelX, labelY: y, }; }); dy = ".32em"; canvas_dy = fontSize * 0.32; textAnchor = sign < 0 ? "end" : "start"; } return Object.assign({ orient, ticks, scale, tickStrokeStyle, tickLabelFill: tickLabelFill || tickStrokeStyle, tickStrokeWidth, tickStrokeDasharray, dy, canvas_dy, textAnchor, fontSize, fontFamily, fontWeight, format, showTickLabel }, rest); }; const drawAxisLine = (ctx, props, range) => { const { orient, outerTickSize, strokeStyle, strokeWidth } = props; const sign = orient === "top" || orient === "left" ? -1 : 1; const xAxis = orient === "bottom" || orient === "top"; ctx.lineWidth = strokeWidth; ctx.strokeStyle = strokeStyle; ctx.beginPath(); const firstPoint = first(range); const lastPoint = last(range); const tickSize = sign * outerTickSize; if (xAxis) { ctx.moveTo(firstPoint, tickSize); ctx.lineTo(firstPoint, 0); ctx.lineTo(lastPoint, 0); ctx.lineTo(lastPoint, tickSize); } else { ctx.moveTo(tickSize, firstPoint); ctx.lineTo(0, firstPoint); ctx.lineTo(0, lastPoint); ctx.lineTo(tickSize, lastPoint); } ctx.stroke(); }; const drawTicks = (ctx, result) => { const { ticks, tickStrokeStyle } = result; if (tickStrokeStyle !== undefined) { ctx.strokeStyle = tickStrokeStyle; ctx.fillStyle = tickStrokeStyle; } ticks.forEach((tick) => { drawEachTick(ctx, tick, result); }); }; const drawGridLine = (ctx, tick, result, moreProps) => { const { orient, gridLinesStrokeWidth, gridLinesStrokeStyle, gridLinesStrokeDasharray } = result; const { chartConfig } = moreProps; const { height, width } = chartConfig; if (gridLinesStrokeStyle !== undefined) { ctx.strokeStyle = gridLinesStrokeStyle; } ctx.beginPath(); const sign = orient === "top" || orient === "left" ? 1 : -1; switch (orient) { case "top": case "bottom": ctx.moveTo(tick.x1, 0); ctx.lineTo(tick.x2, sign * height); break; default: ctx.moveTo(0, tick.y1); ctx.lineTo(sign * width, tick.y2); break; } ctx.lineWidth = gridLinesStrokeWidth; const lineDash = getStrokeDasharrayCanvas(gridLinesStrokeDasharray); ctx.setLineDash(lineDash); ctx.stroke(); }; const drawEachTick = (ctx, tick, result) => { const { tickStrokeWidth, tickStrokeDasharray } = result; ctx.beginPath(); ctx.moveTo(tick.x1, tick.y1); ctx.lineTo(tick.x2, tick.y2); ctx.lineWidth = tickStrokeWidth; const lineDash = getStrokeDasharrayCanvas(tickStrokeDasharray); ctx.setLineDash(lineDash); ctx.stroke(); }; const drawEachTickLabel = (ctx, tick, result) => { const { canvas_dy, format } = result; const text = format(tick.value); ctx.beginPath(); ctx.fillText(text, tick.labelX, tick.labelY + canvas_dy); }; //# sourceMappingURL=Axis.js.map