UNPKG

d3-er

Version:

Custom d3 module created using some d3 modules and custom functions

216 lines (179 loc) 6.56 kB
import * as d3Sel from 'd3-selection' import * as d3Array from 'd3-array' import * as d3Scale from 'd3-scale' import * as d3Timer from 'd3-timer' export default function () { let orient = 'left' let reverse = false let duration = 0 let ranges = d => d.ranges let markers = d => d.markers let measures = d => d.measures let width = 380 let height = 30 let tickFormat = null function bulletTranslate(x) { return function (d) { return `translate(${x(d)},0)` } } function bulletWidth(x) { const x0 = x(0) return function (d) { return Math.abs(x(d) - x0) } } function bullet(g) { g.each(function (d, i) { const rangez = ranges.call(this, d, i).slice().sort(d3Array.descending) const markerz = markers.call(this, d, i).slice().sort(d3Array.descending) const measurez = measures.call(this, d, i).slice().sort(d3Array.descending) const group = d3Sel.select(this) const x1 = d3Scale.scaleLinear() .domain([0, Math.max(rangez[0], markerz[0], measurez[0])]) .range(reverse ? [width, 0] : [0, width]) const x0 = this.__chart__ || d3Scale.scaleLinear() .domain([0, Infinity]) .range(x1.range()) this.__chart__ = x1 const w0 = bulletWidth(x0) const w1 = bulletWidth(x1) const range = group.selectAll('rect.range').data(rangez) range.enter().append('rect') .attr('class', (d, i) => `range s${i}`) .attr('width', w0) .attr('height', height) .attr('x', reverse ? x0 : 0) .transition() .duration(duration) .attr('width', w1) .attr('x', reverse ? x1 : 0) range.transition() .duration(duration) .attr('x', reverse ? x1 : 0) .attr('width', w1) .attr('height', height) // Update the measure rects. const measure = group.selectAll('rect.measure') .data(measurez) measure.enter().append('rect') .attr('class', (d, i) => `measure s${i}`) .attr('width', w0) .attr('height', height / 3) .attr('x', reverse ? x0 : 0) .attr('y', height / 3) .transition() .duration(duration) .attr('width', w1) .attr('x', reverse ? x1 : 0) measure.transition() .duration(duration) .attr('width', w1) .attr('height', height / 3) .attr('x', reverse ? x1 : 0) .attr('y', height / 3) // Update the marker lines. const marker = group.selectAll('line.marker') .data(markerz) marker.enter().append('line') .attr('class', 'marker') .attr('x1', x0) .attr('x2', x0) .attr('y1', height / 6) .attr('y2', (height * 5) / 6) .transition() .duration(duration) .attr('x1', x1) .attr('x2', x1) marker.transition() .duration(duration) .attr('x1', x1) .attr('x2', x1) .attr('y1', height / 6) .attr('y2', (height * 5) / 6) // Compute the tick format. const format = tickFormat || x1.tickFormat(8) // Update the tick groups. const tick = group.selectAll('g.tick') .data(x1.ticks(8), d => this.textContent || format(d)) // Initialize the ticks with the old scale, x0. const tickEnter = tick.enter().append('g') .attr('class', 'tick') .attr('transform', bulletTranslate(x0)) .style('opacity', 1e-6) tickEnter.append('line') .attr('y1', height) .attr('y2', (height * 7) / 6) tickEnter.append('text') .attr('text-anchor', 'middle') .attr('dy', '1em') .attr('y', (height * 7) / 6) .text(format) // Transition the entering ticks to the new scale, x1. tickEnter.transition() .duration(duration) .attr('transform', bulletTranslate(x1)) .style('opacity', 1) // Transition the updating ticks to the new scale, x1. const tickUpdate = tick.transition() .duration(duration) .attr('transform', bulletTranslate(x1)) .style('opacity', 1) tickUpdate.select('line') .attr('y1', height) .attr('y2', (height * 7) / 6) tickUpdate.select('text') .attr('y', (height * 7) / 6) // Transition the exiting ticks to the new scale, x1. tick.exit().transition() .duration(duration) .attr('transform', bulletTranslate(x1)) .style('opacity', 1e-6) .remove() }) d3Timer.timerFlush() } bullet.orient = function (x) { if (!arguments.length) return orient orient = x reverse = orient === 'right' || orient === 'bottom' return bullet } bullet.ranges = function (x) { if (!arguments.length) return ranges ranges = x return bullet } bullet.markers = function (x) { if (!arguments.length) return markers markers = x return bullet } // measures (actual, forecast) bullet.measures = function (x) { if (!arguments.length) return measures measures = x return bullet } bullet.width = function (x) { if (!arguments.length) return width width = x return bullet } bullet.height = function (x) { if (!arguments.length) return height height = x return bullet } bullet.tickFormat = function (x) { if (!arguments.length) return tickFormat tickFormat = x return bullet } bullet.duration = function (x) { if (!arguments.length) return duration duration = x return bullet } return bullet }