Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 29 additions & 18 deletions docs/docs/developers/charts.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,21 @@ Dataset controllers must implement the following interface.

```javascript
{
// Create elements for each piece of data in the dataset. Store elements in an array on the dataset as dataset.metaData
addElements: function() {},

// Draw the representation of the dataset
draw: function() {},

// Remove hover styling from the given element
removeHoverStyle: function(element, datasetIndex, index) {},
// Defaults for charts of this type
defaults: {
// If set to `false` or `null`, no dataset level element is created.
// If set to a string, this is the type of element to create for the dataset.
// For example, a line create needs to create a line element so this is the string 'line'
datasetElementType: string | null | false,

// If set to `false` or `null`, no elements are created for each data value.
// If set to a string, this is the type of element to create for each data value.
// For example, a line create needs to create a point element so this is the string 'point'
dataElementType: string | null | false,
}

// Add hover styling to the given element
setHoverStyle: function(element, datasetIndex, index) {},
// ID of the controller
id: string;

// Update the elements in response to new data
// @param mode : update mode, core calls this method using any of `'active'`, `'hide'`, `'reset'`, `'resize'`, `'show'` or `undefined`
Expand All @@ -48,15 +52,20 @@ The following methods may optionally be overridden by derived dataset controller

```javascript
{
// Draw the representation of the dataset. The base implementation works in most cases, and an example of a derived version
// can be found in the line controller
draw: function() {},

// Initializes the controller
initialize: function() {},

// Ensures that the dataset represented by this controller is linked to a scale. Overridden to helpers.noop in the polar area and doughnut controllers as these
// chart types using a single scale
linkScales: function() {},

// Called by the main chart controller when an update is triggered. The default implementation handles the number of data points changing and creating elements appropriately.
buildOrUpdateElements: function() {}
// Parse the data into the controller meta data. The default implementation will work for cartesian parsing, but an example of an overridden
// version can be found in the doughnut controller
parse: function(start, count) {},
}
```

Expand All @@ -83,19 +92,21 @@ For example, to derive a new chart type that extends from a bubble chart, you wo
import {BubbleController} from 'chart.js';
class Custom extends BubbleController {
draw() {
// Call super method first
// Call bubble controller method to draw all the points
super.draw(arguments);

// Now we can do some custom drawing for this dataset. Here we'll draw a red box around the first point in each dataset
var meta = this.getMeta();
var pt0 = meta.data[0];
var radius = pt0.radius;
const meta = this.getMeta();
const pt0 = meta.data[0];

const {x, y} = pt0.getProps(['x', 'y']);
const {radius} = pt0.options;

var ctx = this.chart.chart.ctx;
const ctx = this.chart.ctx;
ctx.save();
ctx.strokeStyle = 'red';
ctx.lineWidth = 1;
ctx.strokeRect(pt0.x - radius, pt0.y - radius, 2 * radius, 2 * radius);
ctx.strokeRect(x - radius, y - radius, 2 * radius, 2 * radius);
ctx.restore();
}
});
Expand Down
136 changes: 136 additions & 0 deletions samples/advanced/derived-axis-type.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<!doctype html>
<html>

<head>
<title>Logarithmic Line Chart</title>
<script src="../../dist/chart.min.js"></script>
<script src="../utils.js"></script>
<style>
canvas {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
</style>
</head>

<body>
<div style="width:75%;">
<canvas id="canvas"></canvas>
</div>
<script>
var randomScalingFactor = function() {
return Math.pow(2, Math.ceil(Math.random() * 10));
};

class Log2Axis extends Chart.Scale {
constructor(cfg) {
super(cfg);
this._startValue = undefined;
this._valueRange = 0;
}

parse(raw, index) {
const value = Chart.registry.getScale('linear').prototype.parse.apply(this, [raw, index]);
return isFinite(value) && value > 0 ? value : null;
}

determineDataLimits() {
const {min, max} = this.getMinMax(true);
this.min = isFinite(min) ? Math.max(0, min) : null;
this.max = isFinite(max) ? Math.max(0, max) : null;
}

buildTicks() {
const ticks = [];

let power = Math.floor(Math.log2(this.min));
let maxPower = Math.ceil(Math.log2(this.max));
while (power <= maxPower) {
ticks.push({value: Math.pow(2, power)});
power += 1;
}

this.min = ticks[0].value;
this.max = ticks[ticks.length - 1].value;
return ticks;
}

/**
* @protected
*/
configure() {
const start = this.min;

super.configure();

this._startValue = Math.log2(start);
this._valueRange = Math.log2(this.max) - Math.log2(start);
}

getPixelForValue(value) {
if (value === undefined || value === 0) {
value = this.min;
}

return this.getPixelForDecimal(value === this.min ? 0 : (Math.log2(value) - this._startValue) / this._valueRange);
}

getValueForPixel(pixel) {
const decimal = this.getDecimalForPixel(pixel);
return Math.pow(2, this._startValue + decimal * this._valueRange);
}
}

Log2Axis.id = 'log2';
Log2Axis.defaults = {};
Chart.register(Log2Axis);

var config = {
type: 'line',
data: {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [{
label: 'My First dataset',
backgroundColor: window.chartColors.red,
borderColor: window.chartColors.red,
fill: false,
data: [
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor()
],
}]
},
options: {
responsive: true,
plugins: {
title: {
display: true,
text: 'Derived Axis Type - Log2'
}
},
scales: {
x: {
display: true,
},
y: {
display: true,
type: 'log2',
}
}
}
};

window.onload = function() {
var ctx = document.getElementById('canvas').getContext('2d');
window.myLine = new Chart(ctx, config);
};
</script>
</body>

</html>
106 changes: 106 additions & 0 deletions samples/advanced/derived-chart-type.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<!doctype html>
<html>

<head>
<title>Derived Chart Type</title>
<script src="../../dist/chart.min.js"></script>
<script src="../utils.js"></script>
<style type="text/css">
canvas{
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
</style>
</head>

<body>
<div id="container" style="width: 75%;">
<canvas id="canvas"></canvas>
</div>
<script>
class Custom extends Chart.controllers.bubble {
draw() {
// Call bubble controller method to draw all the points
super.draw(arguments);

// Now we can do some custom drawing for this dataset. Here we'll draw a red box around the first point in each dataset
var meta = this.getMeta();
var pt0 = meta.data[0];

const {x, y} = pt0.getProps(['x', 'y']);
const {radius} = pt0.options;

var ctx = this.chart.ctx;
ctx.save();
ctx.strokeStyle = 'red';
ctx.lineWidth = 1;
ctx.strokeRect(x - radius, y - radius, 2 * radius, 2 * radius);
ctx.restore();
}
}
Custom.id = 'derivedBubble';
Custom.defaults = Chart.controllers.bubble.defaults;

// Stores the controller so that the chart initialization routine can look it up
Chart.register(Custom);

var color = Chart.helpers.color;
var bubbleChartData = {
datasets: [{
label: 'My First dataset',
backgroundColor: color(window.chartColors.blue).alpha(0.5).rgbString(),
borderColor: window.chartColors.blue,
borderWidth: 1,
data: [{
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
}, {
x: randomScalingFactor(),
y: randomScalingFactor(),
r: Math.abs(randomScalingFactor()) / 5,
}]
}]
};

window.onload = function() {
var ctx = document.getElementById('canvas').getContext('2d');
window.myChart = new Chart(ctx, {
type: 'derivedBubble',
data: bubbleChartData,
options: {
responsive: true,
plugins: {
title: {
display: true,
text: 'Derived Chart Type'
},
}
}
});
};
</script>
</body>

</html>
6 changes: 6 additions & 0 deletions samples/samples.js
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,12 @@
}, {
title: 'Programmatic Event Triggers',
path: 'advanced/programmatic-events.html'
}, {
title: 'Derived Chart Type',
path: 'advanced/derived-chart-type.html'
}, {
title: 'Derived Axis Type',
path: 'advanced/derived-axis-type.html'
}]
}];

Expand Down