İlk temizlik tamamlandı bir önceki projeden
This commit is contained in:
@@ -0,0 +1,620 @@
|
||||
/* global window: false */
|
||||
/* global document: false */
|
||||
'use strict';
|
||||
|
||||
var color = require('chartjs-color');
|
||||
var defaults = require('./core.defaults');
|
||||
var helpers = require('../helpers/index');
|
||||
|
||||
module.exports = function() {
|
||||
|
||||
// -- Basic js utility methods
|
||||
|
||||
helpers.where = function(collection, filterCallback) {
|
||||
if (helpers.isArray(collection) && Array.prototype.filter) {
|
||||
return collection.filter(filterCallback);
|
||||
}
|
||||
var filtered = [];
|
||||
|
||||
helpers.each(collection, function(item) {
|
||||
if (filterCallback(item)) {
|
||||
filtered.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
return filtered;
|
||||
};
|
||||
helpers.findIndex = Array.prototype.findIndex ?
|
||||
function(array, callback, scope) {
|
||||
return array.findIndex(callback, scope);
|
||||
} :
|
||||
function(array, callback, scope) {
|
||||
scope = scope === undefined ? array : scope;
|
||||
for (var i = 0, ilen = array.length; i < ilen; ++i) {
|
||||
if (callback.call(scope, array[i], i, array)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
helpers.findNextWhere = function(arrayToSearch, filterCallback, startIndex) {
|
||||
// Default to start of the array
|
||||
if (helpers.isNullOrUndef(startIndex)) {
|
||||
startIndex = -1;
|
||||
}
|
||||
for (var i = startIndex + 1; i < arrayToSearch.length; i++) {
|
||||
var currentItem = arrayToSearch[i];
|
||||
if (filterCallback(currentItem)) {
|
||||
return currentItem;
|
||||
}
|
||||
}
|
||||
};
|
||||
helpers.findPreviousWhere = function(arrayToSearch, filterCallback, startIndex) {
|
||||
// Default to end of the array
|
||||
if (helpers.isNullOrUndef(startIndex)) {
|
||||
startIndex = arrayToSearch.length;
|
||||
}
|
||||
for (var i = startIndex - 1; i >= 0; i--) {
|
||||
var currentItem = arrayToSearch[i];
|
||||
if (filterCallback(currentItem)) {
|
||||
return currentItem;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// -- Math methods
|
||||
helpers.isNumber = function(n) {
|
||||
return !isNaN(parseFloat(n)) && isFinite(n);
|
||||
};
|
||||
helpers.almostEquals = function(x, y, epsilon) {
|
||||
return Math.abs(x - y) < epsilon;
|
||||
};
|
||||
helpers.almostWhole = function(x, epsilon) {
|
||||
var rounded = Math.round(x);
|
||||
return ((rounded - epsilon) <= x) && ((rounded + epsilon) >= x);
|
||||
};
|
||||
helpers.max = function(array) {
|
||||
return array.reduce(function(max, value) {
|
||||
if (!isNaN(value)) {
|
||||
return Math.max(max, value);
|
||||
}
|
||||
return max;
|
||||
}, Number.NEGATIVE_INFINITY);
|
||||
};
|
||||
helpers.min = function(array) {
|
||||
return array.reduce(function(min, value) {
|
||||
if (!isNaN(value)) {
|
||||
return Math.min(min, value);
|
||||
}
|
||||
return min;
|
||||
}, Number.POSITIVE_INFINITY);
|
||||
};
|
||||
helpers.sign = Math.sign ?
|
||||
function(x) {
|
||||
return Math.sign(x);
|
||||
} :
|
||||
function(x) {
|
||||
x = +x; // convert to a number
|
||||
if (x === 0 || isNaN(x)) {
|
||||
return x;
|
||||
}
|
||||
return x > 0 ? 1 : -1;
|
||||
};
|
||||
helpers.toRadians = function(degrees) {
|
||||
return degrees * (Math.PI / 180);
|
||||
};
|
||||
helpers.toDegrees = function(radians) {
|
||||
return radians * (180 / Math.PI);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the number of decimal places
|
||||
* i.e. the number of digits after the decimal point, of the value of this Number.
|
||||
* @param {number} x - A number.
|
||||
* @returns {number} The number of decimal places.
|
||||
* @private
|
||||
*/
|
||||
helpers._decimalPlaces = function(x) {
|
||||
if (!helpers.isFinite(x)) {
|
||||
return;
|
||||
}
|
||||
var e = 1;
|
||||
var p = 0;
|
||||
while (Math.round(x * e) / e !== x) {
|
||||
e *= 10;
|
||||
p++;
|
||||
}
|
||||
return p;
|
||||
};
|
||||
|
||||
// Gets the angle from vertical upright to the point about a centre.
|
||||
helpers.getAngleFromPoint = function(centrePoint, anglePoint) {
|
||||
var distanceFromXCenter = anglePoint.x - centrePoint.x;
|
||||
var distanceFromYCenter = anglePoint.y - centrePoint.y;
|
||||
var radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);
|
||||
|
||||
var angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);
|
||||
|
||||
if (angle < (-0.5 * Math.PI)) {
|
||||
angle += 2.0 * Math.PI; // make sure the returned angle is in the range of (-PI/2, 3PI/2]
|
||||
}
|
||||
|
||||
return {
|
||||
angle: angle,
|
||||
distance: radialDistanceFromCenter
|
||||
};
|
||||
};
|
||||
helpers.distanceBetweenPoints = function(pt1, pt2) {
|
||||
return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));
|
||||
};
|
||||
|
||||
/**
|
||||
* Provided for backward compatibility, not available anymore
|
||||
* @function Chart.helpers.aliasPixel
|
||||
* @deprecated since version 2.8.0
|
||||
* @todo remove at version 3
|
||||
*/
|
||||
helpers.aliasPixel = function(pixelWidth) {
|
||||
return (pixelWidth % 2 === 0) ? 0 : 0.5;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the aligned pixel value to avoid anti-aliasing blur
|
||||
* @param {Chart} chart - The chart instance.
|
||||
* @param {number} pixel - A pixel value.
|
||||
* @param {number} width - The width of the element.
|
||||
* @returns {number} The aligned pixel value.
|
||||
* @private
|
||||
*/
|
||||
helpers._alignPixel = function(chart, pixel, width) {
|
||||
var devicePixelRatio = chart.currentDevicePixelRatio;
|
||||
var halfWidth = width / 2;
|
||||
return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth;
|
||||
};
|
||||
|
||||
helpers.splineCurve = function(firstPoint, middlePoint, afterPoint, t) {
|
||||
// Props to Rob Spencer at scaled innovation for his post on splining between points
|
||||
// http://scaledinnovation.com/analytics/splines/aboutSplines.html
|
||||
|
||||
// This function must also respect "skipped" points
|
||||
|
||||
var previous = firstPoint.skip ? middlePoint : firstPoint;
|
||||
var current = middlePoint;
|
||||
var next = afterPoint.skip ? middlePoint : afterPoint;
|
||||
|
||||
var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2));
|
||||
var d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2));
|
||||
|
||||
var s01 = d01 / (d01 + d12);
|
||||
var s12 = d12 / (d01 + d12);
|
||||
|
||||
// If all points are the same, s01 & s02 will be inf
|
||||
s01 = isNaN(s01) ? 0 : s01;
|
||||
s12 = isNaN(s12) ? 0 : s12;
|
||||
|
||||
var fa = t * s01; // scaling factor for triangle Ta
|
||||
var fb = t * s12;
|
||||
|
||||
return {
|
||||
previous: {
|
||||
x: current.x - fa * (next.x - previous.x),
|
||||
y: current.y - fa * (next.y - previous.y)
|
||||
},
|
||||
next: {
|
||||
x: current.x + fb * (next.x - previous.x),
|
||||
y: current.y + fb * (next.y - previous.y)
|
||||
}
|
||||
};
|
||||
};
|
||||
helpers.EPSILON = Number.EPSILON || 1e-14;
|
||||
helpers.splineCurveMonotone = function(points) {
|
||||
// This function calculates Bézier control points in a similar way than |splineCurve|,
|
||||
// but preserves monotonicity of the provided data and ensures no local extremums are added
|
||||
// between the dataset discrete points due to the interpolation.
|
||||
// See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
|
||||
|
||||
var pointsWithTangents = (points || []).map(function(point) {
|
||||
return {
|
||||
model: point._model,
|
||||
deltaK: 0,
|
||||
mK: 0
|
||||
};
|
||||
});
|
||||
|
||||
// Calculate slopes (deltaK) and initialize tangents (mK)
|
||||
var pointsLen = pointsWithTangents.length;
|
||||
var i, pointBefore, pointCurrent, pointAfter;
|
||||
for (i = 0; i < pointsLen; ++i) {
|
||||
pointCurrent = pointsWithTangents[i];
|
||||
if (pointCurrent.model.skip) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
|
||||
pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
|
||||
if (pointAfter && !pointAfter.model.skip) {
|
||||
var slopeDeltaX = (pointAfter.model.x - pointCurrent.model.x);
|
||||
|
||||
// In the case of two points that appear at the same x pixel, slopeDeltaX is 0
|
||||
pointCurrent.deltaK = slopeDeltaX !== 0 ? (pointAfter.model.y - pointCurrent.model.y) / slopeDeltaX : 0;
|
||||
}
|
||||
|
||||
if (!pointBefore || pointBefore.model.skip) {
|
||||
pointCurrent.mK = pointCurrent.deltaK;
|
||||
} else if (!pointAfter || pointAfter.model.skip) {
|
||||
pointCurrent.mK = pointBefore.deltaK;
|
||||
} else if (this.sign(pointBefore.deltaK) !== this.sign(pointCurrent.deltaK)) {
|
||||
pointCurrent.mK = 0;
|
||||
} else {
|
||||
pointCurrent.mK = (pointBefore.deltaK + pointCurrent.deltaK) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust tangents to ensure monotonic properties
|
||||
var alphaK, betaK, tauK, squaredMagnitude;
|
||||
for (i = 0; i < pointsLen - 1; ++i) {
|
||||
pointCurrent = pointsWithTangents[i];
|
||||
pointAfter = pointsWithTangents[i + 1];
|
||||
if (pointCurrent.model.skip || pointAfter.model.skip) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (helpers.almostEquals(pointCurrent.deltaK, 0, this.EPSILON)) {
|
||||
pointCurrent.mK = pointAfter.mK = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
alphaK = pointCurrent.mK / pointCurrent.deltaK;
|
||||
betaK = pointAfter.mK / pointCurrent.deltaK;
|
||||
squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2);
|
||||
if (squaredMagnitude <= 9) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tauK = 3 / Math.sqrt(squaredMagnitude);
|
||||
pointCurrent.mK = alphaK * tauK * pointCurrent.deltaK;
|
||||
pointAfter.mK = betaK * tauK * pointCurrent.deltaK;
|
||||
}
|
||||
|
||||
// Compute control points
|
||||
var deltaX;
|
||||
for (i = 0; i < pointsLen; ++i) {
|
||||
pointCurrent = pointsWithTangents[i];
|
||||
if (pointCurrent.model.skip) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;
|
||||
pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;
|
||||
if (pointBefore && !pointBefore.model.skip) {
|
||||
deltaX = (pointCurrent.model.x - pointBefore.model.x) / 3;
|
||||
pointCurrent.model.controlPointPreviousX = pointCurrent.model.x - deltaX;
|
||||
pointCurrent.model.controlPointPreviousY = pointCurrent.model.y - deltaX * pointCurrent.mK;
|
||||
}
|
||||
if (pointAfter && !pointAfter.model.skip) {
|
||||
deltaX = (pointAfter.model.x - pointCurrent.model.x) / 3;
|
||||
pointCurrent.model.controlPointNextX = pointCurrent.model.x + deltaX;
|
||||
pointCurrent.model.controlPointNextY = pointCurrent.model.y + deltaX * pointCurrent.mK;
|
||||
}
|
||||
}
|
||||
};
|
||||
helpers.nextItem = function(collection, index, loop) {
|
||||
if (loop) {
|
||||
return index >= collection.length - 1 ? collection[0] : collection[index + 1];
|
||||
}
|
||||
return index >= collection.length - 1 ? collection[collection.length - 1] : collection[index + 1];
|
||||
};
|
||||
helpers.previousItem = function(collection, index, loop) {
|
||||
if (loop) {
|
||||
return index <= 0 ? collection[collection.length - 1] : collection[index - 1];
|
||||
}
|
||||
return index <= 0 ? collection[0] : collection[index - 1];
|
||||
};
|
||||
// Implementation of the nice number algorithm used in determining where axis labels will go
|
||||
helpers.niceNum = function(range, round) {
|
||||
var exponent = Math.floor(helpers.log10(range));
|
||||
var fraction = range / Math.pow(10, exponent);
|
||||
var niceFraction;
|
||||
|
||||
if (round) {
|
||||
if (fraction < 1.5) {
|
||||
niceFraction = 1;
|
||||
} else if (fraction < 3) {
|
||||
niceFraction = 2;
|
||||
} else if (fraction < 7) {
|
||||
niceFraction = 5;
|
||||
} else {
|
||||
niceFraction = 10;
|
||||
}
|
||||
} else if (fraction <= 1.0) {
|
||||
niceFraction = 1;
|
||||
} else if (fraction <= 2) {
|
||||
niceFraction = 2;
|
||||
} else if (fraction <= 5) {
|
||||
niceFraction = 5;
|
||||
} else {
|
||||
niceFraction = 10;
|
||||
}
|
||||
|
||||
return niceFraction * Math.pow(10, exponent);
|
||||
};
|
||||
// Request animation polyfill - https://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
|
||||
helpers.requestAnimFrame = (function() {
|
||||
if (typeof window === 'undefined') {
|
||||
return function(callback) {
|
||||
callback();
|
||||
};
|
||||
}
|
||||
return window.requestAnimationFrame ||
|
||||
window.webkitRequestAnimationFrame ||
|
||||
window.mozRequestAnimationFrame ||
|
||||
window.oRequestAnimationFrame ||
|
||||
window.msRequestAnimationFrame ||
|
||||
function(callback) {
|
||||
return window.setTimeout(callback, 1000 / 60);
|
||||
};
|
||||
}());
|
||||
// -- DOM methods
|
||||
helpers.getRelativePosition = function(evt, chart) {
|
||||
var mouseX, mouseY;
|
||||
var e = evt.originalEvent || evt;
|
||||
var canvas = evt.target || evt.srcElement;
|
||||
var boundingRect = canvas.getBoundingClientRect();
|
||||
|
||||
var touches = e.touches;
|
||||
if (touches && touches.length > 0) {
|
||||
mouseX = touches[0].clientX;
|
||||
mouseY = touches[0].clientY;
|
||||
|
||||
} else {
|
||||
mouseX = e.clientX;
|
||||
mouseY = e.clientY;
|
||||
}
|
||||
|
||||
// Scale mouse coordinates into canvas coordinates
|
||||
// by following the pattern laid out by 'jerryj' in the comments of
|
||||
// https://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
|
||||
var paddingLeft = parseFloat(helpers.getStyle(canvas, 'padding-left'));
|
||||
var paddingTop = parseFloat(helpers.getStyle(canvas, 'padding-top'));
|
||||
var paddingRight = parseFloat(helpers.getStyle(canvas, 'padding-right'));
|
||||
var paddingBottom = parseFloat(helpers.getStyle(canvas, 'padding-bottom'));
|
||||
var width = boundingRect.right - boundingRect.left - paddingLeft - paddingRight;
|
||||
var height = boundingRect.bottom - boundingRect.top - paddingTop - paddingBottom;
|
||||
|
||||
// We divide by the current device pixel ratio, because the canvas is scaled up by that amount in each direction. However
|
||||
// the backend model is in unscaled coordinates. Since we are going to deal with our model coordinates, we go back here
|
||||
mouseX = Math.round((mouseX - boundingRect.left - paddingLeft) / (width) * canvas.width / chart.currentDevicePixelRatio);
|
||||
mouseY = Math.round((mouseY - boundingRect.top - paddingTop) / (height) * canvas.height / chart.currentDevicePixelRatio);
|
||||
|
||||
return {
|
||||
x: mouseX,
|
||||
y: mouseY
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
// Private helper function to convert max-width/max-height values that may be percentages into a number
|
||||
function parseMaxStyle(styleValue, node, parentProperty) {
|
||||
var valueInPixels;
|
||||
if (typeof styleValue === 'string') {
|
||||
valueInPixels = parseInt(styleValue, 10);
|
||||
|
||||
if (styleValue.indexOf('%') !== -1) {
|
||||
// percentage * size in dimension
|
||||
valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
|
||||
}
|
||||
} else {
|
||||
valueInPixels = styleValue;
|
||||
}
|
||||
|
||||
return valueInPixels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the given value contains an effective constraint.
|
||||
* @private
|
||||
*/
|
||||
function isConstrainedValue(value) {
|
||||
return value !== undefined && value !== null && value !== 'none';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the max width or height of the given DOM node in a cross-browser compatible fashion
|
||||
* @param {HTMLElement} domNode - the node to check the constraint on
|
||||
* @param {string} maxStyle - the style that defines the maximum for the direction we are using ('max-width' / 'max-height')
|
||||
* @param {string} percentageProperty - property of parent to use when calculating width as a percentage
|
||||
* @see {@link https://www.nathanaeljones.com/blog/2013/reading-max-width-cross-browser}
|
||||
*/
|
||||
function getConstraintDimension(domNode, maxStyle, percentageProperty) {
|
||||
var view = document.defaultView;
|
||||
var parentNode = helpers._getParentNode(domNode);
|
||||
var constrainedNode = view.getComputedStyle(domNode)[maxStyle];
|
||||
var constrainedContainer = view.getComputedStyle(parentNode)[maxStyle];
|
||||
var hasCNode = isConstrainedValue(constrainedNode);
|
||||
var hasCContainer = isConstrainedValue(constrainedContainer);
|
||||
var infinity = Number.POSITIVE_INFINITY;
|
||||
|
||||
if (hasCNode || hasCContainer) {
|
||||
return Math.min(
|
||||
hasCNode ? parseMaxStyle(constrainedNode, domNode, percentageProperty) : infinity,
|
||||
hasCContainer ? parseMaxStyle(constrainedContainer, parentNode, percentageProperty) : infinity);
|
||||
}
|
||||
|
||||
return 'none';
|
||||
}
|
||||
// returns Number or undefined if no constraint
|
||||
helpers.getConstraintWidth = function(domNode) {
|
||||
return getConstraintDimension(domNode, 'max-width', 'clientWidth');
|
||||
};
|
||||
// returns Number or undefined if no constraint
|
||||
helpers.getConstraintHeight = function(domNode) {
|
||||
return getConstraintDimension(domNode, 'max-height', 'clientHeight');
|
||||
};
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
helpers._calculatePadding = function(container, padding, parentDimension) {
|
||||
padding = helpers.getStyle(container, padding);
|
||||
|
||||
return padding.indexOf('%') > -1 ? parentDimension * parseInt(padding, 10) / 100 : parseInt(padding, 10);
|
||||
};
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
helpers._getParentNode = function(domNode) {
|
||||
var parent = domNode.parentNode;
|
||||
if (parent && parent.toString() === '[object ShadowRoot]') {
|
||||
parent = parent.host;
|
||||
}
|
||||
return parent;
|
||||
};
|
||||
helpers.getMaximumWidth = function(domNode) {
|
||||
var container = helpers._getParentNode(domNode);
|
||||
if (!container) {
|
||||
return domNode.clientWidth;
|
||||
}
|
||||
|
||||
var clientWidth = container.clientWidth;
|
||||
var paddingLeft = helpers._calculatePadding(container, 'padding-left', clientWidth);
|
||||
var paddingRight = helpers._calculatePadding(container, 'padding-right', clientWidth);
|
||||
|
||||
var w = clientWidth - paddingLeft - paddingRight;
|
||||
var cw = helpers.getConstraintWidth(domNode);
|
||||
return isNaN(cw) ? w : Math.min(w, cw);
|
||||
};
|
||||
helpers.getMaximumHeight = function(domNode) {
|
||||
var container = helpers._getParentNode(domNode);
|
||||
if (!container) {
|
||||
return domNode.clientHeight;
|
||||
}
|
||||
|
||||
var clientHeight = container.clientHeight;
|
||||
var paddingTop = helpers._calculatePadding(container, 'padding-top', clientHeight);
|
||||
var paddingBottom = helpers._calculatePadding(container, 'padding-bottom', clientHeight);
|
||||
|
||||
var h = clientHeight - paddingTop - paddingBottom;
|
||||
var ch = helpers.getConstraintHeight(domNode);
|
||||
return isNaN(ch) ? h : Math.min(h, ch);
|
||||
};
|
||||
helpers.getStyle = function(el, property) {
|
||||
return el.currentStyle ?
|
||||
el.currentStyle[property] :
|
||||
document.defaultView.getComputedStyle(el, null).getPropertyValue(property);
|
||||
};
|
||||
helpers.retinaScale = function(chart, forceRatio) {
|
||||
var pixelRatio = chart.currentDevicePixelRatio = forceRatio || (typeof window !== 'undefined' && window.devicePixelRatio) || 1;
|
||||
if (pixelRatio === 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
var canvas = chart.canvas;
|
||||
var height = chart.height;
|
||||
var width = chart.width;
|
||||
|
||||
canvas.height = height * pixelRatio;
|
||||
canvas.width = width * pixelRatio;
|
||||
chart.ctx.scale(pixelRatio, pixelRatio);
|
||||
|
||||
// If no style has been set on the canvas, the render size is used as display size,
|
||||
// making the chart visually bigger, so let's enforce it to the "correct" values.
|
||||
// See https://github.com/chartjs/Chart.js/issues/3575
|
||||
if (!canvas.style.height && !canvas.style.width) {
|
||||
canvas.style.height = height + 'px';
|
||||
canvas.style.width = width + 'px';
|
||||
}
|
||||
};
|
||||
// -- Canvas methods
|
||||
helpers.fontString = function(pixelSize, fontStyle, fontFamily) {
|
||||
return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;
|
||||
};
|
||||
helpers.longestText = function(ctx, font, arrayOfThings, cache) {
|
||||
cache = cache || {};
|
||||
var data = cache.data = cache.data || {};
|
||||
var gc = cache.garbageCollect = cache.garbageCollect || [];
|
||||
|
||||
if (cache.font !== font) {
|
||||
data = cache.data = {};
|
||||
gc = cache.garbageCollect = [];
|
||||
cache.font = font;
|
||||
}
|
||||
|
||||
ctx.font = font;
|
||||
var longest = 0;
|
||||
var ilen = arrayOfThings.length;
|
||||
var i, j, jlen, thing, nestedThing;
|
||||
for (i = 0; i < ilen; i++) {
|
||||
thing = arrayOfThings[i];
|
||||
|
||||
// Undefined strings and arrays should not be measured
|
||||
if (thing !== undefined && thing !== null && helpers.isArray(thing) !== true) {
|
||||
longest = helpers.measureText(ctx, data, gc, longest, thing);
|
||||
} else if (helpers.isArray(thing)) {
|
||||
// if it is an array lets measure each element
|
||||
// to do maybe simplify this function a bit so we can do this more recursively?
|
||||
for (j = 0, jlen = thing.length; j < jlen; j++) {
|
||||
nestedThing = thing[j];
|
||||
// Undefined strings and arrays should not be measured
|
||||
if (nestedThing !== undefined && nestedThing !== null && !helpers.isArray(nestedThing)) {
|
||||
longest = helpers.measureText(ctx, data, gc, longest, nestedThing);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var gcLen = gc.length / 2;
|
||||
if (gcLen > arrayOfThings.length) {
|
||||
for (i = 0; i < gcLen; i++) {
|
||||
delete data[gc[i]];
|
||||
}
|
||||
gc.splice(0, gcLen);
|
||||
}
|
||||
return longest;
|
||||
};
|
||||
helpers.measureText = function(ctx, data, gc, longest, string) {
|
||||
var textWidth = data[string];
|
||||
if (!textWidth) {
|
||||
textWidth = data[string] = ctx.measureText(string).width;
|
||||
gc.push(string);
|
||||
}
|
||||
if (textWidth > longest) {
|
||||
longest = textWidth;
|
||||
}
|
||||
return longest;
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
helpers.numberOfLabelLines = function(arrayOfThings) {
|
||||
var numberOfLines = 1;
|
||||
helpers.each(arrayOfThings, function(thing) {
|
||||
if (helpers.isArray(thing)) {
|
||||
if (thing.length > numberOfLines) {
|
||||
numberOfLines = thing.length;
|
||||
}
|
||||
}
|
||||
});
|
||||
return numberOfLines;
|
||||
};
|
||||
|
||||
helpers.color = !color ?
|
||||
function(value) {
|
||||
console.error('Color.js not found!');
|
||||
return value;
|
||||
} :
|
||||
function(value) {
|
||||
/* global CanvasGradient */
|
||||
if (value instanceof CanvasGradient) {
|
||||
value = defaults.global.defaultColor;
|
||||
}
|
||||
|
||||
return color(value);
|
||||
};
|
||||
|
||||
helpers.getHoverColor = function(colorValue) {
|
||||
/* global CanvasPattern */
|
||||
return (colorValue instanceof CanvasPattern || colorValue instanceof CanvasGradient) ?
|
||||
colorValue :
|
||||
helpers.color(colorValue).saturate(0.5).darken(0.1).rgbString();
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user