import * as React from 'react'; export type Tick = { position: number; label?: string; }; type SVGAxisProps = { x: number; y: number; length: number; ticks: Tick[]; tickLength: number; rangeLower: number; rangeUpper: number; vertical?: boolean; reverse?: boolean; invertTicks?: boolean; label?: string; verticalLabelPadding?: number; horizontalLabelPadding?: number; tickLabelPadding?: number; }; export default class SVGAxis extends React.Component { public static defaultProps: Partial = { verticalLabelPadding: 30, horizontalLabelPadding: 5, tickLabelPadding: 3, }; private positionToAxisPosition(position: number) { const pos = this.props.reverse ? this.props.rangeUpper - position : position; return ( (pos / (this.props.rangeUpper - this.props.rangeLower)) * this.props.length ); } private get ticks() { return this.props.ticks.map(tick => { const tickLength = this.props.invertTicks ? -this.props.tickLength : this.props.tickLength; const axisPosition = this.positionToAxisPosition(tick.position); const x1 = this.props.vertical ? this.props.x : this.props.x + axisPosition; const y1 = this.props.vertical ? this.props.y + this.props.length - axisPosition : this.props.y; const x2 = this.props.vertical ? this.props.x - tickLength : this.props.x + axisPosition; const y2 = this.props.vertical ? this.props.y + this.props.length - axisPosition : this.props.y + tickLength; const labelPadding = this.props.tickLabelPadding!; let label = null; if (tick.label) { if (this.props.vertical) { label = ( {tick.label} ); } else { label = ( {tick.label} ); } } return ( {label} ); }); } private get label() { if (this.props.label) { const tickLength = this.props.invertTicks ? -this.props.tickLength : this.props.tickLength; const verticalPadding = this.props.verticalLabelPadding!; const horizontalPadding = this.props.horizontalLabelPadding!; let x: number; let y: number; let transform: string; if (this.props.vertical) { x = this.props.x - tickLength + (this.props.invertTicks ? verticalPadding : -verticalPadding); y = this.props.y + this.props.length / 2; transform = `rotate(270,${x},${y})`; } else { x = this.props.x + this.props.length / 2; y = this.props.y + tickLength + (this.props.invertTicks ? -horizontalPadding : horizontalPadding); transform = ''; } let count = 0; let wrappedLabel = this.props.label.split(/\n/g).map(l => ( '; } else { return ''; } }), }} > )); return ( 1 ? transform + ' translate(0, -30)' : transform } > {wrappedLabel.length > 1 ? wrappedLabel : this.props.label} ); } else { return null; } } render() { const x2 = this.props.vertical ? this.props.x : this.props.x + this.props.length; const y2 = this.props.vertical ? this.props.y + this.props.length : this.props.y; return ( {this.ticks} {this.label} ); } }