From 7d450705d4cd3651f4139147b6852b5a630d0a99 Mon Sep 17 00:00:00 2001 From: nagix Date: Wed, 27 Mar 2019 04:56:11 +0000 Subject: [PATCH] Release 0.5.0 --- bower.json | 15 + dist/chartjs-plugin-style.js | 1498 ++++++++++++++++++++++++++++++ dist/chartjs-plugin-style.min.js | 7 + 3 files changed, 1520 insertions(+) create mode 100644 bower.json create mode 100644 dist/chartjs-plugin-style.js create mode 100644 dist/chartjs-plugin-style.min.js diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..8dad944 --- /dev/null +++ b/bower.json @@ -0,0 +1,15 @@ +{ + "name": "chartjs-plugin-style", + "description": "Chart.js plugin for more styling options", + "homepage": "https://nagix.github.io/chartjs-plugin-style", + "license": "MIT", + "version": "0.5.0", + "main": "dist/chartjs-plugin-style.js", + "ignore": [ + ".codeclimate.yml", + ".gitignore", + ".npmignore", + ".travis.yml", + "scripts" + ] +} \ No newline at end of file diff --git a/dist/chartjs-plugin-style.js b/dist/chartjs-plugin-style.js new file mode 100644 index 0000000..2b53201 --- /dev/null +++ b/dist/chartjs-plugin-style.js @@ -0,0 +1,1498 @@ +/*! + * chartjs-plugin-style v0.5.0 + * https://nagix.github.io/chartjs-plugin-style + * (c) 2019 Akihiko Kusanagi + * Released under the MIT license + */ +(function (global, factory) { +typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('chart.js')) : +typeof define === 'function' && define.amd ? define(['chart.js'], factory) : +(global = global || self, global.ChartStyle = factory(global.Chart)); +}(this, function (Chart) { 'use strict'; + +Chart = Chart && Chart.hasOwnProperty('default') ? Chart['default'] : Chart; + +var helpers = Chart.helpers; +var optionsHelpers = helpers.options || {}; + +var optionsHelpers$1 = helpers.extend(optionsHelpers, { + + // For Chart.js 2.6.0 backward compatibility + resolve: optionsHelpers.resolve || function(inputs, context, index) { + var i, ilen, value; + + for (i = 0, ilen = inputs.length; i < ilen; ++i) { + value = inputs[i]; + if (value === undefined) { + continue; + } + if (context !== undefined && typeof value === 'function') { + value = value(context); + } + if (index !== undefined && helpers.isArray(value)) { + value = value[index]; + } + if (value !== undefined) { + return value; + } + } + } +}); + +var helpers$1 = Chart.helpers; + +var resolve = optionsHelpers$1.resolve; + +var OFFSET = 1000000; + +function isColorOption(key) { + return key.indexOf('Color') !== -1; +} + +var styleHelpers = { + + styleKeys: [ + 'shadowOffsetX', + 'shadowOffsetY', + 'shadowBlur', + 'shadowColor', + 'bevelWidth', + 'bevelHighlightColor', + 'bevelShadowColor', + 'innerGlowWidth', + 'innerGlowColor', + 'outerGlowWidth', + 'outerGlowColor', + 'backgroundOverlayColor', + 'backgroundOverlayMode' + ], + + lineStyleKeys: [ + 'shadowOffsetX', + 'shadowOffsetY', + 'shadowBlur', + 'shadowColor', + 'outerGlowWidth', + 'outerGlowColor' + ], + + pointStyleKeys: [ + 'pointShadowOffsetX', + 'pointShadowOffsetY', + 'pointShadowBlur', + 'pointShadowColor', + 'pointBevelWidth', + 'pointBevelHighlightColor', + 'pointBevelShadowColor', + 'pointInnerGlowWidth', + 'pointInnerGlowColor', + 'pointOuterGlowWidth', + 'pointOuterGlowColor', + 'pointBackgroundOverlayColor', + 'pointBackgroundOverlayMode' + ], + + hoverStyleKeys: [ + 'hoverShadowOffsetX', + 'hoverShadowOffsetY', + 'hoverShadowBlur', + 'hoverShadowColor', + 'hoverBevelWidth', + 'hoverBevelHighlightColor', + 'hoverBevelShadowColor', + 'hoverInnerGlowWidth', + 'hoverInnerGlowColor', + 'hoverOuterGlowWidth', + 'hoverOuterGlowColor', + 'hoverBackgroundOverlayColor', + 'hoverBackgroundOverlayMode' + ], + + pointHoverStyleKeys: [ + 'pointHoverShadowOffsetX', + 'pointHoverShadowOffsetY', + 'pointHoverShadowBlur', + 'pointHoverShadowColor', + 'pointHoverBevelWidth', + 'pointHoverBevelHighlightColor', + 'pointHoverBevelShadowColor', + 'pointHoverInnerGlowWidth', + 'pointHoverInnerGlowColor', + 'pointHoverOuterGlowWidth', + 'pointHoverOuterGlowColor', + 'pointHoverBackgroundOverlayColor', + 'pointHoverBackgroundOverlayMode' + ], + + drawBackground: function(view, drawCallback) { + var borderWidth = view.borderWidth; + + view.borderWidth = 0; + drawCallback(); + view.borderWidth = borderWidth; + }, + + drawBorder: function(view, drawCallback) { + var backgroundColor = view.backgroundColor; + + if (view.borderWidth) { + view.backgroundColor = 'rgba(0, 0, 0, 0)'; + drawCallback(); + view.backgroundColor = backgroundColor; + } + }, + + drawShadow: function(chart, options, drawCallback, backmost) { + var ctx = chart.ctx; + var pixelRatio = chart.currentDevicePixelRatio; + + ctx.save(); + + ctx.shadowOffsetX = (options.shadowOffsetX + OFFSET) * pixelRatio; + ctx.shadowOffsetY = options.shadowOffsetY * pixelRatio; + ctx.shadowBlur = options.shadowBlur * pixelRatio; + ctx.shadowColor = options.shadowColor; + if (backmost) { + ctx.globalCompositeOperation = 'destination-over'; + } + ctx.translate(-OFFSET, 0); + + drawCallback(); + + ctx.restore(); + }, + + setPath: function(ctx, drawCallback) { + ctx.save(); + ctx.beginPath(); + ctx.clip(); + drawCallback(); + ctx.restore(); + }, + + drawBevel: function(chart, options, drawCallback) { + var ctx = chart.ctx; + var pixelRatio = chart.currentDevicePixelRatio; + var shadowWidthFactor = pixelRatio * 5 / 6; + var width = options.bevelWidth * shadowWidthFactor; + var borderWidth = options.borderWidth; + var parsedBorderWidth = options.parsedBorderWidth; + var shadowOffset, offset; + + if (!width) { + return; + } + + if (!this.opaque(options.borderColor)) { + shadowOffset = {top: width, left: width, bottom: width, right: width}; + } else if (parsedBorderWidth) { + shadowOffset = { + top: width + parsedBorderWidth.top * pixelRatio, + left: width + parsedBorderWidth.left * pixelRatio, + bottom: width + parsedBorderWidth.bottom * pixelRatio, + right: width + parsedBorderWidth.right * pixelRatio + }; + } else { + offset = width + (borderWidth > 0 ? borderWidth : 0) * pixelRatio / 2; + shadowOffset = {top: offset, left: offset, bottom: offset, right: offset}; + } + + ctx.save(); + + this.setPath(ctx, drawCallback); + ctx.clip(); + + // Make stencil + ctx.translate(-OFFSET, 0); + this.setPath(ctx, drawCallback); + ctx.rect(0, 0, chart.width, chart.height); + + // Draw bevel shadow + ctx.fillStyle = 'black'; + ctx.shadowOffsetX = OFFSET * pixelRatio - shadowOffset.right; + ctx.shadowOffsetY = -shadowOffset.bottom; + ctx.shadowBlur = width; + ctx.shadowColor = options.bevelShadowColor; + // Workaround for the issue on Windows version of FireFox + // https://bugzilla.mozilla.org/show_bug.cgi?id=1333090 + // If the destination has transparency, the result will be different + if (!(navigator && navigator.userAgent.match('Windows.+Firefox'))) { + ctx.globalCompositeOperation = 'source-atop'; + } + ctx.fill('evenodd'); + + // Draw Bevel highlight + ctx.shadowOffsetX = OFFSET * pixelRatio + shadowOffset.left; + ctx.shadowOffsetY = shadowOffset.top; + ctx.shadowColor = options.bevelHighlightColor; + ctx.fill('evenodd'); + + ctx.restore(); + }, + + drawGlow: function(chart, options, drawCallback, isOuter) { + var ctx = chart.ctx; + var width = isOuter ? options.outerGlowWidth : options.innerGlowWidth; + var borderWidth = options.borderWidth; + var pixelRatio = chart.currentDevicePixelRatio; + + if (!width) { + return; + } + + ctx.save(); + + // Clip inner or outer area + this.setPath(ctx, drawCallback); + if (isOuter) { + ctx.rect(0, 0, chart.width, chart.height); + } + ctx.clip('evenodd'); + + // Set path + ctx.translate(-OFFSET, 0); + this.setPath(ctx, drawCallback); + if (!isOuter) { + ctx.rect(0, 0, chart.width, chart.height); + } + + // Draw glow + ctx.lineWidth = borderWidth; + ctx.strokeStyle = 'black'; + ctx.fillStyle = 'black'; + ctx.shadowOffsetX = OFFSET * pixelRatio; + ctx.shadowBlur = width * pixelRatio; + ctx.shadowColor = isOuter ? options.outerGlowColor : options.innerGlowColor; + ctx.fill('evenodd'); + if (borderWidth) { + ctx.stroke(); + } + + ctx.restore(); + }, + + drawInnerGlow: function(chart, options, drawCallback) { + this.drawGlow(chart, options, drawCallback); + }, + + drawOuterGlow: function(chart, options, drawCallback) { + this.drawGlow(chart, options, drawCallback, true); + }, + + drawBackgroundOverlay: function(chart, options, drawCallback) { + var ctx = chart.ctx; + var color = options.backgroundOverlayColor; + + if (!color) { + return; + } + + ctx.save(); + this.setPath(ctx, drawCallback); + ctx.fillStyle = color; + ctx.globalCompositeOperation = options.backgroundOverlayMode; + ctx.fill(); + ctx.restore(); + }, + + opaque: function(color) { + return helpers$1.color(color).alpha() > 0; + }, + + getHoverColor: function(color) { + return color !== undefined ? helpers$1.getHoverColor(color) : color; + }, + + mergeStyle: function(target, source) { + if (target === undefined || source === undefined) { + return; + } + this.styleKeys.forEach(function(key) { + target[key] = source[key]; + }); + return target; + }, + + setHoverStyle: function(target, source) { + var keys = this.styleKeys; + var hoverKeys = this.hoverStyleKeys; + var i, ilen; + + if (target === undefined || source === undefined) { + return; + } + for (i = 0, ilen = keys.length; i < ilen; ++i) { + target[keys[i]] = source[hoverKeys[i]]; + } + return target; + }, + + saveStyle: function(element) { + var model = element._model; + var previousStyle = element.$previousStyle; + + if (previousStyle) { + this.mergeStyle(previousStyle, model); + } + }, + + resolveStyle: function(controller, element, index, options) { + var me = this; + var chart = controller.chart; + var dataset = chart.data.datasets[controller.index]; + var custom = element.custom || {}; + var keys = me.styleKeys; + var hoverKeys = me.hoverStyleKeys; + var values = {}; + var i, ilen, key, value; + + // Scriptable options + var context = { + chart: chart, + dataIndex: index, + dataset: dataset, + datasetIndex: element._datasetIndex + }; + + for (i = 0, ilen = keys.length; i < ilen; ++i) { + key = keys[i]; + values[key] = value = resolve([ + custom[key], + dataset[key], + options[key] + ], context, index); + + key = hoverKeys[i]; + values[key] = resolve([ + custom[key], + dataset[key], + options[key], + isColorOption(key) ? me.getHoverColor(value) : value + ], context, index); + } + + return values; + }, + + resolveLineStyle: function(controller, element, options) { + var chart = controller.chart; + var dataset = chart.data.datasets[controller.index]; + var custom = element.custom || {}; + var keys = this.lineStyleKeys; + var values = {}; + var i, ilen, key; + + // Scriptable options + var context = { + chart: chart, + dataset: dataset, + datasetIndex: element._datasetIndex + }; + + for (i = 0, ilen = keys.length; i < ilen; ++i) { + key = keys[i]; + values[key] = resolve([custom[key], dataset[key], options[key]], context); + } + + return values; + }, + + resolvePointStyle: function(controller, element, index, options) { + var me = this; + var chart = controller.chart; + var dataset = chart.data.datasets[controller.index]; + var custom = element.custom || {}; + var keys = me.styleKeys; + var hoverKeys = me.hoverStyleKeys; + var pointKeys = me.pointStyleKeys; + var pointHoverKeys = me.pointHoverStyleKeys; + var values = {}; + var i, ilen, key, value; + + // Scriptable options + var context = { + chart: chart, + dataIndex: index, + dataset: dataset, + datasetIndex: element._datasetIndex + }; + + for (i = 0, ilen = keys.length; i < ilen; ++i) { + key = keys[i]; + values[key] = value = resolve([ + custom[key], + dataset[pointKeys[i]], + dataset[key], + options[key] + ], context, index); + + key = hoverKeys[i]; + values[key] = resolve([ + custom[key], + dataset[pointHoverKeys[i]], + options[key], + isColorOption(key) ? me.getHoverColor(value) : value + ], context, index); + } + + return values; + } +}; + +var helpers$2 = Chart.helpers; + +/** + * Ported from Chart.js 2.7.3. + * + * Helper method to merge the opacity into a color + * For Chart.js 2.7.3 backward compatibility + */ +function mergeOpacity(colorString, opacity) { + // opacity is not used in Chart.js 2.8 or later + if (opacity === undefined) { + return colorString; + } + var color = helpers$2.color(colorString); + return color.alpha(opacity * color.alpha()).rgbaString(); +} + +var Tooltip = Chart.Tooltip; + +var StyleTooltip = Tooltip.extend({ + + initialize: function() { + var me = this; + + Tooltip.prototype.initialize.apply(me, arguments); + + styleHelpers.mergeStyle(me._model, me._options); + }, + + update: function() { + var me = this; + + Tooltip.prototype.update.apply(me, arguments); + + styleHelpers.mergeStyle(me._model, me._options); + + return me; + }, + + drawBackground: function(pt, vm, ctx, tooltipSize, opacity) { + var me = this; + var args = arguments; + var chart = me._chart; + var options = helpers$2.extend({}, vm, { + bevelHighlightColor: mergeOpacity(vm.bevelHighlightColor, opacity), + bevelShadowColor: mergeOpacity(vm.bevelShadowColor, opacity), + innerGlowColor: mergeOpacity(vm.innerGlowColor, opacity), + outerGlowColor: mergeOpacity(vm.outerGlowColor, opacity) + }); + + var drawCallback = function() { + Tooltip.prototype.drawBackground.apply(me, args); + }; + + styleHelpers.drawShadow(chart, vm, drawCallback); + + if (styleHelpers.opaque(vm.backgroundColor)) { + styleHelpers.drawBackground(vm, drawCallback); + styleHelpers.drawBevel(chart, options, drawCallback); + } + + styleHelpers.drawInnerGlow(chart, options, drawCallback); + styleHelpers.drawOuterGlow(chart, options, drawCallback); + + styleHelpers.drawBorder(vm, drawCallback); + } +}); + +var Rectangle = Chart.elements.Rectangle; + +var StyleRectangle = Rectangle.extend({ + + draw: function() { + var me = this; + var args = arguments; + var chart = me._chart; + var vm = me._view; + + var drawCallback = function() { + Rectangle.prototype.draw.apply(me, args); + }; + var setPathCallback = function() { + me.setPath(); + }; + + styleHelpers.drawShadow(chart, vm, drawCallback, true); + + if (styleHelpers.opaque(vm.backgroundColor)) { + styleHelpers.drawBackground(vm, drawCallback); + styleHelpers.drawBackgroundOverlay(chart, vm, setPathCallback); + styleHelpers.drawBevel(chart, vm, setPathCallback); + } + + styleHelpers.drawInnerGlow(chart, vm, setPathCallback); + styleHelpers.drawOuterGlow(chart, vm, setPathCallback); + + styleHelpers.drawBorder(vm, drawCallback); + }, + + setPath: function() { + var me = this; + var ctx = me._chart.ctx; + var vm = me._view; + var x, y, width, height; + + if (vm.width !== undefined) { + x = vm.x - vm.width / 2; + width = vm.width; + y = Math.min(vm.y, vm.base); + height = Math.abs(vm.y - vm.base); + } else { + x = Math.min(vm.x, vm.base); + width = Math.abs(vm.x - vm.base); + y = vm.y - vm.height / 2; + height = vm.height; + } + + ctx.rect(x, y, width, height); + } +}); + +var helpers$3 = Chart.helpers; + +var extend = helpers$3.extend; + +// Ported from Chart.js 2.8.0 +function swap(orig, v1, v2) { + return orig === v1 ? v2 : orig === v2 ? v1 : orig; +} + +// Ported from Chart.js 2.8.0 +function parseBorderSkipped(vm) { + var edge = vm.borderSkipped; + var res = {}; + + if (!edge) { + return res; + } + + if (vm.horizontal) { + if (vm.base > vm.x) { + edge = swap(edge, 'left', 'right'); + } + } else if (vm.base < vm.y) { + edge = swap(edge, 'bottom', 'top'); + } + + res[edge] = true; + return res; +} + +// Ported from Chart.js 2.8.0. Modified for style bar. +function parseBorderWidth(vm) { + var value = vm.borderWidth; + var skip = parseBorderSkipped(vm); + var maxW, maxH, t, r, b, l; + + if (vm.width !== undefined) { + maxW = vm.width / 2; + maxH = Math.abs(vm.y - vm.base) / 2; + } else { + maxW = Math.abs(vm.x - vm.base) / 2; + maxH = vm.height / 2; + } + + if (value !== null && Object.prototype.toString.call(value) === '[object Object]') { + t = +value.top || 0; + r = +value.right || 0; + b = +value.bottom || 0; + l = +value.left || 0; + } else { + t = r = b = l = +value || 0; + } + + return { + top: skip.top || (t < 0) ? 0 : t > maxH ? maxH : t, + right: skip.right || (r < 0) ? 0 : r > maxW ? maxW : r, + bottom: skip.bottom || (b < 0) ? 0 : b > maxH ? maxH : b, + left: skip.left || (l < 0) ? 0 : l > maxW ? maxW : l + }; +} + +var BarController = Chart.controllers.bar; + +var StyleBarController = BarController.extend({ + + dataElementType: StyleRectangle, + + updateElement: function(rectangle, index) { + var me = this; + var options = styleHelpers.resolveStyle(me, rectangle, index, me.chart.options.elements.rectangle); + var model = {}; + + Object.defineProperty(rectangle, '_model', { + configurable: true, + get: function() { + return model; + }, + set: function(value) { + extend(model, value, options); + } + }); + + BarController.prototype.updateElement.apply(me, arguments); + + delete rectangle._model; + rectangle._model = extend(model, { + parsedBorderWidth: parseBorderWidth(model) + }); + rectangle._styleOptions = options; + }, + + setHoverStyle: function(element) { + var me = this; + + BarController.prototype.setHoverStyle.apply(me, arguments); + + styleHelpers.saveStyle(element); + styleHelpers.setHoverStyle(element._model, element._styleOptions); + }, + + removeHoverStyle: function(element) { + var me = this; + + // For Chart.js 2.7.2 backward compatibility + if (!element.$previousStyle) { + styleHelpers.mergeStyle(element._model, element._styleOptions); + } + + BarController.prototype.removeHoverStyle.apply(me, arguments); + } +}); + +var helpers$4 = Chart.helpers; + +// For Chart.js 2.7.3 backward compatibility +var isPointInArea = helpers$4.canvas._isPointInArea || function(point, area) { + var epsilon = 1e-6; + + return point.x > area.left - epsilon && point.x < area.right + epsilon && + point.y > area.top - epsilon && point.y < area.bottom + epsilon; +}; + +var Point = Chart.elements.Point; + +var StylePoint = Point.extend({ + + draw: function(chartArea) { + var me = this; + var args = arguments; + var chart = me._chart; + var vm = me._view; + + var drawCallback = function() { + Point.prototype.draw.apply(me, args); + }; + + if (vm.skip || chartArea !== undefined && !isPointInArea(vm, chartArea)) { + return; + } + + styleHelpers.drawShadow(chart, vm, drawCallback, true); + + if (styleHelpers.opaque(vm.backgroundColor)) { + styleHelpers.drawBackground(vm, drawCallback); + styleHelpers.drawBackgroundOverlay(chart, vm, drawCallback); + styleHelpers.drawBevel(chart, vm, drawCallback); + } + + styleHelpers.drawInnerGlow(chart, vm, drawCallback); + styleHelpers.drawOuterGlow(chart, vm, drawCallback); + + styleHelpers.drawBorder(vm, drawCallback); + } +}); + +var helpers$5 = Chart.helpers; + +var extend$1 = helpers$5.extend; + +var BubbleController = Chart.controllers.bubble; + +var StyleBubbleController = BubbleController.extend({ + + dataElementType: StylePoint, + + updateElement: function(point, index) { + var me = this; + var options = styleHelpers.resolveStyle(me, point, index, me.chart.options.elements.point); + var model = {}; + + Object.defineProperty(point, '_model', { + configurable: true, + get: function() { + return model; + }, + set: function(value) { + extend$1(model, value, options); + } + }); + + BubbleController.prototype.updateElement.apply(me, arguments); + + delete point._model; + point._model = model; + point._styleOptions = options; + }, + + /** + * @protected + */ + setHoverStyle: function(element) { + var me = this; + + BubbleController.prototype.setHoverStyle.apply(me, arguments); + + styleHelpers.saveStyle(element); + styleHelpers.setHoverStyle(element._model, element._styleOptions); + }, + + /** + * @protected + */ + removeHoverStyle: function(element) { + var me = this; + + // For Chart.js 2.7.2 backward compatibility + if (!element.$previousStyle) { + styleHelpers.mergeStyle(element._model, element._styleOptions); + } + + BubbleController.prototype.removeHoverStyle.apply(me, arguments); + } +}); + +var helpers$6 = Chart.helpers; + +var Arc = Chart.elements.Arc; + +var StyleArc = Arc.extend({ + + draw: function() { + var me = this; + var args = arguments; + var chart = me._chart; + var vm = me._view; + + var drawCallback = function() { + Arc.prototype.draw.apply(me, args); + }; + + styleHelpers.drawShadow(chart, vm, drawCallback, true); + + if (styleHelpers.opaque(vm.backgroundColor)) { + styleHelpers.drawBackground(vm, drawCallback); + styleHelpers.drawBackgroundOverlay(chart, vm, drawCallback); + styleHelpers.drawBevel(chart, vm.borderAlign === 'inner' ? helpers$6.extend({}, vm, { + borderWidth: vm.borderWidth * 2 + }) : vm, drawCallback); + } + + styleHelpers.drawInnerGlow(chart, vm, drawCallback); + styleHelpers.drawOuterGlow(chart, vm, drawCallback); + + styleHelpers.drawBorder(vm, drawCallback); + } +}); + +var defaults = Chart.defaults; +var helpers$7 = Chart.helpers; + +var extend$2 = helpers$7.extend; +var resolve$1 = optionsHelpers$1.resolve; + +// Ported from Chart.js 2.8.0. Modified for style doughnut. +defaults.doughnut.legend.labels.generateLabels = defaults.pie.legend.labels.generateLabels = function(chart) { + var data = chart.data; + if (data.labels.length && data.datasets.length) { + return data.labels.map(function(label, i) { + var meta = chart.getDatasetMeta(0); + var ds = data.datasets[0]; + var arc = meta.data[i] || {}; + var custom = arc.custom || {}; + var arcOpts = chart.options.elements.arc; + var fill = resolve$1([custom.backgroundColor, ds.backgroundColor, arcOpts.backgroundColor], undefined, i); + var stroke = resolve$1([custom.borderColor, ds.borderColor, arcOpts.borderColor], undefined, i); + var bw = resolve$1([custom.borderWidth, ds.borderWidth, arcOpts.borderWidth], undefined, i); + + return extend$2({ + text: label, + fillStyle: fill, + strokeStyle: stroke, + lineWidth: bw, + hidden: isNaN(ds.data[i]) || meta.data[i].hidden, + + // Extra data used for toggling the correct item + index: i + }, styleHelpers.resolveStyle(meta.controller, arc, i, arcOpts)); + }); + } + return []; +}; + +var DoughnutController = Chart.controllers.doughnut; + +var StyleDoughnutController = DoughnutController.extend({ + + dataElementType: StyleArc, + + updateElement: function(arc, index) { + var me = this; + var options = styleHelpers.resolveStyle(me, arc, index, me.chart.options.elements.arc); + var model = {}; + + Object.defineProperty(arc, '_model', { + configurable: true, + get: function() { + return model; + }, + set: function(value) { + extend$2(model, value, options); + } + }); + + DoughnutController.prototype.updateElement.apply(me, arguments); + + delete arc._model; + arc._model = model; + arc._styleOptions = options; + }, + + setHoverStyle: function(element) { + var me = this; + + DoughnutController.prototype.setHoverStyle.apply(me, arguments); + + styleHelpers.saveStyle(element); + styleHelpers.setHoverStyle(element._model, element._styleOptions); + }, + + removeHoverStyle: function(element) { + var me = this; + + // For Chart.js 2.7.2 backward compatibility + if (!element.$previousStyle) { + styleHelpers.mergeStyle(element._model, element._styleOptions); + } + + DoughnutController.prototype.removeHoverStyle.apply(me, arguments); + } +}); + +var StyleHorizontalBarController = StyleBarController.extend({ + /** + * @private + */ + _getValueScaleId: function() { + return this.getMeta().xAxisID; + }, + + /** + * @private + */ + _getIndexScaleId: function() { + return this.getMeta().yAxisID; + }, + + /** + * For Chart.js 2.7.2 backward compatibility + * @private + */ + getValueScaleId: function() { + return this.getMeta().xAxisID; + }, + + /** + * For Chart.js 2.7.2 backward compatibility + * @private + */ + getIndexScaleId: function() { + return this.getMeta().yAxisID; + } +}); + +var Line = Chart.elements.Line; + +var StyleLine = Line.extend({ + + draw: function() { + var me = this; + var args = arguments; + var chart = me._chart; + var vm = me._view; + + var drawCallback = function() { + Line.prototype.draw.apply(me, args); + }; + + styleHelpers.drawShadow(chart, vm, drawCallback); + + // For outer glow + styleHelpers.drawShadow(chart, { + shadowOffsetX: 0, + shadowOffsetY: 0, + shadowBlur: vm.outerGlowWidth, + shadowColor: vm.outerGlowColor + }, drawCallback); + + styleHelpers.drawBorder(vm, drawCallback); + } +}); + +var helpers$8 = Chart.helpers; + +var extend$3 = helpers$8.extend; + +var LineController = Chart.controllers.line; + +var StyleLineController = LineController.extend({ + + datasetElementType: StyleLine, + + dataElementType: StylePoint, + + update: function() { + var me = this; + var line = me.getMeta().dataset; + var options = styleHelpers.resolveLineStyle(me, line, me.chart.options.elements.line); + var model = {}; + + Object.defineProperty(line, '_model', { + configurable: true, + get: function() { + return model; + }, + set: function(value) { + extend$3(model, value, options); + } + }); + + LineController.prototype.update.apply(me, arguments); + + delete line._model; + line._model = model; + line._styleOptions = options; + }, + + updateElement: function(point, index) { + var me = this; + var options = styleHelpers.resolvePointStyle(me, point, index, me.chart.options.elements.point); + + LineController.prototype.updateElement.apply(me, arguments); + + extend$3(point._model, options); + point._styleOptions = options; + }, + + setHoverStyle: function(element) { + // Point + var me = this; + + LineController.prototype.setHoverStyle.apply(me, arguments); + + styleHelpers.saveStyle(element); + styleHelpers.setHoverStyle(element._model, element._styleOptions); + }, + + removeHoverStyle: function(element) { + var me = this; + + // For Chart.js 2.7.2 backward compatibility + if (!element.$previousStyle) { + styleHelpers.mergeStyle(element._model, element._styleOptions); + } + + LineController.prototype.removeHoverStyle.apply(me, arguments); + } +}); + +var helpers$9 = Chart.helpers; + +var extend$4 = helpers$9.extend; +var resolve$2 = optionsHelpers$1.resolve; + +// Ported from Chart.js 2.8.0. Modified for style polarArea. +Chart.defaults.polarArea.legend.labels.generateLabels = function(chart) { + var data = chart.data; + if (data.labels.length && data.datasets.length) { + return data.labels.map(function(label, i) { + var meta = chart.getDatasetMeta(0); + var ds = data.datasets[0]; + var arc = meta.data[i] || {}; + var custom = arc.custom || {}; + var arcOpts = chart.options.elements.arc; + var fill = resolve$2([custom.backgroundColor, ds.backgroundColor, arcOpts.backgroundColor], undefined, i); + var stroke = resolve$2([custom.borderColor, ds.borderColor, arcOpts.borderColor], undefined, i); + var bw = resolve$2([custom.borderWidth, ds.borderWidth, arcOpts.borderWidth], undefined, i); + + return extend$4({ + text: label, + fillStyle: fill, + strokeStyle: stroke, + lineWidth: bw, + hidden: isNaN(ds.data[i]) || meta.data[i].hidden, + + // Extra data used for toggling the correct item + index: i + }, styleHelpers.resolveStyle(meta.controller, arc, i, arcOpts)); + }); + } + return []; +}; + +var PolarAreaController = Chart.controllers.polarArea; + +var StylePolarAreaController = PolarAreaController.extend({ + + dataElementType: StyleArc, + + updateElement: function(arc, index) { + var me = this; + var options = styleHelpers.resolveStyle(me, arc, index, me.chart.options.elements.arc); + var model = {}; + + Object.defineProperty(arc, '_model', { + configurable: true, + get: function() { + return model; + }, + set: function(value) { + extend$4(model, value, options); + } + }); + + PolarAreaController.prototype.updateElement.apply(me, arguments); + + delete arc._model; + arc._model = model; + arc._styleOptions = options; + }, + + setHoverStyle: function(element) { + var me = this; + + PolarAreaController.prototype.setHoverStyle.apply(me, arguments); + + styleHelpers.saveStyle(element); + styleHelpers.setHoverStyle(element._model, element._styleOptions); + }, + + removeHoverStyle: function(element) { + var me = this; + + // For Chart.js 2.7.2 backward compatibility + if (!element.$previousStyle) { + styleHelpers.mergeStyle(element._model, element._styleOptions); + } + + PolarAreaController.prototype.removeHoverStyle.apply(me, arguments); + } +}); + +var helpers$a = Chart.helpers; + +var extend$5 = helpers$a.extend; + +var RadarController = Chart.controllers.radar; + +var StyleRadarController = RadarController.extend({ + + datasetElementType: StyleLine, + + dataElementType: StylePoint, + + update: function() { + var me = this; + var line = me.getMeta().dataset; + var options = styleHelpers.resolveLineStyle(me, line, me.chart.options.elements.line); + var model = {}; + + Object.defineProperty(line, '_model', { + configurable: true, + get: function() { + return model; + }, + set: function(value) { + extend$5(model, value, options); + } + }); + + RadarController.prototype.update.apply(me, arguments); + + delete line._model; + line._model = model; + line._styleOptions = options; + }, + + updateElement: function(point, index) { + var me = this; + var options = styleHelpers.resolvePointStyle(me, point, index, me.chart.options.elements.point); + + RadarController.prototype.updateElement.apply(me, arguments); + + extend$5(point._model, options); + point._styleOptions = options; + }, + + setHoverStyle: function(element) { + // Point + var me = this; + + RadarController.prototype.setHoverStyle.apply(me, arguments); + + styleHelpers.saveStyle(element); + styleHelpers.setHoverStyle(element._model, element._styleOptions); + }, + + removeHoverStyle: function(element) { + var me = this; + + // For Chart.js 2.7.2 backward compatibility + if (!element.$previousStyle) { + styleHelpers.mergeStyle(element._model, element._styleOptions); + } + + RadarController.prototype.removeHoverStyle.apply(me, arguments); + } +}); + +var defaults$1 = Chart.defaults; +var helpers$b = Chart.helpers; + +// For Chart.js 2.7.1 backward compatibility +var layouts = Chart.layouts || Chart.layoutService; + +// For Chart.js 2.6.0 backward compatibility +var valueOrDefault = helpers$b.valueOrDefault || helpers$b.getValueOrDefault; + +// For Chart.js 2.6.0 backward compatibility +var valueAtIndexOrDefault = helpers$b.valueAtIndexOrDefault || helpers$b.getValueAtIndexOrDefault; + +// For Chart.js 2.6.0 backward compatibility +var mergeIf = helpers$b.mergeIf || function(target, source) { + return helpers$b.configMerge.call(this, source, target); +}; + +var extend$6 = helpers$b.extend; + +// Ported from Chart.js 2.8.0. Modified for style legend. +// Generates labels shown in the legend +defaults$1.global.legend.labels.generateLabels = function(chart) { + var data = chart.data; + var options = chart.options.legend || {}; + var usePointStyle = options.labels && options.labels.usePointStyle; + + return helpers$b.isArray(data.datasets) ? data.datasets.map(function(dataset, i) { + var meta = chart.getDatasetMeta(i); + var controller = meta.controller; + var elementOpts = chart.options.elements; + var element, styleOptions; + + if (usePointStyle) { + element = meta.data[0] || {}; + styleOptions = styleHelpers.resolvePointStyle(controller, element, i, elementOpts.point); + } else if (meta.dataset) { + element = meta.dataset; + styleOptions = styleHelpers.resolveLineStyle(controller, element, elementOpts.line); + } else { + element = meta.data[0] || {}; + styleOptions = styleHelpers.resolveStyle(controller, element, i, meta.bar ? elementOpts.rectangle : elementOpts.point); + } + + return extend$6({ + text: dataset.label, + fillStyle: valueAtIndexOrDefault(dataset.backgroundColor, 0), + hidden: !chart.isDatasetVisible(i), + lineCap: dataset.borderCapStyle, + lineDash: dataset.borderDash, + lineDashOffset: dataset.borderDashOffset, + lineJoin: dataset.borderJoinStyle, + lineWidth: dataset.borderWidth, + strokeStyle: dataset.borderColor, + pointStyle: dataset.pointStyle, + + // Below is extra data used for toggling the datasets + datasetIndex: i + }, styleOptions); + }, this) : []; +}; + +function drawLegendBox(chart, options, drawCallback) { + var ctx = chart.ctx; + + styleHelpers.drawShadow(chart, options, drawCallback, true); + + if (styleHelpers.opaque(ctx.fillStyle)) { + ctx.save(); + + ctx.strokeStyle = 'rgba(0, 0, 0, 0)'; + drawCallback(); + + styleHelpers.drawBackgroundOverlay(chart, options, drawCallback); + styleHelpers.drawBevel(chart, options, drawCallback); + + ctx.restore(); + } + + styleHelpers.drawInnerGlow(chart, options, drawCallback); + styleHelpers.drawOuterGlow(chart, options, drawCallback); + + ctx.fillStyle = 'rgba(0, 0, 0, 0)'; + drawCallback(); + + ctx.restore(); +} + +var StyleLegend = Chart.Legend.extend({ + + draw: function() { + var me = this; + var chart = me.chart; + var globalDefaults = defaults$1.global; + var each = helpers$b.each; + var drawPoint = helpers$b.canvas.drawPoint; + var ctx = me.ctx; + var options; + + helpers$b.each = function(loopable, fn) { + each(loopable, function(legendItem) { + var keys = Object.keys(legendItem); + var i, ilen; + + options = {}; + for (i = 0, ilen = keys.length; i < ilen; i++) { + options[keys[i]] = legendItem[keys[i]]; + } + options.borderColor = valueOrDefault(legendItem.strokeStyle, globalDefaults.defaultColor); + options.borderWidth = valueOrDefault(legendItem.lineWidth, globalDefaults.elements.line.borderWidth); + + fn.apply(null, arguments); + }); + }; + + helpers$b.canvas.drawPoint = function() { + var args = arguments; + var drawCallback = function() { + drawPoint.apply(null, args); + }; + + drawLegendBox(chart, options, drawCallback); + }; + + ctx.strokeRect = function() { + // noop + }; + + ctx.fillRect = function(x, y, width, height) { + var drawCallback = function() { + ctx.beginPath(); + ctx.rect(x, y, width, height); + ctx.fill(); + if (options.borderWidth !== 0) { + ctx.stroke(); + } + }; + + drawLegendBox(chart, options, drawCallback); + }; + + Chart.Legend.prototype.draw.apply(me, arguments); + + helpers$b.each = each; + helpers$b.canvas.drawPoint = drawPoint; + delete ctx.fillRect; + delete ctx.strokeRect; + } +}); + +// Ported from Chart.js 2.8.0. Modified for style legend. +function createNewLegendAndAttach(chart, legendOpts) { + var legend = new StyleLegend({ + ctx: chart.ctx, + options: legendOpts, + chart: chart + }); + + layouts.configure(chart, legend, legendOpts); + layouts.addBox(chart, legend); + chart.legend = legend; +} + +var StyleLegendPlugin = { + id: 'legend', + + _element: StyleLegend, + + // Ported from Chart.js 2.8.0. + beforeInit: function(chart) { + var legendOpts = chart.options.legend; + + if (legendOpts) { + createNewLegendAndAttach(chart, legendOpts); + } + }, + + // Ported from Chart.js 2.8.0. + beforeUpdate: function(chart) { + var legendOpts = chart.options.legend; + var legend = chart.legend; + + if (legendOpts) { + mergeIf(legendOpts, defaults$1.global.legend); + + if (legend) { + layouts.configure(chart, legend, legendOpts); + legend.options = legendOpts; + } else { + createNewLegendAndAttach(chart, legendOpts); + } + } else if (legend) { + layouts.removeBox(chart, legend); + delete chart.legend; + } + }, + + // Ported from Chart.js 2.8.0. + afterEvent: function(chart, e) { + var legend = chart.legend; + if (legend) { + legend.handleEvent(e); + } + } +}; + +var helpers$c = Chart.helpers; + +// For Chart.js 2.7.1 backward compatibility +var layouts$1 = Chart.layouts || Chart.layoutService; + +var plugins = Chart.plugins; + +var styleControllers = { + bar: StyleBarController, + bubble: StyleBubbleController, + doughnut: StyleDoughnutController, + horizontalBar: StyleHorizontalBarController, + line: StyleLineController, + polarArea: StylePolarAreaController, + pie: StyleDoughnutController, + radar: StyleRadarController, + scatter: StyleLineController +}; + +// Ported from Chart.js 2.8.0. Modified for style controllers. +function buildOrUpdateControllers() { + var me = this; + var newControllers = []; + + helpers$c.each(me.data.datasets, function(dataset, datasetIndex) { + var meta = me.getDatasetMeta(datasetIndex); + var type = dataset.type || me.config.type; + + if (meta.type && meta.type !== type) { + me.destroyDatasetMeta(datasetIndex); + meta = me.getDatasetMeta(datasetIndex); + } + meta.type = type; + + if (meta.controller) { + meta.controller.updateIndex(datasetIndex); + meta.controller.linkScales(); + } else { + var ControllerClass = styleControllers[meta.type]; + if (ControllerClass === undefined) { + throw new Error('"' + meta.type + '" is not a chart type.'); + } + + meta.controller = new ControllerClass(me, datasetIndex); + newControllers.push(meta.controller); + } + }, me); + + return newControllers; +} + +// Ported from Chart.js 2.8.0. Modified for style tooltip. +function initToolTip() { + var me = this; + me.tooltip = new StyleTooltip({ + _chart: me, + _chartInstance: me, // deprecated, backward compatibility + _data: me.data, + _options: me.options.tooltips + }, me); +} + +var descriptors = plugins.descriptors; + +plugins.descriptors = function(chart) { + var style = chart._style; + + // Replace legend plugin with style legend plugin + if (style) { + // chart._plugins for Chart.js 2.7.1 backward compatibility + var cache = chart.$plugins || chart._plugins || (chart.$plugins = chart._plugins = {}); + if (cache.id === this._cacheId) { + return cache.descriptors; + } + + var p = this._plugins; + var result; + + this._plugins = p.map(function(plugin) { + if (plugin.id === 'legend') { + return StyleLegendPlugin; + } + return plugin; + }); + } + + result = descriptors.apply(this, arguments); + + if (style) { + this._plugins = p; + } + + return result; +}; + +var StylePlugin = { + id: 'style', + + beforeInit: function(chart) { + chart._style = {}; + + chart.buildOrUpdateControllers = buildOrUpdateControllers; + chart.initToolTip = initToolTip; + + // Remove the existing legend if exists + if (chart.legend) { + layouts$1.removeBox(chart, chart.legend); + delete chart.legend; + } + + // Invalidate plugin cache and create new one + delete chart.$plugins; + // For Chart.js 2.7.1 backward compatibility + delete chart._plugins; + plugins.descriptors(chart); + } +}; + +Chart.plugins.register(StylePlugin); + +return StylePlugin; + +})); diff --git a/dist/chartjs-plugin-style.min.js b/dist/chartjs-plugin-style.min.js new file mode 100644 index 0000000..e47f29b --- /dev/null +++ b/dist/chartjs-plugin-style.min.js @@ -0,0 +1,7 @@ +/*! + * chartjs-plugin-style v0.5.0 + * https://nagix.github.io/chartjs-plugin-style + * (c) 2019 Akihiko Kusanagi + * Released under the MIT license + */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("chart.js")):"function"==typeof define&&define.amd?define(["chart.js"],t):(e=e||self).ChartStyle=t(e.Chart)}(this,function(e){"use strict";var t=(e=e&&e.hasOwnProperty("default")?e.default:e).helpers,o=t.options||{},r=t.extend(o,{resolve:o.resolve||function(e,o,r){var l,n,a;for(l=0,n=e.length;l0?s:0)*a/2,left:l,bottom:l,right:l}:{top:d,left:d,bottom:d,right:d},n.save(),this.setPath(n,o),n.clip(),n.translate(-1e6,0),this.setPath(n,o),n.rect(0,0,e.width,e.height),n.fillStyle="black",n.shadowOffsetX=1e6*a-r.right,n.shadowOffsetY=-r.bottom,n.shadowBlur=d,n.shadowColor=t.bevelShadowColor,navigator&&navigator.userAgent.match("Windows.+Firefox")||(n.globalCompositeOperation="source-atop"),n.fill("evenodd"),n.shadowOffsetX=1e6*a+r.left,n.shadowOffsetY=r.top,n.shadowColor=t.bevelHighlightColor,n.fill("evenodd"),n.restore())},drawGlow:function(e,t,o,r){var l=e.ctx,n=r?t.outerGlowWidth:t.innerGlowWidth,a=t.borderWidth,i=e.currentDevicePixelRatio;n&&(l.save(),this.setPath(l,o),r&&l.rect(0,0,e.width,e.height),l.clip("evenodd"),l.translate(-1e6,0),this.setPath(l,o),r||l.rect(0,0,e.width,e.height),l.lineWidth=a,l.strokeStyle="black",l.fillStyle="black",l.shadowOffsetX=1e6*i,l.shadowBlur=n*i,l.shadowColor=r?t.outerGlowColor:t.innerGlowColor,l.fill("evenodd"),a&&l.stroke(),l.restore())},drawInnerGlow:function(e,t,o){this.drawGlow(e,t,o)},drawOuterGlow:function(e,t,o){this.drawGlow(e,t,o,!0)},drawBackgroundOverlay:function(e,t,o){var r=e.ctx,l=t.backgroundOverlayColor;l&&(r.save(),this.setPath(r,o),r.fillStyle=l,r.globalCompositeOperation=t.backgroundOverlayMode,r.fill(),r.restore())},opaque:function(e){return l.color(e).alpha()>0},getHoverColor:function(e){return void 0!==e?l.getHoverColor(e):e},mergeStyle:function(e,t){if(void 0!==e&&void 0!==t)return this.styleKeys.forEach(function(o){e[o]=t[o]}),e},setHoverStyle:function(e,t){var o,r,l=this.styleKeys,n=this.hoverStyleKeys;if(void 0!==e&&void 0!==t){for(o=0,r=l.length;oe.x&&(t=y(t,"left","right")):e.baseo?o:r,right:d.right||l<0?0:l>t?t:l,bottom:d.bottom||n<0?0:n>o?o:n,left:d.left||a<0?0:a>t?t:a}}var g=e.controllers.bar,w=g.extend({dataElementType:c,updateElement:function(e,t){var o=i.resolveStyle(this,e,t,this.chart.options.elements.rectangle),r={};Object.defineProperty(e,"_model",{configurable:!0,get:function(){return r},set:function(e){v(r,e,o)}}),g.prototype.updateElement.apply(this,arguments),delete e._model,e._model=v(r,{parsedBorderWidth:f(r)}),e._styleOptions=o},setHoverStyle:function(e){g.prototype.setHoverStyle.apply(this,arguments),i.saveStyle(e),i.setHoverStyle(e._model,e._styleOptions)},removeHoverStyle:function(e){e.$previousStyle||i.mergeStyle(e._model,e._styleOptions),g.prototype.removeHoverStyle.apply(this,arguments)}}),b=e.helpers.canvas._isPointInArea||function(e,t){return e.x>t.left-1e-6&&e.xt.top-1e-6&&e.y