UNPKG

monte

Version:

A visualization framework for D3.js and SVG. Ships with prebuilt charts and components.

132 lines (105 loc) 4.03 kB
import { ENTER, EXIT, UPDATE } from '../../const/d3'; import { LineChart } from './LineChart'; import { commonEventNames } from '../../tools/commonEventNames'; import { extentFromZero } from '../../util/extents'; import { noop } from '../../tools/noop'; import { resetScaleDomain } from '../../tools/resetScaleDomain'; import { upperFirst } from '../../tools/string'; const AREA = 'area'; const AREA_CHART_DEFAULTS = { chartCss: 'monte-area-chart', margin: { top: 10, right: 10, bottom: 30, left: 40, }, /*********************************************************************************************** * * Area related options * **********************************************************************************************/ areaProp: '', // Callback function to customize the area generator. areaCustomize: null, // Scale function for the `fill` attribute to apply per area. areaFillScale: noop, areaFillScaleAccessor: LineChart.generateScaleAccessor('areaFillScale', 'areaProp'), // Scale function for CSS class to apply per area. Input: line index, Output: String of CSS Class. areaCssScale: noop, areaCssScaleAccessor: LineChart.generateScaleAccessor('areaCssScale', 'areaProp'), // Static CSS class(es) to apply to every area. areaCss: 'area', // OVERRIDES yDomainCustomize: extentFromZero, }; export class AreaChart extends LineChart { _initOptions(...options) { super._initOptions(...options, AREA_CHART_DEFAULTS); } _initCore() { super._initCore(); // Initialize the line generator this.area = d3.area() .x((d) => this.getScaledProp('x', d)) .y0(() => this.height) .y1((d) => this.getScaledProp('y', d)); } _initCustomize() { super._initCustomize(); if (this.opts.areaCustomize) { this.tryInvoke(this.opts.areaCustomize, this.area); } } _initPublicEvents(...events) { super._initPublicEvents(...events, ...commonEventNames(AREA) // Area events ); } _resetStyleDomains() { super._resetStyleDomains(); resetScaleDomain(this.opts.areaCssScale); resetScaleDomain(this.opts.areaFillScale); } _update() { const lineGrps = super._update(); lineGrps.each((d, i, nodes) => { this._updateLineArea(nodes[i], d, i, nodes); }); } _updateLineArea(node, lineDatum, lineIndex, lineNodes) { const lineGrp = d3.select(node); // Data join for the area const area = lineGrp.selectAll('.monte-area').data((d) => [d]); // Create new area and update existing const enterAreas = area.enter().insert('path', ':first-child') .call(this.__bindCommonEvents(AREA)); this._updateLineAreaSelections(enterAreas, ENTER, lineDatum, lineIndex, lineNodes); this._updateLineAreaSelections(area, UPDATE, lineDatum, lineIndex, lineNodes); // Fade out removed area area.exit() .call((sel) => this.fnInvoke(this.opts.areaExitSelectionCustomize, sel)) .transition() .call(this._transitionSetup(AREA, EXIT)) .style('opacity', 0) .call((t) => this.fnInvoke(this.opts.areaExitTransitionCustomize, t)) .remove(); } _updateLineAreaSelections(sel, stage, lineDatum, lineIndex, lineNodes) { const selectionFnName = AREA + upperFirst(stage) + 'SelectionCustomize'; const transitionFnName = AREA + upperFirst(stage) + 'TransitionCustomize'; sel.attr('class', (d) => this._buildCss( ['monte-area', lineDatum.css, this.opts.lineCssScaleAccessor, this.opts.areaCss, this.opts.areaCssScaleAccessor, d.css], lineDatum, lineIndex)) .call((sel) => this.fnInvoke(this.opts[selectionFnName], sel)) .transition() .call(this._transitionSetup(AREA, stage), lineDatum, lineIndex, lineNodes) .attr('d', (d) => this.area(this.getProp('values', d))) .style('fill', this.optionReaderFunc('areaFillScaleAccessor')) .call((t) => this.fnInvoke(this.opts[transitionFnName], t)); } }