Skip to content

Commit

Permalink
feat(bar): add non zero based bar chart
Browse files Browse the repository at this point in the history
Implement bar ranged feature.

When data is given as [start, end] ranged array for bar type
will render as non zerobased bar.

Fix #2408
Close #2438
  • Loading branch information
ajaxlab authored and netil committed Dec 3, 2021
1 parent ff3cf99 commit 3588abe
Show file tree
Hide file tree
Showing 14 changed files with 624 additions and 432 deletions.
1 change: 1 addition & 0 deletions AUTHORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,4 @@ Sung Oh Park <sung-oh.park@navercorp.com>
Adrian Schmutzler <dev@schmutzler.it>
Aziz Gazanchiyan <ZIZ@KMDPoland.pl>
Eben Collins <collinseben@gmail.com>
Shim Heungwoon <ajaxlab7@gmail.com>
194 changes: 133 additions & 61 deletions demo/demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,35 +84,65 @@ var demos = {
];
}
},
BarChart: {
options: {
data: {
columns: [
["data1", 30, 200, 100, 400, 150, 250],
["data2", 130, 100, 140, 200, 150, 50]
],
type: "bar"
},
bar: {
width: {
ratio: 0.5 // this makes bar width 50% of length between ticks
BarChart: [
{
options: {
data: {
columns: [
["data1", 30, 200, 100, 400, 150, 250],
["data2", 130, 100, 140, 200, 150, 50]
],
type: "bar"
},
bar: {
width: {
ratio: 0.5 // this makes bar width 50% of length between ticks
}
// or
//width: 100 // this makes bar width 100px
}
// or
//width: 100 // this makes bar width 100px
},
func: function(chart) {
chart.timer = [
setTimeout(function() {
chart.load({
columns: [
["data3", 130, -150, 200, 300, -200, 100]
]
});
}, 1000)
];
}
},
func: function(chart) {
chart.timer = [
setTimeout(function() {
chart.load({
columns: [
["data3", 130, -150, 200, 300, -200, 100]
]
});
}, 1000)
];
{
options: {
data: {
columns: [
["data1", -100, 100, 200, [-100, 0], [0, 100], [100, 200]],
["data2", 100, 300, 500, [0, 100], [100, 300], [200, 500]],
],
type: "bar"
},
bar: {
width: {
ratio: 0.5
}
}
},
func: function(chart) {
chart.timer = [
setTimeout(function() {
chart.load({
columns: [
["data3", 200, 500, 800, [100, 200], [300, 500], [500, 800]],
],
type: "bar"
});
}, 1000)
];
}
}
},
],
BubbleChart: {
options: {
data: {
Expand Down Expand Up @@ -195,7 +225,7 @@ var demos = {
options: {
data: {
columns: [
["data1",
["data1",
// open, high, low, close, volume (optional)
[1327,1369,1289,1348],
[1348,1371,1314,1320],
Expand Down Expand Up @@ -269,7 +299,7 @@ var demos = {
x: "x",
columns: [
["x", "2021-02-20", "2021-02-21"],
["data1",
["data1",
// open, high, low, close, volume (optional)
{open: 1300, high: 1369, low: 1200, close: 1339, volume: 100},
{open: 1348, high: 1371, low: 1271, close: 1320},
Expand Down Expand Up @@ -720,43 +750,85 @@ var demos = {
}
}
},
StackedBarChart: {
options: {
data: {
columns: [
["data1", -30, 200, 200, 400, -150, 250],
["data2", 130, 100, -100, 200, -150, 50],
["data3", -230, 200, 200, -300, 250, 250]
],
type: "bar",
groups: [
["data1", "data2"]
]
},
grid: {
y: {
lines: [{value: 0}]
StackedBarChart: [
{
options: {
data: {
columns: [
["data1", -30, 200, 200, 400, -150, 250],
["data2", 130, 100, -100, 200, -150, 50],
["data3", -230, 200, 200, -300, 250, 250]
],
type: "bar",
groups: [
["data1", "data2"]
]
},
grid: {
y: {
lines: [{value: 0}]
}
}
},
func: function(chart) {
chart.timer = [
setTimeout(function() {
chart.groups([["data1", "data2", "data3"]])
}, 1000),

setTimeout(function() {
chart.load({
columns: [["data4", 100, -50, 150, 200, -300, -100]]
});
}, 1500),

setTimeout(function() {
chart.groups([["data1", "data2", "data3", "data4"]])
}, 2000)
];
}
},
func: function(chart) {
chart.timer = [
setTimeout(function() {
chart.groups([["data1", "data2", "data3"]])
}, 1000),
{
options: {
data: {
columns: [
["data1", -100, 100, 200, [-100, 0], [0, 100], [100, 200]],
["data2", 100, 300, 500, [0, 100], [100, 300], [200, 500]],
["data3", 200, 500, 800, [100, 200], [300, 500], [500, 800]],
],
type: "bar"
},
grid: {
y: {
lines: [{value: 0}]
}
}
},
func: function(chart) {
chart.timer = [
setTimeout(function() {
chart.groups([["data1", "data2"]])
}, 1000),

setTimeout(function() {
chart.load({
columns: [["data4", 100, -50, 150, 200, -300, -100]]
});
}, 1500),
setTimeout(function() {
chart.groups([["data1", "data2", "data3"]])
}, 1500),

setTimeout(function() {
chart.groups([["data1", "data2", "data3", "data4"]])
}, 2000)
];
setTimeout(function() {
chart.load({
columns: [
["data4", 500, 900, 1500, [400, 500], [700, 900], [1000, 1500]]
],
});
}, 2000),

setTimeout(function() {
chart.groups([["data1", "data2", "data3", "data4"]])
}, 2500),
];
}
}
},
],
StepChart: [
{
options: {
Expand Down Expand Up @@ -1472,7 +1544,7 @@ var demos = {
setTimeout(function() {
chart.resize({width: window.innerWidth * 0.4});
}, 1000),

setTimeout(function() {
chart.resize();
}, 3000)
Expand Down Expand Up @@ -4971,7 +5043,7 @@ d3.select(".chart_area")
chart.export(null, function(dataUrl) {
// append an image element
var img = document.getElementById("exported");

if (!img) {
img = document.createElement("img");

Expand All @@ -4987,7 +5059,7 @@ d3.select(".chart_area")
// append an image element
// append an image element
var img = document.getElementById("exported2");

if (!img) {
img = document.createElement("img");

Expand Down
2 changes: 1 addition & 1 deletion src/ChartInternal/data/convert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default {
* @returns {object}
* @private
*/
convertData(args, callback: Function): object {
convertData(args, callback: Function): any[] | false {
let data;

if (args.bindto) {
Expand Down
15 changes: 14 additions & 1 deletion src/ChartInternal/data/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export default {
* @returns {number} index number
* @private
*/
getIndexByX(x, basedX: (string|Date)[]): number {
getIndexByX(x: Date|number|string, basedX: (Date|number|string)[]): number {
const $$ = this;

return basedX ?
Expand Down Expand Up @@ -986,6 +986,19 @@ export default {
);
},

/**
* Determine if bar has ranged data
* @param {Array} d data value
* @returns {boolean}
* @private
*/
isBarRangeType(d): boolean {
const $$ = this;
const {value} = d;

return $$.isBarType(d) && isArray(value) && value.length === 2 && value.every(v => isNumber(v));
},

/**
* Get data object by id
* @param {string} id data id
Expand Down
4 changes: 4 additions & 0 deletions src/ChartInternal/internals/tooltip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@ export default {
));

value = `<b>Open:</b> ${open} <b>High:</b> ${high} <b>Low:</b> ${low} <b>Close:</b> ${close}${volume ? ` <b>Volume:</b> ${volume}` : ""}`;
} else if ($$.isBarRangeType(row)) {
const [start, end] = row.value;

value = `${valueFormat(start)} ~ ${valueFormat(end)}`;
}

if (value !== undefined) {
Expand Down
13 changes: 9 additions & 4 deletions src/ChartInternal/shape/bar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
* Copyright (c) 2017 ~ present NAVER Corp.
* billboard.js project is licensed under the MIT license
*/
import {DataRow} from "../../../types/types";
import CLASS from "../../config/classes";
import {getRandom, isNumber} from "../../module/util";

type BarTypeDataRow = DataRow<number | number[]>;

export default {
initBar(): void {
const {$el, config, state: {clip}} = this;
Expand All @@ -23,7 +26,7 @@ export default {
}
},

updateTargetsForBar(targets): void {
updateTargetsForBar(targets: BarTypeDataRow[]): void {
const $$ = this;
const {config, $el} = $$;
const classChartBar = $$.getChartClass("Bar");
Expand All @@ -40,7 +43,7 @@ export default {
.data(
// remove
targets.filter(
v => !v.values.every(d => !isNumber(d.value))
v => v.values.some(d => (isNumber(d.value) || $$.isBarRangeType(d)))
)
)
.attr("class", d => classChartBar(d) + classFocus(d));
Expand Down Expand Up @@ -97,7 +100,7 @@ export default {

return [
$$.$T(bar, withTransition, getRandom())
.attr("d", d => isNumber(d.value) && drawFn(d))
.attr("d", d => (isNumber(d.value) || $$.isBarRangeType(d)) && drawFn(d))
.style("fill", this.color)
.style("opacity", null)
];
Expand Down Expand Up @@ -179,7 +182,9 @@ export default {
posY = y0;
}

posY -= (y0 - offset);
if (!$$.isBarRangeType(d)) {
posY -= (y0 - offset);
}

const startPosX = posX + width;

Expand Down
9 changes: 9 additions & 0 deletions src/ChartInternal/shape/shape.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,9 @@ export default {
value = $$.getRatio("index", d, true);
} else if ($$.isBubbleZType(d)) {
value = $$.getBubbleZData(d.value, "y");
} else if ($$.isBarRangeType(d)) {
// TODO use range.getEnd() like method
value = value[1];
}

return $$.getYScaleById(d.id, isSub)(value);
Expand Down Expand Up @@ -275,6 +278,12 @@ export default {
const {id, value, x} = d;
const ind = $$.getIndices(indices, id);
const scale = $$.getYScaleById(id, isSub);

if ($$.isBarRangeType(d)) {
// TODO use range.getStart()
return scale(value[0]);
}

const y0 = scale($$.getShapeYMin(id));

const dataXAsNumber = Number(x);
Expand Down
2 changes: 1 addition & 1 deletion src/Plugin/tableview/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export default class TableView extends Plugin {
title: dataToShow.length ? this.config.categoryTitle : ""
});
let tbody = "";
const rows: number|string[][] = [];
const rows: (number|string)[][] = [];

dataToShow.forEach(v => {
thead += tplProcess(tpl.thead, {title: v.id});
Expand Down
Loading

0 comments on commit 3588abe

Please sign in to comment.