Skip to content

Commit bcd4529

Browse files
authored
Make bar styling options scriptable (chartjs#5780)
The bar `backgroundColor`, `borderColor`, `borderWidth` and `borderSkipped` options are now scriptable (unit tests, docs and a basic sample). Also fix the gulp task that generates the documentation on Windows.
1 parent 03cec64 commit bcd4529

31 files changed

+828
-39
lines changed

docs/charts/bar.md

Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -61,31 +61,69 @@ var myBarChart = new Chart(ctx, {
6161
```
6262

6363
## Dataset Properties
64-
The bar chart allows a number of properties to be specified for each dataset. These are used to set display properties for a specific dataset. For example, the colour of the bars is generally set this way.
6564

66-
Some properties can be specified as an array. If these are set to an array value, the first value applies to the first bar, the second value to the second bar, and so on.
65+
The bar chart allows a number of properties to be specified for each dataset.
66+
These are used to set display properties for a specific dataset. For example,
67+
the color of the bars is generally set this way.
6768

68-
| Name | Type | Description
69-
| ---- | ---- | -----------
70-
| `label` | `String` | The label for the dataset which appears in the legend and tooltips.
71-
| `xAxisID` | `String` | The ID of the x axis to plot this dataset on. If not specified, this defaults to the ID of the first found x axis.
72-
| `yAxisID` | `String` | The ID of the y axis to plot this dataset on. If not specified, this defaults to the ID of the first found y axis.
73-
| `backgroundColor` | `Color/Color[]` | The fill color of the bar. See [Colors](../general/colors.md#colors).
74-
| `borderColor` | `Color/Color[]` | The color of the bar border. See [Colors](../general/colors.md#colors).
75-
| `borderWidth` | `Number/Number[]` | The stroke width of the bar in pixels.
76-
| `borderSkipped` | `String` | Which edge to skip drawing the border for. [more...](#borderskipped)
77-
| `hoverBackgroundColor` | `Color/Color[]` | The fill colour of the bars when hovered.
78-
| `hoverBorderColor` | `Color/Color[]` | The stroke colour of the bars when hovered.
79-
| `hoverBorderWidth` | `Number/Number[]` | The stroke width of the bars when hovered.
80-
81-
### borderSkipped
82-
This setting is used to avoid drawing the bar stroke at the base of the fill. In general, this does not need to be changed except when creating chart types that derive from a bar chart.
69+
| Name | Type | [Scriptable](../general/options.md#scriptable-options) | [Indexable](../general/options.md#indexable-options) | Default
70+
| ---- | ---- | :----: | :----: | ----
71+
| [`backgroundColor`](#styling) | [`Color`](../general/colors.md) | Yes | Yes | `'rgba(0,0,0,0.1)'`
72+
| [`borderColor`](#styling) | [`Color`](../general/colors.md) | Yes | Yes | `'rgba(0,0,0,0.1)'`
73+
| [`borderSkipped`](#borderskipped) | `String` | Yes | Yes | `'bottom'`
74+
| [`borderWidth`](#styling) | `Number` | Yes | Yes | `0`
75+
| [`data`](#data-structure) | `Object[]` | - | - | **required**
76+
| [`hoverBackgroundColor`](#interactions) | [`Color`](../general/colors.md) | - | - | `undefined`
77+
| [`hoverBorderColor`](#interactions) | [`Color`](../general/colors.md) | - | - | `undefined`
78+
| [`hoverBorderWidth`](#interactions) | `Number` | - | - | `1`
79+
| [`label`](#general) | `String` | - | - | `''`
80+
| [`xAxisID`](#general) | `String` | - | - | first x axis
81+
| [`yAxisID`](#general) | `String` | - | - | first y axis
82+
83+
### General
84+
85+
| Name | Description
86+
| ---- | ----
87+
| `label` | The label for the dataset which appears in the legend and tooltips.
88+
| `xAxisID` | The ID of the x axis to plot this dataset on.
89+
| `yAxisID` | The ID of the y axis to plot this dataset on.
90+
91+
### Styling
92+
93+
The style of each bar can be controlled with the following properties:
94+
95+
| Name | Description
96+
| ---- | ----
97+
| `backgroundColor` | The bar background color.
98+
| `borderColor` | The bar border color.
99+
| [`borderSkipped`](#borderskipped) | The edge to skip when drawing bar.
100+
| `borderWidth` | The bar border width (in pixels).
101+
102+
All these values, if `undefined`, fallback to the associated [`elements.rectangle.*`](../configuration/elements.md#rectangle-configuration) options.
103+
104+
#### borderSkipped
105+
106+
This setting is used to avoid drawing the bar stroke at the base of the fill.
107+
In general, this does not need to be changed except when creating chart types
108+
that derive from a bar chart.
83109

84110
Options are:
85-
* 'bottom'
86-
* 'left'
87-
* 'top'
88-
* 'right'
111+
* `'bottom'`
112+
* `'left'`
113+
* `'top'`
114+
* `'right'`
115+
116+
### Interactions
117+
118+
The interaction with each bar can be controlled with the following properties:
119+
120+
| Name | Description
121+
| ---- | -----------
122+
| `hoverBackgroundColor` | The bar background color when hovered.
123+
| `hoverBorderColor` | The bar border color hovered.
124+
| `hoverBorderWidth` | The bar border width when hovered (in pixels).
125+
126+
All these values, if `undefined`, fallback to the associated [`elements.point.*`](../configuration/elements.md#point-configuration) options.
89127

90128
## Configuration Options
91129

gulpfile.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,16 +186,16 @@ function lintHtmlTask() {
186186
}
187187

188188
function docsTask(done) {
189-
const script = require.resolve('gitbook-cli/bin/gitbook.js');
190-
const cmd = process.execPath;
189+
var script = require.resolve('gitbook-cli/bin/gitbook.js');
190+
var cmd = '"' + process.execPath + '"';
191191

192192
exec([cmd, script, 'install', './'].join(' ')).then(() => {
193193
return exec([cmd, script, argv.watch ? 'serve' : 'build', './', './dist/docs'].join(' '));
194-
}).catch((err) => {
195-
console.error(err.stdout);
196194
}).then(() => {
197195
done();
198-
});
196+
}).catch((err) => {
197+
done(new Error(err.stdout || err));
198+
})
199199
}
200200

201201
function unittestTask(done) {

samples/samples.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,9 @@
176176
}, {
177177
title: 'Scriptable',
178178
items: [{
179+
title: 'Bar Chart',
180+
path: 'scriptable/bar.html'
181+
}, {
179182
title: 'Bubble Chart',
180183
path: 'scriptable/bubble.html'
181184
}]

samples/scriptable/bar.html

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<!DOCTYPE html>
2+
<html lang="en-US">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1">
7+
<title>Scriptable > Bar | Chart.js sample</title>
8+
<link rel="stylesheet" type="text/css" href="../style.css">
9+
<script src="../../dist/Chart.js"></script>
10+
<script src="../utils.js"></script>
11+
</head>
12+
<body>
13+
<div class="content">
14+
<div class="wrapper"><canvas id="chart-0"></canvas></div>
15+
<div class="toolbar">
16+
<button onclick="randomize(this)">Randomize</button>
17+
<button onclick="addDataset(this)">Add Dataset</button>
18+
<button onclick="removeDataset(this)">Remove Dataset</button>
19+
</div>
20+
</div>
21+
22+
<script>
23+
var DATA_COUNT = 16;
24+
25+
var utils = Samples.utils;
26+
27+
utils.srand(110);
28+
29+
function colorize(opaque, ctx) {
30+
var v = ctx.dataset.data[ctx.dataIndex];
31+
var c = v < -50 ? '#D60000'
32+
: v < 0 ? '#F46300'
33+
: v < 50 ? '#0358B6'
34+
: '#44DE28';
35+
36+
return opaque ? c : utils.transparentize(c, 1 - Math.abs(v / 150));
37+
}
38+
39+
function generateData() {
40+
return utils.numbers({
41+
count: DATA_COUNT,
42+
min: -100,
43+
max: 100
44+
});
45+
}
46+
47+
var data = {
48+
labels: utils.months({count: DATA_COUNT}),
49+
datasets: [{
50+
data: generateData()
51+
}]
52+
};
53+
54+
var options = {
55+
legend: false,
56+
tooltips: false,
57+
elements: {
58+
rectangle: {
59+
backgroundColor: colorize.bind(null, false),
60+
borderColor: colorize.bind(null, true),
61+
borderWidth: 2
62+
}
63+
}
64+
};
65+
66+
var chart = new Chart('chart-0', {
67+
type: 'bar',
68+
data: data,
69+
options: options
70+
});
71+
72+
// eslint-disable-next-line no-unused-vars
73+
function randomize() {
74+
chart.data.datasets.forEach(function(dataset) {
75+
dataset.data = generateData();
76+
});
77+
chart.update();
78+
}
79+
80+
// eslint-disable-next-line no-unused-vars
81+
function addDataset() {
82+
chart.data.datasets.push({
83+
data: generateData()
84+
});
85+
chart.update();
86+
}
87+
88+
// eslint-disable-next-line no-unused-vars
89+
function removeDataset() {
90+
chart.data.datasets.shift();
91+
chart.update();
92+
}
93+
</script>
94+
</body>
95+
</html>

samples/utils.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ window.chartColors = {
1111
};
1212

1313
(function(global) {
14-
var Months = [
14+
var MONTHS = [
1515
'January',
1616
'February',
1717
'March',
@@ -106,7 +106,7 @@ window.chartColors = {
106106
var i, value;
107107

108108
for (i = 0; i < count; ++i) {
109-
value = Months[Math.ceil(i) % 12];
109+
value = MONTHS[Math.ceil(i) % 12];
110110
values.push(value.substring(0, section));
111111
}
112112

src/controllers/controller.bar.js

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -213,35 +213,32 @@ module.exports = function(Chart) {
213213

214214
updateElement: function(rectangle, index, reset) {
215215
var me = this;
216-
var chart = me.chart;
217216
var meta = me.getMeta();
218217
var dataset = me.getDataset();
219-
var custom = rectangle.custom || {};
220-
var rectangleOptions = chart.options.elements.rectangle;
218+
var options = me._resolveElementOptions(rectangle, index);
221219

222220
rectangle._xScale = me.getScaleForId(meta.xAxisID);
223221
rectangle._yScale = me.getScaleForId(meta.yAxisID);
224222
rectangle._datasetIndex = me.index;
225223
rectangle._index = index;
226-
227224
rectangle._model = {
225+
backgroundColor: options.backgroundColor,
226+
borderColor: options.borderColor,
227+
borderSkipped: options.borderSkipped,
228+
borderWidth: options.borderWidth,
228229
datasetLabel: dataset.label,
229-
label: chart.data.labels[index],
230-
borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleOptions.borderSkipped,
231-
backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.valueAtIndexOrDefault(dataset.backgroundColor, index, rectangleOptions.backgroundColor),
232-
borderColor: custom.borderColor ? custom.borderColor : helpers.valueAtIndexOrDefault(dataset.borderColor, index, rectangleOptions.borderColor),
233-
borderWidth: custom.borderWidth ? custom.borderWidth : helpers.valueAtIndexOrDefault(dataset.borderWidth, index, rectangleOptions.borderWidth)
230+
label: me.chart.data.labels[index]
234231
};
235232

236-
me.updateElementGeometry(rectangle, index, reset);
233+
me._updateElementGeometry(rectangle, index, reset);
237234

238235
rectangle.pivot();
239236
},
240237

241238
/**
242239
* @private
243240
*/
244-
updateElementGeometry: function(rectangle, index, reset) {
241+
_updateElementGeometry: function(rectangle, index, reset) {
245242
var me = this;
246243
var model = rectangle._model;
247244
var vscale = me.getValueScale();
@@ -472,6 +469,47 @@ module.exports = function(Chart) {
472469

473470
helpers.canvas.unclipArea(chart.ctx);
474471
},
472+
473+
/**
474+
* @private
475+
*/
476+
_resolveElementOptions: function(rectangle, index) {
477+
var me = this;
478+
var chart = me.chart;
479+
var datasets = chart.data.datasets;
480+
var dataset = datasets[me.index];
481+
var custom = rectangle.custom || {};
482+
var options = chart.options.elements.rectangle;
483+
var resolve = helpers.options.resolve;
484+
var values = {};
485+
var i, ilen, key;
486+
487+
// Scriptable options
488+
var context = {
489+
chart: chart,
490+
dataIndex: index,
491+
dataset: dataset,
492+
datasetIndex: me.index
493+
};
494+
495+
var keys = [
496+
'backgroundColor',
497+
'borderColor',
498+
'borderSkipped',
499+
'borderWidth'
500+
];
501+
502+
for (i = 0, ilen = keys.length; i < ilen; ++i) {
503+
key = keys[i];
504+
values[key] = resolve([
505+
custom[key],
506+
dataset[key],
507+
options[key]
508+
], context, index);
509+
}
510+
511+
return values;
512+
}
475513
});
476514

477515
Chart.controllers.horizontalBar = Chart.controllers.bar.extend({

src/controllers/controller.bubble.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,14 @@ module.exports = function(Chart) {
103103
setHoverStyle: function(point) {
104104
var model = point._model;
105105
var options = point._options;
106+
106107
point.$previousStyle = {
107108
backgroundColor: model.backgroundColor,
108109
borderColor: model.borderColor,
109110
borderWidth: model.borderWidth,
110111
radius: model.radius
111112
};
113+
112114
model.backgroundColor = helpers.valueOrDefault(options.hoverBackgroundColor, helpers.getHoverColor(options.backgroundColor));
113115
model.borderColor = helpers.valueOrDefault(options.hoverBorderColor, helpers.getHoverColor(options.borderColor));
114116
model.borderWidth = helpers.valueOrDefault(options.hoverBorderWidth, options.borderWidth);
@@ -167,6 +169,7 @@ module.exports = function(Chart) {
167169
dataset.radius,
168170
options.radius
169171
], context, index);
172+
170173
return values;
171174
}
172175
});

0 commit comments

Comments
 (0)