1(function (factory) { 2 'use strict'; 3 if (typeof exports === 'object') { 4 // Node/CommonJS 5 module.exports = factory( 6 typeof angular !== 'undefined' ? angular : require('angular'), 7 typeof Chart !== 'undefined' ? Chart : require('chart.js')); 8 } else if (typeof define === 'function' && define.amd) { 9 // AMD. Register as an anonymous module. 10 define(['angular', 'chart'], factory); 11 } else { 12 // Browser globals 13 factory(angular, Chart); 14 } 15}(function (angular, Chart) { 16 'use strict'; 17 18 Chart.defaults.global.responsive = true; 19 Chart.defaults.global.multiTooltipTemplate = '<%if (datasetLabel){%><%=datasetLabel%>: <%}%><%= value %>'; 20 21 Chart.defaults.global.colours = [ 22 '#97BBCD', // blue 23 '#DCDCDC', // light grey 24 '#F7464A', // red 25 '#46BFBD', // green 26 '#FDB45C', // yellow 27 '#949FB1', // grey 28 '#4D5360' // dark grey 29 ]; 30 31 var usingExcanvas = typeof window.G_vmlCanvasManager === 'object' && 32 window.G_vmlCanvasManager !== null && 33 typeof window.G_vmlCanvasManager.initElement === 'function'; 34 35 if (usingExcanvas) Chart.defaults.global.animation = false; 36 37 return angular.module('chart.js', []) 38 .provider('ChartJs', ChartJsProvider) 39 .factory('ChartJsFactory', ['ChartJs', '$timeout', ChartJsFactory]) 40 .directive('chartBase', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory(); }]) 41 .directive('chartLine', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('Line'); }]) 42 .directive('chartBar', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('Bar'); }]) 43 .directive('chartRadar', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('Radar'); }]) 44 .directive('chartDoughnut', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('Doughnut'); }]) 45 .directive('chartPie', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('Pie'); }]) 46 .directive('chartPolarArea', ['ChartJsFactory', function (ChartJsFactory) { return new ChartJsFactory('PolarArea'); }]); 47 48 /** 49 * Wrapper for chart.js 50 * Allows configuring chart js using the provider 51 * 52 * angular.module('myModule', ['chart.js']).config(function(ChartJsProvider) { 53 * ChartJsProvider.setOptions({ responsive: true }); 54 * ChartJsProvider.setOptions('Line', { responsive: false }); 55 * }))) 56 */ 57 function ChartJsProvider () { 58 var options = {}; 59 var ChartJs = { 60 Chart: Chart, 61 getOptions: function (type) { 62 var typeOptions = type && options[type] || {}; 63 return angular.extend({}, options, typeOptions); 64 } 65 }; 66 67 /** 68 * Allow to set global options during configuration 69 */ 70 this.setOptions = function (type, customOptions) { 71 // If no type was specified set option for the global object 72 if (! customOptions) { 73 customOptions = type; 74 options = angular.extend(options, customOptions); 75 return; 76 } 77 // Set options for the specific chart 78 options[type] = angular.extend(options[type] || {}, customOptions); 79 }; 80 81 this.$get = function () { 82 return ChartJs; 83 }; 84 } 85 86 function ChartJsFactory (ChartJs, $timeout) { 87 return function chart (type) { 88 return { 89 restrict: 'CA', 90 scope: { 91 data: '=?', 92 labels: '=?', 93 options: '=?', 94 series: '=?', 95 colours: '=?', 96 getColour: '=?', 97 chartType: '=', 98 legend: '@', 99 click: '=?', 100 hover: '=?', 101 102 chartData: '=?', 103 chartLabels: '=?', 104 chartOptions: '=?', 105 chartSeries: '=?', 106 chartColours: '=?', 107 chartLegend: '@', 108 chartClick: '=?', 109 chartHover: '=?' 110 }, 111 link: function (scope, elem/*, attrs */) { 112 var chart, container = document.createElement('div'); 113 container.className = 'chart-container'; 114 elem.replaceWith(container); 115 container.appendChild(elem[0]); 116 117 if (usingExcanvas) window.G_vmlCanvasManager.initElement(elem[0]); 118 119 ['data', 'labels', 'options', 'series', 'colours', 'legend', 'click', 'hover'].forEach(deprecated); 120 function aliasVar (fromName, toName) { 121 scope.$watch(fromName, function (newVal) { 122 if (typeof newVal === 'undefined') return; 123 scope[toName] = newVal; 124 }); 125 } 126 /* provide backward compatibility to "old" directive names, by 127 * having an alias point from the new names to the old names. */ 128 aliasVar('chartData', 'data'); 129 aliasVar('chartLabels', 'labels'); 130 aliasVar('chartOptions', 'options'); 131 aliasVar('chartSeries', 'series'); 132 aliasVar('chartColours', 'colours'); 133 aliasVar('chartLegend', 'legend'); 134 aliasVar('chartClick', 'click'); 135 aliasVar('chartHover', 'hover'); 136 137 // Order of setting "watch" matter 138 139 scope.$watch('data', function (newVal, oldVal) { 140 if (! newVal || ! newVal.length || (Array.isArray(newVal[0]) && ! newVal[0].length)) { 141 destroyChart(chart, scope); 142 return; 143 } 144 var chartType = type || scope.chartType; 145 if (! chartType) return; 146
147 if (chart && canUpdateChart(newVal, oldVal)) 148 return updateChart(chart, newVal, scope, elem); 149 150 createChart(chartType); 151 }, true); 152 153 scope.$watch('series', resetChart, true); 154 scope.$watch('labels', resetChart, true); 155 scope.$watch('options', resetChart, true); 156 scope.$watch('colours', resetChart, true); 157 158 scope.$watch('chartType', function (newVal, oldVal) { 159 if (isEmpty(newVal)) return; 160 if (angular.equals(newVal, oldVal)) return; 161 createChart(newVal); 162 }); 163 164 scope.$on('$destroy', function () { 165 destroyChart(chart, scope); 166 }); 167 168 function resetChart (newVal, oldVal) { 169 if (isEmpty(newVal)) return; 170 if (angular.equals(newVal, oldVal)) return; 171 var chartType = type || scope.chartType; 172 if (! chartType) return; 173 174 // chart.update() doesn't work for series and labels 175 // so we have to re-create the chart entirely 176 createChart(chartType); 177 } 178 179 function createChart (type) { 180 if (isResponsive(type, scope) && elem[0].clientHeight === 0 && container.clientHeight === 0) { 181 return $timeout(function () { 182 createChart(type); 183 }, 50, false); 184 } 185 if (! scope.data || ! scope.data.length) return; 186 scope.getColour = typeof scope.getColour === 'function' ? scope.getColour : getRandomColour; 187 var colours = getColours(type, scope); 188 var cvs = elem[0], ctx = cvs.getContext('2d'); 189 var data = Array.isArray(scope.data[0]) ? 190 getDataSets(scope.labels, scope.data, scope.series || [], colours) : 191 getData(scope.labels, scope.data, colours); 192 var options = angular.extend({}, ChartJs.getOptions(type), scope.options); 193 194 // Destroy old chart if it exists to avoid ghost charts issue 195 // https://github.com/jtblin/angular-chart.js/issues/187 196 destroyChart(chart, scope); 197 chart = new ChartJs.Chart(ctx)[type](data, options); 198 scope.$emit('create', chart); 199 200 // Bind events 201 cvs.onclick = scope.click ? getEventHandler(scope, chart, 'click', false) : angular.noop; 202 cvs.onmousemove = scope.hover ? getEventHandler(scope, chart, 'hover', true) : angular.noop; 203 204 if (scope.legend && scope.legend !== 'false') setLegend(elem, chart); 205 } 206 207 function deprecated (attr) { 208 if (typeof console !== 'undefined' && ChartJs.getOptions().env !== 'test') { 209 var warn = typeof console.warn === 'function' ? console.warn : console.log; 210 if (!! scope[attr]) { 211 warn.call(console, '"%s" is deprecated and will be removed in a future version. ' + 212 'Please use "chart-%s" instead.', attr, attr); 213 } 214 } 215 } 216 } 217 }; 218 }; 219 220 function canUpdateChart (newVal, oldVal) { 221 if (newVal && oldVal && newVal.length && oldVal.length) { 222 return Array.isArray(newVal[0]) ? 223 newVal.length === oldVal.length && newVal.every(function (element, index) { 224 return element.length === oldVal[index].length; }) : 225 oldVal.reduce(sum, 0) > 0 ? newVal.length === oldVal.length : false; 226 } 227 return false; 228 } 229 230 function sum (carry, val) { 231 return carry + val; 232 } 233 234 function getEventHandler (scope, chart, action, triggerOnlyOnChange) { 235 var lastState = null; 236 return function (evt) { 237 var atEvent = chart.getPointsAtEvent || chart.getBarsAtEvent || chart.getSegmentsAtEvent; 238 if (atEvent) { 239 var activePoints = atEvent.call(chart, evt); 240 if (triggerOnlyOnChange === false || angular.equals(lastState, activePoints) === false) { 241 lastState = activePoints; 242 scope[action](activePoints, evt); 243 scope.$apply(); 244 } 245 } 246 }; 247 } 248 249 function getColours (type, scope) { 250 var notEnoughColours = false;
251 var colours = angular.copy(scope.colours || 252 ChartJs.getOptions(type).colours || 253 Chart.defaults.global.colours 254 ); 255 while (colours.length < scope.data.length) { 256 colours.push(scope.getColour()); 257 notEnoughColours = true; 258 } 259 // mutate colours in this case as we don't want 260 // the colours to change on each refresh 261 if (notEnoughColours) scope.colours = colours; 262 return colours.map(convertColour); 263 } 264 265 function convertColour (colour) { 266 if (typeof colour === 'object' && colour !== null) return colour; 267 if (typeof colour === 'string' && colour[0] === '#') return getColour(hexToRgb(colour.substr(1))); 268 return getRandomColour(); 269 } 270 271 function getRandomColour () { 272 var colour = [getRandomInt(0, 255), getRandomInt(0, 255), getRandomInt(0, 255)]; 273 return getColour(colour); 274 } 275 276 function getColour (colour) { 277 return { 278 fillColor: rgba(colour, 0.2), 279 strokeColor: rgba(colour, 1), 280 pointColor: rgba(colour, 1), 281 pointStrokeColor: '#fff', 282 pointHighlightFill: '#fff', 283 pointHighlightStroke: rgba(colour, 0.8) 284 }; 285 } 286 287 function getRandomInt (min, max) { 288 return Math.floor(Math.random() * (max - min + 1)) + min; 289 } 290 291 function rgba (colour, alpha) { 292 if (usingExcanvas) { 293 // rgba not supported by IE8 294 return 'rgb(' + colour.join(',') + ')'; 295 } else { 296 return 'rgba(' + colour.concat(alpha).join(',') + ')'; 297 } 298 } 299 300 // Credit: http://stackoverflow.com/a/11508164/1190235 301 function hexToRgb (hex) { 302 var bigint = parseInt(hex, 16), 303 r = (bigint >> 16) & 255, 304 g = (bigint >> 8) & 255, 305 b = bigint & 255; 306 307 return [r, g, b]; 308 } 309 310 function getDataSets (labels, data, series, colours) { 311 return { 312 labels: labels, 313 datasets: data.map(function (item, i) { 314 return angular.extend({}, colours[i], { 315 label: series[i], 316 data: item 317 }); 318 }) 319 }; 320 } 321 322 function getData (labels, data, colours) { 323 return labels.map(function (label, i) { 324 return angular.extend({}, colours[i], { 325 label: label, 326 value: data[i], 327 color: colours[i].strokeColor, 328 highlight: colours[i].pointHighlightStroke 329 }); 330 }); 331 } 332 333 function setLegend (elem, chart) { 334 var $parent = elem.parent(), 335 $oldLegend = $parent.find('chart-legend'), 336 legend = '<chart-legend>' + chart.generateLegend() + '</chart-legend>'; 337 if ($oldLegend.length) $oldLegend.replaceWith(legend); 338 else $parent.append(legend); 339 } 340 341 function updateChart (chart, values, scope, elem) { 342 if (Array.isArray(scope.data[0])) { 343 chart.datasets.forEach(function (dataset, i) { 344 (dataset.points || dataset.bars).forEach(function (dataItem, j) { 345 dataItem.value = values[i][j]; 346 }); 347 }); 348 } else { 349 chart.segments.forEach(function (segment, i) { 350 segment.value = values[i]; 351 }); 352 } 353 chart.update(); 354 scope.$emit('update', chart); 355 if (scope.legend && scope.legend !== 'false') setLegend(elem, chart); 356 } 357 358 function isEmpty (value) { 359 return ! value || 360 (Array.isArray(value) && ! value.length) || 361 (typeof value === 'object' && ! Object.keys(value).length); 362 } 363 364 function isResponsive (type, scope) { 365 var options = angular.extend({}, Chart.defaults.global, ChartJs.getOptions(type), scope.options); 366 return options.responsive; 367 } 368 369 function destroyChart(chart, scope) { 370 if(! chart) return; 371 chart.destroy(); 372 scope.$emit('destroy', chart); 373 } 374 } 375}));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.