EnVisageOnline/Main/Source/EnVisage/Scripts/Kendo/kendo.dataviz.gauge.js

2126 lines
90 KiB
JavaScript

/**
* Kendo UI v2016.1.226 (http://www.telerik.com/kendo-ui)
* Copyright 2016 Telerik AD. All rights reserved.
*
* Kendo UI commercial licenses may be obtained at
* http://www.telerik.com/purchase/license-agreement/kendo-ui-complete
* If you do not own a commercial license, this file shall be governed by the trial license terms.
*/
(function (f, define) {
define('util/main', ['kendo.core'], f);
}(function () {
(function () {
var math = Math, kendo = window.kendo, deepExtend = kendo.deepExtend;
var DEG_TO_RAD = math.PI / 180, MAX_NUM = Number.MAX_VALUE, MIN_NUM = -Number.MAX_VALUE, UNDEFINED = 'undefined';
function defined(value) {
return typeof value !== UNDEFINED;
}
function round(value, precision) {
var power = pow(precision);
return math.round(value * power) / power;
}
function pow(p) {
if (p) {
return math.pow(10, p);
} else {
return 1;
}
}
function limitValue(value, min, max) {
return math.max(math.min(value, max), min);
}
function rad(degrees) {
return degrees * DEG_TO_RAD;
}
function deg(radians) {
return radians / DEG_TO_RAD;
}
function isNumber(val) {
return typeof val === 'number' && !isNaN(val);
}
function valueOrDefault(value, defaultValue) {
return defined(value) ? value : defaultValue;
}
function sqr(value) {
return value * value;
}
function objectKey(object) {
var parts = [];
for (var key in object) {
parts.push(key + object[key]);
}
return parts.sort().join('');
}
function hashKey(str) {
var hash = 2166136261;
for (var i = 0; i < str.length; ++i) {
hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
hash ^= str.charCodeAt(i);
}
return hash >>> 0;
}
function hashObject(object) {
return hashKey(objectKey(object));
}
var now = Date.now;
if (!now) {
now = function () {
return new Date().getTime();
};
}
function arrayLimits(arr) {
var length = arr.length, i, min = MAX_NUM, max = MIN_NUM;
for (i = 0; i < length; i++) {
max = math.max(max, arr[i]);
min = math.min(min, arr[i]);
}
return {
min: min,
max: max
};
}
function arrayMin(arr) {
return arrayLimits(arr).min;
}
function arrayMax(arr) {
return arrayLimits(arr).max;
}
function sparseArrayMin(arr) {
return sparseArrayLimits(arr).min;
}
function sparseArrayMax(arr) {
return sparseArrayLimits(arr).max;
}
function sparseArrayLimits(arr) {
var min = MAX_NUM, max = MIN_NUM;
for (var i = 0, length = arr.length; i < length; i++) {
var n = arr[i];
if (n !== null && isFinite(n)) {
min = math.min(min, n);
max = math.max(max, n);
}
}
return {
min: min === MAX_NUM ? undefined : min,
max: max === MIN_NUM ? undefined : max
};
}
function last(array) {
if (array) {
return array[array.length - 1];
}
}
function append(first, second) {
first.push.apply(first, second);
return first;
}
function renderTemplate(text) {
return kendo.template(text, {
useWithBlock: false,
paramName: 'd'
});
}
function renderAttr(name, value) {
return defined(value) && value !== null ? ' ' + name + '=\'' + value + '\' ' : '';
}
function renderAllAttr(attrs) {
var output = '';
for (var i = 0; i < attrs.length; i++) {
output += renderAttr(attrs[i][0], attrs[i][1]);
}
return output;
}
function renderStyle(attrs) {
var output = '';
for (var i = 0; i < attrs.length; i++) {
var value = attrs[i][1];
if (defined(value)) {
output += attrs[i][0] + ':' + value + ';';
}
}
if (output !== '') {
return output;
}
}
function renderSize(size) {
if (typeof size !== 'string') {
size += 'px';
}
return size;
}
function renderPos(pos) {
var result = [];
if (pos) {
var parts = kendo.toHyphens(pos).split('-');
for (var i = 0; i < parts.length; i++) {
result.push('k-pos-' + parts[i]);
}
}
return result.join(' ');
}
function isTransparent(color) {
return color === '' || color === null || color === 'none' || color === 'transparent' || !defined(color);
}
function arabicToRoman(n) {
var literals = {
1: 'i',
10: 'x',
100: 'c',
2: 'ii',
20: 'xx',
200: 'cc',
3: 'iii',
30: 'xxx',
300: 'ccc',
4: 'iv',
40: 'xl',
400: 'cd',
5: 'v',
50: 'l',
500: 'd',
6: 'vi',
60: 'lx',
600: 'dc',
7: 'vii',
70: 'lxx',
700: 'dcc',
8: 'viii',
80: 'lxxx',
800: 'dccc',
9: 'ix',
90: 'xc',
900: 'cm',
1000: 'm'
};
var values = [
1000,
900,
800,
700,
600,
500,
400,
300,
200,
100,
90,
80,
70,
60,
50,
40,
30,
20,
10,
9,
8,
7,
6,
5,
4,
3,
2,
1
];
var roman = '';
while (n > 0) {
if (n < values[0]) {
values.shift();
} else {
roman += literals[values[0]];
n -= values[0];
}
}
return roman;
}
function romanToArabic(r) {
r = r.toLowerCase();
var digits = {
i: 1,
v: 5,
x: 10,
l: 50,
c: 100,
d: 500,
m: 1000
};
var value = 0, prev = 0;
for (var i = 0; i < r.length; ++i) {
var v = digits[r.charAt(i)];
if (!v) {
return null;
}
value += v;
if (v > prev) {
value -= 2 * prev;
}
prev = v;
}
return value;
}
function memoize(f) {
var cache = Object.create(null);
return function () {
var id = '';
for (var i = arguments.length; --i >= 0;) {
id += ':' + arguments[i];
}
if (id in cache) {
return cache[id];
}
return f.apply(this, arguments);
};
}
function ucs2decode(string) {
var output = [], counter = 0, length = string.length, value, extra;
while (counter < length) {
value = string.charCodeAt(counter++);
if (value >= 55296 && value <= 56319 && counter < length) {
extra = string.charCodeAt(counter++);
if ((extra & 64512) == 56320) {
output.push(((value & 1023) << 10) + (extra & 1023) + 65536);
} else {
output.push(value);
counter--;
}
} else {
output.push(value);
}
}
return output;
}
function ucs2encode(array) {
return array.map(function (value) {
var output = '';
if (value > 65535) {
value -= 65536;
output += String.fromCharCode(value >>> 10 & 1023 | 55296);
value = 56320 | value & 1023;
}
output += String.fromCharCode(value);
return output;
}).join('');
}
deepExtend(kendo, {
util: {
MAX_NUM: MAX_NUM,
MIN_NUM: MIN_NUM,
append: append,
arrayLimits: arrayLimits,
arrayMin: arrayMin,
arrayMax: arrayMax,
defined: defined,
deg: deg,
hashKey: hashKey,
hashObject: hashObject,
isNumber: isNumber,
isTransparent: isTransparent,
last: last,
limitValue: limitValue,
now: now,
objectKey: objectKey,
round: round,
rad: rad,
renderAttr: renderAttr,
renderAllAttr: renderAllAttr,
renderPos: renderPos,
renderSize: renderSize,
renderStyle: renderStyle,
renderTemplate: renderTemplate,
sparseArrayLimits: sparseArrayLimits,
sparseArrayMin: sparseArrayMin,
sparseArrayMax: sparseArrayMax,
sqr: sqr,
valueOrDefault: valueOrDefault,
romanToArabic: romanToArabic,
arabicToRoman: arabicToRoman,
memoize: memoize,
ucs2encode: ucs2encode,
ucs2decode: ucs2decode
}
});
kendo.drawing.util = kendo.util;
kendo.dataviz.util = kendo.util;
}());
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('util/text-metrics', [
'kendo.core',
'util/main'
], f);
}(function () {
(function ($) {
var doc = document, kendo = window.kendo, Class = kendo.Class, util = kendo.util, defined = util.defined;
var LRUCache = Class.extend({
init: function (size) {
this._size = size;
this._length = 0;
this._map = {};
},
put: function (key, value) {
var lru = this, map = lru._map, entry = {
key: key,
value: value
};
map[key] = entry;
if (!lru._head) {
lru._head = lru._tail = entry;
} else {
lru._tail.newer = entry;
entry.older = lru._tail;
lru._tail = entry;
}
if (lru._length >= lru._size) {
map[lru._head.key] = null;
lru._head = lru._head.newer;
lru._head.older = null;
} else {
lru._length++;
}
},
get: function (key) {
var lru = this, entry = lru._map[key];
if (entry) {
if (entry === lru._head && entry !== lru._tail) {
lru._head = entry.newer;
lru._head.older = null;
}
if (entry !== lru._tail) {
if (entry.older) {
entry.older.newer = entry.newer;
entry.newer.older = entry.older;
}
entry.older = lru._tail;
entry.newer = null;
lru._tail.newer = entry;
lru._tail = entry;
}
return entry.value;
}
}
});
var defaultMeasureBox = $('<div style=\'position: absolute !important; top: -4000px !important; width: auto !important; height: auto !important;' + 'padding: 0 !important; margin: 0 !important; border: 0 !important;' + 'line-height: normal !important; visibility: hidden !important; white-space: nowrap!important;\' />')[0];
function zeroSize() {
return {
width: 0,
height: 0,
baseline: 0
};
}
var TextMetrics = Class.extend({
init: function (options) {
this._cache = new LRUCache(1000);
this._initOptions(options);
},
options: { baselineMarkerSize: 1 },
measure: function (text, style, box) {
if (!text) {
return zeroSize();
}
var styleKey = util.objectKey(style), cacheKey = util.hashKey(text + styleKey), cachedResult = this._cache.get(cacheKey);
if (cachedResult) {
return cachedResult;
}
var size = zeroSize();
var measureBox = box ? box : defaultMeasureBox;
var baselineMarker = this._baselineMarker().cloneNode(false);
for (var key in style) {
var value = style[key];
if (defined(value)) {
measureBox.style[key] = value;
}
}
$(measureBox).text(text);
measureBox.appendChild(baselineMarker);
doc.body.appendChild(measureBox);
if ((text + '').length) {
size.width = measureBox.offsetWidth - this.options.baselineMarkerSize;
size.height = measureBox.offsetHeight;
size.baseline = baselineMarker.offsetTop + this.options.baselineMarkerSize;
}
if (size.width > 0 && size.height > 0) {
this._cache.put(cacheKey, size);
}
measureBox.parentNode.removeChild(measureBox);
return size;
},
_baselineMarker: function () {
return $('<div class=\'k-baseline-marker\' ' + 'style=\'display: inline-block; vertical-align: baseline;' + 'width: ' + this.options.baselineMarkerSize + 'px; height: ' + this.options.baselineMarkerSize + 'px;' + 'overflow: hidden;\' />')[0];
}
});
TextMetrics.current = new TextMetrics();
function measureText(text, style, measureBox) {
return TextMetrics.current.measure(text, style, measureBox);
}
function loadFonts(fonts, callback) {
var promises = [];
if (fonts.length > 0 && document.fonts) {
try {
promises = fonts.map(function (font) {
return document.fonts.load(font);
});
} catch (e) {
kendo.logToConsole(e);
}
Promise.all(promises).then(callback, callback);
} else {
callback();
}
}
kendo.util.TextMetrics = TextMetrics;
kendo.util.LRUCache = LRUCache;
kendo.util.loadFonts = loadFonts;
kendo.util.measureText = measureText;
}(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('util/base64', ['util/main'], f);
}(function () {
(function () {
var kendo = window.kendo, deepExtend = kendo.deepExtend, fromCharCode = String.fromCharCode;
var KEY_STR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
function encodeBase64(input) {
var output = '';
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = encodeUTF8(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = (chr1 & 3) << 4 | chr2 >> 4;
enc3 = (chr2 & 15) << 2 | chr3 >> 6;
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output + KEY_STR.charAt(enc1) + KEY_STR.charAt(enc2) + KEY_STR.charAt(enc3) + KEY_STR.charAt(enc4);
}
return output;
}
function encodeUTF8(input) {
var output = '';
for (var i = 0; i < input.length; i++) {
var c = input.charCodeAt(i);
if (c < 128) {
output += fromCharCode(c);
} else if (c < 2048) {
output += fromCharCode(192 | c >>> 6);
output += fromCharCode(128 | c & 63);
} else if (c < 65536) {
output += fromCharCode(224 | c >>> 12);
output += fromCharCode(128 | c >>> 6 & 63);
output += fromCharCode(128 | c & 63);
}
}
return output;
}
deepExtend(kendo.util, {
encodeBase64: encodeBase64,
encodeUTF8: encodeUTF8
});
}());
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('mixins/observers', ['kendo.core'], f);
}(function () {
(function ($) {
var math = Math, kendo = window.kendo, deepExtend = kendo.deepExtend, inArray = $.inArray;
var ObserversMixin = {
observers: function () {
this._observers = this._observers || [];
return this._observers;
},
addObserver: function (element) {
if (!this._observers) {
this._observers = [element];
} else {
this._observers.push(element);
}
return this;
},
removeObserver: function (element) {
var observers = this.observers();
var index = inArray(element, observers);
if (index != -1) {
observers.splice(index, 1);
}
return this;
},
trigger: function (methodName, event) {
var observers = this._observers;
var observer;
var idx;
if (observers && !this._suspended) {
for (idx = 0; idx < observers.length; idx++) {
observer = observers[idx];
if (observer[methodName]) {
observer[methodName](event);
}
}
}
return this;
},
optionsChange: function (e) {
this.trigger('optionsChange', e);
},
geometryChange: function (e) {
this.trigger('geometryChange', e);
},
suspend: function () {
this._suspended = (this._suspended || 0) + 1;
return this;
},
resume: function () {
this._suspended = math.max((this._suspended || 0) - 1, 0);
return this;
},
_observerField: function (field, value) {
if (this[field]) {
this[field].removeObserver(this);
}
this[field] = value;
value.addObserver(this);
}
};
deepExtend(kendo, { mixins: { ObserversMixin: ObserversMixin } });
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));
(function (f, define) {
define('kendo.dataviz.gauge', [
'kendo.dataviz.core',
'kendo.drawing',
'kendo.dataviz.themes'
], f);
}(function () {
var __meta__ = {
id: 'dataviz.gauge',
name: 'Gauge',
category: 'dataviz',
description: 'Radial and Linear gauges.',
depends: [
'dataviz.core',
'dataviz.themes'
]
};
(function ($, undefined) {
var math = Math, kendo = window.kendo, util = kendo.util, Widget = kendo.ui.Widget, deepExtend = kendo.deepExtend, dataviz = kendo.dataviz, autoMajorUnit = dataviz.autoMajorUnit, ChartElement = dataviz.ChartElement, NumericAxis = dataviz.NumericAxis, Axis = dataviz.Axis, Box2D = dataviz.Box2D, Class = kendo.Class, defined = util.defined, isNumber = util.isNumber, interpolateValue = dataviz.interpolateValue, getSpacing = dataviz.getSpacing, round = dataviz.round, geo = dataviz.geometry, draw = dataviz.drawing, Point = geo.Point, Group = draw.Group, Path = draw.Path, Rect = geo.Rect, Text = draw.Text;
var ANGULAR_SPEED = 150, LINEAR_SPEED = 250, ARROW = 'arrow', ARROW_POINTER = 'arrowPointer', BAR_POINTER = 'barPointer', BLACK = '#000', CAP_SIZE = 0.05, COORD_PRECISION = dataviz.COORD_PRECISION, MAX_VALUE = Number.MAX_VALUE, MIN_VALUE = -Number.MAX_VALUE, DEFAULT_HEIGHT = 200, DEFAULT_LINE_WIDTH = 0.5, DEFAULT_WIDTH = 200, DEFAULT_MIN_WIDTH = 60, DEFAULT_MIN_HEIGHT = 60, DEFAULT_MARGIN = 5, DEGREE = math.PI / 180, GEO_ARC_ADJUST_ANGLE = 180, INSIDE = 'inside', LINEAR = 'linear', NEEDLE = 'needle', OUTSIDE = 'outside', RADIAL_POINTER = 'radialPointer', X = 'x', Y = 'y';
var Pointer = Class.extend({
init: function (scale, options) {
var pointer = this;
var scaleOptions = scale.options;
ChartElement.fn.init.call(pointer, options);
options = pointer.options;
options.fill = options.color;
pointer.scale = scale;
if (defined(options.value)) {
options.value = math.min(math.max(options.value, scaleOptions.min), scaleOptions.max);
} else {
options.value = scaleOptions.min;
}
},
options: { color: BLACK },
value: function (newValue) {
var that = this;
var options = that.options;
var value = options.value;
var scaleOptions = that.scale.options;
if (arguments.length === 0) {
return value;
}
options._oldValue = options._oldValue !== undefined ? options.value : scaleOptions.min;
options.value = math.min(math.max(newValue, scaleOptions.min), scaleOptions.max);
if (that.elements) {
that.repaint();
}
}
});
var RadialPointer = Pointer.extend({
options: {
shape: NEEDLE,
cap: { size: CAP_SIZE },
arrow: {
width: 16,
height: 14
},
animation: {
type: RADIAL_POINTER,
duration: ANGULAR_SPEED
}
},
setRadius: function (radius) {
var that = this;
if (radius) {
that.elements.clear();
that.render(that.parent, that.center, radius);
}
},
setAngle: function (angle) {
this.elements.transform(geo.transform().rotate(angle, this.center));
},
repaint: function () {
var that = this;
var scale = that.scale;
var options = that.options;
var oldAngle = scale.slotAngle(options._oldValue);
var newAngle = scale.slotAngle(options.value);
if (options.animation.transitions === false) {
that.setAngle(newAngle);
} else {
new RadialPointerAnimation(that.elements, deepExtend(options.animation, {
oldAngle: oldAngle,
newAngle: newAngle
})).play();
}
},
render: function () {
var that = this;
var scale = that.scale;
var center = scale.arc.center;
var options = that.options;
var elements = new Group();
if (options.animation !== false) {
deepExtend(options.animation, {
startAngle: 0,
center: center,
reverse: scale.options.reverse
});
}
if (options.shape === NEEDLE) {
elements.append(that._renderNeedle(), that._renderCap());
} else {
elements.append(that._renderArrow());
}
that.elements = elements;
that.setAngle(DEGREE);
return elements;
},
reflow: function (arc) {
var that = this;
var center = that.center = arc.center;
var radius = that.radius = arc.getRadiusX();
var capSize = that.capSize = Math.round(radius * that.options.cap.size);
that.bbox = Rect.fromPoints(new Point(center.x - capSize, center.y - capSize), new Point(center.x + capSize, center.y + capSize));
},
_renderNeedle: function () {
var that = this;
var options = that.options;
var minorTickSize = that.scale.options.minorTicks.size;
var center = that.center;
var needleColor = options.color;
var needlePath = new Path({
fill: { color: needleColor },
stroke: {
color: needleColor,
width: DEFAULT_LINE_WIDTH
}
});
needlePath.moveTo(center.x + that.radius - minorTickSize, center.y).lineTo(center.x, center.y - that.capSize / 2).lineTo(center.x, center.y + that.capSize / 2).close();
return needlePath;
},
_renderCap: function () {
var that = this;
var options = that.options;
var capColor = options.cap.color || options.color;
var circle = new geo.Circle(that.center, that.capSize);
var cap = new draw.Circle(circle, {
fill: { color: capColor },
stroke: { color: capColor }
});
return cap;
}
});
var RadialScale = NumericAxis.extend({
init: function (options) {
var scale = this;
scale.options = deepExtend({}, scale.options, options);
scale.options.majorUnit = scale.options.majorUnit || autoMajorUnit(scale.options.min, scale.options.max);
scale.options.minorUnit = scale.options.minorUnit || scale.options.majorUnit / 10;
Axis.fn.init.call(scale, scale.options);
},
options: {
min: 0,
max: 100,
majorTicks: {
size: 15,
align: INSIDE,
color: BLACK,
width: DEFAULT_LINE_WIDTH,
visible: true
},
minorTicks: {
size: 10,
align: INSIDE,
color: BLACK,
width: DEFAULT_LINE_WIDTH,
visible: true
},
startAngle: -30,
endAngle: 210,
labels: {
position: INSIDE,
padding: 2
}
},
render: function (center, radius) {
var that = this;
var arc = that.renderArc(center, radius);
that.bbox = arc.bbox();
that.labelElements = that.renderLabels();
that.ticks = that.renderTicks();
that.ranges = that.renderRanges();
},
reflow: function (bbox) {
var that = this;
var center = bbox.center();
var radius = math.min(bbox.height(), bbox.width()) / 2;
if (that.bbox !== undefined) {
that.bbox = that.arc.bbox();
that.radius(that.arc.getRadiusX());
that.repositionRanges();
that.renderLabels();
} else {
return that.render(center, radius);
}
},
slotAngle: function (value) {
var options = this.options;
var startAngle = options.startAngle;
var reverse = options.reverse;
var angle = options.endAngle - startAngle;
var min = options.min;
var max = options.max;
var result;
if (reverse) {
result = options.endAngle - (value - min) / (max - min) * angle;
} else {
result = (value - min) / (max - min) * angle + startAngle;
}
return result + GEO_ARC_ADJUST_ANGLE;
},
renderLabels: function () {
var that = this;
var options = that.options;
var majorTickSize = options.majorTicks.size;
var arc = that.arc.clone();
var radius = arc.getRadiusX();
var tickAngles = that.tickAngles(arc, options.majorUnit);
var labels = that.labels;
var count = labels.length;
var labelsOptions = options.labels;
var padding = labelsOptions.padding;
var rangeDistance = radius * 0.05;
var rangeSize = options.rangeSize = options.rangeSize || radius * 0.1;
var ranges = options.ranges || [];
var halfWidth, halfHeight, labelAngle;
var angle, label, lp, i, cx, cy, isInside;
var labelsGroup = new Group();
var lbl, labelPos, prevLabelPos, labelTransform;
if (that.options.rangeDistance !== undefined) {
rangeDistance = that.options.rangeDistance;
} else {
that.options.rangeDistance = rangeDistance;
}
if (labelsOptions.position === INSIDE) {
radius -= majorTickSize;
if (ranges.length && that.labelElements === undefined) {
radius -= rangeSize + rangeDistance;
}
arc.setRadiusX(radius).setRadiusY(radius);
}
for (i = 0; i < count; i++) {
label = labels[i];
halfWidth = label.box.width() / 2;
halfHeight = label.box.height() / 2;
angle = tickAngles[i];
labelAngle = (angle - GEO_ARC_ADJUST_ANGLE) * DEGREE;
isInside = labelsOptions.position === INSIDE;
lp = arc.pointAt(angle);
cx = lp.x + math.cos(labelAngle) * (halfWidth + padding) * (isInside ? 1 : -1);
cy = lp.y + math.sin(labelAngle) * (halfHeight + padding) * (isInside ? 1 : -1);
label.reflow(new dataviz.Box2D(cx - halfWidth, cy - halfHeight, cx + halfWidth, cy + halfHeight));
labelPos = new Point(label.box.x1, label.box.y1);
if (that.labelElements === undefined) {
lbl = _buildLabel(label, options.labels);
labelsGroup.append(lbl);
} else {
lbl = that.labelElements.children[i];
prevLabelPos = lbl.bbox().origin;
labelTransform = lbl.transform() || geo.transform();
labelTransform.translate(labelPos.x - prevLabelPos.x, labelPos.y - prevLabelPos.y);
lbl.transform(labelTransform);
}
that.bbox = Rect.union(that.bbox, lbl.bbox());
}
return labelsGroup;
},
repositionRanges: function () {
var that = this;
var ranges = that.ranges.children;
var rangeSize = that.options.rangeSize;
var rangeDistance = that.options.rangeDistance;
var rangeRadius, newRadius;
if (ranges.length > 0) {
rangeRadius = that.getRangeRadius();
if (that.options.labels.position === INSIDE) {
rangeRadius += rangeSize + rangeDistance;
}
newRadius = rangeRadius + rangeSize / 2;
for (var i = 0; i < ranges.length; i++) {
ranges[i]._geometry.setRadiusX(newRadius).setRadiusY(newRadius);
}
that.bbox = Rect.union(that.bbox, that.ranges.bbox());
}
},
renderRanges: function () {
var that = this;
var arc = that.arc;
var result = new Group();
var from, to;
var segments = that.rangeSegments();
var segmentsCount = segments.length;
var reverse = that.options.reverse;
var rangeSize = that.options.rangeSize;
var rangeDistance = that.options.rangeDistance;
var segment, rangeRadius, rangeGeom, i;
if (segmentsCount) {
rangeRadius = that.getRangeRadius();
that.radius(that.radius() - rangeSize - rangeDistance);
for (i = 0; i < segmentsCount; i++) {
segment = segments[i];
from = that.slotAngle(segment[reverse ? 'to' : 'from']);
to = that.slotAngle(segment[!reverse ? 'to' : 'from']);
if (to - from !== 0) {
rangeGeom = new geo.Arc(arc.center, {
radiusX: rangeRadius + rangeSize / 2,
radiusY: rangeRadius + rangeSize / 2,
startAngle: from,
endAngle: to
});
result.append(new draw.Arc(rangeGeom, {
stroke: {
width: rangeSize,
color: segment.color,
opacity: segment.opacity
}
}));
}
}
}
return result;
},
rangeSegments: function () {
var gauge = this;
var options = gauge.options;
var ranges = options.ranges || [];
var count = ranges.length;
var range;
var segmentsCount;
var defaultColor = options.rangePlaceholderColor;
var segments = [];
var segment;
var min = options.min;
var max = options.max;
var i, j;
function rangeSegment(from, to, color, opacity) {
return {
from: from,
to: to,
color: color,
opacity: opacity
};
}
if (count) {
segments.push(rangeSegment(min, max, defaultColor));
for (i = 0; i < count; i++) {
range = getRange(ranges[i], min, max);
segmentsCount = segments.length;
for (j = 0; j < segmentsCount; j++) {
segment = segments[j];
if (segment.from <= range.from && range.from <= segment.to) {
segments.push(rangeSegment(range.from, range.to, range.color, range.opacity));
if (segment.from <= range.to && range.to <= segment.to) {
segments.push(rangeSegment(range.to, segment.to, defaultColor, range.opacity));
}
segment.to = range.from;
break;
}
}
}
}
return segments;
},
getRangeRadius: function () {
var that = this;
var options = that.options;
var majorTickSize = options.majorTicks.size;
var rangeSize = options.rangeSize;
var rangeDistance = options.rangeDistance;
var arc = that.arc;
var r;
if (options.labels.position === OUTSIDE) {
r = arc.getRadiusX() - majorTickSize - rangeDistance - rangeSize;
} else {
r = arc.getRadiusX() - rangeSize;
}
return r;
},
renderArc: function (center, radius) {
var that = this;
var options = that.options;
var arc = that.arc = new geo.Arc(center, {
radiusX: radius,
radiusY: radius,
startAngle: options.startAngle + GEO_ARC_ADJUST_ANGLE,
endAngle: options.endAngle + GEO_ARC_ADJUST_ANGLE
});
return arc;
},
renderTicks: function () {
var that = this;
var arc = that.arc;
var options = that.options;
var labelsPosition = options.labels.position;
var allTicks = new Group();
var majorTickSize = options.majorTicks.size;
var minorTickSize = options.minorTicks.size;
var tickArc = arc.clone();
var radius = tickArc.getRadiusX();
function drawTicks(arc, tickAngles, unit, tickOptions) {
var ticks = new Group(), center = arc.center, radius = arc.getRadiusX(), i, tickStart, tickEnd, visible = tickOptions.visible;
if (visible) {
for (i = 0; i < tickAngles.length; i++) {
tickStart = arc.pointAt(tickAngles[i]);
tickEnd = new Point(center.x + radius - tickOptions.size, center.y).rotate(tickAngles[i], center);
ticks.append(new Path({
stroke: {
color: tickOptions.color,
width: tickOptions.width
}
}).moveTo(tickStart).lineTo(tickEnd));
}
}
return ticks;
}
that.majorTickAngles = that.tickAngles(arc, options.majorUnit);
that.majorTicks = drawTicks(tickArc, that.majorTickAngles, options.majorUnit, options.majorTicks);
allTicks.append(that.majorTicks);
that._tickDifference = majorTickSize - minorTickSize;
if (labelsPosition === OUTSIDE) {
tickArc.setRadiusX(radius - majorTickSize + minorTickSize).setRadiusY(radius - majorTickSize + minorTickSize);
}
that.minorTickAngles = that.normalizeTickAngles(that.tickAngles(arc, options.minorUnit));
that.minorTicks = drawTicks(tickArc, that.minorTickAngles, options.minorUnit, options.minorTicks, options.majorUnit);
allTicks.append(that.minorTicks);
return allTicks;
},
normalizeTickAngles: function (angles) {
var that = this;
var options = that.options;
var skip = options.majorUnit / options.minorUnit;
for (var i = angles.length - 1; i >= 0; i--) {
if (i % skip === 0) {
angles.splice(i, 1);
}
}
return angles;
},
tickAngles: function (ring, stepValue) {
var scale = this;
var options = scale.options;
var reverse = options.reverse;
var range = options.max - options.min;
var angle = ring.endAngle - ring.startAngle;
var pos = ring.startAngle;
var tickCount = range / stepValue;
var step = angle / tickCount;
var positions = [];
var i;
if (reverse) {
pos += angle;
step = -step;
}
for (i = 0; i < tickCount; i++) {
positions.push(round(pos, COORD_PRECISION));
pos += step;
}
if (round(pos) <= ring.endAngle) {
positions.push(pos);
}
return positions;
},
radius: function (radius) {
var that = this;
if (radius) {
that.arc.setRadiusX(radius).setRadiusY(radius);
that.repositionTicks(that.majorTicks.children, that.majorTickAngles);
that.repositionTicks(that.minorTicks.children, that.minorTickAngles, true);
} else {
return that.arc.getRadiusX();
}
},
repositionTicks: function (ticks, tickAngles, minor) {
var that = this;
var diff = minor ? that._tickDifference || 0 : 0;
var tickArc = that.arc;
var radius = tickArc.getRadiusX();
if (minor && that.options.labels.position === OUTSIDE && diff !== 0) {
tickArc = that.arc.clone();
tickArc.setRadiusX(radius - diff).setRadiusY(radius - diff);
}
for (var i = 0; i < ticks.length; i++) {
var newPoint = tickArc.pointAt(tickAngles[i]);
var segments = ticks[i].segments;
var xDiff = newPoint.x - segments[0].anchor().x;
var yDiff = newPoint.y - segments[0].anchor().y;
ticks[i].transform(new geo.Transformation().translate(xDiff, yDiff));
}
}
});
var Gauge = Widget.extend({
init: function (element, userOptions) {
var gauge = this;
var options;
var themeOptions;
var themeName;
var themes = dataviz.ui.themes || {};
var theme;
kendo.destroy(element);
$(element).empty();
Widget.fn.init.call(gauge, element);
gauge.wrapper = gauge.element;
gauge._originalOptions = deepExtend({}, userOptions);
options = deepExtend({}, gauge.options, userOptions);
themeName = options.theme;
theme = themes[themeName] || themes[themeName.toLowerCase()];
themeOptions = themeName && theme ? theme.gauge : {};
gauge.options = deepExtend({}, themeOptions, options);
if ($.isArray(options.pointer)) {
for (var i = 0; i < options.pointer.length; i++) {
gauge.options.pointer[i] = deepExtend({}, themeOptions.pointer, options.pointer[i]);
}
}
gauge.element.addClass('k-gauge');
gauge.surface = gauge._createSurface();
gauge.redraw();
},
options: {
plotArea: {},
theme: 'default',
renderAs: '',
pointer: {},
scale: {},
gaugeArea: {}
},
destroy: function () {
this.surface.destroy();
Widget.fn.destroy.call(this);
},
value: function (value) {
var that = this;
var pointer = that.pointers[0];
if (arguments.length === 0) {
return pointer.value();
}
pointer.value(value);
that._setValueOptions(value);
},
_draw: function () {
var surface = this.surface;
surface.clear();
surface.draw(this._visuals);
},
exportVisual: function () {
return this._visuals;
},
allValues: function (values) {
var that = this;
var pointers = that.pointers;
var allValues = [];
var i;
if (arguments.length === 0) {
for (i = 0; i < pointers.length; i++) {
allValues.push(pointers[i].value());
}
return allValues;
}
if ($.isArray(values)) {
for (i = 0; i < values.length; i++) {
if (isNumber(values[i])) {
pointers[i].value(values[i]);
}
}
}
that._setValueOptions(values);
},
_setValueOptions: function (values) {
var pointers = [].concat(this.options.pointer);
values = [].concat(values);
for (var i = 0; i < values.length; i++) {
pointers[i].value = values[i];
}
},
_resize: function () {
var that = this;
var t = that.options.transitions;
var i;
that.options.transitions = false;
for (i = 0; i < that.pointers.length; i++) {
that.pointers[i].options.animation.transitions = false;
}
that.redraw();
that.options.transitions = t;
for (i = 0; i < that.pointers.length; i++) {
that.pointers[i].options.animation.transitions = t;
}
},
redraw: function () {
var that = this;
var size = deepExtend(that._getSize(), that.options.gaugeArea);
var wrapper = new Rect([
0,
0
], [
size.width,
size.height
]);
var bbox;
that.surface.clear();
that.gaugeArea = that._createGaugeArea();
that.surface.element.css({
width: size.width,
height: size.height
});
that._createModel();
bbox = _unpad(wrapper.bbox(), that._gaugeAreaMargin);
that.reflow(bbox);
},
_createGaugeArea: function () {
var that = this;
var options = that.options.gaugeArea;
var size = that.surface.size();
var border = options.border || {};
var areaGeometry = new Rect([
0,
0
], [
size.width,
size.height
]);
that._gaugeAreaMargin = options.margin || DEFAULT_MARGIN;
if (border.width > 0) {
areaGeometry = _unpad(areaGeometry, border.width);
}
var gaugeArea = Path.fromRect(areaGeometry, {
stroke: {
color: border.width ? border.color : '',
width: border.width,
dashType: border.dashType,
lineJoin: 'round',
lineCap: 'round'
},
fill: { color: options.background }
});
return gaugeArea;
},
_createSurface: function () {
var that = this;
var options = that.options;
var size = that._getSize();
size = options.gaugeArea ? deepExtend(size, options.gaugeArea) : size;
var wrap = $('<div></div>').appendTo(that.element).css({
width: size.width,
height: size.height
});
return new draw.Surface.create(wrap, { type: options.renderAs });
},
getSize: function () {
return this._getSize();
},
_getSize: function () {
var that = this;
var element = that.element;
var width = element.width();
var height = element.height();
if (!width) {
width = DEFAULT_WIDTH;
}
if (!height) {
height = DEFAULT_HEIGHT;
}
return {
width: width,
height: height
};
}
});
var RadialGauge = Gauge.extend({
init: function (element, options) {
var radialGauge = this;
Gauge.fn.init.call(radialGauge, element, options);
kendo.notify(radialGauge, dataviz.ui);
},
options: {
name: 'RadialGauge',
transitions: true,
gaugeArea: { background: '' }
},
reflow: function (bbox) {
var that = this;
var pointers = that.pointers;
that.scale.reflow(bbox);
that._initialPlotArea = that.scale.bbox;
for (var i = 0; i < pointers.length; i++) {
pointers[i].reflow(that.scale.arc);
that._initialPlotArea = Rect.union(that._initialPlotArea, pointers[i].bbox);
}
that.fitScale(bbox);
that.alignScale(bbox);
that._buildVisual(that.gaugeArea, pointers, that.scale);
that._draw();
},
_buildVisual: function (gaugeArea, pointers, scale) {
var visuals = new Group();
var current;
visuals.append(gaugeArea);
visuals.append(scale.ticks);
visuals.append(scale.ranges);
for (var i = 0; i < pointers.length; i++) {
current = pointers[i];
current.render();
visuals.append(current.elements);
current.value(current.options.value);
}
visuals.append(scale.labelElements);
this._visuals = visuals;
},
fitScale: function (bbox) {
var that = this;
var scale = that.scale;
var arc = scale.arc;
var plotAreaBox = that._initialPlotArea;
var step = math.abs(that.getDiff(plotAreaBox, bbox));
var min = round(step, COORD_PRECISION);
var max = round(-step, COORD_PRECISION);
var minDiff, midDiff, maxDiff, mid, oldDiff;
var staleFlag = 0;
var i = 0;
while (i++ < 100) {
staleFlag = oldDiff === maxDiff ? staleFlag + 1 : 0;
if (staleFlag > 5) {
break;
}
if (min != mid) {
minDiff = that.getPlotBox(min, bbox, arc);
if (0 <= minDiff && minDiff <= 2) {
break;
}
}
if (max != mid) {
maxDiff = that.getPlotBox(max, bbox, arc);
if (0 <= maxDiff && maxDiff <= 2) {
break;
}
}
if (minDiff > 0 && maxDiff > 0) {
mid = min * 2;
} else if (minDiff < 0 && maxDiff < 0) {
mid = max * 2;
} else {
mid = round((min + max) / 2 || 1, COORD_PRECISION);
}
midDiff = that.getPlotBox(mid, bbox, arc);
if (0 <= midDiff && midDiff <= 2) {
break;
}
oldDiff = maxDiff;
if (midDiff > 0) {
max = mid;
maxDiff = midDiff;
} else {
min = mid;
minDiff = midDiff;
}
}
},
getPlotBox: function (step, bbox, arc) {
var that = this;
var scale = that.scale;
var pointers = that.pointers;
var radius = arc.getRadiusX();
arc = arc.clone();
arc.setRadiusX(radius + step).setRadiusY(radius + step);
scale.arc = arc;
scale.reflow(bbox);
that.plotBbox = scale.bbox;
for (var i = 0; i < pointers.length; i++) {
pointers[i].reflow(arc);
that.plotBbox = Rect.union(that.plotBbox, pointers[i].bbox);
}
return that.getDiff(that.plotBbox, bbox);
},
getDiff: function (plotBox, box) {
return math.min(box.width() - plotBox.width(), box.height() - plotBox.height());
},
alignScale: function (bbox) {
var that = this;
var plotBoxCenter = that.plotBbox.center();
var boxCenter = bbox.center();
var paddingX = plotBoxCenter.x - boxCenter.x;
var paddingY = plotBoxCenter.y - boxCenter.y;
var scale = that.scale;
var pointers = that.pointers;
scale.arc.center.x -= paddingX;
scale.arc.center.y -= paddingY;
scale.reflow(bbox);
for (var i = 0; i < pointers.length; i++) {
pointers[i].reflow(scale.arc);
that.plotBbox = Rect.union(scale.bbox, pointers[i].bbox);
}
},
_createModel: function () {
var that = this;
var options = that.options;
var pointers = options.pointer;
var scale = that.scale = new RadialScale(options.scale);
var current;
that.pointers = [];
pointers = $.isArray(pointers) ? pointers : [pointers];
for (var i = 0; i < pointers.length; i++) {
current = new RadialPointer(scale, deepExtend({}, pointers[i], { animation: { transitions: options.transitions } }));
that.pointers.push(current);
}
}
});
var LinearGauge = Gauge.extend({
init: function (element, options) {
var linearGauge = this;
Gauge.fn.init.call(linearGauge, element, options);
kendo.notify(linearGauge, dataviz.ui);
},
options: {
name: 'LinearGauge',
transitions: true,
gaugeArea: { background: '' },
scale: { vertical: true }
},
reflow: function (bbox) {
var that = this;
var pointers = that.pointers;
var bboxX = bbox.origin.x;
var bboxY = bbox.origin.y;
var bbox2D = new dataviz.Box2D(bboxX, bboxX, bboxX + bbox.width(), bboxY + bbox.height());
that.scale.reflow(bbox2D);
for (var i = 0; i < pointers.length; i++) {
pointers[i].reflow();
}
that.bbox = that._getBox(bbox2D);
that._alignElements();
that._shrinkElements();
that._buildVisual();
that._draw();
},
_buildVisual: function () {
var that = this;
var visuals = new Group();
var scaleElements = that.scale.render();
var pointers = that.pointers;
var current;
visuals.append(that.gaugeArea);
visuals.append(scaleElements);
for (var i = 0; i < pointers.length; i++) {
current = pointers[i];
visuals.append(current.render());
current.value(current.options.value);
}
that._visuals = visuals;
},
_createModel: function () {
var that = this;
var options = that.options;
var pointers = options.pointer;
var scale = that.scale = new LinearScale(options.scale);
var current, currentOptions;
that.pointers = [];
pointers = $.isArray(pointers) ? pointers : [pointers];
for (var i = 0; i < pointers.length; i++) {
currentOptions = deepExtend({}, pointers[i], { animation: { transitions: options.transitions } });
if (currentOptions.shape === ARROW) {
current = new ArrowLinearPointer(scale, currentOptions);
} else {
current = new BarLinearPointer(scale, currentOptions);
}
that.pointers.push(current);
}
},
_getSize: function () {
var gauge = this;
var element = gauge.element;
var width = element.width();
var height = element.height();
var vertical = gauge.options.scale.vertical;
if (!width) {
width = vertical ? DEFAULT_MIN_WIDTH : DEFAULT_WIDTH;
}
if (!height) {
height = vertical ? DEFAULT_HEIGHT : DEFAULT_MIN_HEIGHT;
}
return {
width: width,
height: height
};
},
_getBox: function (box) {
var that = this;
var scale = that.scale;
var pointers = that.pointers;
var boxCenter = box.center();
var plotAreaBox = pointers[0].box.clone().wrap(scale.box);
var size;
for (var i = 0; i < pointers.length; i++) {
plotAreaBox.wrap(pointers[i].box.clone());
}
if (scale.options.vertical) {
size = plotAreaBox.width() / 2;
plotAreaBox = new Box2D(boxCenter.x - size, box.y1, boxCenter.x + size, box.y2);
} else {
size = plotAreaBox.height() / 2;
plotAreaBox = new Box2D(box.x1, boxCenter.y - size, box.x2, boxCenter.y + size);
}
return plotAreaBox;
},
_alignElements: function () {
var that = this;
var scale = that.scale;
var pointers = that.pointers;
var scaleBox = scale.box;
var box = pointers[0].box.clone().wrap(scale.box);
var plotAreaBox = that.bbox;
var diff, i;
for (i = 0; i < pointers.length; i++) {
box.wrap(pointers[i].box.clone());
}
if (scale.options.vertical) {
diff = plotAreaBox.center().x - box.center().x;
scale.reflow(new Box2D(scaleBox.x1 + diff, plotAreaBox.y1, scaleBox.x2 + diff, plotAreaBox.y2));
} else {
diff = plotAreaBox.center().y - box.center().y;
scale.reflow(new Box2D(plotAreaBox.x1, scaleBox.y1 + diff, plotAreaBox.x2, scaleBox.y2 + diff));
}
for (i = 0; i < pointers.length; i++) {
pointers[i].reflow(that.bbox);
}
},
_shrinkElements: function () {
var that = this;
var scale = that.scale;
var pointers = that.pointers;
var scaleBox = scale.box.clone();
var pos = scale.options.vertical ? 'y' : 'x';
var pointerBox = pointers[0].box;
var i;
for (i = 0; i < pointers.length; i++) {
pointerBox.wrap(pointers[i].box.clone());
}
scaleBox[pos + 1] += math.max(scaleBox[pos + 1] - pointerBox[pos + 1], 0);
scaleBox[pos + 2] -= math.max(pointerBox[pos + 2] - scaleBox[pos + 2], 0);
scale.reflow(scaleBox);
for (i = 0; i < pointers.length; i++) {
pointers[i].reflow(that.bbox);
}
}
});
var LinearScale = NumericAxis.extend({
init: function (options) {
var scale = this;
scale.options = deepExtend({}, scale.options, options);
scale.options = deepExtend({}, scale.options, { labels: { mirror: scale.options.mirror } });
scale.options.majorUnit = scale.options.majorUnit || autoMajorUnit(scale.options.min, scale.options.max);
Axis.fn.init.call(scale, scale.options);
scale.options.minorUnit = scale.options.minorUnit || scale.options.majorUnit / 10;
},
options: {
min: 0,
max: 50,
majorTicks: {
size: 15,
align: INSIDE,
color: BLACK,
width: DEFAULT_LINE_WIDTH,
visible: true
},
minorTicks: {
size: 10,
align: INSIDE,
color: BLACK,
width: DEFAULT_LINE_WIDTH,
visible: true
},
line: { width: DEFAULT_LINE_WIDTH },
labels: {
position: INSIDE,
padding: 2
},
mirror: false,
_alignLines: false
},
render: function () {
var that = this;
var elements = that.elements = new Group();
var labels = that.renderLabels();
var scaleLine = that.renderLine();
var scaleTicks = that.renderTicks();
var ranges = that.renderRanges();
elements.append(scaleLine, labels, scaleTicks, ranges);
return elements;
},
renderRanges: function () {
var that = this;
var options = that.options;
var min = options.min;
var max = options.max;
var ranges = options.ranges || [];
var vertical = options.vertical;
var mirror = options.labels.mirror;
var elements = new Group();
var count = ranges.length;
var rangeSize = options.rangeSize || options.minorTicks.size / 2;
var range, slot, slotX, slotY, i;
if (count) {
for (i = 0; i < count; i++) {
range = getRange(ranges[i], min, max);
slot = that.getSlot(range.from, range.to);
slotX = vertical ? that.lineBox() : slot;
slotY = vertical ? slot : that.lineBox();
if (vertical) {
slotX.x1 -= rangeSize * (mirror ? -1 : 1);
} else {
slotY.y2 += rangeSize * (mirror ? -1 : 1);
}
elements.append(Path.fromRect(new Rect([
slotX.x1,
slotY.y1
], [
slotX.x2 - slotX.x1,
slotY.y2 - slotY.y1
]), {
fill: {
color: range.color,
opacity: range.opacity
},
stroke: {}
}));
}
}
return elements;
},
renderLabels: function () {
var that = this;
var options = that.options;
var labels = that.labels;
var elements = new Group();
for (var i = 0; i < labels.length; i++) {
elements.append(_buildLabel(labels[i], options.labels));
}
return elements;
},
renderLine: function () {
var that = this;
var options = that.options;
var line = options.line;
var lineBox = that.lineBox();
var linePath;
var elements = new Group();
if (line.width > 0 && line.visible) {
linePath = new Path({
stroke: {
color: line.color,
dashType: line.dashType,
width: line.width
}
});
linePath.moveTo(lineBox.x1, lineBox.y1).lineTo(lineBox.x2, lineBox.y2);
elements.append(linePath);
}
return elements;
},
renderTicks: function () {
var that = this;
var ticks = new Group();
var options = that.options;
var lineBox = that.lineBox();
var mirror = options.labels.mirror;
var majorUnit = options.majorTicks.visible ? options.majorUnit : 0;
var tickLineOptions = {
_alignLines: options._alignLines,
vertical: options.vertical
};
function render(tickPositions, tickOptions) {
var i, count = tickPositions.length;
if (tickOptions.visible) {
for (i = tickOptions.skip; i < count; i += tickOptions.step) {
if (i % tickOptions.skipUnit === 0) {
continue;
}
tickLineOptions.tickX = mirror ? lineBox.x2 : lineBox.x2 - tickOptions.size;
tickLineOptions.tickY = mirror ? lineBox.y1 - tickOptions.size : lineBox.y1;
tickLineOptions.position = tickPositions[i];
ticks.append(that.renderAxisTick(tickLineOptions, tickOptions));
}
}
}
render(that.getMajorTickPositions(), options.majorTicks);
render(that.getMinorTickPositions(), deepExtend({}, { skipUnit: majorUnit / options.minorUnit }, options.minorTicks));
return ticks;
},
renderAxisTick: function (options, tickOptions) {
var tickX = options.tickX;
var tickY = options.tickY;
var position = options.position;
var start, end, tickPath;
if (options.vertical) {
start = new Point(tickX, position);
end = new Point(tickX + tickOptions.size, position);
} else {
start = new Point(position, tickY);
end = new Point(position, tickY + tickOptions.size);
}
tickPath = new Path({
stroke: {
color: tickOptions.color,
width: tickOptions.width
}
}).moveTo(start).lineTo(end);
return tickPath;
}
});
var LinearPointer = Pointer.extend({
init: function (scale, options) {
var pointer = this;
Pointer.fn.init.call(pointer, scale, options);
pointer.options = deepExtend({ track: { visible: defined(options.track) } }, pointer.options);
},
options: {
shape: BAR_POINTER,
track: { border: { width: 1 } },
color: BLACK,
border: { width: 1 },
opacity: 1,
margin: getSpacing(3),
animation: { type: BAR_POINTER },
visible: true
},
reflow: function () {
var pointer = this;
var options = pointer.options;
var scale = pointer.scale;
var scaleLine = scale.lineBox();
var trackSize = options.track.size || options.size;
var pointerHalfSize = options.size / 2;
var mirror = scale.options.mirror;
var margin = getSpacing(options.margin);
var vertical = scale.options.vertical;
var space = vertical ? margin[mirror ? 'left' : 'right'] : margin[mirror ? 'bottom' : 'top'];
var pointerBox, pointerRangeBox, trackBox;
space = mirror ? -space : space;
if (vertical) {
trackBox = new Box2D(scaleLine.x1 + space, scaleLine.y1, scaleLine.x1 + space, scaleLine.y2);
if (mirror) {
trackBox.x1 -= trackSize;
} else {
trackBox.x2 += trackSize;
}
if (options.shape !== BAR_POINTER) {
pointerRangeBox = new Box2D(scaleLine.x2 + space, scaleLine.y1 - pointerHalfSize, scaleLine.x2 + space, scaleLine.y2 + pointerHalfSize);
pointerBox = pointerRangeBox;
}
} else {
trackBox = new Box2D(scaleLine.x1, scaleLine.y1 - space, scaleLine.x2, scaleLine.y1 - space);
if (mirror) {
trackBox.y2 += trackSize;
} else {
trackBox.y1 -= trackSize;
}
if (options.shape !== BAR_POINTER) {
pointerRangeBox = new Box2D(scaleLine.x1 - pointerHalfSize, scaleLine.y1 - space, scaleLine.x2 + pointerHalfSize, scaleLine.y1 - space);
pointerBox = pointerRangeBox;
}
}
pointer.trackBox = trackBox;
pointer.pointerRangeBox = pointerRangeBox;
pointer.box = pointerBox || trackBox.clone().pad(options.border.width);
},
getElementOptions: function () {
var options = this.options;
return {
fill: {
color: options.color,
opacity: options.opacity
},
stroke: defined(options.border) ? {
color: options.border.width ? options.border.color || options.color : '',
width: options.border.width,
dashType: options.border.dashType,
opacity: options.opacity
} : null
};
},
_margin: function () {
var pointer = this;
var options = pointer.options;
var scale = pointer.scale;
var mirror = scale.options.mirror;
var margin = getSpacing(options.margin);
var vertical = scale.options.vertical;
var space = vertical ? margin[mirror ? 'left' : 'right'] : margin[mirror ? 'bottom' : 'top'];
return space;
}
});
var ArrowLinearPointer = LinearPointer.extend({
init: function (scale, options) {
LinearPointer.fn.init.call(this, scale, options);
if (this.options.size === undefined) {
this.options.size = this.scale.options.majorTicks.size * 0.6;
}
},
pointerShape: function () {
var that = this;
var options = that.options;
var scale = that.scale;
var size = options.size;
var vertical = scale.options.vertical;
var halfSize = size / 2;
var sign = scale.options.mirror ? -1 : 1;
var reverse = scale.options.reverse;
var pos, shape;
if (vertical) {
pos = reverse ? 'y2' : 'y1';
shape = [
new Point(0, 0 - halfSize),
new Point(0 - sign * size, 0),
new Point(0, 0 + halfSize)
];
} else {
pos = reverse ? 'x1' : 'x2';
shape = [
new Point(0 - halfSize, 0),
new Point(0, 0 + sign * size),
new Point(0 + halfSize, 0)
];
}
return shape;
},
repaint: function () {
var that = this;
var scale = that.scale;
var options = that.options;
var animation = new ArrowLinearPointerAnimation(that.elements, deepExtend(options.animation, {
vertical: scale.options.vertical,
mirror: scale.options.mirror,
margin: that._margin(options.margin),
from: scale.getSlot(options._oldValue),
to: scale.getSlot(options.value)
}));
if (options.animation.transitions === false) {
animation.options.duration = 0;
}
animation.setup();
animation.play();
},
render: function () {
var that = this;
var options = that.options;
var elements = new Group();
var scale = that.scale;
var elementOptions = that.getElementOptions();
var shape = that.pointerShape(options.value);
options.animation.type = ARROW_POINTER;
elements = new Path({
stroke: elementOptions.stroke,
fill: elementOptions.fill
}).moveTo(shape[0]).lineTo(shape[1]).lineTo(shape[2]).close();
var slot = scale.getSlot(options.value);
elements.transform(geo.transform().translate(slot.x1, slot.y1));
that.elements = elements;
return elements;
}
});
var BarLinearPointer = LinearPointer.extend({
init: function (scale, options) {
LinearPointer.fn.init.call(this, scale, options);
if (this.options.size === undefined) {
this.options.size = this.scale.options.majorTicks.size * 0.3;
}
},
pointerShape: function (value) {
var that = this;
var options = that.options;
var scale = that.scale;
var vertical = scale.options.vertical;
var mirror = scale.options.mirror;
var dir = mirror == vertical ? -1 : 1;
var size = options.size * dir;
var minSlot = scale.getSlot(scale.options.min);
var slot = scale.getSlot(value);
var axis = vertical ? Y : X;
var sizeAxis = vertical ? X : Y;
var margin = that._margin() * dir;
var p1 = new Point();
p1[axis] = minSlot[axis + '1'];
p1[sizeAxis] = minSlot[sizeAxis + '1'];
var p2 = new Point();
p2[axis] = slot[axis + '1'];
p2[sizeAxis] = slot[sizeAxis + '1'];
if (vertical) {
p1.translate(margin, 0);
p2.translate(margin, 0);
} else {
p1.translate(0, margin);
p2.translate(0, margin);
}
var p3 = p2.clone();
var p4 = p1.clone();
if (vertical) {
p3.translate(size, 0);
p4.translate(size, 0);
} else {
p3.translate(0, size);
p4.translate(0, size);
}
return [
p1,
p2,
p3,
p4
];
},
repaint: function () {
var that = this;
var scale = that.scale;
var options = that.options;
var shape = that.pointerShape(options.value);
var pointerPath = that.elements.children[0];
var oldShape = that.pointerShape(options._oldValue);
pointerPath.moveTo(shape[0]).lineTo(shape[1]).lineTo(shape[2]).lineTo(shape[3]).close();
var animation = new BarLinearPointerAnimation(pointerPath, deepExtend(options.animation, {
reverse: scale.options.reverse,
vertical: scale.options.vertical,
oldPoints: [
oldShape[1],
oldShape[2]
],
newPoints: [
shape[1],
shape[2]
]
}));
if (options.animation.transitions === false) {
animation.options.duration = 0;
}
animation.setup();
animation.play();
},
render: function () {
var that = this;
var group = new Group();
var elementOptions = that.getElementOptions();
var pointer = new Path({
stroke: elementOptions.stroke,
fill: elementOptions.fill
});
group.append(pointer);
that.elements = group;
return group;
}
});
var RadialPointerAnimation = draw.Animation.extend({
init: function (element, options) {
draw.Animation.fn.init.call(this, element, options);
options = this.options;
options.duration = math.max(math.abs(options.newAngle - options.oldAngle) / options.duration * 1000, 1);
},
options: {
easing: LINEAR,
duration: ANGULAR_SPEED
},
step: function (pos) {
var anim = this;
var options = anim.options;
var angle = interpolateValue(options.oldAngle, options.newAngle, pos);
anim.element.transform(geo.transform().rotate(angle, options.center));
}
});
draw.AnimationFactory.current.register(RADIAL_POINTER, RadialPointerAnimation);
var ArrowLinearPointerAnimation = draw.Animation.extend({
options: {
easing: LINEAR,
duration: LINEAR_SPEED
},
setup: function () {
var options = this.options;
var margin = options.margin;
var from = options.from;
var to = options.to;
var axis = options.vertical ? 'x1' : 'y1';
if (options.mirror == options.vertical) {
from[axis] -= margin;
to[axis] -= margin;
} else {
from[axis] += margin;
to[axis] += margin;
}
var fromScale = this.fromScale = new Point(from.x1, from.y1);
var toScale = this.toScale = new Point(to.x1, to.y1);
if (options.duration !== 0) {
options.duration = math.max(fromScale.distanceTo(toScale) / options.duration * 1000, 1);
}
},
step: function (pos) {
var translateX = interpolateValue(this.fromScale.x, this.toScale.x, pos);
var translateY = interpolateValue(this.fromScale.y, this.toScale.y, pos);
this.element.transform(geo.transform().translate(translateX, translateY));
}
});
draw.AnimationFactory.current.register(ARROW_POINTER, ArrowLinearPointerAnimation);
var BarLinearPointerAnimation = draw.Animation.extend({
options: {
easing: LINEAR,
speed: LINEAR_SPEED
},
setup: function () {
var options = this.options;
var newPoints = options.newPoints;
var oldPoints = options.oldPoints;
var axis = this.axis = options.vertical ? Y : X;
var to = this.to = newPoints[0][axis];
var from = this.from = oldPoints[0][axis];
if (options.duration !== 0) {
options.duration = math.max(math.abs(to - from) / options.speed * 1000, 1);
}
this._set(from);
},
step: function (pos) {
var value = interpolateValue(this.from, this.to, pos);
this._set(value);
},
_set: function (value) {
var setter = 'set' + this.axis.toUpperCase();
var points = this.options.newPoints;
points[0][setter](value);
points[1][setter](value);
}
});
draw.AnimationFactory.current.register(BAR_POINTER, BarLinearPointerAnimation);
function _buildLabel(label, options) {
var labelBox = label.box;
var textBox = label.children[0].box;
var border = options.border || {};
var background = options.background || '';
var elements = new Group();
var styleBox, styleGeometry, wrapper;
wrapper = Path.fromRect(new Rect([
labelBox.x1,
labelBox.y1
], [
labelBox.width(),
labelBox.height()
]), { stroke: {} });
var text = new Text(label.text, new Point(textBox.x1, textBox.y1), {
font: options.font,
fill: { color: options.color }
});
styleGeometry = _pad(text.bbox().clone(), options.padding);
styleBox = Path.fromRect(styleGeometry, {
stroke: {
color: border.width ? border.color : '',
width: border.width,
dashType: border.dashType,
lineJoin: 'round',
lineCap: 'round'
},
fill: { color: background }
});
elements.append(wrapper);
elements.append(styleBox);
elements.append(text);
return elements;
}
function getRange(range, min, max) {
var from = defined(range.from) ? range.from : MIN_VALUE;
var to = defined(range.to) ? range.to : MAX_VALUE;
range.from = math.max(math.min(to, from), min);
range.to = math.min(math.max(to, from), max);
return range;
}
function _pad(bbox, value) {
var origin = bbox.getOrigin();
var size = bbox.getSize();
var spacing = getSpacing(value);
bbox.setOrigin([
origin.x - spacing.left,
origin.y - spacing.top
]);
bbox.setSize([
size.width + (spacing.left + spacing.right),
size.height + (spacing.top + spacing.bottom)
]);
return bbox;
}
function _unpad(bbox, value) {
var spacing = getSpacing(value);
spacing.left = -spacing.left;
spacing.top = -spacing.top;
spacing.right = -spacing.right;
spacing.bottom = -spacing.bottom;
return _pad(bbox, spacing);
}
dataviz.ui.plugin(RadialGauge);
dataviz.ui.plugin(LinearGauge);
dataviz.ExportMixin.extend(Gauge.fn);
deepExtend(dataviz, {
Gauge: Gauge,
RadialPointer: RadialPointer,
LinearPointer: LinearPointer,
ArrowLinearPointer: ArrowLinearPointer,
BarLinearPointer: BarLinearPointer,
LinearScale: LinearScale,
RadialScale: RadialScale,
LinearGauge: LinearGauge,
RadialGauge: RadialGauge
});
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));