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

3723 lines
163 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.core', [
'kendo.core',
'kendo.drawing'
], f);
}(function () {
var __meta__ = {
id: 'dataviz.core',
name: 'Core',
description: 'The DataViz core functions',
category: 'dataviz',
depends: [
'core',
'drawing'
],
hidden: true
};
(function ($, undefined) {
var kendo = window.kendo, util = kendo.util, append = util.append, defined = util.defined, last = util.last, valueOrDefault = util.valueOrDefault, dataviz = kendo.dataviz, geom = dataviz.geometry, draw = dataviz.drawing, measureText = draw.util.measureText, Class = kendo.Class, template = kendo.template, noop = $.noop, indexOf = $.inArray, isPlainObject = $.isPlainObject, trim = $.trim, math = Math, deepExtend = kendo.deepExtend;
var AXIS_LABEL_CLICK = 'axisLabelClick', BLACK = '#000', BOTTOM = 'bottom', CENTER = 'center', COORD_PRECISION = 3, CLIP = 'clip', CIRCLE = 'circle', CROSS = 'cross', DEFAULT_FONT = '12px sans-serif', DEFAULT_HEIGHT = 400, DEFAULT_ICON_SIZE = 7, DEFAULT_PRECISION = 10, DEFAULT_WIDTH = 600, DEG_TO_RAD = math.PI / 180, FORMAT_REGEX = /\{\d+:?/, HEIGHT = 'height', COORDINATE_LIMIT = 100000, INITIAL_ANIMATION_DURATION = 600, INSIDE = 'inside', LEFT = 'left', LINEAR = 'linear', MAX_VALUE = Number.MAX_VALUE, MIN_VALUE = -Number.MAX_VALUE, NONE = 'none', NOTE_CLICK = 'noteClick', NOTE_HOVER = 'noteHover', OUTSIDE = 'outside', RADIAL = 'radial', RIGHT = 'right', TOP = 'top', TRIANGLE = 'triangle', WIDTH = 'width', WHITE = '#fff', X = 'x', Y = 'y', ZERO_THRESHOLD = 0.2;
function getSpacing(value, defaultSpacing) {
var spacing = {
top: 0,
right: 0,
bottom: 0,
left: 0
};
defaultSpacing = defaultSpacing || 0;
if (typeof value === 'number') {
spacing[TOP] = spacing[RIGHT] = spacing[BOTTOM] = spacing[LEFT] = value;
} else {
spacing[TOP] = value[TOP] || defaultSpacing;
spacing[RIGHT] = value[RIGHT] || defaultSpacing;
spacing[BOTTOM] = value[BOTTOM] || defaultSpacing;
spacing[LEFT] = value[LEFT] || defaultSpacing;
}
return spacing;
}
var Point2D = function (x, y) {
var point = this;
if (!(point instanceof Point2D)) {
return new Point2D(x, y);
}
point.x = x || 0;
point.y = y || 0;
};
Point2D.fn = Point2D.prototype = {
clone: function () {
var point = this;
return new Point2D(point.x, point.y);
},
equals: function (point) {
return point && point.x === this.x && point.y === this.y;
},
rotate: function (center, degrees) {
var point = this, theta = degrees * DEG_TO_RAD, cosT = math.cos(theta), sinT = math.sin(theta), cx = center.x, cy = center.y, x = point.x, y = point.y;
point.x = round(cx + (x - cx) * cosT + (y - cy) * sinT, COORD_PRECISION);
point.y = round(cy + (y - cy) * cosT - (x - cx) * sinT, COORD_PRECISION);
return point;
},
multiply: function (a) {
var point = this;
point.x *= a;
point.y *= a;
return point;
},
distanceTo: function (point) {
var dx = this.x - point.x, dy = this.y - point.y;
return math.sqrt(dx * dx + dy * dy);
}
};
Point2D.onCircle = function (c, a, r) {
a *= DEG_TO_RAD;
return new Point2D(c.x - r * math.cos(a), c.y - r * math.sin(a));
};
var Box2D = function (x1, y1, x2, y2) {
var box = this;
if (!(box instanceof Box2D)) {
return new Box2D(x1, y1, x2, y2);
}
box.x1 = x1 || 0;
box.x2 = x2 || 0;
box.y1 = y1 || 0;
box.y2 = y2 || 0;
};
Box2D.fn = Box2D.prototype = {
width: function () {
return this.x2 - this.x1;
},
height: function () {
return this.y2 - this.y1;
},
translate: function (dx, dy) {
var box = this;
box.x1 += dx;
box.x2 += dx;
box.y1 += dy;
box.y2 += dy;
return box;
},
move: function (x, y) {
var box = this, height = box.height(), width = box.width();
if (defined(x)) {
box.x1 = x;
box.x2 = box.x1 + width;
}
if (defined(y)) {
box.y1 = y;
box.y2 = box.y1 + height;
}
return box;
},
wrap: function (targetBox) {
var box = this;
box.x1 = math.min(box.x1, targetBox.x1);
box.y1 = math.min(box.y1, targetBox.y1);
box.x2 = math.max(box.x2, targetBox.x2);
box.y2 = math.max(box.y2, targetBox.y2);
return box;
},
wrapPoint: function (point) {
this.wrap(new Box2D(point.x, point.y, point.x, point.y));
return this;
},
snapTo: function (targetBox, axis) {
var box = this;
if (axis == X || !axis) {
box.x1 = targetBox.x1;
box.x2 = targetBox.x2;
}
if (axis == Y || !axis) {
box.y1 = targetBox.y1;
box.y2 = targetBox.y2;
}
return box;
},
alignTo: function (targetBox, anchor) {
var box = this, height = box.height(), width = box.width(), axis = anchor == TOP || anchor == BOTTOM ? Y : X, offset = axis == Y ? height : width;
if (anchor === CENTER) {
var targetCenter = targetBox.center();
var center = box.center();
box.x1 += targetCenter.x - center.x;
box.y1 += targetCenter.y - center.y;
} else if (anchor === TOP || anchor === LEFT) {
box[axis + 1] = targetBox[axis + 1] - offset;
} else {
box[axis + 1] = targetBox[axis + 2];
}
box.x2 = box.x1 + width;
box.y2 = box.y1 + height;
return box;
},
shrink: function (dw, dh) {
var box = this;
box.x2 -= dw;
box.y2 -= dh;
return box;
},
expand: function (dw, dh) {
this.shrink(-dw, -dh);
return this;
},
pad: function (padding) {
var box = this, spacing = getSpacing(padding);
box.x1 -= spacing.left;
box.x2 += spacing.right;
box.y1 -= spacing.top;
box.y2 += spacing.bottom;
return box;
},
unpad: function (padding) {
var box = this, spacing = getSpacing(padding);
spacing.left = -spacing.left;
spacing.top = -spacing.top;
spacing.right = -spacing.right;
spacing.bottom = -spacing.bottom;
return box.pad(spacing);
},
clone: function () {
var box = this;
return new Box2D(box.x1, box.y1, box.x2, box.y2);
},
center: function () {
var box = this;
return new Point2D(box.x1 + box.width() / 2, box.y1 + box.height() / 2);
},
containsPoint: function (point) {
var box = this;
return point.x >= box.x1 && point.x <= box.x2 && point.y >= box.y1 && point.y <= box.y2;
},
points: function () {
var box = this;
return [
new Point2D(box.x1, box.y1),
new Point2D(box.x2, box.y1),
new Point2D(box.x2, box.y2),
new Point2D(box.x1, box.y2)
];
},
getHash: function () {
var box = this;
return [
box.x1,
box.y1,
box.x2,
box.y2
].join(',');
},
overlaps: function (box) {
return !(box.y2 < this.y1 || this.y2 < box.y1 || box.x2 < this.x1 || this.x2 < box.x1);
},
rotate: function (rotation) {
var box = this;
var width = box.width();
var height = box.height();
var center = box.center();
var cx = center.x;
var cy = center.y;
var r1 = rotatePoint(0, 0, cx, cy, rotation);
var r2 = rotatePoint(width, 0, cx, cy, rotation);
var r3 = rotatePoint(width, height, cx, cy, rotation);
var r4 = rotatePoint(0, height, cx, cy, rotation);
width = math.max(r1.x, r2.x, r3.x, r4.x) - math.min(r1.x, r2.x, r3.x, r4.x);
height = math.max(r1.y, r2.y, r3.y, r4.y) - math.min(r1.y, r2.y, r3.y, r4.y);
box.x2 = box.x1 + width;
box.y2 = box.y1 + height;
return box;
},
toRect: function () {
return new geom.Rect([
this.x1,
this.y1
], [
this.width(),
this.height()
]);
},
hasSize: function () {
return this.width() !== 0 && this.height() !== 0;
},
align: function (targetBox, axis, alignment) {
var box = this, c1 = axis + 1, c2 = axis + 2, sizeFunc = axis === X ? WIDTH : HEIGHT, size = box[sizeFunc]();
if (inArray(alignment, [
LEFT,
TOP
])) {
box[c1] = targetBox[c1];
box[c2] = box[c1] + size;
} else if (inArray(alignment, [
RIGHT,
BOTTOM
])) {
box[c2] = targetBox[c2];
box[c1] = box[c2] - size;
} else if (alignment == CENTER) {
box[c1] = targetBox[c1] + (targetBox[sizeFunc]() - size) / 2;
box[c2] = box[c1] + size;
}
}
};
var Ring = Class.extend({
init: function (center, innerRadius, radius, startAngle, angle) {
var ring = this;
ring.c = center;
ring.ir = innerRadius;
ring.r = radius;
ring.startAngle = startAngle;
ring.angle = angle;
},
clone: function () {
var r = this;
return new Ring(r.c, r.ir, r.r, r.startAngle, r.angle);
},
middle: function () {
return this.startAngle + this.angle / 2;
},
radius: function (newRadius, innerRadius) {
var that = this;
if (innerRadius) {
that.ir = newRadius;
} else {
that.r = newRadius;
}
return that;
},
point: function (angle, innerRadius) {
var ring = this, radianAngle = angle * DEG_TO_RAD, ax = math.cos(radianAngle), ay = math.sin(radianAngle), radius = innerRadius ? ring.ir : ring.r, x = round(ring.c.x - ax * radius, COORD_PRECISION), y = round(ring.c.y - ay * radius, COORD_PRECISION);
return new Point2D(x, y);
},
adjacentBox: function (distance, width, height) {
var sector = this.clone().expand(distance), midAndle = sector.middle(), midPoint = sector.point(midAndle), hw = width / 2, hh = height / 2, x = midPoint.x - hw, y = midPoint.y - hh, sa = math.sin(midAndle * DEG_TO_RAD), ca = math.cos(midAndle * DEG_TO_RAD);
if (math.abs(sa) < 0.9) {
x += hw * -ca / math.abs(ca);
}
if (math.abs(ca) < 0.9) {
y += hh * -sa / math.abs(sa);
}
return new Box2D(x, y, x + width, y + height);
},
containsPoint: function (p) {
var ring = this, c = ring.c, ir = ring.ir, r = ring.r, startAngle = ring.startAngle, endAngle = ring.startAngle + ring.angle, dx = p.x - c.x, dy = p.y - c.y, vector = new Point2D(dx, dy), startPoint = ring.point(startAngle), startVector = new Point2D(startPoint.x - c.x, startPoint.y - c.y), endPoint = ring.point(endAngle), endVector = new Point2D(endPoint.x - c.x, endPoint.y - c.y), dist = round(dx * dx + dy * dy, COORD_PRECISION);
return (startVector.equals(vector) || clockwise(startVector, vector)) && !clockwise(endVector, vector) && dist >= ir * ir && dist <= r * r;
},
getBBox: function () {
var ring = this, box = new Box2D(MAX_VALUE, MAX_VALUE, MIN_VALUE, MIN_VALUE), sa = round(ring.startAngle % 360), ea = round((sa + ring.angle) % 360), innerRadius = ring.ir, allAngles = [
0,
90,
180,
270,
sa,
ea
].sort(numericComparer), saIndex = indexOf(sa, allAngles), eaIndex = indexOf(ea, allAngles), angles, i, point;
if (sa == ea) {
angles = allAngles;
} else {
if (saIndex < eaIndex) {
angles = allAngles.slice(saIndex, eaIndex + 1);
} else {
angles = [].concat(allAngles.slice(0, eaIndex + 1), allAngles.slice(saIndex, allAngles.length));
}
}
for (i = 0; i < angles.length; i++) {
point = ring.point(angles[i]);
box.wrapPoint(point);
box.wrapPoint(point, innerRadius);
}
if (!innerRadius) {
box.wrapPoint(ring.c);
}
return box;
},
expand: function (value) {
this.r += value;
return this;
}
});
var Sector = Ring.extend({
init: function (center, radius, startAngle, angle) {
Ring.fn.init.call(this, center, 0, radius, startAngle, angle);
},
expand: function (value) {
return Ring.fn.expand.call(this, value);
},
clone: function () {
var sector = this;
return new Sector(sector.c, sector.r, sector.startAngle, sector.angle);
},
radius: function (newRadius) {
return Ring.fn.radius.call(this, newRadius);
},
point: function (angle) {
return Ring.fn.point.call(this, angle);
}
});
var ShapeBuilder = function () {
};
ShapeBuilder.fn = ShapeBuilder.prototype = {
createRing: function (sector, options) {
var startAngle = sector.startAngle + 180;
var endAngle = sector.angle + startAngle;
var center = new geom.Point(sector.c.x, sector.c.y);
var radius = math.max(sector.r, 0);
var innerRadius = math.max(sector.ir, 0);
var arc = new geom.Arc(center, {
startAngle: startAngle,
endAngle: endAngle,
radiusX: radius,
radiusY: radius
});
var path = draw.Path.fromArc(arc, options).close();
if (innerRadius) {
arc.radiusX = arc.radiusY = innerRadius;
var innerEnd = arc.pointAt(endAngle);
path.lineTo(innerEnd.x, innerEnd.y);
path.arc(endAngle, startAngle, innerRadius, innerRadius, true);
} else {
path.lineTo(center.x, center.y);
}
return path;
}
};
ShapeBuilder.current = new ShapeBuilder();
var ChartElement = Class.extend({
init: function (options) {
var element = this;
element.children = [];
element.options = deepExtend({}, element.options, options);
},
reflow: function (targetBox) {
var element = this, children = element.children, box, i, currentChild;
for (i = 0; i < children.length; i++) {
currentChild = children[i];
currentChild.reflow(targetBox);
box = box ? box.wrap(currentChild.box) : currentChild.box.clone();
}
element.box = box || targetBox;
},
destroy: function () {
var element = this, children = element.children, i;
if (this.animation) {
this.animation.destroy();
}
for (i = 0; i < children.length; i++) {
children[i].destroy();
}
},
getRoot: function () {
var parent = this.parent;
return parent ? parent.getRoot() : null;
},
getChart: function () {
var root = this.getRoot();
if (root) {
return root.chart;
}
},
translateChildren: function (dx, dy) {
var element = this, children = element.children, childrenCount = children.length, i;
for (i = 0; i < childrenCount; i++) {
children[i].box.translate(dx, dy);
}
},
append: function () {
append(this.children, arguments);
for (var i = 0; i < arguments.length; i++) {
arguments[i].parent = this;
}
},
renderVisual: function () {
if (this.options.visible === false) {
return;
}
this.createVisual();
this.addVisual();
this.renderChildren();
this.createAnimation();
this.renderComplete();
},
addVisual: function () {
if (this.visual) {
this.visual.chartElement = this;
if (this.parent) {
this.parent.appendVisual(this.visual);
}
}
},
renderChildren: function () {
var children = this.children;
for (var i = 0; i < children.length; i++) {
children[i].renderVisual();
}
},
createVisual: function () {
this.visual = new dataviz.drawing.Group({
zIndex: this.options.zIndex,
visible: valueOrDefault(this.options.visible, true)
});
},
createAnimation: function () {
if (this.visual) {
this.animation = draw.Animation.create(this.visual, this.options.animation);
}
},
appendVisual: function (childVisual) {
if (!childVisual.chartElement) {
childVisual.chartElement = this;
}
if (childVisual.options.noclip) {
this.clipRoot().visual.append(childVisual);
} else if (defined(childVisual.options.zIndex)) {
this.stackRoot().stackVisual(childVisual);
} else if (this.visual) {
this.visual.append(childVisual);
} else {
this.parent.appendVisual(childVisual);
}
},
clipRoot: function () {
if (this.parent) {
return this.parent.clipRoot();
}
return this;
},
stackRoot: function () {
if (this.parent) {
return this.parent.stackRoot();
}
return this;
},
stackVisual: function (childVisual) {
var zIndex = childVisual.options.zIndex || 0;
var visuals = this.visual.children;
for (var pos = 0; pos < visuals.length; pos++) {
var sibling = visuals[pos];
var here = valueOrDefault(sibling.options.zIndex, 0);
if (here > zIndex) {
break;
}
}
this.visual.insertAt(childVisual, pos);
},
traverse: function (callback) {
var children = this.children;
for (var i = 0; i < children.length; i++) {
var child = children[i];
callback(child);
if (child.traverse) {
child.traverse(callback);
}
}
},
closest: function (match) {
var element = this;
var matched = false;
while (element && !matched) {
matched = match(element);
if (!matched) {
element = element.parent;
}
}
if (matched) {
return element;
}
},
renderComplete: $.noop,
hasHighlight: function () {
var options = (this.options || {}).highlight;
return !(!this.createHighlight || options && options.visible === false);
},
toggleHighlight: function (show) {
var that = this;
var highlight = that._highlight;
var options = (that.options || {}).highlight;
var customVisual = (options || {}).visual;
if (!highlight) {
var highlightOptions = {
fill: {
color: WHITE,
opacity: 0.2
},
stroke: {
color: WHITE,
width: 1,
opacity: 0.2
}
};
if (customVisual) {
highlight = that._highlight = customVisual($.extend(that.highlightVisualArgs(), {
createVisual: function () {
return that.createHighlight(highlightOptions);
},
sender: that.getChart(),
series: that.series,
dataItem: that.dataItem,
category: that.category,
value: that.value,
percentage: that.percentage,
runningTotal: that.runningTotal,
total: that.total
}));
if (!highlight) {
return;
}
} else {
highlight = that._highlight = that.createHighlight(highlightOptions);
}
highlight.options.zIndex = that.options.zIndex;
that.appendVisual(highlight);
}
highlight.visible(show);
},
createGradientOverlay: function (element, options, gradientOptions) {
var overlay = new draw.Path(deepExtend({
stroke: { color: NONE },
fill: this.createGradient(gradientOptions),
closed: element.options.closed
}, options));
overlay.segments.elements(element.segments.elements());
return overlay;
},
createGradient: function (options) {
if (this.parent) {
return this.parent.createGradient(options);
}
}
});
var RootElement = ChartElement.extend({
init: function (options) {
var root = this;
root.gradients = {};
ChartElement.fn.init.call(root, options);
},
options: {
width: DEFAULT_WIDTH,
height: DEFAULT_HEIGHT,
background: WHITE,
border: {
color: BLACK,
width: 0
},
margin: getSpacing(5),
zIndex: -2
},
reflow: function () {
var root = this, options = root.options, children = root.children, currentBox = new Box2D(0, 0, options.width, options.height);
root.box = currentBox.unpad(options.margin);
for (var i = 0; i < children.length; i++) {
children[i].reflow(currentBox);
currentBox = boxDiff(currentBox, children[i].box) || Box2D();
}
},
createVisual: function () {
this.visual = new draw.Group();
this.createBackground();
},
createBackground: function () {
var options = this.options;
var border = options.border || {};
var box = this.box.clone().pad(options.margin).unpad(border.width);
var background = draw.Path.fromRect(box.toRect(), {
stroke: {
color: border.width ? border.color : '',
width: border.width,
dashType: border.dashType
},
fill: {
color: options.background,
opacity: options.opacity
},
zIndex: -10
});
this.visual.append(background);
},
getRoot: function () {
return this;
},
createGradient: function (options) {
var gradients = this.gradients;
var hashCode = util.objectKey(options);
var gradient = dataviz.Gradients[options.gradient];
var drawingGradient;
if (gradients[hashCode]) {
drawingGradient = gradients[hashCode];
} else {
var gradientOptions = deepExtend({}, gradient, options);
if (gradient.type == 'linear') {
drawingGradient = new draw.LinearGradient(gradientOptions);
} else {
if (options.innerRadius) {
gradientOptions.stops = innerRadialStops(gradientOptions);
}
drawingGradient = new draw.RadialGradient(gradientOptions);
drawingGradient.supportVML = gradient.supportVML !== false;
}
gradients[hashCode] = drawingGradient;
}
return drawingGradient;
}
});
var BoxElement = ChartElement.extend({
options: {
align: LEFT,
vAlign: TOP,
margin: {},
padding: {},
border: {
color: BLACK,
width: 0
},
background: '',
shrinkToFit: false,
width: 0,
height: 0,
visible: true
},
reflow: function (targetBox) {
var element = this, box, contentBox, options = element.options, width = options.width, height = options.height, hasSetSize = width && height, shrinkToFit = options.shrinkToFit, margin = getSpacing(options.margin), padding = getSpacing(options.padding), borderWidth = options.border.width, children = element.children, i, item;
function reflowPaddingBox() {
element.align(targetBox, X, options.align);
element.align(targetBox, Y, options.vAlign);
element.paddingBox = box.clone().unpad(margin).unpad(borderWidth);
}
contentBox = targetBox.clone();
if (hasSetSize) {
contentBox.x2 = contentBox.x1 + width;
contentBox.y2 = contentBox.y1 + height;
}
if (shrinkToFit) {
contentBox.unpad(margin).unpad(borderWidth).unpad(padding);
}
ChartElement.fn.reflow.call(element, contentBox);
if (hasSetSize) {
box = element.box = Box2D(0, 0, width, height);
} else {
box = element.box;
}
if (shrinkToFit && hasSetSize) {
reflowPaddingBox();
contentBox = element.contentBox = element.paddingBox.clone().unpad(padding);
} else {
contentBox = element.contentBox = box.clone();
box.pad(padding).pad(borderWidth).pad(margin);
reflowPaddingBox();
}
element.translateChildren(box.x1 - contentBox.x1 + margin.left + borderWidth + padding.left, box.y1 - contentBox.y1 + margin.top + borderWidth + padding.top);
for (i = 0; i < children.length; i++) {
item = children[i];
item.reflow(item.box);
}
},
align: function (targetBox, axis, alignment) {
this.box.align(targetBox, axis, alignment);
},
hasBox: function () {
var options = this.options;
return options.border.width || options.background;
},
createVisual: function () {
ChartElement.fn.createVisual.call(this);
var options = this.options;
if (options.visible && this.hasBox()) {
this.visual.append(draw.Path.fromRect(this.paddingBox.toRect(), this.visualStyle()));
}
},
visualStyle: function () {
var boxElement = this, options = boxElement.options, border = options.border || {};
return {
stroke: {
width: border.width,
color: border.color,
opacity: valueOrDefault(border.opacity, options.opacity),
dashType: border.dashType
},
fill: {
color: options.background,
opacity: options.opacity
},
cursor: options.cursor
};
}
});
var Text = ChartElement.extend({
init: function (content, options) {
var text = this;
ChartElement.fn.init.call(text, options);
text.content = content;
text.reflow(Box2D());
},
options: {
font: DEFAULT_FONT,
color: BLACK,
align: LEFT,
vAlign: ''
},
reflow: function (targetBox) {
var text = this, options = text.options, size;
size = options.size = measureText(text.content, { font: options.font });
text.baseline = size.baseline;
text.box = Box2D(targetBox.x1, targetBox.y1, targetBox.x1 + size.width, targetBox.y1 + size.height);
},
createVisual: function () {
var opt = this.options;
this.visual = new draw.Text(this.content, this.box.toRect().topLeft(), {
font: opt.font,
fill: {
color: opt.color,
opacity: opt.opacity
},
cursor: opt.cursor
});
}
});
var FloatElement = ChartElement.extend({
init: function (options) {
ChartElement.fn.init.call(this, options);
this._initDirection();
},
_initDirection: function () {
var options = this.options;
if (options.vertical) {
this.groupAxis = X;
this.elementAxis = Y;
this.groupSizeField = WIDTH;
this.elementSizeField = HEIGHT;
this.groupSpacing = options.spacing;
this.elementSpacing = options.vSpacing;
} else {
this.groupAxis = Y;
this.elementAxis = X;
this.groupSizeField = HEIGHT;
this.elementSizeField = WIDTH;
this.groupSpacing = options.vSpacing;
this.elementSpacing = options.spacing;
}
},
options: {
vertical: true,
wrap: true,
vSpacing: 0,
spacing: 0
},
reflow: function (targetBox) {
this.box = targetBox.clone();
this.reflowChildren();
},
reflowChildren: function () {
var floatElement = this;
var box = floatElement.box;
var elementAxis = floatElement.elementAxis;
var groupAxis = floatElement.groupAxis;
var elementSizeField = floatElement.elementSizeField;
var groupSizeField = floatElement.groupSizeField;
var groupOptions = floatElement.groupOptions();
var groups = groupOptions.groups;
var groupsCount = groups.length;
var groupsStart = box[groupAxis + 1] + floatElement.alignStart(groupOptions.groupsSize, box[groupSizeField]());
var groupStart = groupsStart;
var elementStart;
var groupElementStart;
var group;
var groupElements;
var groupElementsCount;
var idx;
var groupIdx;
var element;
var elementBox;
var elementSize;
if (groupsCount) {
for (groupIdx = 0; groupIdx < groupsCount; groupIdx++) {
group = groups[groupIdx];
groupElements = group.groupElements;
groupElementsCount = groupElements.length;
elementStart = box[elementAxis + 1];
for (idx = 0; idx < groupElementsCount; idx++) {
element = groupElements[idx];
elementSize = floatElement.elementSize(element);
groupElementStart = groupStart + floatElement.alignStart(elementSize[groupSizeField], group.groupSize);
elementBox = Box2D();
elementBox[groupAxis + 1] = groupElementStart;
elementBox[groupAxis + 2] = groupElementStart + elementSize[groupSizeField];
elementBox[elementAxis + 1] = elementStart;
elementBox[elementAxis + 2] = elementStart + elementSize[elementSizeField];
element.reflow(elementBox);
elementStart += elementSize[elementSizeField] + floatElement.elementSpacing;
}
groupStart += group.groupSize + floatElement.groupSpacing;
}
box[groupAxis + 1] = groupsStart;
box[groupAxis + 2] = groupsStart + groupOptions.groupsSize;
box[elementAxis + 2] = box[elementAxis + 1] + groupOptions.maxGroupElementsSize;
}
},
alignStart: function (size, maxSize) {
var start = 0;
var align = this.options.align;
if (align == RIGHT || align == BOTTOM) {
start = maxSize - size;
} else if (align == CENTER) {
start = (maxSize - size) / 2;
}
return start;
},
groupOptions: function () {
var floatElement = this;
var box = floatElement.box;
var children = floatElement.children;
var childrenCount = children.length;
var elementSizeField = this.elementSizeField;
var groupSizeField = this.groupSizeField;
var elementSpacing = this.elementSpacing;
var groupSpacing = this.groupSpacing;
var maxSize = round(box[elementSizeField]());
var idx = 0;
var groupSize = 0;
var elementSize;
var element;
var groupElementsSize = 0;
var groupsSize = 0;
var groups = [];
var groupElements = [];
var maxGroupElementsSize = 0;
for (idx = 0; idx < childrenCount; idx++) {
element = children[idx];
if (!element.box) {
element.reflow(box);
}
elementSize = this.elementSize(element);
if (floatElement.options.wrap && round(groupElementsSize + elementSpacing + elementSize[elementSizeField]) > maxSize) {
groups.push({
groupElements: groupElements,
groupSize: groupSize,
groupElementsSize: groupElementsSize
});
maxGroupElementsSize = math.max(maxGroupElementsSize, groupElementsSize);
groupsSize += groupSpacing + groupSize;
groupSize = 0;
groupElementsSize = 0;
groupElements = [];
}
groupSize = math.max(groupSize, elementSize[groupSizeField]);
if (groupElementsSize > 0) {
groupElementsSize += elementSpacing;
}
groupElementsSize += elementSize[elementSizeField];
groupElements.push(element);
}
groups.push({
groupElements: groupElements,
groupSize: groupSize,
groupElementsSize: groupElementsSize
});
maxGroupElementsSize = math.max(maxGroupElementsSize, groupElementsSize);
groupsSize += groupSize;
return {
groups: groups,
groupsSize: groupsSize,
maxGroupElementsSize: maxGroupElementsSize
};
},
elementSize: function (element) {
return {
width: element.box.width(),
height: element.box.height()
};
},
createVisual: noop
});
var TextBox = BoxElement.extend({
ROWS_SPLIT_REGEX: /\n|\\n/m,
init: function (content, options) {
var textbox = this;
textbox.content = content;
BoxElement.fn.init.call(textbox, options);
textbox._initContainer();
textbox.reflow(Box2D());
},
_initContainer: function () {
var textbox = this;
var options = textbox.options;
var rows = (textbox.content + '').split(textbox.ROWS_SPLIT_REGEX);
var floatElement = new FloatElement({
vertical: true,
align: options.align,
wrap: false
});
var textOptions = deepExtend({}, options, {
opacity: 1,
animation: null
});
var text;
var rowIdx;
textbox.container = floatElement;
textbox.append(floatElement);
for (rowIdx = 0; rowIdx < rows.length; rowIdx++) {
text = new Text(trim(rows[rowIdx]), textOptions);
floatElement.append(text);
}
},
reflow: function (targetBox) {
var options = this.options;
var visualFn = options.visual;
this.container.options.align = options.align;
if (visualFn && !this._boxReflow) {
if (!targetBox.hasSize()) {
this._boxReflow = true;
this.reflow(targetBox);
this._boxReflow = false;
targetBox = this.box;
}
this.visual = visualFn(this.visualContext(targetBox));
var visualBox = targetBox;
if (this.visual) {
visualBox = rectToBox(this.visual.clippedBBox() || new geom.Rect());
this.visual.options.zIndex = options.zIndex;
this.visual.options.noclip = options.noclip;
}
this.box = this.contentBox = this.paddingBox = visualBox;
} else {
BoxElement.fn.reflow.call(this, targetBox);
if (options.rotation) {
var margin = getSpacing(options.margin);
var box = this.box.unpad(margin);
this.targetBox = targetBox;
this.normalBox = box.clone();
box = this.rotate();
box.translate(margin.left - margin.right, margin.top - margin.bottom);
this.rotatedBox = box.clone();
box.pad(margin);
}
}
},
createVisual: function () {
var options = this.options;
if (!options.visible) {
return;
}
this.visual = new dataviz.drawing.Group({
transform: this.rotationTransform(),
zIndex: options.zIndex,
noclip: options.noclip
});
if (this.hasBox()) {
var box = draw.Path.fromRect(this.paddingBox.toRect(), this.visualStyle());
this.visual.append(box);
}
},
renderVisual: function () {
if (this.options.visual) {
this.addVisual();
this.createAnimation();
} else {
BoxElement.fn.renderVisual.call(this);
}
},
visualOptions: function () {
var options = this.options;
return {
background: options.background,
border: options.border,
color: options.color,
font: options.font,
margin: options.margin,
padding: options.padding,
visible: options.visible
};
},
visualContext: function (targetBox) {
var textbox = this;
return {
text: textbox.content,
rect: targetBox.toRect(),
sender: this.getChart(),
options: textbox.visualOptions(),
createVisual: function () {
textbox._boxReflow = true;
textbox.reflow(targetBox);
textbox._boxReflow = false;
return textbox.getDefaultVisual();
}
};
},
getDefaultVisual: function () {
this.createVisual();
this.renderChildren();
var visual = this.visual;
delete this.visual;
return visual;
},
rotate: function () {
var options = this.options;
this.box.rotate(options.rotation);
this.align(this.targetBox, X, options.align);
this.align(this.targetBox, Y, options.vAlign);
return this.box;
},
rotationTransform: function () {
var rotation = this.options.rotation;
if (!rotation) {
return null;
}
var center = this.normalBox.center();
var cx = center.x;
var cy = center.y;
var boxCenter = this.rotatedBox.center();
return geom.transform().translate(boxCenter.x - cx, boxCenter.y - cy).rotate(rotation, [
cx,
cy
]);
}
});
var Title = ChartElement.extend({
init: function (options) {
var title = this;
ChartElement.fn.init.call(title, options);
options = title.options;
title.append(new TextBox(options.text, deepExtend({}, options, { vAlign: options.position })));
},
options: {
color: BLACK,
position: TOP,
align: CENTER,
margin: getSpacing(5),
padding: getSpacing(5)
},
reflow: function (targetBox) {
var title = this;
ChartElement.fn.reflow.call(title, targetBox);
title.box.snapTo(targetBox, X);
}
});
Title.buildTitle = function (options, parent, defaultOptions) {
var title;
if (typeof options === 'string') {
options = { text: options };
}
options = deepExtend({ visible: true }, defaultOptions, options);
if (options && options.visible && options.text) {
title = new Title(options);
parent.append(title);
}
return title;
};
var AxisLabel = TextBox.extend({
init: function (value, text, index, dataItem, options) {
var label = this;
label.text = text;
label.value = value;
label.index = index;
label.dataItem = dataItem;
TextBox.fn.init.call(label, text, options);
},
visualContext: function (targetBox) {
var context = TextBox.fn.visualContext.call(this, targetBox);
context.value = this.value;
context.dataItem = this.dataItem;
context.format = this.options.format;
context.culture = this.options.culture;
return context;
},
click: function (widget, e) {
var label = this;
widget.trigger(AXIS_LABEL_CLICK, {
element: $(e.target),
value: label.value,
text: label.text,
index: label.index,
dataItem: label.dataItem,
axis: label.parent.options
});
},
rotate: function () {
if (this.options.alignRotation != CENTER) {
var box = this.normalBox.toRect();
var transform = this.rotationTransform();
this.box = rectToBox(box.bbox(transform.matrix()));
} else {
TextBox.fn.rotate.call(this);
}
return this.box;
},
rotationTransform: function () {
var options = this.options;
var rotation = options.rotation;
if (!rotation) {
return null;
}
if (options.alignRotation == CENTER) {
return TextBox.fn.rotationTransform.call(this);
}
var rotationMatrix = geom.transform().rotate(rotation).matrix();
var box = this.normalBox.toRect();
var rect = this.targetBox.toRect();
var rotationOrigin = options.rotationOrigin || TOP;
var alignAxis = rotationOrigin == TOP || rotationOrigin == BOTTOM ? X : Y;
var distanceAxis = rotationOrigin == TOP || rotationOrigin == BOTTOM ? Y : X;
var axisAnchor = rotationOrigin == TOP || rotationOrigin == LEFT ? rect.origin : rect.bottomRight();
var topLeft = box.topLeft().transformCopy(rotationMatrix);
var topRight = box.topRight().transformCopy(rotationMatrix);
var bottomRight = box.bottomRight().transformCopy(rotationMatrix);
var bottomLeft = box.bottomLeft().transformCopy(rotationMatrix);
var rotatedBox = geom.Rect.fromPoints(topLeft, topRight, bottomRight, bottomLeft);
var translate = {};
translate[distanceAxis] = rect.origin[distanceAxis] - rotatedBox.origin[distanceAxis];
var distanceLeft = math.abs(topLeft[distanceAxis] + translate[distanceAxis] - axisAnchor[distanceAxis]);
var distanceRight = math.abs(topRight[distanceAxis] + translate[distanceAxis] - axisAnchor[distanceAxis]);
var alignStart;
var alignEnd;
if (round(distanceLeft, DEFAULT_PRECISION) === round(distanceRight, DEFAULT_PRECISION)) {
alignStart = topLeft;
alignEnd = topRight;
} else if (distanceRight < distanceLeft) {
alignStart = topRight;
alignEnd = bottomRight;
} else {
alignStart = topLeft;
alignEnd = bottomLeft;
}
var alignCenter = alignStart[alignAxis] + (alignEnd[alignAxis] - alignStart[alignAxis]) / 2;
translate[alignAxis] = rect.center()[alignAxis] - alignCenter;
return geom.transform().translate(translate.x, translate.y).rotate(rotation);
}
});
function createAxisTick(options, tickOptions) {
var tickX = options.tickX, tickY = options.tickY, position = options.position;
var tick = new draw.Path({
stroke: {
width: tickOptions.width,
color: tickOptions.color
}
});
if (options.vertical) {
tick.moveTo(tickX, position).lineTo(tickX + tickOptions.size, position);
} else {
tick.moveTo(position, tickY).lineTo(position, tickY + tickOptions.size);
}
alignPathToPixel(tick);
return tick;
}
function createAxisGridLine(options, gridLine) {
var lineStart = options.lineStart, lineEnd = options.lineEnd, position = options.position;
var line = new draw.Path({
stroke: {
width: gridLine.width,
color: gridLine.color,
dashType: gridLine.dashType
}
});
if (options.vertical) {
line.moveTo(lineStart, position).lineTo(lineEnd, position);
} else {
line.moveTo(position, lineStart).lineTo(position, lineEnd);
}
alignPathToPixel(line);
return line;
}
var Axis = ChartElement.extend({
init: function (options) {
var axis = this;
ChartElement.fn.init.call(axis, options);
if (!axis.options.visible) {
axis.options = deepExtend({}, axis.options, {
labels: { visible: false },
line: { visible: false },
margin: 0,
majorTickSize: 0,
minorTickSize: 0
});
}
axis.options.minorTicks = deepExtend({}, {
color: axis.options.line.color,
width: axis.options.line.width,
visible: axis.options.minorTickType != NONE
}, axis.options.minorTicks, {
size: axis.options.minorTickSize,
align: axis.options.minorTickType
});
axis.options.majorTicks = deepExtend({}, {
color: axis.options.line.color,
width: axis.options.line.width,
visible: axis.options.majorTickType != NONE
}, axis.options.majorTicks, {
size: axis.options.majorTickSize,
align: axis.options.majorTickType
});
if (!this.options._deferLabels) {
axis.createLabels();
}
axis.createTitle();
axis.createNotes();
},
options: {
labels: {
visible: true,
rotation: 0,
mirror: false,
step: 1,
skip: 0
},
line: {
width: 1,
color: BLACK,
visible: true
},
title: {
visible: true,
position: CENTER
},
majorTicks: {
align: OUTSIDE,
size: 4,
skip: 0,
step: 1
},
minorTicks: {
align: OUTSIDE,
size: 3,
skip: 0,
step: 1
},
axisCrossingValue: 0,
majorTickType: OUTSIDE,
minorTickType: NONE,
majorGridLines: {
skip: 0,
step: 1
},
minorGridLines: {
visible: false,
width: 1,
color: BLACK,
skip: 0,
step: 1
},
margin: 5,
visible: true,
reverse: false,
justified: true,
notes: { label: { text: '' } },
_alignLines: true,
_deferLabels: false
},
labelsRange: function () {
return {
min: this.options.labels.skip,
max: this.labelsCount()
};
},
createLabels: function () {
var axis = this, options = axis.options, align = options.vertical ? RIGHT : CENTER, labelOptions = deepExtend({}, options.labels, {
align: align,
zIndex: options.zIndex
}), step = math.max(1, labelOptions.step);
axis.children = $.grep(axis.children, function (child) {
return !(child instanceof AxisLabel);
});
axis.labels = [];
if (labelOptions.visible) {
var range = axis.labelsRange(), rotation = labelOptions.rotation, label, i;
if (isPlainObject(rotation)) {
labelOptions.alignRotation = rotation.align;
labelOptions.rotation = rotation.angle;
}
if (labelOptions.rotation == 'auto') {
labelOptions.rotation = 0;
options.autoRotateLabels = true;
}
for (i = range.min; i < range.max; i += step) {
label = axis.createAxisLabel(i, labelOptions);
if (label) {
axis.append(label);
axis.labels.push(label);
}
}
}
},
lineBox: function () {
var axis = this, options = axis.options, box = axis.box, vertical = options.vertical, mirror = options.labels.mirror, axisX = mirror ? box.x1 : box.x2, axisY = mirror ? box.y2 : box.y1, lineWidth = options.line.width || 0;
return vertical ? Box2D(axisX, box.y1, axisX, box.y2 - lineWidth) : Box2D(box.x1, axisY, box.x2 - lineWidth, axisY);
},
createTitle: function () {
var axis = this, options = axis.options, titleOptions = deepExtend({
rotation: options.vertical ? -90 : 0,
text: '',
zIndex: 1,
visualSize: true
}, options.title), title;
if (titleOptions.visible && titleOptions.text) {
title = new TextBox(titleOptions.text, titleOptions);
axis.append(title);
axis.title = title;
}
},
createNotes: function () {
var axis = this, options = axis.options, notes = options.notes, items = notes.data || [], i, item, note;
axis.notes = [];
for (i = 0; i < items.length; i++) {
item = deepExtend({}, notes, items[i]);
item.value = axis.parseNoteValue(item.value);
note = new Note(item.value, item.label.text, null, null, null, item);
if (note.options.visible) {
if (defined(note.options.position)) {
if (options.vertical && !inArray(note.options.position, [
LEFT,
RIGHT
])) {
note.options.position = options.reverse ? LEFT : RIGHT;
} else if (!options.vertical && !inArray(note.options.position, [
TOP,
BOTTOM
])) {
note.options.position = options.reverse ? BOTTOM : TOP;
}
} else {
if (options.vertical) {
note.options.position = options.reverse ? LEFT : RIGHT;
} else {
note.options.position = options.reverse ? BOTTOM : TOP;
}
}
axis.append(note);
axis.notes.push(note);
}
}
},
parseNoteValue: function (value) {
return value;
},
renderVisual: function () {
ChartElement.fn.renderVisual.call(this);
this.createPlotBands();
},
createVisual: function () {
ChartElement.fn.createVisual.call(this);
this.createBackground();
this.createLine();
},
gridLinesVisual: function () {
var gridLines = this._gridLines;
if (!gridLines) {
gridLines = this._gridLines = new draw.Group({ zIndex: -2 });
this.appendVisual(this._gridLines);
}
return gridLines;
},
createTicks: function (lineGroup) {
var axis = this, options = axis.options, lineBox = axis.lineBox(), mirror = options.labels.mirror, majorUnit = options.majorTicks.visible ? options.majorUnit : 0, tickLineOptions = { vertical: options.vertical };
function render(tickPositions, tickOptions, skipUnit) {
var i, count = tickPositions.length;
if (tickOptions.visible) {
for (i = tickOptions.skip; i < count; i += tickOptions.step) {
if (defined(skipUnit) && i % 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];
lineGroup.append(createAxisTick(tickLineOptions, tickOptions));
}
}
}
render(axis.getMajorTickPositions(), options.majorTicks);
render(axis.getMinorTickPositions(), options.minorTicks, majorUnit / options.minorUnit);
},
createLine: function () {
var axis = this, options = axis.options, line = options.line, lineBox = axis.lineBox();
if (line.width > 0 && line.visible) {
var path = new draw.Path({
stroke: {
width: line.width,
color: line.color,
dashType: line.dashType
}
});
path.moveTo(lineBox.x1, lineBox.y1).lineTo(lineBox.x2, lineBox.y2);
if (options._alignLines) {
alignPathToPixel(path);
}
var group = this._lineGroup = new draw.Group();
group.append(path);
this.visual.append(group);
this.createTicks(group);
}
},
getActualTickSize: function () {
var axis = this, options = axis.options, tickSize = 0;
if (options.majorTicks.visible && options.minorTicks.visible) {
tickSize = math.max(options.majorTicks.size, options.minorTicks.size);
} else if (options.majorTicks.visible) {
tickSize = options.majorTicks.size;
} else if (options.minorTicks.visible) {
tickSize = options.minorTicks.size;
}
return tickSize;
},
createBackground: function () {
var axis = this, options = axis.options, background = options.background, box = axis.box;
if (background) {
axis._backgroundPath = draw.Path.fromRect(box.toRect(), {
fill: { color: background },
stroke: null
});
this.visual.append(axis._backgroundPath);
}
},
createPlotBands: function () {
var axis = this, options = axis.options, plotBands = options.plotBands || [], vertical = options.vertical, plotArea = axis.plotArea, slotX, slotY, from, to;
if (plotBands.length === 0) {
return;
}
var group = this._plotbandGroup = new draw.Group({ zIndex: -1 });
var altAxis = $.grep(axis.pane.axes, function (a) {
return a.options.vertical !== axis.options.vertical;
})[0];
$.each(plotBands, function (i, item) {
from = valueOrDefault(item.from, MIN_VALUE);
to = valueOrDefault(item.to, MAX_VALUE);
if (vertical) {
slotX = (altAxis || plotArea.axisX).lineBox();
slotY = axis.getSlot(item.from, item.to, true);
} else {
slotX = axis.getSlot(item.from, item.to, true);
slotY = (altAxis || plotArea.axisY).lineBox();
}
if (slotX.width() !== 0 && slotY.height() !== 0) {
var bandRect = new geom.Rect([
slotX.x1,
slotY.y1
], [
slotX.width(),
slotY.height()
]);
var path = draw.Path.fromRect(bandRect, {
fill: {
color: item.color,
opacity: item.opacity
},
stroke: null
});
group.append(path);
}
});
axis.appendVisual(group);
},
createGridLines: function (altAxis) {
var axis = this, options = axis.options, axisLineVisible = altAxis.options.line.visible, majorGridLines = options.majorGridLines, majorUnit = majorGridLines.visible ? options.majorUnit : 0, vertical = options.vertical, lineBox = altAxis.lineBox(), linePos = lineBox[vertical ? 'y1' : 'x1'], lineOptions = {
lineStart: lineBox[vertical ? 'x1' : 'y1'],
lineEnd: lineBox[vertical ? 'x2' : 'y2'],
vertical: vertical
}, pos, majorTicks = [];
var container = this.gridLinesVisual();
function render(tickPositions, gridLine, skipUnit) {
var count = tickPositions.length, i;
if (gridLine.visible) {
for (i = gridLine.skip; i < count; i += gridLine.step) {
pos = round(tickPositions[i]);
if (!inArray(pos, majorTicks)) {
if (i % skipUnit !== 0 && (!axisLineVisible || linePos !== pos)) {
lineOptions.position = pos;
container.append(createAxisGridLine(lineOptions, gridLine));
majorTicks.push(pos);
}
}
}
}
}
render(axis.getMajorTickPositions(), options.majorGridLines);
render(axis.getMinorTickPositions(), options.minorGridLines, majorUnit / options.minorUnit);
return container.children;
},
reflow: function (box) {
var axis = this, options = axis.options, vertical = options.vertical, labels = axis.labels, count = labels.length, title = axis.title, sizeFn = vertical ? WIDTH : HEIGHT, titleSize = title ? title.box[sizeFn]() : 0, space = axis.getActualTickSize() + options.margin + titleSize, maxLabelSize = 0, rootBox = (this.getRoot() || {}).box || box, boxSize = rootBox[sizeFn](), labelSize, i;
for (i = 0; i < count; i++) {
labelSize = labels[i].box[sizeFn]();
if (labelSize + space <= boxSize) {
maxLabelSize = math.max(maxLabelSize, labelSize);
}
}
if (vertical) {
axis.box = Box2D(box.x1, box.y1, box.x1 + maxLabelSize + space, box.y2);
} else {
axis.box = Box2D(box.x1, box.y1, box.x2, box.y1 + maxLabelSize + space);
}
axis.arrangeTitle();
axis.arrangeLabels();
axis.arrangeNotes();
},
getLabelsTickPositions: function () {
return this.getMajorTickPositions();
},
labelTickIndex: function (label) {
return label.index;
},
arrangeLabels: function () {
var axis = this, options = axis.options, labels = axis.labels, labelsBetweenTicks = !options.justified, vertical = options.vertical, lineBox = axis.lineBox(), mirror = options.labels.mirror, tickPositions = axis.getLabelsTickPositions(), labelOffset = axis.getActualTickSize() + options.margin, labelBox, labelY, i;
for (i = 0; i < labels.length; i++) {
var label = labels[i], tickIx = axis.labelTickIndex(label), labelSize = vertical ? label.box.height() : label.box.width(), labelPos = tickPositions[tickIx] - labelSize / 2, firstTickPosition, nextTickPosition, middle, labelX;
if (vertical) {
if (labelsBetweenTicks) {
firstTickPosition = tickPositions[tickIx];
nextTickPosition = tickPositions[tickIx + 1];
middle = firstTickPosition + (nextTickPosition - firstTickPosition) / 2;
labelPos = middle - labelSize / 2;
}
labelX = lineBox.x2;
if (mirror) {
labelX += labelOffset;
label.options.rotationOrigin = LEFT;
} else {
labelX -= labelOffset + label.box.width();
label.options.rotationOrigin = RIGHT;
}
labelBox = label.box.move(labelX, labelPos);
} else {
if (labelsBetweenTicks) {
firstTickPosition = tickPositions[tickIx];
nextTickPosition = tickPositions[tickIx + 1];
} else {
firstTickPosition = labelPos;
nextTickPosition = labelPos + labelSize;
}
labelY = lineBox.y1;
if (mirror) {
labelY -= labelOffset + label.box.height();
label.options.rotationOrigin = BOTTOM;
} else {
labelY += labelOffset;
label.options.rotationOrigin = TOP;
}
labelBox = Box2D(firstTickPosition, labelY, nextTickPosition, labelY + label.box.height());
}
label.reflow(labelBox);
}
},
autoRotateLabels: function () {
if (this.options.autoRotateLabels && !this.options.vertical) {
var tickPositions = this.getMajorTickPositions();
var labels = this.labels;
var labelBox, angle, width, idx;
for (idx = 0; idx < labels.length; idx++) {
width = tickPositions[idx + 1] - tickPositions[idx];
labelBox = labels[idx].box;
if (labelBox.width() > width) {
if (labelBox.height() > width) {
angle = -90;
break;
}
angle = -45;
}
}
if (angle) {
for (idx = 0; idx < labels.length; idx++) {
labels[idx].options.rotation = angle;
labels[idx].reflow(Box2D());
}
return true;
}
}
},
arrangeTitle: function () {
var axis = this, options = axis.options, mirror = options.labels.mirror, vertical = options.vertical, title = axis.title;
if (title) {
if (vertical) {
title.options.align = mirror ? RIGHT : LEFT;
title.options.vAlign = title.options.position;
} else {
title.options.align = title.options.position;
title.options.vAlign = mirror ? TOP : BOTTOM;
}
title.reflow(axis.box);
}
},
arrangeNotes: function () {
var axis = this, i, item, slot, value;
for (i = 0; i < axis.notes.length; i++) {
item = axis.notes[i];
value = item.options.value;
if (defined(value)) {
if (axis.shouldRenderNote(value)) {
item.show();
} else {
item.hide();
}
slot = axis.getSlot(value);
} else {
item.hide();
}
item.reflow(slot || axis.lineBox());
}
},
alignTo: function (secondAxis) {
var axis = this, lineBox = secondAxis.lineBox(), vertical = axis.options.vertical, pos = vertical ? Y : X;
axis.box.snapTo(lineBox, pos);
if (vertical) {
axis.box.shrink(0, axis.lineBox().height() - lineBox.height());
} else {
axis.box.shrink(axis.lineBox().width() - lineBox.width(), 0);
}
axis.box[pos + 1] -= axis.lineBox()[pos + 1] - lineBox[pos + 1];
axis.box[pos + 2] -= axis.lineBox()[pos + 2] - lineBox[pos + 2];
},
axisLabelText: function (value, dataItem, options) {
var text = value;
if (options.template) {
var tmpl = template(options.template);
text = tmpl({
value: value,
dataItem: dataItem,
format: options.format,
culture: options.culture
});
} else if (options.format) {
if (options.format.match(FORMAT_REGEX)) {
text = kendo.format(options.format, value);
} else {
text = kendo.toString(value, options.format, options.culture);
}
}
return text;
},
slot: function (from, to) {
var slot = this.getSlot(from, to);
if (slot) {
return slot.toRect();
}
},
contentBox: function () {
var box = this.box.clone();
var labels = this.labels;
if (labels.length) {
if (labels[0].options.visible) {
box.wrap(labels[0].box);
}
if (last(labels).options.visible) {
box.wrap(last(labels).box);
}
}
return box;
},
limitRange: function (from, to, min, max, offset) {
var options = this.options;
if (from < min && offset < 0 && (!defined(options.min) || options.min <= min) || max < to && offset > 0 && (!defined(options.max) || max <= options.max)) {
return;
}
if (to < min && offset > 0 || max < from && offset < 0) {
return {
min: from,
max: to
};
}
var rangeSize = to - from;
if (from < min) {
from = util.limitValue(from, min, max);
to = util.limitValue(from + rangeSize, min + rangeSize, max);
} else if (to > max) {
to = util.limitValue(to, min, max);
from = util.limitValue(to - rangeSize, min, max - rangeSize);
}
return {
min: from,
max: to
};
}
});
var Note = BoxElement.extend({
init: function (value, text, dataItem, category, series, options) {
var note = this;
BoxElement.fn.init.call(note, options);
note.value = value;
note.text = text;
note.dataItem = dataItem;
note.category = category;
note.series = series;
note.render();
},
options: {
icon: {
visible: true,
type: CIRCLE
},
label: {
position: INSIDE,
visible: true,
align: CENTER,
vAlign: CENTER
},
line: { visible: true },
visible: true,
position: TOP,
zIndex: 2
},
hide: function () {
this.options.visible = false;
},
show: function () {
this.options.visible = true;
},
render: function () {
var note = this, options = note.options, label = options.label, text = note.text, icon = options.icon, size = icon.size, box = Box2D(), marker, width, height, noteTemplate;
if (options.visible) {
if (defined(label) && label.visible) {
if (label.template) {
noteTemplate = template(label.template);
text = noteTemplate({
dataItem: note.dataItem,
category: note.category,
value: note.value,
text: text,
series: note.series
});
} else if (label.format) {
text = autoFormat(label.format, text);
}
note.label = new TextBox(text, deepExtend({}, label));
if (label.position === INSIDE && !defined(size)) {
if (icon.type === CIRCLE) {
size = math.max(note.label.box.width(), note.label.box.height());
} else {
width = note.label.box.width();
height = note.label.box.height();
}
box.wrap(note.label.box);
}
}
icon.width = width || size || DEFAULT_ICON_SIZE;
icon.height = height || size || DEFAULT_ICON_SIZE;
marker = new ShapeElement(deepExtend({}, icon));
note.marker = marker;
note.append(marker);
if (note.label) {
note.append(note.label);
}
marker.reflow(Box2D());
note.wrapperBox = box.wrap(marker.box);
}
},
reflow: function (targetBox) {
var note = this, options = note.options, center = targetBox.center(), wrapperBox = note.wrapperBox, length = options.line.length, position = options.position, label = note.label, marker = note.marker, lineStart, box, contentBox;
if (options.visible) {
if (inArray(position, [
LEFT,
RIGHT
])) {
if (position === LEFT) {
contentBox = wrapperBox.alignTo(targetBox, position).translate(-length, targetBox.center().y - wrapperBox.center().y);
if (options.line.visible) {
lineStart = [
targetBox.x1,
center.y
];
note.linePoints = [
lineStart,
[
contentBox.x2,
center.y
]
];
box = contentBox.clone().wrapPoint(lineStart);
}
} else {
contentBox = wrapperBox.alignTo(targetBox, position).translate(length, targetBox.center().y - wrapperBox.center().y);
if (options.line.visible) {
lineStart = [
targetBox.x2,
center.y
];
note.linePoints = [
lineStart,
[
contentBox.x1,
center.y
]
];
box = contentBox.clone().wrapPoint(lineStart);
}
}
} else {
if (position === BOTTOM) {
contentBox = wrapperBox.alignTo(targetBox, position).translate(targetBox.center().x - wrapperBox.center().x, length);
if (options.line.visible) {
lineStart = [
center.x,
targetBox.y2
];
note.linePoints = [
lineStart,
[
center.x,
contentBox.y1
]
];
box = contentBox.clone().wrapPoint(lineStart);
}
} else {
contentBox = wrapperBox.alignTo(targetBox, position).translate(targetBox.center().x - wrapperBox.center().x, -length);
if (options.line.visible) {
lineStart = [
center.x,
targetBox.y1
];
note.linePoints = [
lineStart,
[
center.x,
contentBox.y2
]
];
box = contentBox.clone().wrapPoint(lineStart);
}
}
}
if (marker) {
marker.reflow(contentBox);
}
if (label) {
label.reflow(contentBox);
if (marker) {
if (options.label.position === OUTSIDE) {
label.box.alignTo(marker.box, position);
}
label.reflow(label.box);
}
}
note.contentBox = contentBox;
note.targetBox = targetBox;
note.box = box || contentBox;
}
},
createVisual: function () {
BoxElement.fn.createVisual.call(this);
if (this.options.visible) {
this.createLine();
}
},
renderVisual: function () {
var that = this;
var options = that.options;
var customVisual = options.visual;
if (options.visible && customVisual) {
that.visual = customVisual({
dataItem: that.dataItem,
category: that.category,
value: that.value,
text: that.text,
sender: that.getChart(),
series: that.series,
rect: that.targetBox.toRect(),
options: {
background: options.background,
border: options.background,
icon: options.icon,
label: options.label,
line: options.line,
position: options.position,
visible: options.visible
},
createVisual: function () {
that.createVisual();
that.renderChildren();
var defaultVisual = that.visual;
delete that.visual;
return defaultVisual;
}
});
that.addVisual();
} else {
BoxElement.fn.renderVisual.call(that);
}
},
createLine: function () {
var options = this.options.line;
if (this.linePoints) {
var path = draw.Path.fromPoints(this.linePoints, {
stroke: {
color: options.color,
width: options.width,
dashType: options.dashType
}
});
alignPathToPixel(path);
this.visual.append(path);
}
},
click: function (widget, e) {
var args = this.eventArgs(e);
if (!widget.trigger(NOTE_CLICK, args)) {
e.preventDefault();
}
},
hover: function (widget, e) {
var args = this.eventArgs(e);
if (!widget.trigger(NOTE_HOVER, args)) {
e.preventDefault();
}
},
leave: function (widget) {
widget._unsetActivePoint();
},
eventArgs: function (e) {
var note = this, options = note.options;
return {
element: $(e.target),
text: defined(options.label) ? options.label.text : '',
dataItem: note.dataItem,
series: note.series,
value: note.value,
category: note.category,
visual: note.visual
};
}
});
var ShapeElement = BoxElement.extend({
init: function (options, pointData) {
this.pointData = pointData;
BoxElement.fn.init.call(this, options);
},
options: {
type: CIRCLE,
align: CENTER,
vAlign: CENTER
},
getElement: function () {
var marker = this, options = marker.options, type = options.type, rotation = options.rotation, box = marker.paddingBox, element, center = box.center(), halfWidth = box.width() / 2;
if (!options.visible || !marker.hasBox()) {
return;
}
var style = marker.visualStyle();
if (type === CIRCLE) {
element = new draw.Circle(new geom.Circle([
round(box.x1 + halfWidth, COORD_PRECISION),
round(box.y1 + box.height() / 2, COORD_PRECISION)
], halfWidth), style);
} else if (type === TRIANGLE) {
element = draw.Path.fromPoints([
[
box.x1 + halfWidth,
box.y1
],
[
box.x1,
box.y2
],
[
box.x2,
box.y2
]
], style).close();
} else if (type === CROSS) {
element = new draw.MultiPath(style);
element.moveTo(box.x1, box.y1).lineTo(box.x2, box.y2);
element.moveTo(box.x1, box.y2).lineTo(box.x2, box.y1);
} else {
element = draw.Path.fromRect(box.toRect(), style);
}
if (rotation) {
element.transform(geom.transform().rotate(-rotation, [
center.x,
center.y
]));
}
element.options.zIndex = this.options.zIndex;
return element;
},
createElement: function () {
var that = this;
var customVisual = that.options.visual;
var pointData = that.pointData || {};
var visual;
if (customVisual) {
visual = customVisual({
value: pointData.value,
dataItem: pointData.dataItem,
sender: that.getChart(),
series: pointData.series,
category: pointData.category,
rect: that.paddingBox.toRect(),
options: that.visualOptions(),
createVisual: function () {
return that.getElement();
}
});
} else {
visual = that.getElement();
}
return visual;
},
visualOptions: function () {
var options = this.options;
return {
background: options.background,
border: options.border,
margin: options.margin,
padding: options.padding,
type: options.type,
size: options.width,
visible: options.visible
};
},
createVisual: function () {
this.visual = this.createElement();
}
});
var NumericAxis = Axis.extend({
init: function (seriesMin, seriesMax, options) {
var axis = this, defaultOptions = axis.initDefaults(seriesMin, seriesMax, options);
Axis.fn.init.call(axis, defaultOptions);
},
startValue: function () {
return 0;
},
options: {
type: 'numeric',
min: 0,
max: 1,
vertical: true,
majorGridLines: {
visible: true,
width: 1,
color: BLACK
},
labels: { format: '#.####################' },
zIndex: 1
},
initDefaults: function (seriesMin, seriesMax, options) {
var axis = this, narrowRange = options.narrowRange, autoMin = axis.autoAxisMin(seriesMin, seriesMax, narrowRange), autoMax = axis.autoAxisMax(seriesMin, seriesMax, narrowRange), majorUnit = autoMajorUnit(autoMin, autoMax), autoOptions = { majorUnit: majorUnit }, userSetLimits;
if (options.roundToMajorUnit !== false) {
if (autoMin < 0 && remainderClose(autoMin, majorUnit, 1 / 3)) {
autoMin -= majorUnit;
}
if (autoMax > 0 && remainderClose(autoMax, majorUnit, 1 / 3)) {
autoMax += majorUnit;
}
}
autoOptions.min = floor(autoMin, majorUnit);
autoOptions.max = ceil(autoMax, majorUnit);
this.totalMin = defined(options.min) ? math.min(autoOptions.min, options.min) : autoOptions.min;
this.totalMax = defined(options.max) ? math.max(autoOptions.max, options.max) : autoOptions.max;
this.totalMajorUnit = majorUnit;
if (options) {
userSetLimits = defined(options.min) || defined(options.max);
if (userSetLimits) {
if (options.min === options.max) {
if (options.min > 0) {
options.min = 0;
} else {
options.max = 1;
}
}
}
if (options.majorUnit) {
autoOptions.min = floor(autoOptions.min, options.majorUnit);
autoOptions.max = ceil(autoOptions.max, options.majorUnit);
} else if (userSetLimits) {
options = deepExtend(autoOptions, options);
autoOptions.majorUnit = autoMajorUnit(options.min, options.max);
}
}
autoOptions.minorUnit = (options.majorUnit || autoOptions.majorUnit) / 5;
return deepExtend(autoOptions, options);
},
range: function () {
var options = this.options;
return {
min: options.min,
max: options.max
};
},
autoAxisMax: function (min, max, narrow) {
var axisMax, diff;
if (!min && !max) {
return 1;
}
if (min <= 0 && max <= 0) {
max = min == max ? 0 : max;
diff = math.abs((max - min) / max);
if (narrow === false || !narrow && diff > ZERO_THRESHOLD) {
return 0;
}
axisMax = math.min(0, max - (min - max) / 2);
} else {
min = min == max ? 0 : min;
axisMax = max;
}
return axisMax;
},
autoAxisMin: function (min, max, narrow) {
var axisMin, diff;
if (!min && !max) {
return 0;
}
if (min >= 0 && max >= 0) {
min = min == max ? 0 : min;
diff = (max - min) / max;
if (narrow === false || !narrow && diff > ZERO_THRESHOLD) {
return 0;
}
axisMin = math.max(0, min - (max - min) / 2);
} else {
max = min == max ? 0 : max;
axisMin = min;
}
return axisMin;
},
getDivisions: function (stepValue) {
if (stepValue === 0) {
return 1;
}
var options = this.options, range = options.max - options.min;
return math.floor(round(range / stepValue, COORD_PRECISION)) + 1;
},
getTickPositions: function (unit, skipUnit) {
var axis = this, options = axis.options, vertical = options.vertical, reverse = options.reverse, lineBox = axis.lineBox(), lineSize = vertical ? lineBox.height() : lineBox.width(), range = options.max - options.min, scale = lineSize / range, step = unit * scale, skipStep = 0, divisions = axis.getDivisions(unit), dir = (vertical ? -1 : 1) * (reverse ? -1 : 1), startEdge = dir === 1 ? 1 : 2, pos = lineBox[(vertical ? Y : X) + startEdge], positions = [], i;
if (skipUnit) {
skipStep = skipUnit / unit;
}
for (i = 0; i < divisions; i++) {
if (i % skipStep !== 0) {
positions.push(round(pos, COORD_PRECISION));
}
pos = pos + step * dir;
}
return positions;
},
getMajorTickPositions: function () {
var axis = this;
return axis.getTickPositions(axis.options.majorUnit);
},
getMinorTickPositions: function () {
var axis = this;
return axis.getTickPositions(axis.options.minorUnit);
},
getSlot: function (a, b, limit) {
var axis = this, options = axis.options, reverse = options.reverse, vertical = options.vertical, valueAxis = vertical ? Y : X, lineBox = axis.lineBox(), lineStart = lineBox[valueAxis + (reverse ? 2 : 1)], lineSize = vertical ? lineBox.height() : lineBox.width(), dir = reverse ? -1 : 1, step = dir * (lineSize / (options.max - options.min)), p1, p2, slotBox = new Box2D(lineBox.x1, lineBox.y1, lineBox.x1, lineBox.y1);
if (!defined(a)) {
a = b || 0;
}
if (!defined(b)) {
b = a || 0;
}
if (limit) {
a = math.max(math.min(a, options.max), options.min);
b = math.max(math.min(b, options.max), options.min);
}
if (vertical) {
p1 = options.max - math.max(a, b);
p2 = options.max - math.min(a, b);
} else {
p1 = math.min(a, b) - options.min;
p2 = math.max(a, b) - options.min;
}
slotBox[valueAxis + 1] = math.max(math.min(lineStart + step * (reverse ? p2 : p1), COORDINATE_LIMIT), -COORDINATE_LIMIT);
slotBox[valueAxis + 2] = math.max(math.min(lineStart + step * (reverse ? p1 : p2), COORDINATE_LIMIT), -COORDINATE_LIMIT);
return slotBox;
},
getValue: function (point) {
var axis = this, options = axis.options, reverse = options.reverse, vertical = options.vertical, max = options.max * 1, min = options.min * 1, valueAxis = vertical ? Y : X, lineBox = axis.lineBox(), lineStart = lineBox[valueAxis + (reverse ? 2 : 1)], lineSize = vertical ? lineBox.height() : lineBox.width(), dir = reverse ? -1 : 1, offset = dir * (point[valueAxis] - lineStart), step = (max - min) / lineSize, valueOffset = offset * step, value;
if (offset < 0 || offset > lineSize) {
return null;
}
value = vertical ? max - valueOffset : min + valueOffset;
return round(value, DEFAULT_PRECISION);
},
translateRange: function (delta) {
var axis = this, options = axis.options, lineBox = axis.lineBox(), vertical = options.vertical, reverse = options.reverse, size = vertical ? lineBox.height() : lineBox.width(), range = options.max - options.min, scale = size / range, offset = round(delta / scale, DEFAULT_PRECISION);
if ((vertical || reverse) && !(vertical && reverse)) {
offset = -offset;
}
return {
min: options.min + offset,
max: options.max + offset
};
},
scaleRange: function (delta) {
var axis = this, options = axis.options, offset = -delta * options.majorUnit;
return {
min: options.min - offset,
max: options.max + offset
};
},
labelsCount: function () {
return this.getDivisions(this.options.majorUnit);
},
createAxisLabel: function (index, labelOptions) {
var axis = this, options = axis.options, value = round(options.min + index * options.majorUnit, DEFAULT_PRECISION), text = axis.axisLabelText(value, null, labelOptions);
return new AxisLabel(value, text, index, null, labelOptions);
},
shouldRenderNote: function (value) {
var range = this.range();
return range.min <= value && value <= range.max;
},
pan: function (delta) {
var range = this.translateRange(delta);
return this.limitRange(range.min, range.max, this.totalMin, this.totalMax);
},
pointsRange: function (start, end) {
var startValue = this.getValue(start);
var endValue = this.getValue(end);
var min = math.min(startValue, endValue);
var max = math.max(startValue, endValue);
return {
min: min,
max: max
};
},
zoomRange: function (delta) {
var newRange = this.scaleRange(delta);
var totalMax = this.totalMax;
var totalMin = this.totalMin;
var min = util.limitValue(newRange.min, totalMin, totalMax);
var max = util.limitValue(newRange.max, totalMin, totalMax);
var optionsRange = this.options.max - this.options.min;
if (optionsRange < this.totalMajorUnit || max - min >= this.totalMajorUnit) {
return {
min: min,
max: max
};
}
}
});
var LogarithmicAxis = Axis.extend({
init: function (seriesMin, seriesMax, options) {
this.options = this._initOptions(seriesMin, seriesMax, options);
Axis.fn.init.call(this, options);
},
startValue: function () {
return this.options.min;
},
options: {
type: 'log',
majorUnit: 10,
minorUnit: 1,
axisCrossingValue: 1,
vertical: true,
majorGridLines: {
visible: true,
width: 1,
color: BLACK
},
zIndex: 1
},
getSlot: function (a, b, limit) {
var axis = this, options = axis.options, reverse = options.reverse, vertical = options.vertical, valueAxis = vertical ? Y : X, lineBox = axis.lineBox(), lineStart = lineBox[valueAxis + (reverse ? 2 : 1)], lineSize = vertical ? lineBox.height() : lineBox.width(), dir = reverse ? -1 : 1, base = options.majorUnit, logMin = axis.logMin, logMax = axis.logMax, step = dir * (lineSize / (logMax - logMin)), p1, p2, slotBox = new Box2D(lineBox.x1, lineBox.y1, lineBox.x1, lineBox.y1);
if (!defined(a)) {
a = b || 1;
}
if (!defined(b)) {
b = a || 1;
}
if (a <= 0 || b <= 0) {
return;
}
if (limit) {
a = math.max(math.min(a, options.max), options.min);
b = math.max(math.min(b, options.max), options.min);
}
a = log(a, base);
b = log(b, base);
if (vertical) {
p1 = logMax - math.max(a, b);
p2 = logMax - math.min(a, b);
} else {
p1 = math.min(a, b) - logMin;
p2 = math.max(a, b) - logMin;
}
slotBox[valueAxis + 1] = lineStart + step * (reverse ? p2 : p1);
slotBox[valueAxis + 2] = lineStart + step * (reverse ? p1 : p2);
return slotBox;
},
getValue: function (point) {
var axis = this, options = axis.options, reverse = options.reverse, vertical = options.vertical, lineBox = axis.lineBox(), base = options.majorUnit, logMin = axis.logMin, logMax = axis.logMax, dir = vertical === reverse ? 1 : -1, startEdge = dir === 1 ? 1 : 2, lineSize = vertical ? lineBox.height() : lineBox.width(), step = (logMax - logMin) / lineSize, valueAxis = vertical ? Y : X, lineStart = lineBox[valueAxis + startEdge], offset = dir * (point[valueAxis] - lineStart), valueOffset = offset * step, value;
if (offset < 0 || offset > lineSize) {
return null;
}
value = logMin + valueOffset;
return round(math.pow(base, value), DEFAULT_PRECISION);
},
range: function () {
var options = this.options;
return {
min: options.min,
max: options.max
};
},
scaleRange: function (delta) {
var axis = this, options = axis.options, base = options.majorUnit, offset = -delta;
return {
min: math.pow(base, axis.logMin - offset),
max: math.pow(base, axis.logMax + offset)
};
},
translateRange: function (delta) {
var axis = this, options = axis.options, base = options.majorUnit, lineBox = axis.lineBox(), vertical = options.vertical, reverse = options.reverse, size = vertical ? lineBox.height() : lineBox.width(), scale = size / (axis.logMax - axis.logMin), offset = round(delta / scale, DEFAULT_PRECISION);
if ((vertical || reverse) && !(vertical && reverse)) {
offset = -offset;
}
return {
min: math.pow(base, axis.logMin + offset),
max: math.pow(base, axis.logMax + offset)
};
},
labelsCount: function () {
var axis = this, floorMax = math.floor(axis.logMax), count = math.floor(floorMax - axis.logMin) + 1;
return count;
},
getMajorTickPositions: function () {
var axis = this, ticks = [];
axis.traverseMajorTicksPositions(function (position) {
ticks.push(position);
}, {
step: 1,
skip: 0
});
return ticks;
},
createTicks: function (lineGroup) {
var axis = this, ticks = [], options = axis.options, lineBox = axis.lineBox(), mirror = options.labels.mirror, majorTicks = options.majorTicks, minorTicks = options.minorTicks, tickLineOptions = { vertical: options.vertical };
function render(tickPosition, tickOptions) {
tickLineOptions.tickX = mirror ? lineBox.x2 : lineBox.x2 - tickOptions.size;
tickLineOptions.tickY = mirror ? lineBox.y1 - tickOptions.size : lineBox.y1;
tickLineOptions.position = tickPosition;
lineGroup.append(createAxisTick(tickLineOptions, tickOptions));
}
if (majorTicks.visible) {
axis.traverseMajorTicksPositions(render, majorTicks);
}
if (minorTicks.visible) {
axis.traverseMinorTicksPositions(render, minorTicks);
}
return ticks;
},
createGridLines: function (altAxis) {
var axis = this, options = axis.options, majorGridLines = options.majorGridLines, minorGridLines = options.minorGridLines, vertical = options.vertical, lineBox = altAxis.lineBox(), lineOptions = {
lineStart: lineBox[vertical ? 'x1' : 'y1'],
lineEnd: lineBox[vertical ? 'x2' : 'y2'],
vertical: vertical
}, majorTicks = [];
var container = this.gridLinesVisual();
function render(tickPosition, gridLine) {
if (!inArray(tickPosition, majorTicks)) {
lineOptions.position = tickPosition;
container.append(createAxisGridLine(lineOptions, gridLine));
majorTicks.push(tickPosition);
}
}
if (majorGridLines.visible) {
axis.traverseMajorTicksPositions(render, majorGridLines);
}
if (minorGridLines.visible) {
axis.traverseMinorTicksPositions(render, minorGridLines);
}
return container.children;
},
traverseMajorTicksPositions: function (callback, tickOptions) {
var axis = this, lineOptions = axis._lineOptions(), lineStart = lineOptions.lineStart, step = lineOptions.step, logMin = axis.logMin, logMax = axis.logMax, power, position;
for (power = math.ceil(logMin) + tickOptions.skip; power <= logMax; power += tickOptions.step) {
position = round(lineStart + step * (power - logMin), DEFAULT_PRECISION);
callback(position, tickOptions);
}
},
traverseMinorTicksPositions: function (callback, tickOptions) {
var axis = this, options = axis.options, lineOptions = axis._lineOptions(), lineStart = lineOptions.lineStart, lineStep = lineOptions.step, base = options.majorUnit, logMin = axis.logMin, logMax = axis.logMax, start = math.floor(logMin), max = options.max, min = options.min, minorUnit = options.minorUnit, power, value, position, minorOptions;
for (power = start; power < logMax; power++) {
minorOptions = axis._minorIntervalOptions(power);
for (var idx = tickOptions.skip; idx < minorUnit; idx += tickOptions.step) {
value = minorOptions.value + idx * minorOptions.minorStep;
if (value > max) {
break;
}
if (value >= min) {
position = round(lineStart + lineStep * (log(value, base) - logMin), DEFAULT_PRECISION);
callback(position, tickOptions);
}
}
}
},
createAxisLabel: function (index, labelOptions) {
var axis = this, options = axis.options, power = math.ceil(axis.logMin + index), value = Math.pow(options.majorUnit, power), text = axis.axisLabelText(value, null, labelOptions);
return new AxisLabel(value, text, index, null, labelOptions);
},
shouldRenderNote: function (value) {
var range = this.range();
return range.min <= value && value <= range.max;
},
_throwNegativeValuesError: function () {
throw new Error('Non positive values cannot be used for a logarithmic axis');
},
_initOptions: function (seriesMin, seriesMax, options) {
var axis = this, axisOptions = deepExtend({}, axis.options, {
min: seriesMin,
max: seriesMax
}, options), min = axisOptions.min, max = axisOptions.max, base = axisOptions.majorUnit, autoMax = this._autoMax(seriesMax, base), autoMin = this._autoMin(seriesMin, seriesMax, axisOptions);
if (axisOptions.axisCrossingValue <= 0) {
axis._throwNegativeValuesError();
}
if (!defined(options.max)) {
max = autoMax;
} else if (options.max <= 0) {
axis._throwNegativeValuesError();
}
if (!defined(options.min)) {
min = autoMin;
} else if (options.min <= 0) {
axis._throwNegativeValuesError();
}
this.totalMin = defined(options.min) ? math.min(autoMin, options.min) : autoMin;
this.totalMax = defined(options.max) ? math.max(autoMax, options.max) : autoMax;
axis.logMin = round(log(min, base), DEFAULT_PRECISION);
axis.logMax = round(log(max, base), DEFAULT_PRECISION);
axisOptions.max = max;
axisOptions.min = min;
axisOptions.minorUnit = options.minorUnit || round(base - 1, DEFAULT_PRECISION);
return axisOptions;
},
_autoMin: function (min, max, options) {
var autoMin = min;
var base = options.majorUnit;
if (min <= 0) {
autoMin = max <= 1 ? math.pow(base, -2) : 1;
} else if (!options.narrowRange) {
autoMin = math.pow(base, math.floor(log(min, base)));
}
return autoMin;
},
_autoMax: function (max, base) {
var logMaxRemainder = round(log(max, base), DEFAULT_PRECISION) % 1;
var autoMax;
if (max <= 0) {
autoMax = base;
} else if (logMaxRemainder !== 0 && (logMaxRemainder < 0.3 || logMaxRemainder > 0.9)) {
autoMax = math.pow(base, log(max, base) + 0.2);
} else {
autoMax = math.pow(base, math.ceil(log(max, base)));
}
return autoMax;
},
pan: function (delta) {
var range = this.translateRange(delta);
return this.limitRange(range.min, range.max, this.totalMin, this.totalMax, -delta);
},
pointsRange: function (start, end) {
var startValue = this.getValue(start);
var endValue = this.getValue(end);
var min = math.min(startValue, endValue);
var max = math.max(startValue, endValue);
return {
min: min,
max: max
};
},
zoomRange: function (delta) {
var options = this.options;
var newRange = this.scaleRange(delta);
var totalMax = this.totalMax;
var totalMin = this.totalMin;
var min = util.limitValue(newRange.min, totalMin, totalMax);
var max = util.limitValue(newRange.max, totalMin, totalMax);
var base = options.majorUnit;
var acceptOptionsRange = max > min && options.min && options.max && round(log(options.max, base) - log(options.min, base), DEFAULT_PRECISION) < 1;
var acceptNewRange = !(options.min === totalMin && options.max === totalMax) && round(log(max, base) - log(min, base), DEFAULT_PRECISION) >= 1;
if (acceptOptionsRange || acceptNewRange) {
return {
min: min,
max: max
};
}
},
_minorIntervalOptions: function (power) {
var base = this.options.majorUnit, value = math.pow(base, power), nextValue = math.pow(base, power + 1), difference = nextValue - value, minorStep = difference / this.options.minorUnit;
return {
value: value,
minorStep: minorStep
};
},
_lineOptions: function () {
var axis = this, options = axis.options, reverse = options.reverse, vertical = options.vertical, valueAxis = vertical ? Y : X, lineBox = axis.lineBox(), dir = vertical === reverse ? 1 : -1, startEdge = dir === 1 ? 1 : 2, lineSize = vertical ? lineBox.height() : lineBox.width(), step = dir * (lineSize / (axis.logMax - axis.logMin)), lineStart = lineBox[valueAxis + startEdge];
return {
step: step,
lineStart: lineStart,
lineBox: lineBox
};
}
});
dataviz.Gradients = {
glass: {
type: LINEAR,
rotation: 0,
stops: [
{
offset: 0,
color: WHITE,
opacity: 0
},
{
offset: 0.25,
color: WHITE,
opacity: 0.3
},
{
offset: 1,
color: WHITE,
opacity: 0
}
]
},
sharpBevel: {
type: RADIAL,
stops: [
{
offset: 0,
color: WHITE,
opacity: 0.55
},
{
offset: 0.65,
color: WHITE,
opacity: 0
},
{
offset: 0.95,
color: WHITE,
opacity: 0.25
}
]
},
roundedBevel: {
type: RADIAL,
stops: [
{
offset: 0.33,
color: WHITE,
opacity: 0.06
},
{
offset: 0.83,
color: WHITE,
opacity: 0.2
},
{
offset: 0.95,
color: WHITE,
opacity: 0
}
]
},
roundedGlass: {
type: RADIAL,
supportVML: false,
stops: [
{
offset: 0,
color: WHITE,
opacity: 0
},
{
offset: 0.5,
color: WHITE,
opacity: 0.3
},
{
offset: 0.99,
color: WHITE,
opacity: 0
}
]
},
sharpGlass: {
type: RADIAL,
supportVML: false,
stops: [
{
offset: 0,
color: WHITE,
opacity: 0.2
},
{
offset: 0.15,
color: WHITE,
opacity: 0.15
},
{
offset: 0.17,
color: WHITE,
opacity: 0.35
},
{
offset: 0.85,
color: WHITE,
opacity: 0.05
},
{
offset: 0.87,
color: WHITE,
opacity: 0.15
},
{
offset: 0.99,
color: WHITE,
opacity: 0
}
]
}
};
var ExportMixin = {
extend: function (proto, skipLegacy) {
if (!proto.exportVisual) {
throw new Error('Mixin target has no exportVisual method defined.');
}
proto.exportSVG = this.exportSVG;
proto.exportImage = this.exportImage;
proto.exportPDF = this.exportPDF;
if (!skipLegacy) {
proto.svg = this.svg;
proto.imageDataURL = this.imageDataURL;
}
},
exportSVG: function (options) {
return draw.exportSVG(this.exportVisual(), options);
},
exportImage: function (options) {
return draw.exportImage(this.exportVisual(options), options);
},
exportPDF: function (options) {
return draw.exportPDF(this.exportVisual(), options);
},
svg: function () {
if (draw.svg.Surface) {
return draw.svg._exportGroup(this.exportVisual());
} else {
throw new Error('SVG Export failed. Unable to export instantiate kendo.drawing.svg.Surface');
}
},
imageDataURL: function () {
if (!kendo.support.canvas) {
return null;
}
if (draw.canvas.Surface) {
var container = $('<div />').css({
display: 'none',
width: this.element.width(),
height: this.element.height()
}).appendTo(document.body);
var surface = new draw.canvas.Surface(container);
surface.draw(this.exportVisual());
var image = surface._rootElement.toDataURL();
surface.destroy();
container.remove();
return image;
} else {
throw new Error('Image Export failed. Unable to export instantiate kendo.drawing.canvas.Surface');
}
}
};
function autoMajorUnit(min, max) {
var diff = round(max - min, DEFAULT_PRECISION - 1);
if (diff === 0) {
if (max === 0) {
return 0.1;
}
diff = math.abs(max);
}
var scale = math.pow(10, math.floor(math.log(diff) / math.log(10))), relativeValue = round(diff / scale, DEFAULT_PRECISION), scaleMultiplier = 1;
if (relativeValue < 1.904762) {
scaleMultiplier = 0.2;
} else if (relativeValue < 4.761904) {
scaleMultiplier = 0.5;
} else if (relativeValue < 9.523809) {
scaleMultiplier = 1;
} else {
scaleMultiplier = 2;
}
return round(scale * scaleMultiplier, DEFAULT_PRECISION);
}
function rotatePoint(x, y, cx, cy, angle) {
var theta = angle * DEG_TO_RAD;
return new Point2D(cx + (x - cx) * math.cos(theta) + (y - cy) * math.sin(theta), cy - (x - cx) * math.sin(theta) + (y - cy) * math.cos(theta));
}
function boxDiff(r, s) {
if (r.x1 == s.x1 && r.y1 == s.y1 && r.x2 == s.x2 && r.y2 == s.y2) {
return s;
}
var a = math.min(r.x1, s.x1), b = math.max(r.x1, s.x1), c = math.min(r.x2, s.x2), d = math.max(r.x2, s.x2), e = math.min(r.y1, s.y1), f = math.max(r.y1, s.y1), g = math.min(r.y2, s.y2), h = math.max(r.y2, s.y2), result = [];
result[0] = Box2D(b, e, c, f);
result[1] = Box2D(a, f, b, g);
result[2] = Box2D(c, f, d, g);
result[3] = Box2D(b, g, c, h);
if (r.x1 == a && r.y1 == e || s.x1 == a && s.y1 == e) {
result[4] = Box2D(a, e, b, f);
result[5] = Box2D(c, g, d, h);
} else {
result[4] = Box2D(c, e, d, f);
result[5] = Box2D(a, g, b, h);
}
return $.grep(result, function (box) {
return box.height() > 0 && box.width() > 0;
})[0];
}
function inArray(value, array) {
return indexOf(value, array) != -1;
}
function ceil(value, step) {
return round(math.ceil(value / step) * step, DEFAULT_PRECISION);
}
function floor(value, step) {
return round(math.floor(value / step) * step, DEFAULT_PRECISION);
}
function round(value, precision) {
var power = math.pow(10, precision || 0);
return math.round(value * power) / power;
}
function log(y, x) {
return math.log(y) / math.log(x);
}
function remainderClose(value, divisor, ratio) {
var remainder = round(math.abs(value % divisor), DEFAULT_PRECISION), threshold = divisor * (1 - ratio);
return remainder === 0 || remainder > threshold;
}
function interpolateValue(start, end, progress) {
return round(start + (end - start) * progress, COORD_PRECISION);
}
function numericComparer(a, b) {
return a - b;
}
function autoFormat(format, value) {
if (format.match(FORMAT_REGEX)) {
return kendo.format.apply(this, arguments);
}
return kendo.toString(value, format);
}
function clockwise(v1, v2) {
return -v1.x * v2.y + v1.y * v2.x < 0;
}
function dateComparer(a, b) {
if (a && b) {
return a.getTime() - b.getTime();
}
return -1;
}
var CurveProcessor = function (closed) {
this.closed = closed;
};
CurveProcessor.prototype = CurveProcessor.fn = {
WEIGHT: 0.333,
EXTREMUM_ALLOWED_DEVIATION: 0.01,
process: function (dataPoints) {
var that = this, closed = that.closed, points = dataPoints.slice(0), length = points.length, segments = [], p0, p1, p2, controlPoints, initialControlPoint, lastControlPoint, tangent;
if (length > 2) {
that.removeDuplicates(0, points);
length = points.length;
}
if (length < 2 || length == 2 && points[0].equals(points[1])) {
return segments;
}
p0 = points[0];
p1 = points[1];
p2 = points[2];
segments.push(new draw.Segment(p0));
while (p0.equals(points[length - 1])) {
closed = true;
points.pop();
length--;
}
if (length == 2) {
tangent = that.tangent(p0, p1, X, Y);
last(segments).controlOut(that.firstControlPoint(tangent, p0, p1, X, Y));
segments.push(new draw.Segment(p1, that.secondControlPoint(tangent, p0, p1, X, Y)));
return segments;
}
if (closed) {
p0 = points[length - 1];
p1 = points[0];
p2 = points[1];
controlPoints = that.controlPoints(p0, p1, p2);
initialControlPoint = controlPoints[1];
lastControlPoint = controlPoints[0];
} else {
tangent = that.tangent(p0, p1, X, Y);
initialControlPoint = that.firstControlPoint(tangent, p0, p1, X, Y);
}
var cp0 = initialControlPoint;
for (var idx = 0; idx <= length - 3; idx++) {
that.removeDuplicates(idx, points);
length = points.length;
if (idx + 3 <= length) {
p0 = points[idx];
p1 = points[idx + 1];
p2 = points[idx + 2];
controlPoints = that.controlPoints(p0, p1, p2);
last(segments).controlOut(cp0);
cp0 = controlPoints[1];
var cp1 = controlPoints[0];
segments.push(new draw.Segment(p1, cp1));
}
}
if (closed) {
p0 = points[length - 2];
p1 = points[length - 1];
p2 = points[0];
controlPoints = that.controlPoints(p0, p1, p2);
last(segments).controlOut(cp0);
segments.push(new draw.Segment(p1, controlPoints[0]));
last(segments).controlOut(controlPoints[1]);
segments.push(new draw.Segment(p2, lastControlPoint));
} else {
tangent = that.tangent(p1, p2, X, Y);
last(segments).controlOut(cp0);
segments.push(new draw.Segment(p2, that.secondControlPoint(tangent, p1, p2, X, Y)));
}
return segments;
},
removeDuplicates: function (idx, points) {
while (points[idx].equals(points[idx + 1]) || points[idx + 1].equals(points[idx + 2])) {
points.splice(idx + 1, 1);
}
},
invertAxis: function (p0, p1, p2) {
var that = this, fn, y2, invertAxis = false;
if (p0.x === p1.x) {
invertAxis = true;
} else if (p1.x === p2.x) {
if (p1.y < p2.y && p0.y <= p1.y || p2.y < p1.y && p1.y <= p0.y) {
invertAxis = true;
}
} else {
fn = that.lineFunction(p0, p1);
y2 = that.calculateFunction(fn, p2.x);
if (!(p0.y <= p1.y && p2.y <= y2) && !(p1.y <= p0.y && p2.y >= y2)) {
invertAxis = true;
}
}
return invertAxis;
},
isLine: function (p0, p1, p2) {
var that = this, fn = that.lineFunction(p0, p1), y2 = that.calculateFunction(fn, p2.x);
return p0.x == p1.x && p1.x == p2.x || round(y2, 1) === round(p2.y, 1);
},
lineFunction: function (p1, p2) {
var a = (p2.y - p1.y) / (p2.x - p1.x), b = p1.y - a * p1.x;
return [
b,
a
];
},
controlPoints: function (p0, p1, p2) {
var that = this, xField = X, yField = Y, restrict = false, switchOrientation = false, tangent, monotonic, firstControlPoint, secondControlPoint, allowedDeviation = that.EXTREMUM_ALLOWED_DEVIATION;
if (that.isLine(p0, p1, p2)) {
tangent = that.tangent(p0, p1, X, Y);
} else {
monotonic = {
x: that.isMonotonicByField(p0, p1, p2, X),
y: that.isMonotonicByField(p0, p1, p2, Y)
};
if (monotonic.x && monotonic.y) {
tangent = that.tangent(p0, p2, X, Y);
restrict = true;
} else {
if (that.invertAxis(p0, p1, p2)) {
xField = Y;
yField = X;
}
if (monotonic[xField]) {
tangent = 0;
} else {
var sign;
if (p2[yField] < p0[yField] && p0[yField] <= p1[yField] || p0[yField] < p2[yField] && p1[yField] <= p0[yField]) {
sign = that.sign((p2[yField] - p0[yField]) * (p1[xField] - p0[xField]));
} else {
sign = -that.sign((p2[xField] - p0[xField]) * (p1[yField] - p0[yField]));
}
tangent = allowedDeviation * sign;
switchOrientation = true;
}
}
}
secondControlPoint = that.secondControlPoint(tangent, p0, p1, xField, yField);
if (switchOrientation) {
var oldXField = xField;
xField = yField;
yField = oldXField;
}
firstControlPoint = that.firstControlPoint(tangent, p1, p2, xField, yField);
if (restrict) {
that.restrictControlPoint(p0, p1, secondControlPoint, tangent);
that.restrictControlPoint(p1, p2, firstControlPoint, tangent);
}
return [
secondControlPoint,
firstControlPoint
];
},
sign: function (x) {
return x <= 0 ? -1 : 1;
},
restrictControlPoint: function (p1, p2, cp, tangent) {
if (p1.y < p2.y) {
if (p2.y < cp.y) {
cp.x = p1.x + (p2.y - p1.y) / tangent;
cp.y = p2.y;
} else if (cp.y < p1.y) {
cp.x = p2.x - (p2.y - p1.y) / tangent;
cp.y = p1.y;
}
} else {
if (cp.y < p2.y) {
cp.x = p1.x - (p1.y - p2.y) / tangent;
cp.y = p2.y;
} else if (p1.y < cp.y) {
cp.x = p2.x + (p1.y - p2.y) / tangent;
cp.y = p1.y;
}
}
},
tangent: function (p0, p1, xField, yField) {
var tangent, x = p1[xField] - p0[xField], y = p1[yField] - p0[yField];
if (x === 0) {
tangent = 0;
} else {
tangent = y / x;
}
return tangent;
},
isMonotonicByField: function (p0, p1, p2, field) {
return p2[field] > p1[field] && p1[field] > p0[field] || p2[field] < p1[field] && p1[field] < p0[field];
},
firstControlPoint: function (tangent, p0, p3, xField, yField) {
var that = this, t1 = p0[xField], t2 = p3[xField], distance = (t2 - t1) * that.WEIGHT;
return that.point(t1 + distance, p0[yField] + distance * tangent, xField, yField);
},
secondControlPoint: function (tangent, p0, p3, xField, yField) {
var that = this, t1 = p0[xField], t2 = p3[xField], distance = (t2 - t1) * that.WEIGHT;
return that.point(t2 - distance, p3[yField] - distance * tangent, xField, yField);
},
point: function (xValue, yValue, xField, yField) {
var controlPoint = new geom.Point();
controlPoint[xField] = xValue;
controlPoint[yField] = yValue;
return controlPoint;
},
calculateFunction: function (fn, x) {
var result = 0, length = fn.length;
for (var i = 0; i < length; i++) {
result += Math.pow(x, i) * fn[i];
}
return result;
}
};
function mwDelta(e) {
var origEvent = e.originalEvent, delta = 0;
if (origEvent.wheelDelta) {
delta = -origEvent.wheelDelta / 120;
delta = delta > 0 ? math.ceil(delta) : math.floor(delta);
}
if (origEvent.detail) {
delta = round(origEvent.detail / 3);
}
return delta;
}
function decodeEntities(text) {
if (!text || !text.indexOf || text.indexOf('&') < 0) {
return text;
} else {
var element = decodeEntities._element;
element.innerHTML = text;
return element.textContent || element.innerText;
}
}
function alignPathToPixel(path) {
if (!kendo.support.vml) {
var offset = 0.5;
if (path.options.stroke && defined(path.options.stroke.width)) {
if (path.options.stroke.width % 2 === 0) {
offset = 0;
}
}
for (var i = 0; i < path.segments.length; i++) {
path.segments[i].anchor().round(0).translate(offset, offset);
}
}
return path;
}
function innerRadialStops(options) {
var stops = options.stops, usedSpace = options.innerRadius / options.radius * 100, i, length = stops.length, currentStop, currentStops = [];
for (i = 0; i < length; i++) {
currentStop = deepExtend({}, stops[i]);
currentStop.offset = (currentStop.offset * (100 - usedSpace) + usedSpace) / 100;
currentStops.push(currentStop);
}
return currentStops;
}
function rectToBox(rect) {
var origin = rect.origin;
var bottomRight = rect.bottomRight();
return new Box2D(origin.x, origin.y, bottomRight.x, bottomRight.y);
}
decodeEntities._element = document.createElement('span');
deepExtend(kendo.dataviz, {
AXIS_LABEL_CLICK: AXIS_LABEL_CLICK,
COORD_PRECISION: COORD_PRECISION,
DEFAULT_PRECISION: DEFAULT_PRECISION,
DEFAULT_WIDTH: DEFAULT_WIDTH,
DEFAULT_HEIGHT: DEFAULT_HEIGHT,
DEFAULT_FONT: DEFAULT_FONT,
INITIAL_ANIMATION_DURATION: INITIAL_ANIMATION_DURATION,
NOTE_CLICK: NOTE_CLICK,
NOTE_HOVER: NOTE_HOVER,
CLIP: CLIP,
Axis: Axis,
AxisLabel: AxisLabel,
Box2D: Box2D,
BoxElement: BoxElement,
ChartElement: ChartElement,
CurveProcessor: CurveProcessor,
ExportMixin: ExportMixin,
FloatElement: FloatElement,
LogarithmicAxis: LogarithmicAxis,
Note: Note,
NumericAxis: NumericAxis,
Point2D: Point2D,
Ring: Ring,
RootElement: RootElement,
Sector: Sector,
ShapeBuilder: ShapeBuilder,
ShapeElement: ShapeElement,
Text: Text,
TextBox: TextBox,
Title: Title,
alignPathToPixel: alignPathToPixel,
autoFormat: autoFormat,
autoMajorUnit: autoMajorUnit,
boxDiff: boxDiff,
dateComparer: dateComparer,
decodeEntities: decodeEntities,
getSpacing: getSpacing,
inArray: inArray,
interpolateValue: interpolateValue,
mwDelta: mwDelta,
rectToBox: rectToBox,
rotatePoint: rotatePoint,
round: round,
ceil: ceil,
floor: floor
});
}(window.kendo.jQuery));
return window.kendo;
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
(a3 || a2)();
}));