]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Update chart extension docs + add samples (#8540)
authorEvert Timberg <evert.timberg+github@gmail.com>
Sun, 28 Feb 2021 21:02:44 +0000 (16:02 -0500)
committerGitHub <noreply@github.com>
Sun, 28 Feb 2021 21:02:44 +0000 (16:02 -0500)
* Update docs on chart extensions
* Working sample for derived chart types
* Add derived axis example
* Remove duplicated line

docs/docs/developers/charts.md
samples/advanced/derived-axis-type.html [new file with mode: 0644]
samples/advanced/derived-chart-type.html [new file with mode: 0644]
samples/samples.js

index 652cd41f5a0c09dc1413aa6942dd3d91b386697a..ef326c09fa3403c932e1c27bd5c503fe20f8ab12 100644 (file)
@@ -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`
@@ -48,6 +52,10 @@ 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() {},
 
@@ -55,8 +63,9 @@ The following methods may optionally be overridden by derived dataset controller
     // 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) {},
 }
 ```
 
@@ -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();
     }
 });
diff --git a/samples/advanced/derived-axis-type.html b/samples/advanced/derived-axis-type.html
new file mode 100644 (file)
index 0000000..e53a2be
--- /dev/null
@@ -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>
diff --git a/samples/advanced/derived-chart-type.html b/samples/advanced/derived-chart-type.html
new file mode 100644 (file)
index 0000000..3bb7a1d
--- /dev/null
@@ -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>
index f0062a6593994559a083a3a6a0dbd371af465c43..4f3671dd8ec584570281710447eec39137de96af 100644 (file)
                }, {
                        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'
                }]
        }];