UNPKG

lucid-ui

Version:

A UI component library from Xandr.

161 lines (151 loc) 3.89 kB
import { Selection } from 'd3-selection'; import _ from 'lodash'; import * as d3Array from 'd3-array'; import ReactDOM from 'react-dom'; import { IData } from './DraggableLineChartD3'; export type IXAxisRenderProp = ({ x, y, ref, }: { x: string; y: number; ref?: any; }) => JSX.Element; export type ISelection = Selection<SVGElement | any, {} | any, null, undefined>; const getGroup = (selection: ISelection, className: string): ISelection => { const xAxisGroup = selection.select(`.${className}`); if (xAxisGroup.empty()) { return selection.append('g').classed(className, true); } return xAxisGroup; }; const getGroups = ( selection: ISelection, className: string, dataset: any ): ISelection => { const selectionGroup = selection.selectAll(`.${className}`); if (selectionGroup.empty()) { const xAxisGroup = selectionGroup.data(dataset).order(); return xAxisGroup.enter().append('g').classed(className, true); } return selectionGroup; }; const getTickObj = (selection: ISelection): ISelection => { let data = selection.selectAll('.innerDiv'); if (data.empty()) { data = selection .selectAll('foreignObject') .append('xhtml:div') .attr('tabindex', 0) .style('position', 'fixed') .style('transform', 'translate(0px, -50px)') .classed('innerDiv', true); } return data; }; const getTickRender = ( selection: ISelection, containerWidth: number ): ISelection => { const tickRender = selection.selectAll('.tickRender'); if (!tickRender.empty()) { tickRender.remove(); } return selection .append('xhtml:div') .style('width', `${containerWidth}px`) .attr('id', (d: any) => d) .classed('tickRender', true); }; const getLines = ( selection: ISelection, xScale: any, tickSize: number ): ISelection => { const lines = selection.selectAll('line'); if (lines.empty()) { return selection .append('line') .attr('x1', 0) .attr('x2', 0) .attr('y1', 0) .attr('y2', -tickSize || 5); } return lines; }; const getForeignObject = (selection: ISelection): ISelection => { const fO = selection.selectAll('foreignObject'); if (fO.empty()) { return selection .append('foreignObject') .style('overflow', 'visible') .style('display', 'flex') .attr('x', 0) .attr('y', 0) .attr('height', 1) .attr('width', 1); } return fO; }; const lucidXAxis = ( selection: ISelection, { xScale, tickSize, xAxisRenderProp, dataIsCentered, data, }: { xScale: any; tickSize: number; xAxisRenderProp?: IXAxisRenderProp; dataIsCentered?: boolean; data: IData; } ): void => { const range = xScale.range(); const domain = xScale.domain(); const rMin = Number(d3Array.min(range)) || 0; const rMax = Number(d3Array.max(range)) || 0; const domainLength = dataIsCentered ? domain.length - 1 : domain.length; const axisGroup = getGroup(selection, 'axis'); axisGroup .append('line') .attr('stroke', 'black') .attr('x1', rMin) .attr('x2', rMax) .attr('y1', 0) .attr('y2', 0); axisGroup .append('line') .attr('stroke', 'black') .attr('x1', rMin) .attr('x2', rMax) .attr('y1', -tickSize) .attr('y2', -tickSize); const xLines = getGroups(axisGroup, 'xLines', domain); const xLine = xLines.attr( 'transform', (d: any) => `translate( ${xScale(d)}, 0)` ); getLines(xLine, xScale, tickSize); getForeignObject(xLine); if (!xAxisRenderProp) { xLine.append('text').text((d: any) => d); } else { const tickObj = getTickObj(xLine); const tickRender = getTickRender(tickObj, (rMax - rMin) / domainLength); tickRender.html((xValue: any, num: any, node: any) => { if (xValue !== '' && !_.isNil(xValue)) { const subData = _.find(data, { x: xValue }) || { y: 0, ref: undefined }; ReactDOM.render( xAxisRenderProp({ x: xValue, y: subData.y, ref: subData.ref }), node[0] ); } else return xValue; }); } }; export { lucidXAxis, getGroup };