UNPKG

d3-visualize

Version:

d3-view components for data visualization

148 lines (124 loc) 4.61 kB
import {map} from 'd3-collection'; import {range} from 'd3-array'; import {color} from 'd3-color'; import {isObject, isFunction, isArray} from 'd3-let'; import globalOptions from '../core/options'; import {vizPrototype} from '../core/chart'; export const colorScales = map(); globalOptions.color = { scale: 'cool', // Minumim number of colors in a sequantial color scale // This helps in keeping a consistent palette when few colors are used scaleMinPoints: 6, // An offset in the color scale, useful for combined visuals scaleOffset: 0, stroke: '#333', strokeOpacity: 1, fillOpacity: 1, }; colorScales.set('viridis', (d3) => d3.scaleSequential(d3.interpolateViridis)); colorScales.set('inferno', (d3) => d3.scaleSequential(d3.interpolateInferno)); colorScales.set('magma', (d3) => d3.scaleSequential(d3.interpolateMagma)); colorScales.set('plasma', (d3) => d3.scaleSequential(d3.interpolatePlasma)); colorScales.set('warm', (d3) => d3.scaleSequential(d3.interpolateWarm)); colorScales.set('cool', (d3) => d3.scaleSequential(d3.interpolateCool)); colorScales.set('rainbow', (d3) => d3.scaleSequential(d3.interpolateRainbow)); colorScales.set('cubehelix', (d3) => d3.scaleSequential(d3.interpolateCubehelixDefault)); vizPrototype.getColorScale = function (name) { return colorScales.get(name)(this.$); }; // // Color scale method // ========================== vizPrototype.colors = function (n, opacity) { var model = this.getModel('color'); let reversed = false, scaleDef, scale; if (isArray(model.scale)) scale = this.getScale('ordinal').range(model.scale); else { scaleDef = this.getColorScale(model.scale); if (!scaleDef) throw new Error(`Unknown scale ${model.scale}`); if (!isObject(scaleDef)) scaleDef = {scale: scaleDef}; if (scaleDef.minPoints === undefined) scaleDef.minPoints = model.scaleMinPoints; scale = scaleDef.scale; reversed = scaleDef.reversed; } if (isFunction(scale.interpolator)) { var offset = model.scaleOffset, npoints = n + offset, points = Math.max(npoints, scaleDef.minPoints), domain = reversed ? [points-1, 0] : [0, points-1]; scale.domain(domain); let c; return range(offset, Math.min(npoints, points)).map(v => { c = color(scale(v)); c.opacity = opacity; return c; }); } else { var colors = scale.range().slice(); if (reversed) colors.reverse(); let b, c, m; for (let i=0; i<model.scaleOffset; ++i) { colors.push(colors.shift()); } return range(n).map(() => { b = colors.shift(); c = color(b); m = color(b); c.opacity = opacity; colors.push(''+m.brighter(0.2)); return c; }); } }; vizPrototype.fill = function (data) { var model = this.getModel('color'), opacity = this.modelProperty('fillOpacity', model), colors = this.colors(data.length, opacity); function fill (d, idx) { return colors[idx]; } fill.colors = colors; return fill; }; vizPrototype.stroke = function (data) { var model = this.getModel('color'), opacity = this.modelProperty('strokeOpacity', model), colors = this.colors(data.length, opacity); function stroke (d, idx) { return colors[idx]; } stroke.colors = colors; return stroke; }; // // Linear Gradient method // ========================== // // Create a monocromatic linear gradient in the visualization box, // either horizontal or vertical vizPrototype.linearGradient = function (col, box, orientation, gid) { var paper = this.paper().sel, defs = paper.select('defs'); if (!defs.node()) defs = paper.append('defs'); const grad = defs.selectAll(`#${gid}`).data([0]), colto = color(col); colto.opacity = 0.1; grad.enter() .append('linearGradient') .attr('id', gid) .attr('x1', '0%') .attr('y1', '0%') .attr('x2', orientation === 'vertical' ? '0%' : '100%') .attr('y2', orientation === 'vertical' ? '100%' : '0%'); var stops = defs.select(`#${gid}`) .selectAll('stop') .data([{offset: '0%', color: col}, {offset: '100%', color: colto}]); stops.enter() .append('stop') .merge(stops) .attr('offset', d => d.offset) .attr('stop-color', d => d.color); return `url(#${gid})`; };