diff --git a/CHANGELOG.md b/CHANGELOG.md index c013c36b5c..f6e0f0fea3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,86 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.9.7](https://github.com/IBM/carbon-charts/compare/v0.9.6...v0.9.7) (2019-02-22) + +**Note:** Version bump only for package @carbon/charts-monorepo + + + + + +## [0.9.6](https://github.com/IBM/carbon-charts/compare/v0.9.4...v0.9.6) (2019-02-21) + + +### Bug Fixes + +* **bar:** add maxWidth and other bar fixes ([3866d86](https://github.com/IBM/carbon-charts/commit/3866d86)) + + + + + +## [0.9.5](https://github.com/IBM/carbon-charts/compare/v0.9.4...v0.9.5) (2019-02-20) + + +### Bug Fixes + +* **$core:** Fixes opacity transitions not completing when data is updated. Ensures use SVG vs CSS op ([f6b245e](https://github.com/IBM/carbon-charts/commit/f6b245e)) + + + + + +## [0.9.4](https://github.com/IBM/carbon-charts/compare/v0.9.3...v0.9.4) (2019-02-16) + + +### Bug Fixes + +* **$browser:** Fix duplication of titles during title resize ([4698efd](https://github.com/IBM/carbon-charts/commit/4698efd)) + + +### Features + +* **$browser:** Add y axis ([8e2a86b](https://github.com/IBM/carbon-charts/commit/8e2a86b)) +* **$browser:** Y axis titles ([7e03ff7](https://github.com/IBM/carbon-charts/commit/7e03ff7)) + + + + + +## [0.9.3](https://github.com/IBM/carbon-charts/compare/v0.9.2...v0.9.3) (2019-02-15) + + +### Bug Fixes + +* **core:** Fix NPM vulnerabilities ([73ef611](https://github.com/IBM/carbon-charts/commit/73ef611)) + + + + + +## [0.9.2](https://github.com/IBM/carbon-charts/compare/v0.9.1...v0.9.2) (2019-02-15) + + +### Bug Fixes + +* **core:** Allow custom circle size for line chart ([5fb93bd](https://github.com/IBM/carbon-charts/commit/5fb93bd)) + + + + + +## [0.9.1](https://github.com/IBM/carbon-charts/compare/v0.9.0...v0.9.1) (2019-02-07) + + +### Bug Fixes + +* **core:** Allow the usage of different size variants of tooltip ([4f6aa1d](https://github.com/IBM/carbon-charts/commit/4f6aa1d)) + + + + + # [0.9.0](https://github.com/IBM/carbon-charts/compare/v0.8.6...v0.9.0) (2019-01-28) diff --git a/README.md b/README.md index 4b547ff224..71813179a6 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,9 @@ + + + diff --git a/lerna.json b/lerna.json index c49ffe3385..63ec8d5756 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ ] } }, - "version": "0.9.0" + "version": "0.9.7" } diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index 2fb2c4eb36..9981807519 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -3,6 +3,80 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.9.7](https://github.com/IBM/carbon-charts/compare/v0.9.6...v0.9.7) (2019-02-22) + +**Note:** Version bump only for package @carbon/charts + + + + + +## [0.9.6](https://github.com/IBM/carbon-charts/compare/v0.9.4...v0.9.6) (2019-02-21) + + +### Bug Fixes + +* **bar:** add maxWidth and other bar fixes ([3866d86](https://github.com/IBM/carbon-charts/commit/3866d86)) + + + + + +## [0.9.5](https://github.com/IBM/carbon-charts/compare/v0.9.4...v0.9.5) (2019-02-20) + + +### Bug Fixes + +* **$core:** Fixes opacity transitions not completing when data is updated. Ensures use SVG vs CSS op ([f6b245e](https://github.com/IBM/carbon-charts/commit/f6b245e)) + + + + + +## [0.9.4](https://github.com/IBM/carbon-charts/compare/v0.9.3...v0.9.4) (2019-02-16) + + +### Bug Fixes + +* **$browser:** Fix duplication of titles during title resize ([4698efd](https://github.com/IBM/carbon-charts/commit/4698efd)) + + + + + +## [0.9.3](https://github.com/IBM/carbon-charts/compare/v0.9.2...v0.9.3) (2019-02-15) + + +### Bug Fixes + +* **core:** Fix NPM vulnerabilities ([73ef611](https://github.com/IBM/carbon-charts/commit/73ef611)) + + + + + +## [0.9.2](https://github.com/IBM/carbon-charts/compare/v0.9.1...v0.9.2) (2019-02-15) + + +### Bug Fixes + +* **core:** Allow custom circle size for line chart ([5fb93bd](https://github.com/IBM/carbon-charts/commit/5fb93bd)) + + + + + +## [0.9.1](https://github.com/IBM/carbon-charts/compare/v0.9.0...v0.9.1) (2019-02-07) + + +### Bug Fixes + +* **core:** Allow the usage of different size variants of tooltip ([4f6aa1d](https://github.com/IBM/carbon-charts/commit/4f6aa1d)) + + + + + # [0.9.0](https://github.com/IBM/carbon-charts/compare/v0.8.6...v0.9.0) (2019-01-28) diff --git a/packages/core/demo/demo-data/bar.ts b/packages/core/demo/demo-data/bar.ts index 328bf279dd..515c3b4c96 100644 --- a/packages/core/demo/demo-data/bar.ts +++ b/packages/core/demo/demo-data/bar.ts @@ -56,6 +56,7 @@ export const groupedBarOptions = { title: "2018 Annual Sales Figures", }, y: { + title: "Dollars (CAD)", formatter: axisValue => `${axisValue / 1000}k`, yMaxAdjuster: yMaxValue => yMaxValue * 1.1, }, @@ -67,6 +68,9 @@ export const groupedBarOptions = { formatter: axisValue => `${axisValue * 100}%` } }, + tooltip: { + size: "compact" + }, legendClickable: true, containerResizable: true }; @@ -96,13 +100,17 @@ export const simpleBarOptions = { title: "2018 Annual Sales Figures", }, y: { + title: "Dollars (CAD)", formatter: axisValue => `${axisValue / 1000}k`, yMaxAdjuster: yMaxValue => yMaxValue * 1.1, stacked: false } }, legendClickable: true, - containerResizable: true + containerResizable: true, + bars: { + maxWidth: 50 + } }; // Stacked bar @@ -163,11 +171,15 @@ export const stackedBarOptions = { title: "2018 Annual Sales Figures", }, y: { + title: "Dollars (CAD)", formatter: axisValue => `${axisValue / 1000}k`, yMaxAdjuster: yMaxValue => yMaxValue * 1.1, stacked: true } }, + tooltip: { + size: "compact" + }, legendClickable: true, containerResizable: true }; diff --git a/packages/core/demo/demo-data/line.ts b/packages/core/demo/demo-data/line.ts index 62a785e0cc..70b9a380f1 100644 --- a/packages/core/demo/demo-data/line.ts +++ b/packages/core/demo/demo-data/line.ts @@ -46,6 +46,7 @@ export const curvedLineOptions = { title: "2018 Annual Sales Figures", }, y: { + title: "Dollars (CAD)", yMaxAdjuster: yMax => yMax * 1.2, yMinAdjuster: yMin => yMin * 1.2, formatter: axisValue => `${axisValue / 1000}k` @@ -111,6 +112,7 @@ export const lineOptions = { title: "2018 Annual Sales Figures", }, y: { + title: "Dollars (CAD)", yMaxAdjuster: yMax => yMax * 1.2, yMinAdjuster: yMin => yMin * 1.2, formatter: axisValue => `${axisValue / 1000}k`, @@ -130,6 +132,9 @@ export const lineOptions = { ] } }, + points: { + radius: 4 + }, legendClickable: true, containerResizable: true }; diff --git a/packages/core/package.json b/packages/core/package.json index 045abf4b90..097ad0a277 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@carbon/charts", - "version": "0.9.0", + "version": "0.9.7", "description": "Carbon charting components", "files": [ "dist", @@ -67,7 +67,7 @@ "webpack": "4.18.0", "webpack-bundle-analyzer": "2.13.1", "webpack-cli": "3.1.0", - "webpack-dev-server": "3.1.8", + "webpack-dev-server": "3.1.14", "webpack-node-externals": "1.6.0" }, "publishConfig": { diff --git a/packages/core/src/bar-chart.ts b/packages/core/src/bar-chart.ts index 98a2b0e942..8e2033baa6 100644 --- a/packages/core/src/bar-chart.ts +++ b/packages/core/src/bar-chart.ts @@ -7,6 +7,8 @@ import { BaseAxisChart } from "./base-axis-chart"; import { StackedBarChart } from "./stacked-bar-chart"; import * as Configuration from "./configuration"; +import { Tools } from "./tools"; + const getYMin = configs => { const { datasets } = configs.data; const { scales } = configs.options; @@ -25,6 +27,31 @@ const getYMin = configs => { return yMin; }; +// returns the configured max width or the calculated bandwidth +// whichever is lower +// defaults to the calculated bandwidth if no maxWidth is defined +const getMaxBarWidth = (maxWidth, currentBandWidth) => { + if (!maxWidth) { + return currentBandWidth; + } + if (currentBandWidth <= maxWidth) { + return currentBandWidth; + } + return maxWidth; +}; + +// returns true if the calculated bandwidth is greater than the maxWidth (if deinfed) +// i.e. if we should be constraining ourselves to a specific bar width +const isWidthConstrained = (maxWidth, currentBandWidth) => { + if (!maxWidth) { + return false; + } + if (currentBandWidth <= maxWidth) { + return false; + } + return true; +}; + export class BarChart extends BaseAxisChart { x: any; x1?: any; @@ -51,7 +78,8 @@ export class BarChart extends BaseAxisChart { const width = chartSize.width - margins.left - margins.right; this.x1 = scaleBand().rangeRound([0, width]).padding(Configuration.bars.spacing.bars); - this.x1.domain(configs.data.datasets.map(dataset => dataset.label)).rangeRound([0, this.x.bandwidth()]); + this.x1.domain(configs.data.datasets.map(dataset => dataset.label)) + .rangeRound([0, getMaxBarWidth(Tools.getProperty(this.options, "bars", "maxWidth"), this.x.bandwidth())]); } this.options.type = "bar"; @@ -69,8 +97,23 @@ export class BarChart extends BaseAxisChart { this.x.domain(this.displayData.labels); } - this.x1 = scaleBand().rangeRound([0, width]).padding(Configuration.bars.spacing.bars); - this.x1.domain(this.displayData.datasets.map(dataset => dataset.label)).rangeRound([0, this.x.bandwidth()]); + // if it's a grouped bar, use additoinal padding so the bars don't group up + if (this.displayData.datasets.length > 1) { + this.x1 = scaleBand().rangeRound([0, width]).padding(Configuration.bars.spacing.bars); + } else { + this.x1 = scaleBand().rangeRound([0, width]); + } + + this.x1.domain(this.displayData.datasets.map(dataset => dataset.label)) + .rangeRound([0, getMaxBarWidth(Tools.getProperty(this.options, "bars", "maxWidth"), this.x.bandwidth())]); + } + + getBarX(d) { + if (!isWidthConstrained(Tools.getProperty(this.options, "bars", "maxWidth"), this.x.bandwidth())) { + return this.x1(d.datasetLabel); + } + + return (this.x.bandwidth() / 2) - (Tools.getProperty(this.options, "bars", "maxWidth") / 2); } draw() { @@ -99,7 +142,7 @@ export class BarChart extends BaseAxisChart { .enter() .append("rect") .classed("bar", true) - .attr("x", d => this.x1(d.datasetLabel)) + .attr("x", this.getBarX.bind(this)) .attr("y", d => this.y(Math.max(0, d.value))) .attr("width", this.x1.bandwidth()) .attr("height", d => Math.abs(this.y(d.value) - this.y(0))) @@ -144,14 +187,14 @@ export class BarChart extends BaseAxisChart { .enter() .append("rect") .attr("class", "bar") - .attr("x", d => this.x1(d.datasetLabel)) + .attr("x", this.getBarX.bind(this)) .attr("y", d => this.y(Math.max(0, d.value))) .attr("width", this.x1.bandwidth()) .attr("height", d => Math.abs(this.y(d.value) - this.y(0))) - .attr("opacity", 0) + .style("opacity", 0) .transition(this.getFillTransition()) .attr("fill", d => this.getFillScale()[d.datasetLabel](d.label)) - .attr("opacity", 1) + .style("opacity", 1) .attr("stroke", (d: any) => this.colorScale[d.datasetLabel](d.label)) .attr("stroke-width", Configuration.bars.default.strokeWidth); @@ -160,14 +203,14 @@ export class BarChart extends BaseAxisChart { .enter() .append("rect") .attr("class", "bar") - .attr("x", d => this.x1(d.datasetLabel)) + .attr("x", this.getBarX.bind(this)) .attr("y", d => this.y(Math.max(0, d.value))) .attr("width", this.x1.bandwidth()) .attr("height", d => Math.abs(this.y(d.value) - this.y(0))) - .attr("opacity", 0) + .style("opacity", 0) .transition(this.getFillTransition()) .attr("fill", d => this.getFillScale()[d.datasetLabel](d.label)) - .attr("opacity", 1) + .style("opacity", 1) .attr("stroke", (d: any) => this.colorScale[d.datasetLabel](d.label)) .attr("stroke-width", Configuration.bars.default.strokeWidth); @@ -205,7 +248,8 @@ export class BarChart extends BaseAxisChart { if (g) { g.transition(animate ? this.getDefaultTransition() : this.getInstantTransition()) - .attr("transform", d => `translate(${this.x(d)}, 0)`); + .attr("transform", d => `translate(${this.x(d)}, 0)`) + .style("opacity", 1); } // Update existing bars @@ -213,7 +257,8 @@ export class BarChart extends BaseAxisChart { .transition(animate ? this.getFillTransition() : this.getInstantTransition()) // TODO // .ease(d3.easeCircle) - .attr("x", d => this.x1(d.datasetLabel)) + .style("opacity", 1) + .attr("x", this.getBarX.bind(this)) .attr("y", d => this.y(Math.max(0, d.value))) .attr("width", this.x1.bandwidth()) .attr("height", d => Math.abs(this.y(d.value) - this.y(0))) diff --git a/packages/core/src/base-axis-chart.ts b/packages/core/src/base-axis-chart.ts index 9fb2256eba..001dc45f38 100644 --- a/packages/core/src/base-axis-chart.ts +++ b/packages/core/src/base-axis-chart.ts @@ -15,14 +15,19 @@ export class BaseAxisChart extends BaseChart { y2: any; thresholdDimensions: any; + options: any = Object.assign({}, Configuration.options.AXIS); + constructor(holder: Element, configs: any) { super(holder, configs); - const { axis } = configs.options; - if (axis) { - this.x = axis.x; - this.y = axis.y; - this.y2 = axis.y2; + if (configs.options) { + this.options = Object.assign({}, this.options, configs.options); + const { axis } = configs.options; + if (axis) { + this.x = axis.x; + this.y = axis.y; + this.y2 = axis.y2; + } } } @@ -172,10 +177,14 @@ export class BaseAxisChart extends BaseChart { // Reposition the legend this.positionLegend(); - if (this.innerWrap.select(".axis-label.x").nodes().length > 0 && this.options.scales.x.title) { + if (this.innerWrap.select(".axis-label.x").nodes().length > 0 || this.options.scales.x.title) { this.repositionXAxisTitle(); } + if (this.innerWrap.select(".axis-label.y").nodes().length > 0 || this.options.scales.y.title) { + this.repositionYAxisTitle(); + } + this.dispatchEvent("resize"); } @@ -260,6 +269,27 @@ export class BaseAxisChart extends BaseChart { .text(this.options.scales.x.title); } + repositionYAxisTitle() { + const yAxisRef = this.svg.select("g.y.axis"); + const tickHeight = this.getLargestTickHeight(yAxisRef.selectAll(".tick")); + + const yAxisTitleRef = this.svg.select("g.y.axis text.y.axis-label"); + + const yAxisCenter = yAxisRef.node().getBBox().height / 2; + const yAxisLabelWidth = this.innerWrap.select(".axis-label.y").node().getBBox().width; + + const yAxisTitleTranslate = { + x: - yAxisCenter + yAxisLabelWidth / 2, + y: - (tickHeight + Configuration.scales.tick.heightAddition) + }; + + // Align y axis title with y axis + yAxisTitleRef.attr("class", "y axis-label") + .attr("text-align", "center") + .attr("transform", `rotate(-90) translate(${yAxisTitleTranslate.x}, ${yAxisTitleTranslate.y})`) + .text(this.options.scales.y.title); + } + getYMax() { const { datasets } = this.displayData; const { scales } = this.options; @@ -362,6 +392,27 @@ export class BaseAxisChart extends BaseChart { .attr("stroke-width", Configuration.scales.domain.strokeWidth); } + const tickHeight = this.getLargestTickHeight(yAxisRef.selectAll(".tick")); + + // Add y-axis title + if (this.innerWrap.select(".axis-label.y").nodes().length === 0 && this.options.scales.y.title) { + yAxisRef.append("text") + .attr("class", "y axis-label") + .text(this.options.scales.y.title); + + const yAxisCenter = yAxisRef.node().getBBox().height / 2; + const yAxisLabelWidth = this.innerWrap.select(".axis-label.y").node().getBBox().width; + + const yAxisTitleTranslate = { + x: - yAxisCenter + yAxisLabelWidth / 2, + y: - (tickHeight + Configuration.scales.tick.heightAddition) + }; + + // Align y axis title on the y axis + this.innerWrap.select(".axis-label.y") + .attr("transform", `rotate(-90) translate(${yAxisTitleTranslate.x}, ${yAxisTitleTranslate.y})`); + } + Tools.moveToFront(horizontalLine); if (scales.y2 && scales.y2.ticks.max) { @@ -475,9 +526,9 @@ export class BaseAxisChart extends BaseChart { .attr("width", width) .attr("height", d => calculateHeight(d)) .attr("fill", d => Configuration.scales.y.thresholds.colors[d.theme]) - .attr("opacity", 0) + .style("opacity", 0) .transition(t) - .attr("opacity", d => calculateOpacity(d)); + .style("opacity", d => calculateOpacity(d)); // Update thresholds thresholdRects @@ -486,7 +537,7 @@ export class BaseAxisChart extends BaseChart { .attr("y", d => calculateYPosition(d)) .attr("width", width) .attr("height", d => calculateHeight(d)) - .attr("opacity", d => calculateOpacity(d)) + .style("opacity", d => calculateOpacity(d)) .attr("fill", d => Configuration.scales.y.thresholds.colors[d.theme]); // Applies to thresholds getting removed diff --git a/packages/core/src/base-chart.ts b/packages/core/src/base-chart.ts index 2324edb1b8..965a1e4569 100644 --- a/packages/core/src/base-chart.ts +++ b/packages/core/src/base-chart.ts @@ -46,8 +46,6 @@ export class BaseChart { tooltips: null }; - - constructor(holder: Element, configs: any) { this.id = `chart-${BaseChart.chartCount++}`; @@ -413,20 +411,12 @@ export class BaseChart { resetOpacity() { const svg = selectAll("svg.chart-svg"); - svg.selectAll("path").attr("fill-opacity", Configuration.charts.resetOpacity.opacity); - - svg.selectAll("circle") - .attr("stroke-opacity", Configuration.charts.resetOpacity.opacity) - .attr("fill", Configuration.charts.resetOpacity.circle.fill); svg.selectAll("rect") .attr("fill-opacity", Configuration.charts.resetOpacity.opacity) .attr("stroke-opacity", Configuration.charts.resetOpacity.opacity); } reduceOpacity(exception) { - // this.svg.selectAll("rect, path").attr("fill-opacity", Configuration.charts.reduceOpacity.opacity); - // this.svg.selectAll("rect, path").attr("stroke-opacity", Configuration.charts.reduceOpacity.opacity); - const exceptedElement = select(exception); const exceptedElementData = exceptedElement.datum() as any; select(exception).attr("fill-opacity", false); @@ -852,6 +842,17 @@ export class BaseChart { this.holder.removeEventListener("click", this.eventHandlers.tooltips); } + generateTooltipHTML(label, value) { + if (this.options.tooltip.size === Configuration.tooltip.size.COMPACT) { + return `${label}: ${value}
`; + } else { + return ` +

${label}

+

${value}

+ `; + } + } + showTooltip(d, clickedElement) { // Rest opacity of all elements in the chart this.resetOpacity(); @@ -869,13 +870,9 @@ export class BaseChart { let tooltipHTML = ""; const formattedValue = this.options.tooltip.formatter ? this.options.tooltip.formatter(d.value) : d.value.toLocaleString("en"); if (this.getLegendType() === Configuration.legend.basedOn.LABELS) { - tooltipHTML += ` - ${d.label}: ${formattedValue}
- `; + tooltipHTML += this.generateTooltipHTML(d.label, formattedValue); } else { - tooltipHTML += ` - ${d.datasetLabel}: ${formattedValue}
- `; + tooltipHTML += this.generateTooltipHTML(d.datasetLabel, formattedValue); } tooltip.append("div").attr("class", "text-box").html(tooltipHTML); diff --git a/packages/core/src/configuration.ts b/packages/core/src/configuration.ts index 6760a821cf..536dc8fc9f 100644 --- a/packages/core/src/configuration.ts +++ b/packages/core/src/configuration.ts @@ -43,6 +43,10 @@ const axisOptions: any = Object.assign({}, baseOptions, { domain: null, ticks: 10 } + }, + // Only used for line chart + points: { + radius: null } }); @@ -81,7 +85,7 @@ export const charts = { opacity: 0.25, outline: "grey" }, - pointCircles: { + points: { radius: 4 }, patternFills: { @@ -162,12 +166,16 @@ export const bars = { spacing: { bars: 0.2, datasets: 0.25 + }, + bars: { + maxWidth: null } }; export const lines = { points: { strokeWidth: 4, + minNonFilledRadius: 4, mouseover: { strokeWidth: 4, strokeOpacity: 0.5 @@ -258,6 +266,9 @@ export const tooltip = { }, fadeOut: { duration: 250 + }, + size: { + COMPACT: "compact" } }; diff --git a/packages/core/src/line-chart.ts b/packages/core/src/line-chart.ts index 5694baebe0..1eb47d2770 100644 --- a/packages/core/src/line-chart.ts +++ b/packages/core/src/line-chart.ts @@ -1,5 +1,5 @@ // D3 Imports -import { select, mouse } from "d3-selection"; +import { select, selectAll, mouse } from "d3-selection"; import { line } from "d3-shape"; import { BaseAxisChart } from "./base-axis-chart"; @@ -35,6 +35,15 @@ export class LineChart extends BaseAxisChart { })); } + getCircleRadius() { + return this.options.points.radius || Configuration.charts.points.radius; + } + + getCircleFill(radius, d) { + const circleShouldBeFilled = radius < Configuration.lines.points.minNonFilledRadius; + return circleShouldBeFilled ? this.colorScale[d.datasetLabel](d.label) : "white"; + } + draw() { this.innerWrap.style("width", "100%") .style("height", "100%"); @@ -81,6 +90,7 @@ export class LineChart extends BaseAxisChart { .attr("class", "line") .attr("d", this.lineGenerator); + const circleRadius = this.getCircleRadius(); gLines.selectAll("circle.dot") .data((d, i) => this.addLabelsToDataPoints(d, i)) .enter() @@ -88,7 +98,8 @@ export class LineChart extends BaseAxisChart { .attr("class", "dot") .attr("cx", d => this.x(d.label) + this.x.step() / 2) .attr("cy", d => this.y(d.value)) - .attr("r", Configuration.charts.pointCircles.radius) + .attr("r", circleRadius) + .attr("fill", d => this.getCircleFill(circleRadius, d)) .attr("stroke", d => this.colorScale[d.datasetLabel](d.label)); // Hide the overlay @@ -104,6 +115,9 @@ export class LineChart extends BaseAxisChart { const width = chartSize.width - margins.left - margins.right; const height = chartSize.height - this.getBBox(".x.axis").height; + this.innerWrap.selectAll(".removed") + .remove(); + // Apply new data to the lines const gLines = this.innerWrap.selectAll("g.lines") .data(newData.datasets); @@ -125,6 +139,7 @@ export class LineChart extends BaseAxisChart { .attr("d", this.lineGenerator); // Add line circles + const circleRadius = this.getCircleRadius(); addedLineGroups.selectAll("circle.dot") .data((d, i) => this.addLabelsToDataPoints(d, i)) .enter() @@ -132,14 +147,16 @@ export class LineChart extends BaseAxisChart { .attr("class", "dot") .attr("cx", (d, i) => this.x(d.label) + this.x.step() / 2) .attr("cy", (d: any) => this.y(d.value)) - .attr("r", 4) + .attr("r", circleRadius) .style("opacity", 0) .transition(this.getDefaultTransition()) .style("opacity", 1) + .attr("fill", d => this.getCircleFill(circleRadius, d)) .attr("stroke", d => this.colorScale[d.datasetLabel](d.label)); // Remove lines that are no longer needed gLines.exit() + .classed("removed", true) // mark this element with "removed" class so it isn't reused .transition(this.getDefaultTransition()) .style("opacity", 0) .remove(); @@ -173,6 +190,7 @@ export class LineChart extends BaseAxisChart { return parentDatum.data; }) .transition(transitionToUse) + .style("opacity", 1) .attr("stroke", function(d) { const parentDatum = select(this.parentNode).datum() as any; @@ -182,6 +200,7 @@ export class LineChart extends BaseAxisChart { .attr("d", this.lineGenerator); const { line: margins } = Configuration.charts.margin; + const circleRadius = this.getCircleRadius(); gLines.selectAll("circle.dot") .data(function(d, i) { const parentDatum = select(this).datum() as any; @@ -191,7 +210,8 @@ export class LineChart extends BaseAxisChart { .transition(transitionToUse) .attr("cx", d => this.x(d.label) + this.x.step() / 2) .attr("cy", d => this.y(d.value)) - .attr("r", Configuration.lines.points.strokeWidth) + .attr("r", circleRadius) + .attr("fill", d => this.getCircleFill(circleRadius, d)) .attr("stroke", d => this.colorScale[d.datasetLabel](d.label)); } @@ -224,6 +244,20 @@ export class LineChart extends BaseAxisChart { this.x.padding(0); // override BaseAxisChart padding so points aren't misaligned by a few pixels } + resetOpacity() { + const circleRadius = this.getCircleRadius(); + this.innerWrap.selectAll("circle") + .attr("stroke-opacity", Configuration.charts.resetOpacity.opacity) + .attr("fill", d => this.getCircleFill(circleRadius, d)); + } + + reduceOpacity(exception) { + const circleRadius = this.getCircleRadius(); + select(exception).attr("fill-opacity", false); + select(exception).attr("stroke-opacity", Configuration.charts.reduceOpacity.opacity); + select(exception).attr("fill", (d: any) => this.getCircleFill(circleRadius, d)); + } + addDataPointEventListener() { const self = this; const { accessibility } = this.options; diff --git a/packages/core/src/pie-chart.ts b/packages/core/src/pie-chart.ts index 024a9c699a..4dfa18ce98 100644 --- a/packages/core/src/pie-chart.ts +++ b/packages/core/src/pie-chart.ts @@ -159,6 +159,7 @@ export class PieChart extends BaseChart { .attr("stroke-width", Configuration.pie.default.strokeWidth) .attr("stroke-opacity", d => this.options.accessibility ? 1 : 0) .transition() + .style("opacity", 1) .duration(Configuration.transitions.default.duration) .attr("fill", d => this.getFillScale()[this.displayData.datasets[0].label](d.data.label)) .attrTween("d", function (a) { @@ -264,10 +265,7 @@ export class PieChart extends BaseChart { .style("top", mouse(this.holder as SVGSVGElement)[1] - Configuration.tooltip.magicTop2 + "px"); const dVal = d.value.toLocaleString(); - const tooltipHTML = ` -

${dVal}

-

${d.data.label}

- `; + const tooltipHTML = this.generateTooltipHTML(d.data.label, dVal); tooltip.append("div").attr("class", "text-box").html(tooltipHTML); if (mouse(this.holder as SVGSVGElement)[0] + (tooltip.node() as Element).clientWidth > this.holder.clientWidth) { diff --git a/packages/core/src/stacked-bar-chart.ts b/packages/core/src/stacked-bar-chart.ts index acf0888931..345e452dac 100644 --- a/packages/core/src/stacked-bar-chart.ts +++ b/packages/core/src/stacked-bar-chart.ts @@ -68,6 +68,9 @@ export class StackedBarChart extends BaseAxisChart { return stackDataArray; } + // currently unused, but required to match the BarChart class + getBarX(d) {} + draw() { this.innerWrap.style("width", "100%") .style("height", "100%"); @@ -110,6 +113,9 @@ export class StackedBarChart extends BaseAxisChart { const stackDataArray = this.getStackData(); const stackKeys = this.displayData.datasets.map(dataset => dataset.label); + this.innerWrap.selectAll(".removed") + .remove(); + const g = this.innerWrap.selectAll("g.bars-wrapper") .selectAll("g") .data(stack().keys(stackKeys)(stackDataArray)); @@ -128,9 +134,9 @@ export class StackedBarChart extends BaseAxisChart { .attr("height", d => this.y(d[0]) - this.y(d[1])) .attr("width", d => this.x.bandwidth()) .attr("fill", d => this.getFillScale()[d.datasetLabel](d.data.label)) - .attr("opacity", 0) + .style("opacity", 0) .transition(this.getFillTransition()) - .attr("opacity", 1) + .style("opacity", 1) .attr("stroke", d => this.options.accessibility ? this.colorScale[d.datasetLabel](d.data.label) : null) .attr("stroke-width", Configuration.bars.default.strokeWidth) .attr("stroke-opacity", d => this.options.accessibility ? 1 : 0); @@ -146,11 +152,13 @@ export class StackedBarChart extends BaseAxisChart { addRect(rect); g.exit() + .classed("removed", true) // mark this element with "removed" class so it isn't reused .transition(this.getDefaultTransition()) .style("opacity", 0) .remove(); rect.exit() + .classed("removed", true) // mark this element with "removed" class so it isn't reused .transition(this.getDefaultTransition()) .style("opacity", 0) .remove(); @@ -198,6 +206,7 @@ export class StackedBarChart extends BaseAxisChart { // Update existing bars rect .transition(animate ? this.getFillTransition() : this.getInstantTransition()) + .style("opacity", 1) .attr("x", d => this.x(d.data.label)) .attr("y", d => this.y(d[1])) .attr("height", d => this.y(d[0]) - this.y(d[1])) diff --git a/packages/core/src/style.scss b/packages/core/src/style.scss index fe5167ba13..136c225c1c 100644 --- a/packages/core/src/style.scss +++ b/packages/core/src/style.scss @@ -56,7 +56,6 @@ div.chart-holder { circle { &.dot { - fill: #fff; stroke-width: 2; } } @@ -69,6 +68,11 @@ div.chart-holder { stroke-width: .3; @include fonts(); + &.title{ + font-size: 18px; + font-weight: bold; + } + &.donut { &-figure { font-size: 24px; diff --git a/packages/core/src/tools.ts b/packages/core/src/tools.ts index b689645a3d..ea9da9404c 100644 --- a/packages/core/src/tools.ts +++ b/packages/core/src/tools.ts @@ -210,4 +210,16 @@ export namespace Tools { return transformMatrixArray[4]; } + + export const getProperty = (object, ...propPath) => { + let position = object; + for (const prop of propPath) { + if (position[prop]) { + position = position[prop]; + } else { + return null; + } + } + return position; + }; } diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index 950d0b4ac9..a593ec85c3 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -3,6 +3,65 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [0.9.7](https://github.com/IBM/carbon-charts/compare/v0.9.6...v0.9.7) (2019-02-22) + +**Note:** Version bump only for package @carbon/charts-react + + + + + +## [0.9.6](https://github.com/IBM/carbon-charts/compare/v0.9.4...v0.9.6) (2019-02-21) + + +### Bug Fixes + +* **bar:** add maxWidth and other bar fixes ([3866d86](https://github.com/IBM/carbon-charts/commit/3866d86)) + + + + + +## [0.9.5](https://github.com/IBM/carbon-charts/compare/v0.9.4...v0.9.5) (2019-02-20) + +**Note:** Version bump only for package @carbon/charts-react + + + + + +## [0.9.4](https://github.com/IBM/carbon-charts/compare/v0.9.3...v0.9.4) (2019-02-16) + +**Note:** Version bump only for package @carbon/charts-react + + + + + +## [0.9.3](https://github.com/IBM/carbon-charts/compare/v0.9.2...v0.9.3) (2019-02-15) + +**Note:** Version bump only for package @carbon/charts-react + + + + + +## [0.9.2](https://github.com/IBM/carbon-charts/compare/v0.9.1...v0.9.2) (2019-02-15) + +**Note:** Version bump only for package @carbon/charts-react + + + + + +## [0.9.1](https://github.com/IBM/carbon-charts/compare/v0.9.0...v0.9.1) (2019-02-07) + +**Note:** Version bump only for package @carbon/charts-react + + + + + # [0.9.0](https://github.com/IBM/carbon-charts/compare/v0.8.6...v0.9.0) (2019-01-28) **Note:** Version bump only for package @carbon/charts-react diff --git a/packages/react/package.json b/packages/react/package.json index 6413a7481a..5c73e4eb34 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@carbon/charts-react", - "version": "0.9.0", + "version": "0.9.7", "description": "Carbon charting components for React", "main": "index.js", "files": [ @@ -27,7 +27,7 @@ }, "homepage": "https://github.com/IBM/carbon-charts#readme", "dependencies": { - "@carbon/charts": "^0.9.0", + "@carbon/charts": "^0.9.7", "react": "16.6.3", "react-dom": "16.6.3" },