Skip to content

Commit

Permalink
fix(gauge): Correct background rendering on fullCircle (#141)
Browse files Browse the repository at this point in the history
* fix(gauge): Correct background rendering on fullCircle

- Correct to draw full circle background when fullCircle options is set
- Changed max text label display on fullCircle
- Add missing gauge API docs

Close #140
Fixed #141
  • Loading branch information
netil authored and sculove committed Sep 20, 2017
1 parent 7709c32 commit 7f5fda2
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 66 deletions.
139 changes: 96 additions & 43 deletions spec/arc-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,17 @@ describe("ARC", () => {
});

it("should have correct classes", () => {
const chartArc = chart.internal.main.select(".bb-chart-arcs");
const chartArc = chart.internal.main.select(`.${CLASS.chartArcs}`);
const arcs = {
data1: chartArc.select(".bb-chart-arc.bb-target.bb-target-data1")
.select("g.bb-shapes.bb-shapes-data1.bb-arcs.bb-arcs-data1")
.select("path.bb-shape.bb-shape.bb-arc.bb-arc-data1"),
data2: chartArc.select(".bb-chart-arc.bb-target.bb-target-data2")
.select("g.bb-shapes.bb-shapes-data2.bb-arcs.bb-arcs-data2")
.select("path.bb-shape.bb-shape.bb-arc.bb-arc-data2"),
data3: chartArc.select(".bb-chart-arc.bb-target.bb-target-data3")
.select("g.bb-shapes.bb-shapes-data3.bb-arcs.bb-arcs-data3")
.select("path.bb-shape.bb-shape.bb-arc.bb-arc-data3")
data1: chartArc.select(`.${CLASS.chartArc}.${CLASS.target}.${CLASS.target}-data1`)
.select(`g.${CLASS.shapes}.${CLASS.shapes}-data1.${CLASS.arcs}.${CLASS.arcs}-data1`)
.select(`path.${CLASS.shape}.${CLASS.arc}.${CLASS.arc}-data1`),
data2: chartArc.select(`.${CLASS.chartArc}.${CLASS.target}.${CLASS.target}-data2`)
.select(`g.${CLASS.shapes}.${CLASS.shapes}-data2.${CLASS.arcs}.${CLASS.arcs}-data2`)
.select(`path.${CLASS.shape}.${CLASS.arc}.${CLASS.arc}-data2`),
data3: chartArc.select(`.${CLASS.chartArc}.${CLASS.target}.${CLASS.target}-data3`)
.select(`g.${CLASS.shapes}.${CLASS.shapes}-data3.${CLASS.arcs}.${CLASS.arcs}-data3`)
.select(`path.${CLASS.shape}.${CLASS.arc}.${CLASS.arc}-data3`)
};

expect(arcs.data1.size()).to.be.equal(1);
Expand All @@ -41,9 +41,9 @@ describe("ARC", () => {
it("should have correct d", () => {
const main = chart.internal.main;

expect(main.select(".bb-arc-data1").attr("d")).to.match(/M-124\..+,-171\..+A211\..+,211\..+,0,0,1,-3\..+,-211\..+L0,0Z/);
expect(main.select(".bb-arc-data2").attr("d")).to.match(/M1\..+,-211\..+A211\..+,211\..+,0,0,1,1\..+,211\..+L0,0Z/);
expect(main.select(".bb-arc-data3").attr("d")).to.match(/M1\..+,211\..+A211\..+,211\..+,0,0,1,-124\..+,-171\..+L0,0Z/);
expect(main.select(`.${CLASS.arc}-data1`).attr("d")).to.match(/M-124\..+,-171\..+A211\..+,211\..+,0,0,1,-3\..+,-211\..+L0,0Z/);
expect(main.select(`.${CLASS.arc}-data2`).attr("d")).to.match(/M1\..+,-211\..+A211\..+,211\..+,0,0,1,1\..+,211\..+L0,0Z/);
expect(main.select(`.${CLASS.arc}-data3`).attr("d")).to.match(/M1\..+,211\..+A211\..+,211\..+,0,0,1,-124\..+,-171\..+L0,0Z/);
});

it("should have correct d even if data id can be converted to a color", done => {
Expand All @@ -59,7 +59,7 @@ describe("ARC", () => {
});

setTimeout(() => {
expect(chart.internal.main.select(".bb-arc-black").attr("d"))
expect(chart.internal.main.select(`.${CLASS.arc}-black`).attr("d"))
.to.match(/M-124\..+,-171\..+A211\..+,211\..+,0,0,1,-3\..+,-211\..+L0,0Z/);

done();
Expand All @@ -80,17 +80,17 @@ describe("ARC", () => {
});

it("should have correct d attribute", () => {
const chartArc = chart.internal.main.select(".bb-chart-arcs");
const chartArc = chart.internal.main.select(`.${CLASS.chartArcs}`);
const arcs = {
data1: chartArc.select(".bb-chart-arc.bb-target.bb-target-data1")
.select("g.bb-shapes.bb-shapes-data1.bb-arcs.bb-arcs-data1")
.select("path.bb-shape.bb-shape.bb-arc.bb-arc-data1"),
data2: chartArc.select(".bb-chart-arc.bb-target.bb-target-data2")
.select("g.bb-shapes.bb-shapes-data2.bb-arcs.bb-arcs-data2")
.select("path.bb-shape.bb-shape.bb-arc.bb-arc-data2"),
data3: chartArc.select(".bb-chart-arc.bb-target.bb-target-data3")
.select("g.bb-shapes.bb-shapes-data3.bb-arcs.bb-arcs-data3")
.select("path.bb-shape.bb-shape.bb-arc.bb-arc-data3")
data1: chartArc.select(`.${CLASS.chartArc}.${CLASS.target}.${CLASS.target}-data1`)
.select(`g.${CLASS.shapes}.${CLASS.shapes}-data1.${CLASS.arcs}.${CLASS.arcs}-data1`)
.select(`path.${CLASS.shape}.${CLASS.arc}.${CLASS.arc}-data1`),
data2: chartArc.select(`.${CLASS.chartArc}.${CLASS.target}.${CLASS.target}-data2`)
.select(`g.${CLASS.shapes}.${CLASS.shapes}-data2.${CLASS.arcs}.${CLASS.arcs}-data2`)
.select(`path.${CLASS.shape}.${CLASS.arc}.${CLASS.arc}-data2`),
data3: chartArc.select(`.${CLASS.chartArc}.${CLASS.target}.${CLASS.target}-data3`)
.select(`g.${CLASS.shapes}.${CLASS.shapes}-data3.${CLASS.arcs}.${CLASS.arcs}-data3`)
.select(`path.${CLASS.shape}.${CLASS.arc}.${CLASS.arc}-data3`)
};

expect(arcs.data1.attr("d").indexOf("NaN")).to.be.equal(-1);
Expand Down Expand Up @@ -135,13 +135,14 @@ describe("ARC", () => {
}
});

setTimeout(() => {
const chartArc = chart.internal.main.select(".bb-chart-arcs");
const data = chartArc.select(".bb-chart-arc.bb-target.bb-target-data")
.select("g.bb-shapes.bb-shapes-data.bb-arcs.bb-arcs-data")
.select("path.bb-shape.bb-shape.bb-arc.bb-arc-data");
const chartArc = chart.internal.main.select(`.${CLASS.chartArcs}`);
const data = chartArc.select(`.${CLASS.chartArc}.${CLASS.target}.${CLASS.target}-data`)
.select(`g.${CLASS.shapes}.${CLASS.shapes}-data.${CLASS.arcs}.${CLASS.arcs}-data`)
.select(`path.${CLASS.shape}.${CLASS.arc}.${CLASS.arc}-data`);

setTimeout(() => {
expect(data.attr("d")).to.match(/M-304,-3\..+A304,304,0,0,1,245\..+,-178\..+L237\..+,-172\..+A294,294,0,0,0,-294,-3\..+Z/);
expect(chartArc.select(`.${CLASS.gaugeValue}`).attr("dy")).to.be.equal("-.1em");

done();
}, 500);
Expand All @@ -159,24 +160,24 @@ describe("ARC", () => {
columns: [
["data", 8]
],
type: "gauge",
fullCircle: true,
startingAngle: Math.PI/2
type: "gauge"
}
});

const chartArc = chart.internal.main.select(".bb-chart-arcs");
const data = chartArc.select(".bb-chart-arc.bb-target.bb-target-data")
.select("g.bb-shapes.bb-shapes-data.bb-arcs.bb-arcs-data")
.select("path.bb-shape.bb-shape.bb-arc.bb-arc-data");
const chartArc = chart.internal.main.select(`.${CLASS.chartArcs}`);
const data = chartArc.select(`.${CLASS.chartArc}.${CLASS.target}.${CLASS.target}-data`)
.select(`g.${CLASS.shapes}.${CLASS.shapes}-data.${CLASS.arcs}.${CLASS.arcs}-data`)
.select(`path.${CLASS.shape}.${CLASS.arc}.${CLASS.arc}-data`);

setTimeout(() => {
// This test has bee updated to make tests pass. @TODO double-check this test is accurate.
expect(data.attr("d")).to.match(/M-221.*?,-2\..+A221.*?,221.*?,0,1,1,-68.*?,210.*?L-65.*?,201.*?A211.*?,211.*?,0,1,0,-211.*?,-2.*?Z/);
done();
}, 500);
});

it("should show custom min/max guage labels", () => {

it("should show custom min/max gauge labels", () => {
const chart = util.generate({
gauge: {
width: 10,
Expand All @@ -196,18 +197,70 @@ describe("ARC", () => {
columns: [
["data", 8]
],
type: "gauge",
fullCircle: true,
startingAngle: Math.PI/2
type: "gauge"
}
});

const chartArc = chart.internal.main.select(".bb-chart-arcs");
const min = chartArc.select(".bb-chart-arcs-gauge-min");
const max = chartArc.select(".bb-chart-arcs-gauge-max");
const chartArc = chart.internal.main.select(`.${CLASS.chartArcs}`);
const min = chartArc.select(`.${CLASS.chartArcsGaugeMin}`);
const max = chartArc.select(`.${CLASS.chartArcsGaugeMax}`);

expect(min.text()).to.equal("Min: 0%");
expect(max.text()).to.equal("Max: 100%");
});

it("should not show gauge labels", () => {
const chart = util.generate({
gauge: {
label: {
show: false
}
},
data: {
columns: [
["data", 75]
],
type: "gauge"
}
});

const chartArc = chart.internal.main.select(`.${CLASS.chartArcs}`);
const min = chartArc.select(`.${CLASS.chartArcsGaugeMin}`);
const max = chartArc.select(`.${CLASS.chartArcsGaugeMax}`)

expect(min.empty()).to.be.true;
expect(max.empty()).to.be.true;
});

it("check for fullCircle option", () => {
const chart = util.generate({
gauge: {
width: 10,
max: 10,
expand: true,
fullCircle: true
},
data: {
columns: [
["data", 75]
],
type: "gauge"
}
});

const chartArc = chart.internal.main.select(`.${CLASS.chartArcs}`);
const min = chartArc.select(`.${CLASS.chartArcsGaugeMin}`);
const max = chartArc.select(`.${CLASS.chartArcsGaugeMax}`)

// check if gauge value text is centered
expect(+chartArc.select(`.${CLASS.gaugeValue}`).attr("dy")).to.be.above(0);

// check background height
expect(chartArc.select(`.${CLASS.chartArcsBackground}`).node().getBBox().height).to.be.above(400);

// with fullCircle option, only min text is showed
expect(min.empty()).to.be.false;
expect(max.empty()).to.be.true;
});
});
});
14 changes: 12 additions & 2 deletions src/config/Options.js
Original file line number Diff line number Diff line change
Expand Up @@ -2175,25 +2175,35 @@ export default class Options {
* @name gauge
* @memberof Options
* @type {Object}
* @property {Boolean} [gauge.fullCircle=false]
* @property {Boolean} [gauge.fullCircle=false] Show full circle as donut. When set to 'true', the max label will not be showed due to start and end points are same location.
* @property {Boolean} [gauge.label.show=true] Show or hide label on gauge.
* @property {Function} [gauge.label.format] Set formatter for the label on gauge.
* @property {Function} [gauge.label.extents] Set customized min/max label text.
* @property {Boolean} [gauge.expand=true] Enable or disable expanding gauge.
* @property {Number} [gauge.expand.duration=50]
* @property {Number} [gauge.expand.duration=50] Set the expand transition time in milliseconds.
* @property {Number} [gauge.min=0] Set min value of the gauge.
* @property {Number} [gauge.max=100] Set max value of the gauge.
* @property {Number} [gauge.startingAngle=-1 * Math.PI / 2]
* @property {String} [gauge.units] Set units of the gauge.
* @property {Number} [gauge.width] Set width of gauge chart.
* @example
* gauge: {
* fullCircle: false,
* label: {
* show: false,
* format: function(value, ratio) {
* return value;
* },
* extents: function(value, isMax) {
* return (isMax ? "Max:" : "Min:") + value;
* }
* },
* expand: false,
*
* // or set duration
* expand: {
* duration: 20
* },
* min: -100,
* max: 200,
* units: "%",
Expand Down
61 changes: 40 additions & 21 deletions src/internals/arc.js
Original file line number Diff line number Diff line change
Expand Up @@ -608,10 +608,14 @@ extend(ChartInternal.prototype, {
}
}

main.selectAll(`.${CLASS.chartArc}`)
const gaugeTextValue = main.selectAll(`.${CLASS.chartArc}`)
.select("text")
.style("opacity", "0")
.attr("class", d => ($$.isGaugeType(d.data) ? CLASS.gaugeValue : ""))
.attr("class", d => ($$.isGaugeType(d.data) ? CLASS.gaugeValue : ""));

config.gauge_fullCircle && gaugeTextValue.attr("dy", `${Math.round($$.radius / 14)}`);

gaugeTextValue
.text($$.textForArcLabel.bind($$))
.attr("transform", $$.transformForArcLabel.bind($$))
.style("font-size", d => ($$.isGaugeType(d.data) ? `${Math.round($$.radius / 5)}px` : ""))
Expand All @@ -623,48 +627,63 @@ extend(ChartInternal.prototype, {
.style("opacity", $$.hasType("donut") || $$.hasType("gauge") ? "1" : "0");

if ($$.hasType("gauge")) {
const endAngle = (config.gauge_fullCircle ? -4 : -1) * config.gauge_startingAngle;

$$.arcs.select(`.${CLASS.chartArcsBackground}`)
.attr("d", () => {
const d = {
data: [{value: config.gauge_max}],
startAngle: config.gauge_startingAngle,
endAngle: -1 * config.gauge_startingAngle
endAngle: endAngle
};

return $$.getArc(d, true, true);
});

$$.arcs.select(`.${CLASS.chartArcsGaugeUnit}`)
.attr("dy", ".75em")
.text(config.gauge_label_show ? config.gauge_units : "");
$$.arcs.select(`.${CLASS.chartArcsGaugeMin}`)
.attr("dx", `${-1 * ($$.innerRadius + (($$.radius - $$.innerRadius) / (config.gauge_fullCircle ? 1 : 2)))}px`)
.attr("dy", "1.2em")
.text(config.gauge_label_show ? $$.textForGaugeMinMax(config.gauge_min, false) : "");
$$.arcs.select(`.${CLASS.chartArcsGaugeMax}`)
.attr("dx", `${$$.innerRadius + (($$.radius - $$.innerRadius) / (config.gauge_fullCircle ? 1 : 2))}px`)
.attr("dy", "1.2em")
.text(config.gauge_label_show ? $$.textForGaugeMinMax(config.gauge_max, true) : "");

if (config.gauge_label_show) {
$$.arcs.select(`.${CLASS.chartArcsGaugeMin}`)
.attr("dx", `${-1 * ($$.innerRadius + (($$.radius - $$.innerRadius) / (config.gauge_fullCircle ? 1 : 2)))}px`)
.attr("dy", "1.2em")
.text($$.textForGaugeMinMax(config.gauge_min, false));

// show max text when isn't fullCircle
!config.gauge_fullCircle && $$.arcs.select(`.${CLASS.chartArcsGaugeMax}`)
.attr("dx", `${$$.innerRadius + (($$.radius - $$.innerRadius) / 2)}px`)
.attr("dy", "1.2em")
.text($$.textForGaugeMinMax(config.gauge_max, true));
}
}
},

initGauge() {
const arcs = this.arcs;
const $$ = this;
const config = $$.config;
const arcs = $$.arcs;

if (this.hasType("gauge")) {
if ($$.hasType("gauge")) {
arcs.append("path")
.attr("class", CLASS.chartArcsBackground);

arcs.append("text")
.attr("class", CLASS.chartArcsGaugeUnit)
.style("text-anchor", "middle")
.style("pointer-events", "none");
arcs.append("text")
.attr("class", CLASS.chartArcsGaugeMin)
.style("text-anchor", "middle")
.style("pointer-events", "none");
arcs.append("text")
.attr("class", CLASS.chartArcsGaugeMax)
.style("text-anchor", "middle")
.style("pointer-events", "none");

if (config.gauge_label_show) {
arcs.append("text")
.attr("class", CLASS.chartArcsGaugeMin)
.style("text-anchor", "middle")
.style("pointer-events", "none");

!config.gauge_fullCircle && arcs.append("text")
.attr("class", CLASS.chartArcsGaugeMax)
.style("text-anchor", "middle")
.style("pointer-events", "none");
}
}
},

Expand Down

0 comments on commit 7f5fda2

Please sign in to comment.