Comparing version 0.13.2 to 0.14.0
@@ -115,3 +115,3 @@ { | ||
"no-loop-func": 2, // functions in loops are difficult to reason about. | ||
"no-magic-numbers": [2, {"enforceConst": true, "ignore": [0,1,2]}], // what the number represents gets lost. | ||
"no-magic-numbers": 0, // what the number represents gets lost. | ||
"no-mixed-requires": 1, // group requires and seperate from other init for clearer code. | ||
@@ -166,3 +166,3 @@ "no-mixed-spaces-and-tabs": 2, // just spaces for consistency. | ||
"no-undefined": 2, // better to check typeof | ||
"no-underscore-dangle": 2, // should not rely on variable name to reason about scoping, as it may change. | ||
"no-underscore-dangle": 0, // should not rely on variable name to reason about scoping, as it may change. | ||
"no-unexpected-multiline": 2, // prevents issues related to semicolons. | ||
@@ -169,0 +169,0 @@ "no-unmodified-loop-condition": 2, // possible infinite loop; probably a mistake. |
{ | ||
"name": "mapd3", | ||
"version": "0.13.2", | ||
"version": "0.14.0", | ||
"description": "A fast chart library for the fastest DB", | ||
@@ -20,3 +20,5 @@ "main": "dist/mapd3.js", | ||
"dev": "webpack --env.dev --watch", | ||
"clean": "yarn cache clean && rm -rf node_modules" | ||
"clean": "yarn cache clean && rm -rf node_modules", | ||
"test": "mocha-webpack test/**/*.spec.js --require test/setup.js --webpack-config webpack.config-spec.js --watch", | ||
"format": "eslint \"src/**/*.js\" --fix" | ||
}, | ||
@@ -50,23 +52,30 @@ "repository": { | ||
"@babel/core": "^7.0.0-beta.36", | ||
"@babel/plugin-proposal-object-rest-spread": "^7.0.0-beta.41", | ||
"@babel/preset-env": "^7.0.0-beta.36", | ||
"babel-core": "^6.25.0", | ||
"babel-eslint": "^7.2.3", | ||
"babel-loader": "^8.0.0-beta.0", | ||
"babel-plugin-add-module-exports": "^0.2.1", | ||
"chai": "^4.1.2", | ||
"css-loader": "^0.28.7", | ||
"eslint": "^4.18.2", | ||
"extract-text-webpack-plugin": "^3.0.2", | ||
"ink-docstrap": "^1.3.0", | ||
"jsdoc": "^3.5.4", | ||
"jsdom": "^11.6.2", | ||
"json-loader": "^0.5.7", | ||
"mocha": "^5.0.5", | ||
"mocha-webpack": "^1.1.0", | ||
"node-sass": "^4.7.2", | ||
"null-loader": "^0.1.1", | ||
"requirejs-plugins": "^1.0.2", | ||
"sanitize-html": "^1.13.0", | ||
"sass-loader": "^6.0.6", | ||
"sinon": "^4.5.0", | ||
"text": "requirejs/text", | ||
"webpack": "^3.10.0", | ||
"webpack-bundle-analyzer": "^2.9.0", | ||
"webpack-dev-server": "^1.16.2", | ||
"webpack-livereload-plugin": "^0.9.0", | ||
"webpack-node-externals": "^1.6.0", | ||
"yargs": "^10.0.3" | ||
} | ||
} |
@@ -0,1 +1,2 @@ | ||
import * as d3 from "./charts/helpers/d3-service" | ||
import Chart from "./charts/chart.js" | ||
@@ -29,3 +30,4 @@ import Tooltip from "./charts/tooltip.js" | ||
Interactors, | ||
colors | ||
colors, | ||
d3 | ||
} |
import * as d3 from "./helpers/d3-service" | ||
import {override, getSizes} from "./helpers/common" | ||
import {override} from "./helpers/common" | ||
import {autoFormat, multiFormat, getExtractFormatter} from "./helpers/formatters" | ||
@@ -34,3 +34,8 @@ | ||
yDomain: "auto", | ||
y2Domain: "auto" | ||
y2Domain: "auto", | ||
labelsAreRotated: false, | ||
chartWidth: null, | ||
chartHeight: null, | ||
markPanelWidth: null | ||
} | ||
@@ -47,5 +52,7 @@ | ||
container: _container, | ||
root: null, | ||
xAxisRoot: null, | ||
yAxisRoot: null, | ||
y2AxisRoot: null, | ||
background: null, | ||
chartHeight: null, | ||
chartWidth: null, | ||
xAxis: null, | ||
@@ -60,20 +67,26 @@ yAxis: null, | ||
if (!cache.root) { | ||
cache.root = cache.container.append("g") | ||
.classed("axis-group", true) | ||
.style("pointer-events", "none") | ||
cache.root.append("g").attr("class", "grid-lines-group") | ||
cache.root.append("g").attr("class", "axis x") | ||
cache.root.append("g").attr("class", "axis y") | ||
cache.root.append("g").attr("class", "axis y2") | ||
cache.root = cache.container.select("svg.chart > g.chart-group") | ||
cache.xAxisRoot = cache.root.append("g") | ||
.classed("axis-group", true) | ||
.style("pointer-events", "none") | ||
cache.xAxisRoot.append("g").attr("class", "grid-lines-group") | ||
cache.xAxisRoot.append("g").attr("class", "axis x") | ||
cache.yAxisRoot = cache.container.select(".y-axis-container > svg") | ||
cache.y2AxisRoot = cache.container.select(".y2-axis-container > svg") | ||
cache.yAxisRoot.select(".axis-group").append("g").attr("class", "axis y") | ||
cache.y2AxisRoot.select(".axis-group").append("g").attr("class", "axis y2") | ||
} | ||
const {chartWidth, chartHeight} = getSizes(config, cache) | ||
cache.chartWidth = chartWidth | ||
cache.chartHeight = chartHeight | ||
const DOMAIN_LINE_WIDTH = 1 | ||
cache.yAxisRoot | ||
.attr("width", config.margin.left) | ||
.attr("height", config.chartHeight + config.margin.top + config.margin.bottom) | ||
.select(".axis-group") | ||
.attr("transform", `translate(${config.margin.left - DOMAIN_LINE_WIDTH}, ${config.margin.top})`) | ||
cache.root.attr("transform", `translate(${config.margin.left}, ${config.margin.top})`) | ||
cache.y2AxisRoot | ||
.attr("width", config.margin.left) | ||
.attr("height", config.chartHeight + config.margin.top + config.margin.bottom) | ||
.select(".axis-group") | ||
.attr("transform", `translate(0, ${config.margin.top})`) | ||
} | ||
@@ -90,3 +103,7 @@ | ||
} else if (config.keyType === "string") { | ||
cache.xAxis.tickValues(scales.xScale.domain().filter((d, i) => !(i % config.xTickSkip))) | ||
let xTickSkip = config.xTickSkip | ||
if (config.xTickSkip === "auto") { | ||
xTickSkip = getNumberOfLabelsToSkip() | ||
} | ||
cache.xAxis.tickValues(scales.xScale.domain().filter((d, i) => !(i % xTickSkip))) | ||
} else if (config.keyType === "number") { | ||
@@ -109,6 +126,8 @@ if (config.extractType) { | ||
const yExtent = config.yDomain === "auto" ? scales.yScale.domain() : config.yDomain | ||
let yFormat = autoFormat(yExtent, config.numberFormat) | ||
const yFormat = autoFormat(yExtent, config.numberFormat) | ||
axis.tickFormat(d3.format(yFormat)) | ||
} else if (typeof config.yAxisFormat === "string") { | ||
axis.tickFormat(d3.format(config.yAxisFormat)) | ||
} else if (Array.isArray(config.yAxisFormat)) { | ||
axis.tickFormat(d3.format(config.yAxisFormat[0])) | ||
} | ||
@@ -123,6 +142,8 @@ } | ||
const y2Extent = config.y2Domain === "auto" ? scales.y2Scale.domain() : config.y2Domain | ||
let y2Format = autoFormat(y2Extent, config.numberFormat) | ||
const y2Format = autoFormat(y2Extent, config.numberFormat) | ||
axis.tickFormat(d3.format(y2Format)) | ||
} else if (typeof config.y2AxisFormat === "string") { | ||
axis.tickFormat(d3.format(config.y2AxisFormat)) | ||
} else if (Array.isArray(config.y2AxisFormat)) { | ||
axis.tickFormat(d3.format(config.y2AxisFormat[0])) | ||
} | ||
@@ -133,5 +154,5 @@ } | ||
cache.xAxis = d3.axisBottom(scales.xScale) | ||
.tickSize(config.tickSizes, 0) | ||
.tickPadding(config.tickPadding) | ||
.tickSizeOuter(0) | ||
.tickSize(config.tickSizes, 0) | ||
.tickPadding(config.tickPadding) | ||
.tickSizeOuter(0) | ||
@@ -142,5 +163,5 @@ formatXAxis() | ||
cache.yAxis = d3.axisLeft(scales.yScale) | ||
.tickSize([config.tickSizes]) | ||
.tickPadding(config.tickPadding) | ||
.tickSizeOuter(0) | ||
.tickSize([config.tickSizes]) | ||
.tickPadding(config.tickPadding) | ||
.tickSizeOuter(0) | ||
@@ -152,3 +173,3 @@ formatYAxis(cache.yAxis) | ||
} else { | ||
cache.yAxis.ticks(Math.ceil(cache.chartHeight / config.tickSpacing)) | ||
cache.yAxis.ticks(Math.ceil(config.chartHeight / config.tickSpacing)) | ||
} | ||
@@ -159,5 +180,5 @@ } | ||
cache.y2Axis = d3.axisRight(scales.y2Scale) | ||
.tickSize([config.tickSizes]) | ||
.tickPadding(config.tickPadding) | ||
.tickSizeOuter(0) | ||
.tickSize([config.tickSizes]) | ||
.tickPadding(config.tickPadding) | ||
.tickSizeOuter(0) | ||
@@ -172,26 +193,53 @@ formatY2Axis(cache.y2Axis) | ||
function rotateXLabels () { | ||
cache.xAxisRoot.select(".axis.x").selectAll("text") | ||
.attr("y", 0) | ||
.attr("x", 9) | ||
.attr("dy", ".35em") | ||
.attr("transform", "rotate(90)") | ||
.style("text-anchor", "start") | ||
return this | ||
} | ||
function getNumberOfLabelsToSkip () { | ||
const APPROX_FONT_WIDTH = 5 | ||
const labels = scales.xScale.domain() | ||
let longestLabelApproxWidth = null | ||
if (config.labelsAreRotated) { | ||
longestLabelApproxWidth = APPROX_FONT_WIDTH | ||
} else { | ||
const longestLabel = labels.reduce((longest, d) => (d.length > longest.length ? d : longest), {length: 0}) | ||
longestLabelApproxWidth = longestLabel.length * APPROX_FONT_WIDTH | ||
} | ||
return Math.ceil(longestLabelApproxWidth / (config.markPanelWidth / labels.length)) | ||
} | ||
function drawAxis () { | ||
cache.root.select(".axis.x") | ||
.attr("transform", `translate(0, ${cache.chartHeight})`) | ||
.call(cache.xAxis) | ||
cache.xAxisRoot.select(".axis.x") | ||
.attr("transform", `translate(0, ${config.chartHeight})`) | ||
.call(cache.xAxis) | ||
if (config.labelsAreRotated) { | ||
rotateXLabels() | ||
} | ||
if (scales.yScale) { | ||
cache.root.select(".axis.y") | ||
.transition() | ||
.duration(config.axisTransitionDuration) | ||
.ease(config.ease) | ||
.call(cache.yAxis) | ||
cache.yAxisRoot.select(".axis.y") | ||
.transition() | ||
.duration(config.axisTransitionDuration) | ||
.ease(config.ease) | ||
.call(cache.yAxis) | ||
} else { | ||
cache.root.select(".axis.y").selectAll("*").remove() | ||
cache.yAxisRoot.select(".axis.y").selectAll("*").remove() | ||
} | ||
if (scales.y2Scale) { | ||
cache.root.select(".axis.y2") | ||
.attr("transform", `translate(${cache.chartWidth}, 0)`) | ||
.transition() | ||
.duration(config.axisTransitionDuration) | ||
.ease(config.ease) | ||
.call(cache.y2Axis) | ||
cache.y2AxisRoot.select(".axis.y2") | ||
.transition() | ||
.duration(config.axisTransitionDuration) | ||
.ease(config.ease) | ||
.call(cache.y2Axis) | ||
} else { | ||
cache.root.select(".axis.y2").selectAll("*").remove() | ||
cache.y2AxisRoot.select(".axis.y2").selectAll("*").remove() | ||
} | ||
@@ -208,9 +256,9 @@ | ||
} else { | ||
ticks = Math.ceil(cache.chartHeight / config.tickSpacing) | ||
ticks = Math.ceil(config.chartHeight / config.tickSpacing) | ||
} | ||
if (scales.yScale) { | ||
cache.horizontalGridLines = cache.root.select(".grid-lines-group") | ||
.selectAll("line.horizontal-grid-line") | ||
.data(scales.yScale.ticks(ticks)) | ||
cache.horizontalGridLines = cache.xAxisRoot.select(".grid-lines-group") | ||
.selectAll("line.horizontal-grid-line") | ||
.data(scales.yScale.ticks(ticks)) | ||
@@ -223,3 +271,3 @@ cache.horizontalGridLines.enter() | ||
.duration(config.axisTransitionDuration) | ||
.attr("x2", cache.chartWidth) | ||
.attr("x2", config.markPanelWidth) | ||
.attr("y1", scales.yScale) | ||
@@ -235,5 +283,5 @@ .attr("y2", scales.yScale) | ||
if (config.grid === "vertical" || config.grid === "full") { | ||
cache.verticalGridLines = cache.root.select(".grid-lines-group") | ||
.selectAll("line.vertical-grid-line") | ||
.data(cache.xAxis.tickValues()) | ||
cache.verticalGridLines = cache.xAxisRoot.select(".grid-lines-group") | ||
.selectAll("line.vertical-grid-line") | ||
.data(cache.xAxis.tickValues()) | ||
@@ -247,3 +295,3 @@ cache.verticalGridLines.enter() | ||
.attr("y1", 0) | ||
.attr("y2", cache.chartHeight) | ||
.attr("y2", config.chartHeight) | ||
.attr("x1", scales.xScale) | ||
@@ -276,6 +324,14 @@ .attr("x2", scales.xScale) | ||
function destroy () { | ||
if (cache.root) { | ||
cache.root.remove() | ||
cache.root = null | ||
if (cache.xAxisRoot) { | ||
cache.xAxisRoot.remove() | ||
cache.xAxisRoot = null | ||
} | ||
if (cache.yAxisRoot) { | ||
cache.yAxisRoot.remove() | ||
cache.yAxisRoot = null | ||
} | ||
if (cache.y2AxisRoot) { | ||
cache.y2AxisRoot.remove() | ||
cache.y2AxisRoot = null | ||
} | ||
} | ||
@@ -282,0 +338,0 @@ |
@@ -1,3 +0,3 @@ | ||
import {keys, MAX_MARK_WIDTH} from "./helpers/constants" | ||
import {override, getSizes} from "./helpers/common" | ||
import {keys} from "./helpers/constants" | ||
import {override} from "./helpers/common" | ||
@@ -11,3 +11,3 @@ export default function Bar (_container) { | ||
bottom: 40, | ||
left: 70 | ||
left: 0 | ||
}, | ||
@@ -18,3 +18,9 @@ width: 800, | ||
chartType: null, | ||
barSpacingPercent: 10 | ||
barSpacingPercent: 10, | ||
markWidth: null, | ||
chartWidth: null, | ||
chartHeight: null, | ||
markPanelWidth: null, | ||
selectedKeys: [] | ||
} | ||
@@ -32,5 +38,3 @@ | ||
container: _container, | ||
svg: null, | ||
chartHeight: null, | ||
chartWidth: null | ||
svg: null | ||
} | ||
@@ -46,18 +50,27 @@ | ||
const MIN_BAR_HEIGHT = 1 | ||
const DIMMED_COLOR = "silver" | ||
const getColor = (d) => scales.colorScale(d[keys.ID]) | ||
const getColor = (d) => { | ||
const key = d.data && d.data.key | ||
if (key && Array.isArray(config.selectedKeys) && config.selectedKeys.length) { | ||
if (config.selectedKeys.indexOf(key) > -1) { | ||
return scales.colorScale(d.id) | ||
} else { | ||
return DIMMED_COLOR | ||
} | ||
} else { | ||
return scales.colorScale(d.id) | ||
} | ||
} | ||
function build () { | ||
if (!cache.root) { | ||
cache.root = cache.container.append("g") | ||
.classed("mark-group", true) | ||
.classed("mark-group", true) | ||
} | ||
const {chartWidth, chartHeight} = getSizes(config, cache) | ||
cache.chartWidth = chartWidth | ||
cache.chartHeight = chartHeight | ||
} | ||
function drawBars () { | ||
const stack = data.stack(data.stackData) | ||
const markCount = data.dataByKey && data.dataByKey.length || 1 | ||
@@ -67,10 +80,8 @@ let barData = [] | ||
barData = data.dataBySeries.filter((d, i) => config.chartType[i] === "bar") | ||
} else if(config.chartType === "bar" || config.chartType === "groupedBar") { | ||
} else if (config.chartType === "bar" || config.chartType === "groupedBar") { | ||
barData = data.dataBySeries | ||
} | ||
const groupCount = stack[0].length | ||
const groupMemberCount = barData.length | ||
const groupW = groupCount ? (cache.chartWidth / groupCount) : 0 | ||
const barW = Math.min(groupW, MAX_MARK_WIDTH) | ||
const groupW = markCount ? (config.markPanelWidth / markCount) : 0 | ||
const gutterW = groupW / 100 * config.barSpacingPercent | ||
@@ -80,3 +91,3 @@ const groupedBarW = groupMemberCount ? ((groupW - gutterW) / groupMemberCount) : 0 | ||
const barLayer = cache.root.selectAll(".bar-layer") | ||
.data(barData) | ||
.data(barData) | ||
@@ -91,12 +102,12 @@ const barLayerUpdate = barLayer.enter() | ||
const bars = barLayerUpdate.selectAll(".mark") | ||
.data((d, i) => { | ||
const datum = d.values.map(dB => { | ||
const dBClone = Object.assign({}, dB) | ||
dBClone.id = d[keys.ID] | ||
dBClone.group = d[keys.GROUP] | ||
dBClone.index = i | ||
return dBClone | ||
}) | ||
return datum | ||
.data((d, i) => { | ||
const datum = d.values.map(dB => { | ||
const dBClone = Object.assign({}, dB) | ||
dBClone.id = d[keys.ID] | ||
dBClone.group = d[keys.GROUP] | ||
dBClone.index = i | ||
return dBClone | ||
}) | ||
return datum | ||
}) | ||
@@ -106,5 +117,5 @@ bars.enter() | ||
.attr("class", "mark bar") | ||
.attr('clip-path', `url(#mark-clip-${config.chartId})`) | ||
.attr("clip-path", `url(#mark-clip-${config.chartId})`) | ||
.merge(bars) | ||
.attr("x", (d, i) => { | ||
.attr("x", (d) => { | ||
if (config.chartType === "groupedBar" || barData.length > 1) { | ||
@@ -114,3 +125,3 @@ const x = scales.xScale(d[keys.KEY]) - groupW / 2 + groupedBarW * d.index + gutterW / 2 | ||
} else { | ||
return Math.max(scales.xScale(d[keys.KEY]) - barW / 2, 0) | ||
return Math.max(scales.xScale(d[keys.KEY]) - config.markWidth / 2, 0) | ||
} | ||
@@ -120,5 +131,5 @@ }) | ||
if (d[keys.GROUP] === 0) { | ||
return Math.min(scales.yScale(d[keys.VALUE]), cache.chartHeight - MIN_BAR_HEIGHT) | ||
return Math.min(scales.yScale(d[keys.VALUE]), config.chartHeight - MIN_BAR_HEIGHT) | ||
} else { | ||
return Math.min(scales.y2Scale(d[keys.VALUE]), cache.chartHeight - MIN_BAR_HEIGHT) | ||
return Math.min(scales.y2Scale(d[keys.VALUE]), config.chartHeight - MIN_BAR_HEIGHT) | ||
} | ||
@@ -130,3 +141,3 @@ }) | ||
} else { | ||
return barW | ||
return config.markWidth | ||
} | ||
@@ -136,5 +147,5 @@ }) | ||
if (d[keys.GROUP] === 0) { | ||
return Math.max(cache.chartHeight - scales.yScale(d[keys.VALUE]), MIN_BAR_HEIGHT) | ||
return Math.max(config.chartHeight - scales.yScale(d[keys.VALUE]), MIN_BAR_HEIGHT) | ||
} else { | ||
return Math.max(cache.chartHeight - scales.y2Scale(d[keys.VALUE]), MIN_BAR_HEIGHT) | ||
return Math.max(config.chartHeight - scales.y2Scale(d[keys.VALUE]), MIN_BAR_HEIGHT) | ||
} | ||
@@ -150,7 +161,6 @@ }) | ||
const stack = data.stack(data.stackData) | ||
const barW = Math.min(cache.chartWidth / stack[0].length, MAX_MARK_WIDTH) | ||
const gutterW = barW / 100 * config.barSpacingPercent | ||
const gutterW = config.markWidth / 100 * config.barSpacingPercent | ||
const stackedBarGroups = cache.root.selectAll(".bar-group") | ||
.data(stack) | ||
.data(stack) | ||
@@ -161,3 +171,2 @@ const stackedUpdate = stackedBarGroups.enter() | ||
.merge(stackedBarGroups) | ||
.attr("fill", (d) => scales.colorScale(d.key)) | ||
.attr("stroke", "white") | ||
@@ -168,3 +177,7 @@ | ||
const stackedBars = stackedUpdate.selectAll(".mark") | ||
.data((d) => d) | ||
.data((d, i, p) => { | ||
// add the id to individual datum to use for choosing color | ||
const datum = d.map(dB => ({...dB, id: p[i].__data__.key})) | ||
return datum | ||
}) | ||
@@ -174,8 +187,9 @@ stackedBars.enter() | ||
.attr("class", "mark bar") | ||
.attr('clip-path', `url(#mark-clip-${config.chartId})`) | ||
.attr("clip-path", `url(#mark-clip-${config.chartId})`) | ||
.merge(stackedBars) | ||
.attr("x", (d) => scales.xScale(d.data[keys.KEY])- barW / 2 + gutterW / 2) | ||
.attr("y", (d) => scales.yScale(d[1]) ) | ||
.attr("x", (d) => scales.xScale(d.data[keys.KEY]) - config.markWidth / 2 + gutterW / 2) | ||
.attr("y", (d) => scales.yScale(d[1])) | ||
.attr("height", (d) => Math.max(scales.yScale(d[0]) - scales.yScale(d[1]), MIN_BAR_HEIGHT)) | ||
.attr("width", barW - gutterW) | ||
.attr("width", config.markWidth - gutterW) | ||
.attr("fill", getColor) | ||
@@ -182,0 +196,0 @@ stackedBars.exit().remove() |
@@ -37,19 +37,19 @@ import * as d3 from "./helpers/d3-service" | ||
cache.root = cache.container.append("div") | ||
.attr("class", "binning-group") | ||
.style("float", "left") | ||
.style("padding-top", "12px") | ||
.style("padding-left", "12px") | ||
.attr("class", "binning-group") | ||
.style("float", "left") | ||
.style("padding-top", "12px") | ||
.style("padding-left", "12px") | ||
cache.label = cache.root.append("div") | ||
.attr("class", "bin-label") | ||
.text(config.label) | ||
.attr("class", "bin-label") | ||
.text(config.label) | ||
cache.autoItem = cache.root.append("div") | ||
.attr("class", "item item-auto toggleOnOff") | ||
.on("click.select", function click () { | ||
const isSelected = this.classList.contains("selected") | ||
const toggled = !isSelected | ||
dispatcher.call("change", this, {name: config.autoLabel, isSelected: toggled}) | ||
}) | ||
.text(config.autoLabel) | ||
.attr("class", "item item-auto toggleOnOff") | ||
.on("click.select", function click () { | ||
const isSelected = this.classList.contains("selected") | ||
const toggled = !isSelected | ||
dispatcher.call("change", this, {name: config.autoLabel, isSelected: toggled}) | ||
}) | ||
.text(config.autoLabel) | ||
} | ||
@@ -70,12 +70,12 @@ | ||
cache.binningItems = cache.root.selectAll(".toggleExclusive") | ||
.data(_binningToggles) | ||
.data(_binningToggles) | ||
cache.binningItems.enter().append("div") | ||
.attr("class", (d) => `item item-${d} toggleExclusive`) | ||
.on("click.select", function click (d) { | ||
const isSelected = this.classList.contains("selected") | ||
dispatcher.call("change", this, {name: d, isSelected}) | ||
}) | ||
.merge(cache.binningItems) | ||
.text((d) => d) | ||
.on("click.select", function click (d) { | ||
const isSelected = this.classList.contains("selected") | ||
dispatcher.call("change", this, {name: d, isSelected}) | ||
}) | ||
.merge(cache.binningItems) | ||
.attr("class", (d) => `item item-${d} toggleExclusive`) | ||
.text((d) => d) | ||
@@ -82,0 +82,0 @@ cache.binningItems.exit().remove() |
import * as d3 from "./helpers/d3-service" | ||
import {override, stringToType, getSizes, extendIsValid} from "./helpers/common" | ||
import {override, stringToType, extendIsValid} from "./helpers/common" | ||
import {blurOnEnter} from "./interactors" | ||
@@ -9,10 +9,2 @@ | ||
let config = { | ||
margin: { | ||
top: 60, | ||
right: 30, | ||
bottom: 40, | ||
left: 70 | ||
}, | ||
width: 800, | ||
height: 500, | ||
keyType: "time", | ||
@@ -30,5 +22,3 @@ dateFormat: "%b %d, %Y", | ||
inputMin: null, | ||
inputMax: null, | ||
chartWidth: null, | ||
chartHeight: null | ||
inputMax: null | ||
} | ||
@@ -44,3 +34,3 @@ | ||
function handleFocus (selection) { | ||
return function() { | ||
return () => { | ||
let text = selection.text() | ||
@@ -58,6 +48,6 @@ const parsed = d3.timeParse(config.dateFormat)(text) | ||
cache.root = cache.container | ||
.append("div") | ||
.attr("class", "brush-range-input-group") | ||
.style("top", 0) | ||
.style("padding-top", "12px") | ||
.append("div") | ||
.attr("class", "brush-range-input-group") | ||
.style("top", 0) | ||
.style("padding-top", "12px") | ||
@@ -84,3 +74,3 @@ cache.inputMax = cache.root.append("div") | ||
this, | ||
{ extent: [rangeMin, cache.rangeMax] } | ||
{extent: [rangeMin, cache.rangeMax]} | ||
) | ||
@@ -123,3 +113,3 @@ } else { | ||
this, | ||
{ extent: [cache.rangeMin, rangeMax] } | ||
{extent: [cache.rangeMin, rangeMax]} | ||
) | ||
@@ -138,6 +128,2 @@ } else { | ||
const {chartWidth, chartHeight} = getSizes(config, cache) | ||
cache.chartWidth = chartWidth | ||
cache.chartHeight = chartHeight | ||
const domain = scales.xScale.domain() | ||
@@ -144,0 +130,0 @@ |
import * as d3 from "./helpers/d3-service" | ||
import {invertScale, override, getSizes, extendIsValid} from "./helpers/common" | ||
import {clamp, invertScale, override, extendIsValid} from "./helpers/common" | ||
@@ -18,3 +18,6 @@ export default function Brush (_container) { | ||
brushRangeMax: null, | ||
brushIsEnabled: true | ||
brushIsEnabled: true, | ||
markPanelWidth: null, | ||
chartHeight: null | ||
} | ||
@@ -31,5 +34,3 @@ | ||
chartBrush: null, | ||
handle: null, | ||
chartWidth: null, | ||
chartHeight: null | ||
handle: null | ||
} | ||
@@ -47,3 +48,3 @@ | ||
cache.root = cache.container.append("g") | ||
.classed("brush-group", true) | ||
.classed("brush-group", true) | ||
@@ -55,10 +56,6 @@ cache.brush = d3.brushX() | ||
} | ||
const {chartWidth, chartHeight} = getSizes(config, cache) | ||
cache.chartWidth = chartWidth | ||
cache.chartHeight = chartHeight | ||
} | ||
function buildBrush () { | ||
cache.brush.extent([[0, 0], [cache.chartWidth, cache.chartHeight]]) | ||
cache.brush.extent([[0, 0], [config.markPanelWidth, config.chartHeight]]) | ||
@@ -68,3 +65,3 @@ cache.chartBrush = cache.root.call(cache.brush) | ||
cache.chartBrush.selectAll(".brush-rect") | ||
.attr("height", cache.chartHeight) | ||
.attr("height", config.chartHeight) | ||
@@ -80,6 +77,2 @@ moveBrush() | ||
function clamp (value, _dataExtent) { | ||
return Math.min(Math.max(_dataExtent[0], value), _dataExtent[1]) | ||
} | ||
function clampBrush (_dataExtent) { | ||
@@ -86,0 +79,0 @@ if (config.keyType === "time") { |
@@ -10,5 +10,5 @@ import * as d3 from "./helpers/d3-service" | ||
rebind, | ||
getSizes, | ||
uniqueId | ||
} from "./helpers/common" | ||
import {autoConfigure} from "./helpers/auto-config" | ||
@@ -30,5 +30,6 @@ import Scale from "./scale" | ||
export default function Chart (_container) { | ||
let config = { | ||
let inputConfig = { | ||
// common | ||
@@ -48,2 +49,3 @@ margin: { | ||
ease: d3.easeLinear, | ||
useScrolling: false, | ||
@@ -66,2 +68,3 @@ // intro animation | ||
y2AxisFormat: ".2f", | ||
tooltipFormat: ".2f", | ||
tickSizes: 8, | ||
@@ -73,3 +76,7 @@ yTicks: "auto", | ||
axisTransitionDuration: 0, | ||
labelsAreRotated: false, | ||
// data | ||
sortBy: null, | ||
xTitle: "", | ||
@@ -128,3 +135,4 @@ yTitle: "", | ||
// bar | ||
barSpacingPercent: 10 | ||
barSpacingPercent: 10, | ||
selectedKeys: [] | ||
} | ||
@@ -159,3 +167,4 @@ | ||
stack: null, | ||
flatDataSorted: null | ||
flatDataSorted: null, | ||
allKeyTotals: null | ||
} | ||
@@ -165,29 +174,66 @@ | ||
let eventCollector = {} | ||
let config = null | ||
setConfig(inputConfig) // init with config = inputConfig | ||
// events | ||
const dispatcher = d3.dispatch("mouseOverPanel", "mouseOutPanel", "mouseMovePanel") | ||
const dispatcher = d3.dispatch("mouseOverPanel", "mouseOutPanel", "mouseMovePanel", "mouseClickPanel") | ||
const dataManager = DataManager() | ||
function build () { | ||
if (!cache.svg) { | ||
const template = `<div class="mapd3 mapd3-container"> | ||
const createTemplate = (chartType) => { | ||
const chartClassName = _chartType => { | ||
switch (chartType) { | ||
case "bar": | ||
case "stackedBar": | ||
return "bar" | ||
case "line": | ||
case "stackedArea": | ||
return "line" | ||
// TO DO: handle bar line combo chartType... | ||
case Array.isArray(_chartType): | ||
return "combo" | ||
default: | ||
return "" | ||
} | ||
} | ||
const className = chartClassName(chartType) | ||
return `<div class="mapd3 mapd3-container ${className}"> | ||
<div class="header-group"></div> | ||
<svg class="chart"> | ||
<g class="chart-group"></g> | ||
<g class="panel-group"> | ||
<rect class="panel-background"></rect> | ||
</g> | ||
<rect class="masking-rectangle"></rect> | ||
</svg> | ||
<div class="y-axis-container"> | ||
<svg> | ||
<g class="axis-group"></g> | ||
</svg> | ||
</div> | ||
<div class="svg-wrapper"> | ||
<svg class="chart ${className}"> | ||
<g class="chart-group"></g> | ||
<g class="panel-group"> | ||
<rect class="panel-background"></rect> | ||
</g> | ||
<rect class="masking-rectangle"></rect> | ||
</svg> | ||
</div> | ||
<div class="y2-axis-container"> | ||
<svg> | ||
<g class="axis-group"></g> | ||
</svg> | ||
</div> | ||
</div>` | ||
} | ||
function build () { | ||
if (!cache.root) { | ||
const base = d3.select(cache.container) | ||
.html(template) | ||
.html(createTemplate(config.chartType)) | ||
cache.container = base.select(".mapd3-container") | ||
.style("position", "relative") | ||
cache.root = base.select(".mapd3-container") | ||
.style("position", "relative") | ||
cache.svg = base.select("svg") | ||
cache.svgWrapper = base.select(".svg-wrapper") | ||
cache.svg = base.select("svg.chart") | ||
cache.headerGroup = base.select(".header-group") | ||
.style("position", "absolute") | ||
.style("position", "absolute") | ||
cache.panel = cache.svg.select(".panel-group") | ||
@@ -200,13 +246,13 @@ cache.chart = cache.svg.select(".chart-group") | ||
scale: Scale(), | ||
axis: Axis(cache.chart), | ||
axis: Axis(cache.root), | ||
line: Line(cache.panel), | ||
bar: Bar(cache.panel), | ||
tooltip: Tooltip(cache.container), | ||
legend: Legend(cache.container), | ||
tooltip: Tooltip(cache.root), | ||
legend: Legend(cache.root), | ||
brush: Brush(cache.panel), | ||
hover: Hover(cache.panel), | ||
binning: Binning(cache.headerGroup), | ||
domainEditor: DomainEditor(cache.container), | ||
domainEditor: DomainEditor(cache.root), | ||
brushRangeEditor: BrushRangeEditor(cache.headerGroup), | ||
label: Label(cache.container), | ||
label: Label(cache.root), | ||
clipPath: ClipPath(cache.svg) | ||
@@ -226,24 +272,21 @@ } | ||
const {width, height, chartWidth, chartHeight} = getSizes(config, cache) | ||
cache.width = width | ||
cache.height = height | ||
cache.chartWidth = chartWidth | ||
cache.chartHeight = chartHeight | ||
cache.svgWrapper | ||
.style("flex", `0 0 ${config.chartWidth}px`) | ||
.style("height", `${config.height}px`) | ||
cache.svg | ||
.attr("width", cache.width) | ||
.attr("height", cache.height) | ||
.style("flex", `0 0 ${config.markPanelWidth}px`) | ||
.style("height", `${config.chartHeight + config.margin.bottom}`) | ||
.attr("transform", `translate(0,${config.margin.top})`) | ||
cache.headerGroup | ||
.style("width", `${cache.chartWidth}px`) | ||
.style("width", `${config.chartWidth}px`) | ||
.style("left", `${config.margin.left}px`) | ||
cache.panel | ||
.attr("transform", `translate(${config.margin.left},${config.margin.top})`) | ||
.select(".panel-background") | ||
.attr("width", cache.chartWidth) | ||
.attr("height", cache.chartHeight) | ||
.style("width", `${config.markPanelWidth}px`) | ||
.style("height", `${config.chartHeight}px`) | ||
.attr("fill", "transparent") | ||
return this | ||
@@ -258,2 +301,6 @@ } | ||
components.clipPath | ||
.setConfig(config) | ||
.render() | ||
components.axis | ||
@@ -316,6 +363,2 @@ .setConfig(config) | ||
components.clipPath | ||
.setConfig(config) | ||
.render() | ||
triggerIntroAnimation() | ||
@@ -327,5 +370,8 @@ return this | ||
dataObject.data = cloneData(_data[keys.SERIES]) | ||
const cleanedData = dataManager.cleanData(_data, config.keyType) | ||
const cleanedData = dataManager.cleanData(_data, config.keyType, config.sortBy) | ||
Object.assign(dataObject, cleanedData) | ||
const autoConfig = autoConfigure(inputConfig, cache, dataObject) | ||
config = Object.assign({}, inputConfig, autoConfig) | ||
render() | ||
@@ -347,3 +393,3 @@ return this | ||
.attr("width", 0) | ||
.attr("x", cache.width - config.margin.right) | ||
.attr("x", config.width - config.margin.right) | ||
.on("end", () => cache.maskingRectangle.remove()) | ||
@@ -368,2 +414,3 @@ } | ||
const [mouseX, mouseY] = d3.mouse(cache.panel.node()) | ||
const [panelMouseX] = d3.mouse(cache.svgWrapper.node()) | ||
if (!dataObject.data) { return } | ||
@@ -375,9 +422,19 @@ const xPosition = mouseX | ||
const dataPointXPosition = scales.xScale(dataPoint[keys.KEY]) | ||
throttledDispatch("mouseMovePanel", null, dataPoint, dataPointXPosition, mouseY) | ||
throttledDispatch("mouseMovePanel", null, dataPoint, dataPointXPosition, mouseY, panelMouseX) | ||
} | ||
}) | ||
.on("click.dispatch", () => { | ||
const [mouseX] = d3.mouse(cache.panel.node()) | ||
if (!dataObject.data) { return } | ||
const xPosition = mouseX | ||
const dataPoint = dataManager.getNearestDataPoint(xPosition, dataObject, scales, config.keyType) | ||
if (dataPoint) { | ||
throttledDispatch("mouseClickPanel", null, dataPoint) | ||
} | ||
}) | ||
} | ||
function getEvents () { | ||
if (!cache.svg) { | ||
if (!cache.root) { | ||
render() | ||
@@ -394,3 +451,6 @@ } | ||
function setConfig (_config) { | ||
config = override(config, _config) | ||
inputConfig = override(inputConfig, _config) | ||
const autoConfig = autoConfigure(inputConfig, cache, dataObject) | ||
config = Object.assign({}, inputConfig, autoConfig) | ||
return this | ||
@@ -409,3 +469,3 @@ } | ||
function destroy () { | ||
cache.svg.on(".", null).remove() | ||
cache.root.on(".", null).remove() | ||
} | ||
@@ -412,0 +472,0 @@ |
@@ -1,3 +0,2 @@ | ||
import * as d3 from "./helpers/d3-service" | ||
import {override, getSizes} from "./helpers/common" | ||
import {override} from "./helpers/common" | ||
@@ -19,3 +18,6 @@ /** | ||
height: 500, | ||
chartId : null, | ||
chartId: null, | ||
markPanelWidth: null, | ||
chartHeight: null | ||
} | ||
@@ -25,5 +27,3 @@ | ||
container: _container, | ||
clipPath: null, | ||
chartWidth: null, | ||
chartHeight: null, | ||
clipPath: null | ||
} | ||
@@ -33,15 +33,11 @@ | ||
if (!cache.clipPath) { | ||
cache.clipPath = cache.container.append('defs') | ||
.append('clipPath') | ||
.attr('id', `mark-clip-${config.chartId}`) | ||
.append('rect') | ||
cache.clipPath = cache.container.append("defs") | ||
.append("clipPath") | ||
.attr("id", `mark-clip-${config.chartId}`) | ||
.append("rect") | ||
} | ||
const {chartWidth, chartHeight} = getSizes(config, cache) | ||
cache.chartWidth = chartWidth | ||
cache.chartHeight = chartHeight | ||
cache.clipPath | ||
.attr('width', cache.chartWidth) | ||
.attr('height', cache.chartHeight) | ||
.attr("width", config.markPanelWidth) | ||
.attr("height", config.chartHeight) | ||
} | ||
@@ -54,3 +50,3 @@ | ||
function render() { | ||
function render () { | ||
build() | ||
@@ -57,0 +53,0 @@ } |
import * as d3 from "./helpers/d3-service" | ||
import {keys} from "./helpers/constants" | ||
import {invertScale, sortData, cloneData, getUnique} from "./helpers/common" | ||
import {comparators, keys} from "./helpers/constants" | ||
import {ascendingComparator, descendingComparator, clamp, invertScale, sortData, cloneData, getUnique} from "./helpers/common" | ||
@@ -14,3 +14,4 @@ | ||
groupCount: 2, | ||
lineCount: 4 | ||
lineCount: 4, | ||
stringMinMaxLength: [4, 8] | ||
} | ||
@@ -29,15 +30,17 @@ const cache = { | ||
function generateRandomString (_length) { | ||
return Math.random().toString(36).replace(/[^a-z0-9]+/g, "").substr(0, _length || 5) | ||
let stringLength = _length | ||
if (!_length) { | ||
const range = config.stringMinMaxLength | ||
stringLength = Math.round(Math.random() * (range[1] - range[0])) + range[0] | ||
} | ||
return [...Array(stringLength)].map(() => String.fromCharCode(Math.round(Math.random() * 25) + 97)).join("") | ||
} | ||
function generateSeries (_dataKeys, _range, _allowNegative) { | ||
function generateSeries (_dataKeys, _range) { | ||
let value = d3.randomUniform(..._range)() | ||
const variabilityRatio = 50 | ||
const randomWalkStepSize = (_range[1] - _range[0]) / variabilityRatio | ||
const variabilityDivider = 10 | ||
const randomWalkStepSize = (_range[1] - _range[0]) / variabilityDivider | ||
const rnd = d3.randomNormal(0, 1) | ||
return _dataKeys.map((d) => { | ||
value = value + rnd() * randomWalkStepSize | ||
if (!_allowNegative && value < randomWalkStepSize) { | ||
value = value + randomWalkStepSize | ||
} | ||
value = clamp(value + rnd() * randomWalkStepSize, _range) | ||
return { | ||
@@ -82,3 +85,3 @@ value, | ||
function cleanData (_data, _keyType) { | ||
function cleanData (_data, _keyType, _sortBy) { | ||
const dataBySeries = cloneData(_data[keys.SERIES]) | ||
@@ -153,19 +156,43 @@ dataBySeries.forEach((serie) => { | ||
const stackData = dataByKey | ||
.map((d) => { | ||
const points = { | ||
key: d[keys.KEY] | ||
} | ||
d.series.forEach((dB) => { | ||
points[dB[keys.ID]] = dB[keys.VALUE] | ||
}) | ||
return points | ||
.map((d) => { | ||
const points = { | ||
key: d[keys.KEY] | ||
} | ||
d.series.forEach((dB) => { | ||
points[dB[keys.ID]] = dB[keys.VALUE] | ||
}) | ||
return points | ||
}) | ||
// d3 stack | ||
const stack = d3.stack() | ||
.keys(dataBySeries.map(getID)) | ||
.order(d3.stackOrderNone) | ||
.offset(d3.stackOffsetNone) | ||
.keys(dataBySeries.map(getID)) | ||
.order(d3.stackOrderNone) | ||
.offset(d3.stackOffsetNone) | ||
return {dataBySeries, dataByKey, stack, stackData, flatDataSorted, groupKeys} | ||
// get stack totals | ||
const allKeyTotals = dataByKey.map(d => ({ | ||
key: d[keys.KEY], | ||
total: d3.sum(d[keys.SERIES].map(dB => dB[keys.VALUE])) | ||
})) | ||
// sort | ||
switch (_sortBy) { | ||
case comparators.TOTAL_ASCENDING: | ||
allKeyTotals.sort(ascendingComparator("total")) | ||
break | ||
case comparators.TOTAL_DESCENDING: | ||
allKeyTotals.sort(descendingComparator("total")) | ||
break | ||
case comparators.ALPHA_ASCENDING: | ||
allKeyTotals.sort(ascendingComparator("key")) | ||
break | ||
case comparators.ALPHA_DESCENDING: | ||
allKeyTotals.sort(descendingComparator("key")) | ||
break | ||
default: | ||
break | ||
} | ||
return {dataBySeries, dataByKey, stack, stackData, flatDataSorted, groupKeys, allKeyTotals} | ||
} | ||
@@ -172,0 +199,0 @@ |
import * as d3 from "./helpers/d3-service" | ||
import {override, stringToType, getSizes} from "./helpers/common" | ||
import {override, stringToType} from "./helpers/common" | ||
import {blurOnEnter} from "./interactors" | ||
@@ -28,3 +28,6 @@ | ||
yDomainEditorIsEnabled: true, | ||
y2DomainEditorIsEnabled: true | ||
y2DomainEditorIsEnabled: true, | ||
chartWidth: null, | ||
chartHeight: null | ||
} | ||
@@ -46,5 +49,3 @@ | ||
xMaxInput: null, | ||
xLockIcon: null, | ||
chartWidth: null, | ||
chartHeight: null | ||
xLockIcon: null | ||
} | ||
@@ -91,28 +92,28 @@ | ||
cache.root = cache.container | ||
.append("div") | ||
.attr("class", "domain-input-group") | ||
.style("position", "absolute") | ||
.style("top", 0) | ||
.append("div") | ||
.attr("class", "domain-input-group") | ||
.style("position", "absolute") | ||
.style("top", 0) | ||
// hit zones | ||
cache.xHitZone = cache.root.append("div") | ||
.attr("class", "hit-zone x") | ||
.style("pointer-events", "all") | ||
.style("position", "absolute") | ||
.on("mouseover.dispatch", showXEditor) | ||
.on("mouseout.dispatch", hideXEditor) | ||
.attr("class", "hit-zone x") | ||
.style("pointer-events", "all") | ||
.style("position", "absolute") | ||
.on("mouseover.dispatch", showXEditor) | ||
.on("mouseout.dispatch", hideXEditor) | ||
cache.yHitZone = cache.root.append("div") | ||
.attr("class", "hit-zone y") | ||
.style("pointer-events", "all") | ||
.style("position", "absolute") | ||
.on("mouseover.dispatch", showYEditor) | ||
.on("mouseout.dispatch", hideYEditor) | ||
.attr("class", "hit-zone y") | ||
.style("pointer-events", "all") | ||
.style("position", "absolute") | ||
.on("mouseover.dispatch", showYEditor) | ||
.on("mouseout.dispatch", hideYEditor) | ||
cache.y2HitZone = cache.root.append("div") | ||
.attr("class", "hit-zone y2") | ||
.style("pointer-events", "all") | ||
.style("position", "absolute") | ||
.on("mouseover.dispatch", showY2Editor) | ||
.on("mouseout.dispatch", hideY2Editor) | ||
.attr("class", "hit-zone y2") | ||
.style("pointer-events", "all") | ||
.style("position", "absolute") | ||
.on("mouseover.dispatch", showY2Editor) | ||
.on("mouseout.dispatch", hideY2Editor) | ||
@@ -273,12 +274,8 @@ // y input group | ||
const {chartWidth, chartHeight} = getSizes(config, cache) | ||
cache.chartWidth = chartWidth | ||
cache.chartHeight = chartHeight | ||
if (config.xDomainEditorIsEnabled) { | ||
cache.xHitZone.style("display", "block") | ||
cache.xHitZone | ||
.style("width", `${cache.chartWidth + LOCK_SIZE}px`) | ||
.style("width", `${config.chartWidth + LOCK_SIZE}px`) | ||
.style("height", `${HOVER_ZONE_SIZE}px`) | ||
.style("top", `${config.margin.top + cache.chartHeight}px`) | ||
.style("top", `${config.margin.top + config.chartHeight}px`) | ||
.style("left", `${config.margin.left}px`) | ||
@@ -288,5 +285,5 @@ .style("display", "block") | ||
cache.xMinInput | ||
.style("top", `${PADDING}px`) | ||
.style("left", "0px") | ||
.text(xFormatter(xDomain[0])) | ||
.style("top", `${PADDING}px`) | ||
.style("left", "0px") | ||
.text(xFormatter(xDomain[0])) | ||
@@ -311,3 +308,3 @@ cache.xMaxInput | ||
.style("width", `${HOVER_ZONE_SIZE}px`) | ||
.style("height", `${cache.chartHeight + LOCK_SIZE}px`) | ||
.style("height", `${config.chartHeight + LOCK_SIZE}px`) | ||
.style("top", `${config.margin.top - LOCK_SIZE}px`) | ||
@@ -323,3 +320,3 @@ .style("left", `${config.margin.left - HOVER_ZONE_SIZE}px`) | ||
cache.yMinInput | ||
.style("top", `${cache.chartHeight + LOCK_SIZE - INPUT_HEIGHT}px`) | ||
.style("top", `${config.chartHeight + LOCK_SIZE - INPUT_HEIGHT}px`) | ||
.style("right", "0px") | ||
@@ -342,5 +339,5 @@ .text(yFormatter(yDomain[0])) | ||
.style("width", `${HOVER_ZONE_SIZE}px`) | ||
.style("height", `${cache.chartHeight + LOCK_SIZE}px`) | ||
.style("height", `${config.chartHeight + LOCK_SIZE}px`) | ||
.style("top", `${config.margin.top - LOCK_SIZE}px`) | ||
.style("left", `${config.margin.left + cache.chartWidth}px`) | ||
.style("left", `${config.margin.left + config.chartWidth}px`) | ||
@@ -353,3 +350,3 @@ cache.y2MaxInput | ||
cache.y2MinInput | ||
.style("top", `${cache.chartHeight + LOCK_SIZE - INPUT_HEIGHT}px`) | ||
.style("top", `${config.chartHeight + LOCK_SIZE - INPUT_HEIGHT}px`) | ||
.style("left", `${PADDING}px`) | ||
@@ -356,0 +353,0 @@ .text(y2Formatter(y2Domain[0])) |
@@ -30,10 +30,10 @@ import {keys} from "./constants" | ||
const obj = {} | ||
arr.forEach(d =>{ | ||
arr.forEach(d => { | ||
obj[d] = null | ||
}) | ||
const keys = Object.keys(obj) | ||
const allKeys = Object.keys(obj) | ||
if (_keyType === "time") { | ||
return keys.map(d => new Date(d)) | ||
return allKeys.map(d => new Date(d)) | ||
} else { | ||
return keys | ||
return allKeys | ||
} | ||
@@ -90,26 +90,7 @@ } | ||
} | ||
console.log("stringToType", str, type, converted) | ||
return converted | ||
} | ||
export function getSizes (config, cache) { | ||
const width = config.width === "auto" | ||
? (cache.container && cache.container.clientWidth || 0) | ||
: config.width | ||
const height = config.height === "auto" | ||
? (cache.container && cache.container.clientHeight || 0) | ||
: config.height | ||
const chartWidth = Math.max(width - config.margin.left - config.margin.right, 0) | ||
const chartHeight = Math.max(height - config.margin.top - config.margin.bottom, 0) | ||
return { | ||
width, | ||
height, | ||
chartWidth, | ||
chartHeight | ||
} | ||
} | ||
export function isNumeric (val) { | ||
return Number(parseFloat(val)) === val; | ||
return Number(parseFloat(val)) === val | ||
} | ||
@@ -123,3 +104,3 @@ | ||
&& d !== null | ||
).length == 2 | ||
).length === 2 | ||
} | ||
@@ -130,1 +111,36 @@ | ||
} | ||
export function ascendingComparator (key) { | ||
return (a, b) => { | ||
if (a[key] < b[key]) { | ||
return -1 | ||
} | ||
if (a[key] > b[key]) { | ||
return 1 | ||
} | ||
return 0 | ||
} | ||
} | ||
export function descendingComparator (key) { | ||
return (a, b) => { | ||
if (b[key] < a[key]) { | ||
return -1 | ||
} | ||
if (b[key] > a[key]) { | ||
return 1 | ||
} | ||
return 0 | ||
} | ||
} | ||
export function clamp (value, clampMinMax) { | ||
return Math.min(Math.max(clampMinMax[0], value), clampMinMax[1]) | ||
} | ||
export function hasBars (_chartType) { | ||
return _chartType === "bar" | ||
|| _chartType === "stackedBar" | ||
|| _chartType === "groupedBar" | ||
|| (Array.isArray(_chartType) && _chartType.filter(d => d === "bar").length > 0) | ||
} |
@@ -20,2 +20,10 @@ export const keys = { | ||
export const MIN_MARK_WIDTH = 20 | ||
export const MAX_MARK_WIDTH = 200 | ||
export const comparators = { | ||
TOTAL_ASCENDING: "totalAscending", | ||
TOTAL_DESCENDING: "totalDescending", | ||
ALPHA_ASCENDING: "alphaAscending", | ||
ALPHA_DESCENDING: "alphaDescending" | ||
} |
export { | ||
axisBottom, | ||
axisLeft, | ||
axisRight, | ||
timeParse, | ||
timeFormat, | ||
utcFormat, | ||
format, | ||
bisector, | ||
extent, | ||
sum, | ||
range, | ||
merge, | ||
nest, | ||
dispatch, | ||
easeLinear, | ||
easeQuadInOut, | ||
select, | ||
mouse, | ||
event, | ||
transition, | ||
randomUniform, | ||
randomNormal, | ||
timeDay, | ||
timeMonth, | ||
timeSecond, | ||
timeMinute, | ||
timeHour, | ||
timeWeek, | ||
timeYear, | ||
utcYear, | ||
utcDay, | ||
area, | ||
curveCatmullRom, | ||
line, | ||
stack, | ||
stackOffsetNone, | ||
stackOrderNone, | ||
scaleTime, | ||
scalePoint, | ||
scaleBand, | ||
scaleLinear, | ||
scaleOrdinal, | ||
symbol, | ||
symbolTriangle, | ||
brushX | ||
axisBottom, | ||
axisLeft, | ||
axisRight, | ||
timeParse, | ||
timeFormat, | ||
utcFormat, | ||
format, | ||
formatPrefix, | ||
bisector, | ||
extent, | ||
sum, | ||
range, | ||
merge, | ||
nest, | ||
dispatch, | ||
easeLinear, | ||
easeQuadInOut, | ||
select, | ||
mouse, | ||
event, | ||
transition, | ||
randomUniform, | ||
randomNormal, | ||
timeDay, | ||
timeMonth, | ||
timeSecond, | ||
timeMinute, | ||
timeHour, | ||
timeWeek, | ||
timeYear, | ||
utcYear, | ||
utcDay, | ||
area, | ||
curveCatmullRom, | ||
line, | ||
stack, | ||
stackOffsetNone, | ||
stackOrderNone, | ||
scaleTime, | ||
scalePoint, | ||
scaleBand, | ||
scaleLinear, | ||
scaleOrdinal, | ||
symbol, | ||
symbolTriangle, | ||
brushX | ||
} from "d3/build/d3" |
@@ -76,10 +76,10 @@ import * as d3 from "./d3-service" | ||
// slightly modified version of d3's default time-formatting to always use abbrev month names | ||
const formatMillisecond = d3.timeFormat(".%L"); | ||
const formatSecond = d3.timeFormat(":%S"); | ||
const formatMinute = d3.timeFormat("%I:%M"); | ||
const formatHour = d3.timeFormat("%I %p"); | ||
const formatDay = d3.timeFormat("%a %d"); | ||
const formatWeek = d3.timeFormat("%b %d"); | ||
const formatMonth = d3.timeFormat("%b"); | ||
const formatYear = d3.timeFormat("%Y"); | ||
const formatMillisecond = d3.timeFormat(".%L") | ||
const formatSecond = d3.timeFormat(":%S") | ||
const formatMinute = d3.timeFormat("%I:%M") | ||
const formatHour = d3.timeFormat("%I %p") | ||
const formatDay = d3.timeFormat("%a %d") | ||
const formatWeek = d3.timeFormat("%b %d") | ||
const formatMonth = d3.timeFormat("%b") | ||
const formatYear = d3.timeFormat("%Y") | ||
@@ -91,10 +91,12 @@ /** | ||
*/ | ||
export function multiFormat(date) { | ||
export function multiFormat (date) { | ||
/* eslint-disable no-nested-ternary */ | ||
return (d3.timeSecond(date) < date ? formatMillisecond | ||
: d3.timeMinute(date) < date ? formatSecond | ||
: d3.timeMinute(date) < date ? formatSecond | ||
: d3.timeHour(date) < date ? formatMinute | ||
: d3.timeDay(date) < date ? formatHour | ||
: d3.timeMonth(date) < date ? (d3.timeWeek(date) < date ? formatDay : formatWeek) | ||
: d3.timeYear(date) < date ? formatMonth | ||
: formatYear)(date); | ||
: d3.timeDay(date) < date ? formatHour | ||
: d3.timeMonth(date) < date ? (d3.timeWeek(date) < date ? formatDay : formatWeek) | ||
: d3.timeYear(date) < date ? formatMonth | ||
: formatYear)(date) | ||
/* eslint-enable no-nested-ternary */ | ||
} | ||
@@ -105,16 +107,16 @@ | ||
*/ | ||
export function formatOddDateBin(specifier, value) { | ||
export function formatOddDateBin (specifier, value) { | ||
switch (specifier) { | ||
// reproducing the old line chart behavior, even if it's wrong | ||
case "1w": | ||
return `${d3.utcFormat("%b %d")(value)} - ${d3.utcFormat("%b %d,")(d3.utcDay.offset(value, 6))}` | ||
case "1c": | ||
return `${d3.utcFormat("%Y")(value)} - ${d3.utcFormat("%Y")(d3.utcYear.offset(value, 99))}` | ||
case "10y": | ||
return `${d3.utcFormat("%Y")(value)} - ${d3.utcFormat("%Y")(d3.utcYear.offset(value, 9))}` | ||
case "1q": | ||
const monthNumber = d3.utcFormat('%m')(value) // convert to integer month (01 - 12) | ||
return `Q${Math.floor((parseInt(monthNumber, 10) + 3) / 3)} ${d3.utcFormat('%Y')(value)}`; | ||
default: | ||
return | ||
// reproducing the old line chart behavior, even if it's wrong | ||
case "1w": | ||
return `${d3.utcFormat("%b %d")(value)} - ${d3.utcFormat("%b %d,")(d3.utcDay.offset(value, 6))}` | ||
case "1c": | ||
return `${d3.utcFormat("%Y")(value)} - ${d3.utcFormat("%Y")(d3.utcYear.offset(value, 99))}` | ||
case "10y": | ||
return `${d3.utcFormat("%Y")(value)} - ${d3.utcFormat("%Y")(d3.utcYear.offset(value, 9))}` | ||
case "1q": | ||
const monthNumber = d3.utcFormat("%m")(value) // convert to integer month (01 - 12) | ||
return `Q${Math.floor((parseInt(monthNumber, 10) + 3) / 3)} ${d3.utcFormat("%Y")(value)}` | ||
default: | ||
return value | ||
} | ||
@@ -133,5 +135,5 @@ } | ||
export function formatTooltipNumber(d) { | ||
export function formatTooltipNumber (d) { | ||
// comma separator, max 2 decimals | ||
return d3.format(",")(Math.round(d * 100) / 100) | ||
} |
import * as d3 from "./helpers/d3-service" | ||
import {keys, LEFT_AXIS_GROUP_INDEX, RIGHT_AXIS_GROUP_INDEX} from "./helpers/constants" | ||
import {override, getSizes} from "./helpers/common" | ||
import {keys, LEFT_AXIS_GROUP_INDEX} from "./helpers/constants" | ||
import {override} from "./helpers/common" | ||
@@ -18,3 +18,6 @@ export default function Hover (_container) { | ||
dotRadius: null, | ||
chartType: null | ||
chartType: null, | ||
chartWidth: null, | ||
chartHeight: null | ||
} | ||
@@ -32,4 +35,2 @@ | ||
svg: null, | ||
chartWidth: null, | ||
chartHeight: null, | ||
dateRange: [null, null], | ||
@@ -56,9 +57,5 @@ brush: null, | ||
cache.root = cache.container.append("g") | ||
.classed("hover-group", true) | ||
.style("pointer-events", "none") | ||
.classed("hover-group", true) | ||
.style("pointer-events", "none") | ||
} | ||
const {chartWidth, chartHeight} = getSizes(config, cache) | ||
cache.chartWidth = chartWidth | ||
cache.chartHeight = chartHeight | ||
} | ||
@@ -103,3 +100,3 @@ | ||
const dots = cache.root.selectAll(".dot") | ||
.data(_dotsData) | ||
.data(_dotsData) | ||
@@ -115,3 +112,3 @@ dots.enter() | ||
} else { | ||
return scales.y2Scale(d[keys.VALUE]) | ||
return scales.y2Scale ? scales.y2Scale(d[keys.VALUE]) : scales.yScale(d[keys.VALUE]) | ||
} | ||
@@ -145,3 +142,3 @@ }) | ||
const verticalMarkerLine = cache.root.selectAll("line") | ||
.data([0]) | ||
.data([0]) | ||
@@ -153,3 +150,3 @@ verticalMarkerLine.enter() | ||
.attr("y1", 0) | ||
.attr("y2", cache.chartHeight) | ||
.attr("y2", config.chartHeight) | ||
@@ -156,0 +153,0 @@ verticalMarkerLine.exit().remove() |
import * as d3 from "./helpers/d3-service" | ||
import {override, getSizes} from "./helpers/common" | ||
import {override} from "./helpers/common" | ||
@@ -18,3 +18,6 @@ export default function Label (_container) { | ||
yLabel: "", | ||
y2Label: "" | ||
y2Label: "", | ||
chartWidth: null, | ||
chartHeight: null | ||
} | ||
@@ -27,5 +30,3 @@ | ||
yAxisLabel: null, | ||
y2AxisLabel: null, | ||
chartWidth: null, | ||
chartHeight: null | ||
y2AxisLabel: null | ||
} | ||
@@ -39,7 +40,7 @@ | ||
cache.root = cache.container | ||
.append("div") | ||
.attr("class", "label-group") | ||
.style("position", "absolute") | ||
.style("top", 0) | ||
.style("white-space", "nowrap") | ||
.append("div") | ||
.attr("class", "label-group") | ||
.style("position", "absolute") | ||
.style("top", 0) | ||
.style("white-space", "nowrap") | ||
@@ -90,9 +91,5 @@ cache.xAxisLabel = cache.root.append("div") | ||
const {chartWidth, chartHeight} = getSizes(config, cache) | ||
cache.chartWidth = chartWidth | ||
cache.chartHeight = chartHeight | ||
cache.xAxisLabel | ||
.text(config.xLabel) | ||
.style("max-width", `${cache.chartWidth}px`) | ||
.style("max-width", `${config.chartWidth}px`) | ||
.style("top", function top () { | ||
@@ -103,8 +100,8 @@ const LABEL_PADDING = 18 | ||
}) | ||
.style("left", `${config.margin.left + cache.chartWidth / 2}px`) | ||
.style("left", `${config.margin.left + config.chartWidth / 2}px`) | ||
cache.yAxisLabel | ||
.text(config.yLabel) | ||
.style("max-width", `${cache.chartHeight}px`) | ||
.style("top", `${config.margin.top + cache.chartHeight / 2}px`) | ||
.style("max-width", `${config.chartHeight}px`) | ||
.style("top", `${config.margin.top + config.chartHeight / 2}px`) | ||
.style("left", function top () { | ||
@@ -118,4 +115,4 @@ const LABEL_PADDING = 4 | ||
.text(config.y2Label) | ||
.style("max-width", `${cache.chartHeight}px`) | ||
.style("top", `${config.margin.top + cache.chartHeight / 2}px`) | ||
.style("max-width", `${config.chartHeight}px`) | ||
.style("top", `${config.margin.top + config.chartHeight / 2}px`) | ||
.style("left", function top () { | ||
@@ -122,0 +119,0 @@ const LABEL_PADDING = 4 |
import * as d3 from "./helpers/d3-service" | ||
import {keys, dashStylesTranslation} from "./helpers/constants" | ||
import {override, getSizes} from "./helpers/common" | ||
import {override} from "./helpers/common" | ||
@@ -9,14 +9,8 @@ export default function Line (_container) { | ||
let config = { | ||
margin: { | ||
top: 60, | ||
right: 30, | ||
bottom: 40, | ||
left: 70 | ||
}, | ||
width: 800, | ||
height: 500, | ||
chartId: null, | ||
chartType: null, | ||
colorSchema: ["skyblue"], | ||
xDomain: "auto" | ||
xDomain: "auto", | ||
chartHeight: null | ||
} | ||
@@ -35,4 +29,3 @@ | ||
container: _container, | ||
svg: null, | ||
chartHeight: null, | ||
svg: null | ||
} | ||
@@ -52,8 +45,4 @@ | ||
cache.root = cache.container.append("g") | ||
.classed("mark-group", true) | ||
.classed("mark-group", true) | ||
} | ||
const {chartWidth, chartHeight} = getSizes(config, cache) | ||
cache.chartWidth = chartWidth | ||
cache.chartHeight = chartHeight | ||
} | ||
@@ -63,8 +52,8 @@ | ||
const seriesLine = d3.line() | ||
.x((d) => scales.xScale(d[keys.KEY])) | ||
.y((d) => scales.yScale(d[keys.VALUE])) | ||
.x((d) => scales.xScale(d[keys.KEY])) | ||
.y((d) => scales.yScale(d[keys.VALUE])) | ||
const seriesLine2 = d3.line() | ||
.x((d) => scales.xScale(d[keys.KEY])) | ||
.y((d) => scales.y2Scale(d[keys.VALUE])) | ||
.x((d) => scales.xScale(d[keys.KEY])) | ||
.y((d) => scales.y2Scale(d[keys.VALUE])) | ||
@@ -81,3 +70,3 @@ if (Array.isArray(config.xDomain)) { | ||
const lines = cache.root.selectAll(".mark") | ||
.data(lineData) | ||
.data(lineData) | ||
@@ -88,3 +77,3 @@ lines.enter() | ||
.attr("class", "mark line") | ||
.attr('clip-path', `url(#mark-clip-${config.chartId})`) | ||
.attr("clip-path", `url(#mark-clip-${config.chartId})`) | ||
.classed("y2-line", (d) => d[keys.GROUP] > 0) | ||
@@ -110,14 +99,14 @@ .attr("d", (d) => { | ||
const seriesArea = d3.area() | ||
.x((d) => scales.xScale(d[keys.KEY])) | ||
.y0((d) => scales.yScale(d[keys.VALUE])) | ||
.y1(() => cache.chartHeight) | ||
.x((d) => scales.xScale(d[keys.KEY])) | ||
.y0((d) => scales.yScale(d[keys.VALUE])) | ||
.y1(() => config.chartHeight) | ||
const seriesArea2 = d3.area() | ||
.x((d) => scales.xScale(d[keys.KEY])) | ||
.y0((d) => scales.y2Scale(d[keys.VALUE])) | ||
.y1(() => cache.chartHeight) | ||
.curve(d3.curveCatmullRom) | ||
.x((d) => scales.xScale(d[keys.KEY])) | ||
.y0((d) => scales.y2Scale(d[keys.VALUE])) | ||
.y1(() => config.chartHeight) | ||
.curve(d3.curveCatmullRom) | ||
const areas = cache.root.selectAll(".mark") | ||
.data(data.dataBySeries) | ||
.data(data.dataBySeries) | ||
@@ -128,3 +117,3 @@ areas.enter() | ||
.attr("class", "mark area") | ||
.attr('clip-path', `url(#mark-clip-${config.chartId})`) | ||
.attr("clip-path", `url(#mark-clip-${config.chartId})`) | ||
.classed("y2-area", (d) => d[keys.GROUP] > 0) | ||
@@ -146,8 +135,8 @@ .attr("d", (d) => { | ||
const seriesLine = d3.area() | ||
.x((d) => scales.xScale(d.data[keys.KEY])) | ||
.y0((d) => scales.yScale(d[0])) | ||
.y1((d) => scales.yScale(d[1])) | ||
.x((d) => scales.xScale(d.data[keys.KEY])) | ||
.y0((d) => scales.yScale(d[0])) | ||
.y1((d) => scales.yScale(d[1])) | ||
const areas = cache.root.selectAll(".mark") | ||
.data(data.stack(data.stackData)) | ||
.data(data.stack(data.stackData)) | ||
@@ -158,3 +147,3 @@ areas.enter() | ||
.attr("class", "mark stacked-area") | ||
.attr('clip-path', `url(#mark-clip-${config.chartId})`) | ||
.attr("clip-path", `url(#mark-clip-${config.chartId})`) | ||
.attr("d", seriesLine) | ||
@@ -161,0 +150,0 @@ .style("stroke", "none") |
import * as d3 from "./helpers/d3-service" | ||
import {keys, LEFT_AXIS_GROUP_INDEX, RIGHT_AXIS_GROUP_INDEX, MAX_MARK_WIDTH} from "./helpers/constants" | ||
import {getUnique, override, getSizes} from "./helpers/common" | ||
import { | ||
keys, | ||
LEFT_AXIS_GROUP_INDEX, | ||
RIGHT_AXIS_GROUP_INDEX | ||
} from "./helpers/constants" | ||
import {override} from "./helpers/common" | ||
@@ -9,10 +13,2 @@ export default function Scale () { | ||
let config = { | ||
margin: { | ||
top: 60, | ||
right: 30, | ||
bottom: 40, | ||
left: 70 | ||
}, | ||
height: null, | ||
width: null, | ||
keyType: null, | ||
@@ -24,8 +20,8 @@ chartType: null, | ||
yDomain: "auto", | ||
y2Domain: "auto" | ||
} | ||
y2Domain: "auto", | ||
const cache = { | ||
chartWidth: null, | ||
chartHeight: null | ||
chartHeight: null, | ||
markPanelWidth: null, | ||
markWidth: null | ||
} | ||
@@ -37,3 +33,4 @@ | ||
flatDataSorted: null, | ||
groupKeys: null | ||
groupKeys: null, | ||
allKeyTotals: null | ||
} | ||
@@ -45,19 +42,5 @@ | ||
function hasBars (_chartType) { | ||
return _chartType === "bar" | ||
|| _chartType === "stackedBar" | ||
|| _chartType === "groupedBar" | ||
|| (Array.isArray(_chartType) && _chartType.filter(d => d === "bar").length > 0) | ||
} | ||
function getScaleSizes () { | ||
const {chartWidth, chartHeight} = getSizes(config, cache) | ||
cache.chartWidth = chartWidth | ||
cache.chartHeight = chartHeight | ||
} | ||
function buildXScale (_allKeys) { | ||
let xScale = null | ||
let domain = null | ||
const markW = Math.min(hasBars(config.chartType) ? cache.chartWidth / _allKeys.length : 0, MAX_MARK_WIDTH) | ||
@@ -85,4 +68,5 @@ if (config.keyType === "time") { | ||
const markWidthOffset = config.markWidth ? config.markWidth / 2 : 0 | ||
xScale.domain(domain) | ||
.range([markW / 2, cache.chartWidth - markW / 2]) | ||
.range([markWidthOffset, config.markPanelWidth - markWidthOffset]) | ||
@@ -94,4 +78,4 @@ return xScale | ||
const yScale = d3.scaleLinear() | ||
.domain(_extent) | ||
.rangeRound([cache.chartHeight, 0]) | ||
.domain(_extent) | ||
.rangeRound([config.chartHeight, 0]) | ||
@@ -104,5 +88,5 @@ return yScale | ||
const colorScale = d3.scaleOrdinal() | ||
.range(config.colorSchema.map((d) => d.value)) | ||
.domain(config.colorSchema.map((d, i) => (typeof d.id === "undefined") ? ids[i] : d.id)) | ||
.unknown(config.defaultColor) | ||
.range(config.colorSchema.map((d) => d.value)) | ||
.domain(config.colorSchema.map((d, i) => ((typeof d.id === "undefined") ? ids[i] : d.id))) | ||
.unknown(config.defaultColor) | ||
@@ -115,5 +99,5 @@ return colorScale | ||
const styleScale = d3.scaleOrdinal() | ||
.range(config.colorSchema.map((d) => d.style)) | ||
.domain(config.colorSchema.map((d, i) => d.id || ids[i])) | ||
.unknown("solid") | ||
.range(config.colorSchema.map((d) => d.style)) | ||
.domain(config.colorSchema.map((d, i) => d.id || ids[i])) | ||
.unknown("solid") | ||
@@ -126,5 +110,5 @@ return styleScale | ||
const chartTypeScale = d3.scaleOrdinal() | ||
.range(config.colorSchema.map((d) => d.type)) | ||
.domain(config.colorSchema.map((d, i) => d.id || ids[i])) | ||
.unknown("line") | ||
.range(config.colorSchema.map((d) => d.type)) | ||
.domain(config.colorSchema.map((d, i) => d.id || ids[i])) | ||
.unknown("line") | ||
@@ -153,7 +137,5 @@ return chartTypeScale | ||
const allStackHeights = data.dataByKey.map((d) => d3.sum(d.series.map((dB) => dB.value))) | ||
const allKeys = data.allKeyTotals.map(getKey) | ||
const allKeys = data.flatDataSorted.map(getKey) | ||
const allUniqueKeys = getUnique(allKeys, config.keyType) | ||
const xScale = buildXScale(allUniqueKeys) | ||
const xScale = buildXScale(allKeys) | ||
const colorScale = buildColorScale() | ||
@@ -192,2 +174,3 @@ const styleScale = buildStyleScale() | ||
const groupKeys = Object.keys(groups) || [] | ||
const allKeys = data.allKeyTotals.map(getKey) | ||
@@ -197,4 +180,3 @@ const hasLeftAxis = groupKeys.indexOf(LEFT_AXIS_GROUP_INDEX) > -1 | ||
const allUniqueKeys = data.dataByKey.map(d => d.key) | ||
const xScale = buildXScale(allUniqueKeys) | ||
const xScale = buildXScale(allKeys) | ||
@@ -242,3 +224,2 @@ const colorScale = buildColorScale() | ||
function getScales () { | ||
getScaleSizes() | ||
if (config.chartType === "stackedBar" | ||
@@ -245,0 +226,0 @@ || config.chartType === "stackedArea") { |
import * as d3 from "./helpers/d3-service" | ||
import {keys, dashStylesTranslation} from "./helpers/constants" | ||
import {cloneData, isNumeric, override} from "./helpers/common" | ||
import {binTranslation, formatOddDateBin, multiFormat, formatTooltipNumber} from "./helpers/formatters" | ||
import {isNumeric, override} from "./helpers/common" | ||
import {binTranslation, formatOddDateBin, formatTooltipNumber} from "./helpers/formatters" | ||
export default function Tooltip (_container, isLegend = false) { | ||
export default function Tooltip (_container, _isLegend = false) { | ||
@@ -20,3 +20,2 @@ let config = { | ||
dateFormat: "%b %d, %Y", | ||
numberFormat: null, | ||
tooltipIsEnabled: true, | ||
@@ -28,3 +27,8 @@ tooltipTitle: null, | ||
colorSchema: ["skyblue"], | ||
keyType: "time" | ||
keyType: "time", | ||
tooltipFormat: null, | ||
markPanelWidth: null, | ||
chartWidth: null, | ||
chartHeight: null | ||
} | ||
@@ -40,4 +44,2 @@ | ||
root: null, | ||
chartWidth: null, | ||
chartHeight: null, | ||
tooltipDivider: null, | ||
@@ -54,9 +56,6 @@ tooltipBody: null, | ||
function build () { | ||
cache.chartWidth = config.width - config.margin.left - config.margin.right | ||
cache.chartHeight = config.height - config.margin.top - config.margin.bottom | ||
if (!cache.root) { | ||
cache.root = cache.container.append("div") | ||
.attr("class", isLegend ? "legend-group" : "tooltip-group") | ||
.style("position", "absolute") | ||
.attr("class", _isLegend ? "legend-group" : "tooltip-group") | ||
.style("position", "absolute") | ||
@@ -67,11 +66,11 @@ const panel = cache.root.append("div") | ||
cache.tooltipTitleSection = panel.append("div") | ||
.attr("class", "tooltip-title-section") | ||
.attr("class", "tooltip-title-section") | ||
cache.tooltipTitle = cache.tooltipTitleSection.append("div") | ||
.attr("class", "tooltip-title") | ||
.attr("class", "tooltip-title") | ||
cache.tooltipBody = panel.append("div") | ||
.attr("class", "tooltip-body") | ||
.attr("class", "tooltip-body") | ||
if (isLegend) { | ||
if (_isLegend) { | ||
cache.tooltipTitleSection.append("div") | ||
@@ -81,3 +80,3 @@ .attr("class", "tooltip-collapse") | ||
cache.tooltipTitleSection.on("click", function () { | ||
cache.tooltipTitleSection.on("click", function click () { | ||
const isCollapsed = this.classList.toggle("collapsed") | ||
@@ -95,4 +94,4 @@ toggleCollapse(isCollapsed) | ||
if (isLegend) { | ||
cache.root.style("max-height", cache.chartHeight) | ||
if (_isLegend) { | ||
cache.root.style("max-height", config.chartHeight) | ||
if (config.tooltipIsEnabled) { | ||
@@ -113,5 +112,6 @@ show() | ||
if (_mouseX > (cache.chartWidth / 2)) { | ||
if (_mouseX > (config.chartWidth / 2)) { | ||
avoidanceOffset = -tooltipSize.width - OFFSET | ||
} | ||
return [tooltipX + avoidanceOffset, tooltipY] | ||
@@ -122,8 +122,8 @@ } | ||
const xPosition = cache.xPosition === "auto" | ||
? cache.chartWidth | ||
: cache.xPosition | ||
? config.chartWidth | ||
: cache.xPosition | ||
const yPosition = cache.yPosition === "auto" | ||
? config.margin.top | ||
: cache.yPosition | ||
? config.margin.top | ||
: cache.yPosition | ||
@@ -137,5 +137,5 @@ cache.root | ||
if (isLegend) { | ||
if (_isLegend) { | ||
// set max-height in case there are too many legend items | ||
cache.root.style("max-height", `${cache.chartHeight}px`) | ||
cache.root.style("max-height", `${config.chartHeight}px`) | ||
} | ||
@@ -146,5 +146,15 @@ | ||
function formatValue (_value, _format, _index) { | ||
if (typeof _format === "string" && _format !== "auto") { | ||
return d3.format(_format)(_value) | ||
} else if (Array.isArray(_format)) { | ||
return _format[_index] ? d3.format(_format[_index])(_value) : formatTooltipNumber(_value) | ||
} else { | ||
return formatTooltipNumber(_value) | ||
} | ||
} | ||
function drawContent () { | ||
const tooltipItems = cache.tooltipBody.selectAll(".tooltip-item") | ||
.data(cache.content) | ||
.data(cache.content) | ||
const tooltipItemsUpdate = tooltipItems.enter().append("div") | ||
@@ -156,3 +166,3 @@ .attr("class", "tooltip-item") | ||
const tooltipItem = tooltipItemsUpdate.selectAll(".section") | ||
.data((d) => { | ||
.data((d, i) => { | ||
const legendData = [ | ||
@@ -163,6 +173,6 @@ { | ||
style: scales.styleScale(d[keys.ID]) | ||
}, | ||
} | ||
] | ||
if (isLegend) { | ||
if (typeof d[keys.LABEL] !== "undefined") { | ||
legendData.push({key: "tooltip-label", value: d[keys.LABEL]}) | ||
@@ -172,3 +182,4 @@ } | ||
if (typeof d[keys.VALUE] !== "undefined") { | ||
legendData.push({key: "value", value: d[keys.VALUE]}) | ||
const formattedValue = formatValue(d[keys.VALUE], config.tooltipFormat, i) | ||
legendData.push({key: "value", value: formattedValue}) | ||
} | ||
@@ -200,5 +211,3 @@ return legendData | ||
.attr("stroke-width", 2.5) | ||
.attr("stroke-dasharray", d => { | ||
return dashStylesTranslation[d.style] | ||
}) | ||
.attr("stroke-dasharray", dB => dashStylesTranslation[dB.style]) | ||
} else { | ||
@@ -213,4 +222,2 @@ svg | ||
} | ||
} else if (d.key === "value") { | ||
selection.html(formatTooltipNumber(d.value)) | ||
} else { | ||
@@ -225,4 +232,4 @@ selection.html(d.value) | ||
function toggleCollapse (isCollapsed) { | ||
if (isCollapsed) { | ||
function toggleCollapse (_isCollapsed) { | ||
if (_isCollapsed) { | ||
cache.tooltipTitle.html("Legend") | ||
@@ -244,4 +251,4 @@ cache.tooltipBody.style("display", "none") | ||
if (title instanceof Date) { | ||
const { binningResolution } = config; | ||
let specifier = binTranslation[binningResolution] | ||
const {binningResolution} = config | ||
const specifier = binTranslation[binningResolution] | ||
@@ -265,5 +272,3 @@ if (specifier) { | ||
function setupContent (_series) { | ||
let series = _series | ||
cache.content = sortSeries(series) | ||
cache.content = sortSeries(_series) | ||
return this | ||
@@ -288,5 +293,5 @@ } | ||
function setupTooltip (_dataPoint, _xPosition, _yPosition) { | ||
function setupTooltip (_dataPoint, _xPosition, _yPosition, _panelXPosition) { | ||
build() | ||
const [tooltipX, tooltipY] = calculateTooltipPosition(_xPosition, _yPosition) | ||
const [tooltipX, tooltipY] = calculateTooltipPosition(_panelXPosition, _yPosition) | ||
setXPosition(tooltipX) | ||
@@ -293,0 +298,0 @@ setYPosition(tooltipY) |
@@ -1,27 +0,27 @@ | ||
var requireConfig = { | ||
const requireConfig = { | ||
baseUrl: '', | ||
baseUrl: "", | ||
paths: { | ||
'es6': './node_modules/js-common/src/utils/es6', | ||
'd3': 'node_modules/d3/d3' | ||
}, | ||
shim: { | ||
'd3': { exports: 'd3'}, | ||
}, | ||
map: {}, | ||
packages: [] | ||
}; | ||
paths: { | ||
es6: "./node_modules/js-common/src/utils/es6", | ||
d3: "node_modules/d3/d3" | ||
}, | ||
shim: { | ||
d3: {exports: "d3"} | ||
}, | ||
map: {}, | ||
packages: [] | ||
} | ||
if (typeof require === 'undefined') { | ||
// any values set on require before it loads will be used as config | ||
// ignore the "redefinition error" due to the line below | ||
window.require = window.requireConfig; | ||
} else if (typeof module === 'undefined') { | ||
window.require.config(window.requireConfig); | ||
if (typeof require === "undefined") { | ||
// any values set on require before it loads will be used as config | ||
// ignore the "redefinition error" due to the line below | ||
window.require = window.requireConfig | ||
} else if (typeof module === "undefined") { | ||
window.require.config(window.requireConfig) | ||
} | ||
// allow for loading in nodejs | ||
if (typeof module !== 'undefined' && module.exports) { | ||
exports = module.exports = requireConfig; | ||
if (typeof module !== "undefined" && module.exports) { | ||
exports = module.exports = requireConfig | ||
} |
const webpack = require("webpack") | ||
const path = require("path") | ||
const LiveReloadPlugin = require("webpack-livereload-plugin") | ||
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin | ||
const ExtractTextPlugin = require("extract-text-webpack-plugin") | ||
const chartModulesPath = path.resolve("./src/charts") | ||
const fixturesPath = path.resolve("./test/fixtures") | ||
const vendorsPath = path.resolve("./node_modules") | ||
const bundleIndexPath = path.resolve("./src/bundle.js") | ||
const scssIndexPath = path.resolve("./src/styles/mapd3.scss") | ||
const defaultJSLoader = { | ||
test: /\.js$/, | ||
include: /src/, | ||
exclude: /(node_modules)/, | ||
use: { | ||
loader: 'babel-loader', | ||
options: { | ||
presets: ["@babel/preset-env"], | ||
cacheDirectory: false | ||
} | ||
} | ||
} | ||
const config = function (env) { | ||
const config = (env) => { | ||
if (env.prod) { | ||
return { | ||
entry: { | ||
mapd3: bundleIndexPath, | ||
mapd3: bundleIndexPath | ||
}, | ||
@@ -35,5 +18,5 @@ | ||
path: path.resolve(__dirname, "dist"), | ||
filename: '[name].min.js', | ||
filename: "[name].min.js", | ||
library: "[name]", | ||
libraryTarget: "umd", | ||
libraryTarget: "umd" | ||
}, | ||
@@ -51,3 +34,3 @@ | ||
use: { | ||
loader: 'babel-loader', | ||
loader: "babel-loader", | ||
options: { | ||
@@ -73,8 +56,6 @@ presets: ["@babel/preset-env"], | ||
} | ||
} | ||
if (env.dev) { | ||
} else if (env.dev) { | ||
return { | ||
entry: { | ||
mapd3: bundleIndexPath, | ||
mapd3: bundleIndexPath | ||
}, | ||
@@ -86,5 +67,5 @@ | ||
path: path.resolve(__dirname, "dist"), | ||
filename: '[name].js', | ||
filename: "[name].js", | ||
library: "[name]", | ||
libraryTarget: "umd", | ||
libraryTarget: "umd" | ||
}, | ||
@@ -102,3 +83,3 @@ | ||
use: { | ||
loader: 'babel-loader', | ||
loader: "babel-loader", | ||
options: { | ||
@@ -120,6 +101,7 @@ presets: ["@babel/preset-env"], | ||
allChunks: true | ||
}), | ||
// new BundleAnalyzerPlugin() | ||
}) | ||
] | ||
} | ||
} else { | ||
return | ||
} | ||
@@ -126,0 +108,0 @@ } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
1084296
59
0
28
6459