Skip to content

Commit bfcef41

Browse files
committed
chore: modernize repository to v2.0.0 (Node 20, ES6, Gulp 4, Playwright)
Breaking Changes: - Dropped support for IE11 and below. - Migrated codebase to ES6 baseline (arrow functions, const/let, template literals). - Updated minimum requirements: AngularJS 1.8.x and Chart.js 2.x. Core Upgrades: - Updated Node.js engine to v20. - Upgraded dependencies: AngularJS 1.8.3 and Chart.js 2.9.4 (security fixes). - Migrated build system from Gulp 3 to Gulp 4 (series/parallel task orchestration). Testing Infrastructure Overhaul: - Replaced deprecated PhantomJS with Karma and Headless Chrome for unit testing. - Replaced broken/legacy webshot integration suite with modern Playwright visual regression testing. - Integrated all tests into a unified `npm run test` and `gulp check` pipeline. Documentation & DX: - Refactored README.md to remove legacy browser info and modernize all code examples. - Updated examples/charts.template.html with new dependency info and ES6 logic. - Added `npm run serve` (http-server) task for easier local example viewing. - Cleaned up obsolete dependencies (testatic, webshot, etc.). - Modernized JSHint configuration to support ES11 (ES2020) globally.
1 parent 6872a8d commit bfcef41

35 files changed

Lines changed: 12292 additions & 370 deletions

.jshintrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
2-
"strict" : true, // true: Requires all functions run in ES5 Strict Mode
2+
"esversion" : 11,
3+
"strict" : true,
34
"undef" : true, // true: Require all non-global variables to be declared (prevents global leaks)
45
"unused" : true, // true: Require all defined variables be used
56
"noempty" : true, // Prohibit use of empty blocks

.node-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
4.4.3
1+
20

README.md

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,12 @@ script and options.
1414

1515
# Installation
1616

17-
This is the `1.x` branch which requires Chart.js 2.x version. Following semantic versioning,
18-
there are numerous **breaking changes** since 0.x, notably:
17+
This is the `2.x` branch which requires Chart.js 2.x version and AngularJS 1.8.x.
18+
This version drops support for legacy browsers (IE11 and below) and uses ES6 syntax.
19+
Following semantic versioning, there are numerous **breaking changes** since 1.x, notably:
20+
21+
* **ES6 Baseline**: The library and examples now use ES6 features (arrow functions, `const`/`let`, etc.).
22+
* **Dropped IE Support**: Support for IE11 and below has been removed.
1923

2024
* all options now need to use the `chart-` prefix
2125
* `chart-colours` is now `chart-colors` and `chart-get-colour` is now `chart-get-color`
@@ -98,7 +102,7 @@ See also [stacked bar example](http://jtblin.github.io/angular-chart.js/examples
98102
```javascript
99103
angular.module("app", ["chart.js"])
100104
// Optional configuration
101-
.config(['ChartJsProvider', function (ChartJsProvider) {
105+
.config(['ChartJsProvider', (ChartJsProvider) => {
102106
// Configure all charts
103107
ChartJsProvider.setOptions({
104108
chartColors: ['#FF5252', '#FF8A80'],
@@ -109,20 +113,20 @@ angular.module("app", ["chart.js"])
109113
showLines: false
110114
});
111115
}])
112-
.controller("LineCtrl", ['$scope', '$timeout', function ($scope, $timeout) {
116+
.controller("LineCtrl", ['$scope', '$timeout', ($scope, $timeout) => {
113117

114118
$scope.labels = ["January", "February", "March", "April", "May", "June", "July"];
115119
$scope.series = ['Series A', 'Series B'];
116120
$scope.data = [
117121
[65, 59, 80, 81, 56, 55, 40],
118122
[28, 48, 40, 19, 86, 27, 90]
119123
];
120-
$scope.onClick = function (points, evt) {
124+
$scope.onClick = (points, evt) => {
121125
console.log(points, evt);
122126
};
123127

124128
// Simulate async data update
125-
$timeout(function () {
129+
$timeout(() => {
126130
$scope.data = [
127131
[28, 48, 40, 19, 86, 27, 90],
128132
[65, 59, 80, 81, 56, 55, 40]
@@ -197,7 +201,7 @@ They may be used alongside RGB colors and/or Hex colors.
197201
## Example - RGBA Colors
198202
```
199203
angular.module('app',['chart.js'])
200-
.controller('MainController', function($scope){
204+
.controller('MainController', ($scope) => {
201205
$scope.colors = ["rgba(159,204,0,0.5)","rgba(250,109,33,0.7)","rgba(154,154,154,0.5)"];
202206
$scope.labels = ["Green", "Orange", "Grey"];
203207
$scope.data = [300, 500, 100];
@@ -226,26 +230,6 @@ angular.module('app',['chart.js'])
226230
});
227231
```
228232

229-
## Browser compatibility
230-
231-
For IE8 and older browsers, you will need
232-
to include [excanvas](https://code.google.com/p/explorercanvas/wiki/Instructions).
233-
You will also need a [shim](https://github.com/es-shims/es5-shim) for ES5 functions.
234-
235-
You also need to have ```height``` and ```width``` attributes for the ```<canvas>``` tag of your chart
236-
if using IE8 and older browsers. If you *do not* have these attributes, you will need a
237-
[getComputedStyle shim](https://github.com/Financial-Times/polyfill-service/blob/master/polyfills/getComputedStyle/polyfill.js)
238-
and the line ```document.defaultView = window;```, but there still may be errors (due to code in Chart.js).
239-
240-
```html
241-
<head>
242-
<!--[if lt IE 9]>
243-
<script src="excanvas.js"></script>
244-
<script src="es5-shim.js"></script>
245-
<![endif]-->
246-
</head>
247-
```
248-
249233
# Issues
250234

251235
**Issues or feature requests for Chart.js (e.g. new chart type, new axis, etc.) need to be opened on
@@ -258,12 +242,6 @@ Please check if issue exists first, otherwise open issue in [github](https://git
258242

259243
Here is a [jsbin template](http://jsbin.com/rodunob/edit?html,js,output) for convenience.
260244

261-
# v0.x - Chart.js v1.x - deprecated
262-
263-
This is the deprecated version of angular-chart.js that uses the v1.x version of Chart.js.
264-
If you want to use this version, please checkout the
265-
[chartjs-1.x branch](https://github.com/jtblin/angular-chart.js/tree/chartjs-1.x)
266-
267245
# Contributing
268246

269247
Pull requests welcome!

angular-chart.js

Lines changed: 51 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
module.exports = factory(
66
typeof angular !== 'undefined' ? angular : require('angular'),
77
typeof Chart !== 'undefined' ? Chart : require('chart.js'));
8-
} else if (typeof define === 'function' && define.amd) {
8+
} else if (typeof define === 'function' && define.amd) {
99
// AMD. Register as an anonymous module.
1010
define(['angular', 'chart'], factory);
1111
} else {
1212
// Browser globals
1313
if (typeof angular === 'undefined') {
14-
throw new Error('AngularJS framework needs to be included, see https://angularjs.org/');
14+
throw new Error('AngularJS framework needs to be included, see https://angularjs.org/');
1515
} else if (typeof Chart === 'undefined') {
1616
throw new Error('Chart.js library needs to be included, see http://jtblin.github.io/angular-chart.js/');
1717
}
@@ -35,7 +35,7 @@
3535
'#4D5360' // dark grey
3636
];
3737

38-
var useExcanvas = typeof window.G_vmlCanvasManager === 'object' &&
38+
const useExcanvas = typeof window.G_vmlCanvasManager === 'object' &&
3939
window.G_vmlCanvasManager !== null &&
4040
typeof window.G_vmlCanvasManager.initElement === 'function';
4141

@@ -44,15 +44,15 @@
4444
return angular.module('chart.js', [])
4545
.provider('ChartJs', ChartJsProvider)
4646
.factory('ChartJsFactory', ['ChartJs', '$timeout', ChartJsFactory])
47-
.directive('chartBase', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory(); }])
48-
.directive('chartLine', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('line'); }])
49-
.directive('chartBar', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('bar'); }])
50-
.directive('chartHorizontalBar', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('horizontalBar'); }])
51-
.directive('chartRadar', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('radar'); }])
52-
.directive('chartDoughnut', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('doughnut'); }])
53-
.directive('chartPie', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('pie'); }])
54-
.directive('chartPolarArea', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('polarArea'); }])
55-
.directive('chartBubble', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('bubble'); }])
47+
.directive('chartBase', ['ChartJsFactory', (ChartJsFactory) => new ChartJsFactory()])
48+
.directive('chartLine', ['ChartJsFactory', (ChartJsFactory) => new ChartJsFactory('line')])
49+
.directive('chartBar', ['ChartJsFactory', (ChartJsFactory) => new ChartJsFactory('bar')])
50+
.directive('chartHorizontalBar', ['ChartJsFactory', (ChartJsFactory) => new ChartJsFactory('horizontalBar')])
51+
.directive('chartRadar', ['ChartJsFactory', (ChartJsFactory) => new ChartJsFactory('radar')])
52+
.directive('chartDoughnut', ['ChartJsFactory', (ChartJsFactory) => new ChartJsFactory('doughnut')])
53+
.directive('chartPie', ['ChartJsFactory', (ChartJsFactory) => new ChartJsFactory('pie')])
54+
.directive('chartPolarArea', ['ChartJsFactory', (ChartJsFactory) => new ChartJsFactory('polarArea')])
55+
.directive('chartBubble', ['ChartJsFactory', (ChartJsFactory) => new ChartJsFactory('bubble')])
5656
.name;
5757

5858
/**
@@ -65,11 +65,11 @@
6565
* })))
6666
*/
6767
function ChartJsProvider () {
68-
var options = { responsive: true };
69-
var ChartJs = {
68+
let options = { responsive: true };
69+
const ChartJs = {
7070
Chart: Chart,
71-
getOptions: function (type) {
72-
var typeOptions = type && options[type] || {};
71+
getOptions: (type) => {
72+
const typeOptions = type && options[type] || {};
7373
return angular.extend({}, options, typeOptions);
7474
}
7575
};
@@ -90,9 +90,7 @@
9090
angular.merge(ChartJs.Chart.defaults, options);
9191
};
9292

93-
this.$get = function () {
94-
return ChartJs;
95-
};
93+
this.$get = () => ChartJs;
9694
}
9795

9896
function ChartJsFactory (ChartJs, $timeout) {
@@ -123,11 +121,9 @@
123121
scope.$watch('chartDatasetOverride', watchOther, true);
124122
scope.$watch('chartType', watchType, false);
125123

126-
scope.$on('$destroy', function () {
127-
destroyChart(scope);
128-
});
124+
scope.$on('$destroy', () => destroyChart(scope));
129125

130-
scope.$on('$resize', function () {
126+
scope.$on('$resize', () => {
131127
if (scope.chart) scope.chart.resize();
132128
});
133129

@@ -136,7 +132,7 @@
136132
destroyChart(scope);
137133
return;
138134
}
139-
var chartType = type || scope.chartType;
135+
const chartType = type || scope.chartType;
140136
if (! chartType) return;
141137

142138
if (scope.chart && canUpdateChart(newVal, oldVal))
@@ -148,7 +144,7 @@
148144
function watchOther (newVal, oldVal) {
149145
if (isEmpty(newVal)) return;
150146
if (angular.equals(newVal, oldVal)) return;
151-
var chartType = type || scope.chartType;
147+
const chartType = type || scope.chartType;
152148
if (! chartType) return;
153149

154150
// chart.update() doesn't work for series and labels
@@ -166,14 +162,14 @@
166162
};
167163

168164
function createChart (type, scope, elem) {
169-
var options = getChartOptions(type, scope);
165+
const options = getChartOptions(type, scope);
170166
if (! hasData(scope) || ! canDisplay(type, scope, elem, options)) return;
171167

172-
var cvs = elem[0];
173-
var ctx = cvs.getContext('2d');
168+
const cvs = elem[0];
169+
const ctx = cvs.getContext('2d');
174170

175171
scope.chartGetColor = getChartColorFn(scope);
176-
var data = getChartData(type, scope);
172+
const data = getChartData(type, scope);
177173
// Destroy old chart if it exists to avoid ghost charts issue
178174
// https://github.com/jtblin/angular-chart.js/issues/187
179175
destroyChart(scope);
@@ -190,8 +186,7 @@
190186
function canUpdateChart (newVal, oldVal) {
191187
if (newVal && oldVal && newVal.length && oldVal.length) {
192188
return Array.isArray(newVal[0]) ?
193-
newVal.length === oldVal.length && newVal.every(function (element, index) {
194-
return element.length === oldVal[index].length; }) :
189+
newVal.length === oldVal.length && newVal.every((element, index) => element.length === oldVal[index].length) :
195190
oldVal.reduce(sum, 0) > 0 ? newVal.length === oldVal.length : false;
196191
}
197192
return false;
@@ -202,16 +197,16 @@
202197
}
203198

204199
function getEventHandler (scope, action, triggerOnlyOnChange) {
205-
var lastState = {
206-
point: void 0,
207-
points: void 0
200+
const lastState = {
201+
point: undefined,
202+
points: undefined
208203
};
209204
return function (evt) {
210-
var atEvent = scope.chart.getElementAtEvent || scope.chart.getPointAtEvent;
211-
var atEvents = scope.chart.getElementsAtEvent || scope.chart.getPointsAtEvent;
205+
const atEvent = scope.chart.getElementAtEvent || scope.chart.getPointAtEvent;
206+
const atEvents = scope.chart.getElementsAtEvent || scope.chart.getPointsAtEvent;
212207
if (atEvents) {
213-
var points = atEvents.call(scope.chart, evt);
214-
var point = atEvent ? atEvent.call(scope.chart, evt)[0] : void 0;
208+
const points = atEvents.call(scope.chart, evt);
209+
const point = atEvent ? atEvent.call(scope.chart, evt)[0] : undefined;
215210

216211
if (triggerOnlyOnChange === false ||
217212
(! angular.equals(lastState.points, points) && ! angular.equals(lastState.point, point))
@@ -225,11 +220,11 @@
225220
}
226221

227222
function getColors (type, scope) {
228-
var colors = angular.copy(scope.chartColors ||
223+
const colors = angular.copy(scope.chartColors ||
229224
ChartJs.getOptions(type).chartColors ||
230225
Chart.defaults.global.colors
231226
);
232-
var notEnoughColors = colors.length < scope.chartData.length;
227+
const notEnoughColors = colors.length < scope.chartData.length;
233228
while (colors.length < scope.chartData.length) {
234229
colors.push(scope.chartGetColor());
235230
}
@@ -250,12 +245,12 @@
250245
}
251246

252247
function getRandomColor () {
253-
var color = [getRandomInt(0, 255), getRandomInt(0, 255), getRandomInt(0, 255)];
248+
const color = [getRandomInt(0, 255), getRandomInt(0, 255), getRandomInt(0, 255)];
254249
return getColor(color);
255250
}
256251

257252
function getColor (color) {
258-
var alpha = color[3] || 1;
253+
const alpha = color[3] || 1;
259254
color = color.slice(0, 3);
260255
return {
261256
backgroundColor: rgba(color, 0.2),
@@ -273,21 +268,21 @@
273268

274269
function rgba (color, alpha) {
275270
// rgba not supported by IE8
276-
return useExcanvas ? 'rgb(' + color.join(',') + ')' : 'rgba(' + color.concat(alpha).join(',') + ')';
271+
return useExcanvas ? `rgb(${color.join(',')})` : `rgba(${color.concat(alpha).join(',')})`;
277272
}
278273

279274
// Credit: http://stackoverflow.com/a/11508164/1190235
280275
function hexToRgb (hex) {
281-
var bigint = parseInt(hex, 16),
282-
r = (bigint >> 16) & 255,
283-
g = (bigint >> 8) & 255,
284-
b = bigint & 255;
276+
const bigint = parseInt(hex, 16);
277+
const r = (bigint >> 16) & 255;
278+
const g = (bigint >> 8) & 255;
279+
const b = bigint & 255;
285280

286281
return [r, g, b];
287282
}
288283

289284
function rgbStringToRgb (color) {
290-
var match = color.match(/^rgba?\(([\d,.]+)\)$/);
285+
const match = color.match(/^rgba?\(([\d,.]+)\)$/);
291286
if (! match) throw new Error('Cannot parse rgb value');
292287
color = match[1].split(',');
293288
return color.map(Number);
@@ -302,7 +297,7 @@
302297
}
303298

304299
function getChartData (type, scope) {
305-
var colors = getColors(type, scope);
300+
const colors = getColors(type, scope);
306301
return Array.isArray(scope.chartData[0]) ?
307302
getDataSets(scope.chartLabels, scope.chartData, scope.chartSeries || [], colors, scope.chartDatasetOverride) :
308303
getData(scope.chartLabels, scope.chartData, colors, scope.chartDatasetOverride);
@@ -311,8 +306,8 @@
311306
function getDataSets (labels, data, series, colors, datasetOverride) {
312307
return {
313308
labels: labels,
314-
datasets: data.map(function (item, i) {
315-
var dataset = angular.extend({}, colors[i], {
309+
datasets: data.map((item, i) => {
310+
const dataset = angular.extend({}, colors[i], {
316311
label: series[i],
317312
data: item
318313
});
@@ -325,16 +320,12 @@
325320
}
326321

327322
function getData (labels, data, colors, datasetOverride) {
328-
var dataset = {
323+
const dataset = {
329324
labels: labels,
330325
datasets: [{
331326
data: data,
332-
backgroundColor: colors.map(function (color) {
333-
return color.pointBackgroundColor;
334-
}),
335-
hoverBackgroundColor: colors.map(function (color) {
336-
return color.backgroundColor;
337-
})
327+
backgroundColor: colors.map((color) => color.pointBackgroundColor),
328+
hoverBackgroundColor: colors.map((color) => color.backgroundColor)
338329
}]
339330
};
340331
if (datasetOverride) {
@@ -354,7 +345,7 @@
354345

355346
function updateChart (values, scope) {
356347
if (Array.isArray(scope.chartData[0])) {
357-
scope.chart.data.datasets.forEach(function (dataset, i) {
348+
scope.chart.data.datasets.forEach((dataset, i) => {
358349
dataset.data = values[i];
359350
});
360351
} else {
@@ -374,7 +365,7 @@
374365
function canDisplay (type, scope, elem, options) {
375366
// TODO: check parent?
376367
if (options.responsive && elem[0].clientHeight === 0) {
377-
$timeout(function () {
368+
$timeout(() => {
378369
createChart(type, scope, elem);
379370
}, 50, false);
380371
return false;

0 commit comments

Comments
 (0)