@progress/kendo-ui
Version:
This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.
10,170 lines • 309 kB
JavaScript
module.exports =
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ({
/***/ 0:
/***/ (function(module, exports, __webpack_require__) {
__webpack_require__(921);
module.exports = __webpack_require__(921);
/***/ }),
/***/ 3:
/***/ (function(module, exports) {
module.exports = function() { throw new Error("define cannot be used indirect"); };
/***/ }),
/***/ 921:
/***/ (function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/***********************************************************************
* WARNING: this file is auto-generated. If you change it directly,
* your modifications will eventually be lost. The source code is in
* `kendo-drawing` repository, you should make your changes there and
* run `src-modules/sync.sh` in this repository.
*/
(function(f, define){
!(__WEBPACK_AMD_DEFINE_ARRAY__ = [ __webpack_require__(922), __webpack_require__(923), __webpack_require__(924) ], __WEBPACK_AMD_DEFINE_FACTORY__ = (f), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
})(function(){
(function ($) {
/* jshint eqnull:true */
/* jshint -W069 */
/* jshint latedef: nofunc */
window.kendo = window.kendo || {};
var kendoDrawing = kendo.drawing;
var kendoDrawingUtil = kendoDrawing.util;
var Class = kendo.Class;
var kendoUtil = kendo.util;
var support = kendo.support;
var supportBrowser = support.browser;
var createPromise = kendoDrawingUtil.createPromise;
var promiseAll = kendoDrawingUtil.promiseAll;
var ObserversMixin = {
extend: function(proto) {
var this$1 = this;
for (var method in this) {
if (method !== "extend") {
proto[method] = this$1[method];
}
}
},
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 = observers.indexOf(element);
if (index !== -1) {
observers.splice(index, 1);
}
return this;
},
trigger: function(methodName, event) {
var observers = this._observers;
if (observers && !this._suspended) {
for (var idx = 0; idx < observers.length; idx++) {
var observer = observers[idx];
if (observer[methodName]) {
observer[methodName](event);
}
}
}
return this;
},
optionsChange: function(e) {
if (e === void 0) { e = {}; }
e.element = this;
this.trigger("optionsChange", e);
},
geometryChange: function() {
this.trigger("geometryChange", {
element: this
});
},
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);
}
};
function append(first, second) {
first.push.apply(first, second);
return first;
}
/* eslint-disable key-spacing,no-multi-spaces,no-param-reassign */
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"
};
function arabicToRoman(n) {
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;
}
var UNDEFINED = "undefined";
function defined(value) {
return typeof value !== UNDEFINED;
}
var defId = 1;
function definitionId() {
return "kdef" + defId++;
}
var DEG_TO_RAD = Math.PI / 180;
var MAX_NUM = Number.MAX_VALUE;
var MIN_NUM = -Number.MAX_VALUE;
function deg(radians) {
return radians / DEG_TO_RAD;
}
var KEY_STR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var fromCharCode = String.fromCharCode;
function encodeUTF8(input) {
var output = "";
for (var i = 0; i < input.length; i++) {
var c = input.charCodeAt(i);
if (c < 0x80) {
// One byte
output += fromCharCode(c);
} else if (c < 0x800) {
// Two bytes
output += fromCharCode(0xC0 | (c >>> 6));
output += fromCharCode(0x80 | (c & 0x3f));
} else if (c < 0x10000) {
// Three bytes
output += fromCharCode(0xE0 | (c >>> 12));
output += fromCharCode(0x80 | (c >>> 6 & 0x3f));
output += fromCharCode(0x80 | (c & 0x3f));
}
}
return output;
}
function encodeBase64(input) {
var output = "";
var i = 0;
var utfInput = encodeUTF8(input);
while (i < utfInput.length) {
var chr1 = utfInput.charCodeAt(i++);
var chr2 = utfInput.charCodeAt(i++);
var chr3 = utfInput.charCodeAt(i++);
var enc1 = chr1 >> 2;
var enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
var enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
var 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 eventCoordinates(e) {
if (defined((e.x || {}).location)) {
return {
x: e.x.location,
y: e.y.location
};
}
return {
x: e.pageX || e.clientX || 0,
y: e.pageY || e.clientY || 0
};
}
function eventElement(e) {
if (e === void 0) { e = {}; }
return e.touch ? e.touch.initialTouch : e.target;
}
function isTransparent(color) {
return color === "" || color === null || color === "none" || color === "transparent" || !defined(color);
}
function last(array) {
if (array) {
return array[array.length - 1];
}
}
function limitValue(value, min, max) {
return Math.max(Math.min(value, max), min);
}
/* eslint-disable no-multi-spaces, key-spacing, indent, camelcase, space-before-blocks, eqeqeq, brace-style */
/* eslint-disable space-infix-ops, space-before-function-paren, array-bracket-spacing, object-curly-spacing */
/* eslint-disable no-nested-ternary, max-params, default-case, no-else-return, no-empty */
/* eslint-disable no-param-reassign, no-var, block-scoped-var */
// mergeSort is stable.
function mergeSort(a, cmp) {
if (a.length < 2) {
return a.slice();
}
function merge(a, b) {
var r = [], ai = 0, bi = 0, i = 0;
while (ai < a.length && bi < b.length) {
if (cmp(a[ai], b[bi]) <= 0) {
r[i++] = a[ai++];
} else {
r[i++] = b[bi++];
}
}
if (ai < a.length) {
r.push.apply(r, a.slice(ai));
}
if (bi < b.length) {
r.push.apply(r, b.slice(bi));
}
return r;
}
return (function sort(a) {
if (a.length <= 1) {
return a;
}
var m = Math.floor(a.length / 2);
var left = a.slice(0, m);
var right = a.slice(m);
left = sort(left);
right = sort(right);
return merge(left, right);
})(a);
}
function rad(degrees) {
return degrees * DEG_TO_RAD;
}
function pow(p) {
if (p) {
return Math.pow(10, p);
}
return 1;
}
function round(value, precision) {
var power = pow(precision);
return Math.round(value * power) / power;
}
function valueOrDefault(value, defaultValue) {
return defined(value) ? value : defaultValue;
}
function bindEvents(element, events) {
for (var eventName in events) {
var eventNames = eventName.trim().split(" ");
for (var idx = 0; idx < eventNames.length; idx++) {
element.addEventListener(eventNames[idx], events[eventName], false);
}
}
}
function elementOffset(element) {
var box = element.getBoundingClientRect();
var documentElement = document.documentElement;
return {
top: box.top + (window.pageYOffset || documentElement.scrollTop) - (documentElement.clientTop || 0),
left: box.left + (window.pageXOffset || documentElement.scrollLeft) - (documentElement.clientLeft || 0)
};
}
function elementStyles(element, styles) {
var result = {};
var style = window.getComputedStyle(element) || {};
var stylesArray = Array.isArray(styles) ? styles : [ styles ];
for (var idx = 0; idx < stylesArray.length; idx++) {
var field = stylesArray[idx];
result[field] = style[field];
}
return result;
}
function getPixels(value) {
if (isNaN(value)) {
return value;
}
return value + "px";
}
function elementSize(element, size) {
if (size) {
var width = size.width;
var height = size.height;
if (defined(width)) {
element.style.width = getPixels(width);
}
if (defined(height)) {
element.style.height = getPixels(height);
}
} else {
var size$1 = elementStyles(element, [ 'width', 'height' ]);
return {
width: parseInt(size$1.width, 10),
height: parseInt(size$1.height, 10)
};
}
}
function unbindEvents(element, events) {
if (events === void 0) { events = {}; }
for (var name in events) {
var eventNames = name.trim().split(" ");
for (var idx = 0; idx < eventNames.length; idx++) {
element.removeEventListener(eventNames[idx], events[name], false);
}
}
}
var util = {
append: append,
arabicToRoman: arabicToRoman,
createPromise: createPromise,
defined: defined,
definitionId: definitionId,
deg: deg,
encodeBase64: encodeBase64,
eventCoordinates: eventCoordinates,
eventElement: eventElement,
isTransparent: isTransparent,
last: last,
limitValue: limitValue,
mergeSort: mergeSort,
promiseAll: promiseAll,
rad: rad,
round: round,
valueOrDefault: valueOrDefault,
bindEvents: bindEvents,
elementOffset: elementOffset,
elementSize: elementSize,
elementStyles: elementStyles,
unbindEvents: unbindEvents,
DEG_TO_RAD: DEG_TO_RAD,
MAX_NUM: MAX_NUM,
MIN_NUM: MIN_NUM
};
var toString = {}.toString;
var OptionsStore = Class.extend({
init: function(options, prefix) {
var this$1 = this;
if (prefix === void 0) { prefix = ""; }
this.prefix = prefix;
for (var field in options) {
var member = options[field];
member = this$1._wrap(member, field);
this$1[field] = member;
}
},
get: function(field) {
var parts = field.split(".");
var result = this;
while (parts.length && result) {
var part = parts.shift();
result = result[part];
}
return result;
},
set: function(field, value) {
var current = this.get(field);
if (current !== value) {
this._set(field, this._wrap(value, field));
this.optionsChange({
field: this.prefix + field,
value: value
});
}
},
_set: function(field, value) {
var this$1 = this;
var composite = field.indexOf(".") >= 0;
var parentObj = this;
var fieldName = field;
if (composite) {
var parts = fieldName.split(".");
var prefix = this.prefix;
while (parts.length > 1) {
fieldName = parts.shift();
prefix += fieldName + ".";
var obj = parentObj[fieldName];
if (!obj) {
obj = new OptionsStore({}, prefix);
obj.addObserver(this$1);
parentObj[fieldName] = obj;
}
parentObj = obj;
}
fieldName = parts[0];
}
parentObj._clear(fieldName);
parentObj[fieldName] = value;
},
_clear: function(field) {
var current = this[field];
if (current && current.removeObserver) {
current.removeObserver(this);
}
},
_wrap: function(object, field) {
var type = toString.call(object);
var wrapped = object;
if (wrapped !== null && defined(wrapped) && type === "[object Object]") {
if (!(object instanceof OptionsStore) && !(object instanceof Class)) {
wrapped = new OptionsStore(wrapped, this.prefix + field + ".");
}
wrapped.addObserver(this);
}
return wrapped;
}
});
ObserversMixin.extend(OptionsStore.prototype);
function setAccessor(field) {
return function(value) {
if (this[field] !== value) {
this[field] = value;
this.geometryChange();
}
return this;
};
}
function getAccessor(field) {
return function() {
return this[field];
};
}
function defineAccessors(fn, fields) {
for (var i = 0; i < fields.length; i++) {
var name = fields[i];
var capitalized = name.charAt(0).toUpperCase() +
name.substring(1, name.length);
fn["set" + capitalized] = setAccessor(name);
fn["get" + capitalized] = getAccessor(name);
}
}
var Matrix = Class.extend({
init: function(a, b, c, d, e, f) {
if (a === void 0) { a = 0; }
if (b === void 0) { b = 0; }
if (c === void 0) { c = 0; }
if (d === void 0) { d = 0; }
if (e === void 0) { e = 0; }
if (f === void 0) { f = 0; }
this.a = a;
this.b = b;
this.c = c;
this.d = d;
this.e = e;
this.f = f;
},
multiplyCopy: function(matrix) {
return new Matrix(
this.a * matrix.a + this.c * matrix.b,
this.b * matrix.a + this.d * matrix.b,
this.a * matrix.c + this.c * matrix.d,
this.b * matrix.c + this.d * matrix.d,
this.a * matrix.e + this.c * matrix.f + this.e,
this.b * matrix.e + this.d * matrix.f + this.f
);
},
invert: function() {
var ref = this;
var a = ref.a;
var b = ref.b;
var d = ref.c;
var e = ref.d;
var g = ref.e;
var h = ref.f;
var det = a * e - b * d;
if (det === 0) {
return null;
}
return new Matrix(e / det, -b / det, -d / det, a / det,
(d * h - e * g) / det, (b * g - a * h) / det);
},
clone: function() {
return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f);
},
equals: function(other) {
if (!other) {
return false;
}
return this.a === other.a && this.b === other.b &&
this.c === other.c && this.d === other.d &&
this.e === other.e && this.f === other.f;
},
round: function(precision) {
this.a = round(this.a, precision);
this.b = round(this.b, precision);
this.c = round(this.c, precision);
this.d = round(this.d, precision);
this.e = round(this.e, precision);
this.f = round(this.f, precision);
return this;
},
toArray: function(precision) {
var result = [ this.a, this.b, this.c, this.d, this.e, this.f ];
if (defined(precision)) {
for (var i = 0; i < result.length; i++) {
result[i] = round(result[i], precision);
}
}
return result;
},
toString: function(precision, separator) {
if (separator === void 0) { separator = ","; }
return this.toArray(precision).join(separator);
}
});
Matrix.translate = function(x, y) {
return new Matrix(1, 0, 0, 1, x, y);
};
Matrix.unit = function() {
return new Matrix(1, 0, 0, 1, 0, 0);
};
Matrix.rotate = function(angle, x, y) {
var matrix = new Matrix();
matrix.a = Math.cos(rad(angle));
matrix.b = Math.sin(rad(angle));
matrix.c = -matrix.b;
matrix.d = matrix.a;
matrix.e = (x - x * matrix.a + y * matrix.b) || 0;
matrix.f = (y - y * matrix.a - x * matrix.b) || 0;
return matrix;
};
Matrix.scale = function(scaleX, scaleY) {
return new Matrix(scaleX, 0, 0, scaleY, 0, 0);
};
Matrix.IDENTITY = Matrix.unit();
function toMatrix(transformation) {
if (transformation && typeof transformation.matrix === "function") {
return transformation.matrix();
}
return transformation;
}
var Point = Class.extend({
init: function(x, y) {
this.x = x || 0;
this.y = y || 0;
},
equals: function(other) {
return other && other.x === this.x && other.y === this.y;
},
clone: function() {
return new Point(this.x, this.y);
},
rotate: function(angle, origin) {
var originPoint = Point.create(origin) || Point.ZERO;
return this.transform(Matrix.rotate(angle, originPoint.x, originPoint.y));
},
translate: function(x, y) {
this.x += x;
this.y += y;
this.geometryChange();
return this;
},
translateWith: function(point) {
return this.translate(point.x, point.y);
},
move: function(x, y) {
this.x = this.y = 0;
return this.translate(x, y);
},
scale: function(scaleX, scaleY) {
if (scaleY === void 0) { scaleY = scaleX; }
this.x *= scaleX;
this.y *= scaleY;
this.geometryChange();
return this;
},
scaleCopy: function(scaleX, scaleY) {
return this.clone().scale(scaleX, scaleY);
},
transform: function(transformation) {
var matrix = toMatrix(transformation);
var ref = this;
var x = ref.x;
var y = ref.y;
this.x = matrix.a * x + matrix.c * y + matrix.e;
this.y = matrix.b * x + matrix.d * y + matrix.f;
this.geometryChange();
return this;
},
transformCopy: function(transformation) {
var point = this.clone();
if (transformation) {
point.transform(transformation);
}
return point;
},
distanceTo: function(point) {
var dx = this.x - point.x;
var dy = this.y - point.y;
return Math.sqrt(dx * dx + dy * dy);
},
round: function(digits) {
this.x = round(this.x, digits);
this.y = round(this.y, digits);
this.geometryChange();
return this;
},
toArray: function(digits) {
var doRound = defined(digits);
var x = doRound ? round(this.x, digits) : this.x;
var y = doRound ? round(this.y, digits) : this.y;
return [ x, y ];
},
toString: function(digits, separator) {
if (separator === void 0) { separator = " "; }
var ref = this;
var x = ref.x;
var y = ref.y;
if (defined(digits)) {
x = round(x, digits);
y = round(y, digits);
}
return x + separator + y;
}
});
Point.create = function(arg0, arg1) {
if (defined(arg0)) {
if (arg0 instanceof Point) {
return arg0;
} else if (arguments.length === 1 && arg0.length === 2) {
return new Point(arg0[0], arg0[1]);
}
return new Point(arg0, arg1);
}
};
Point.min = function() {
var arguments$1 = arguments;
var minX = MAX_NUM;
var minY = MAX_NUM;
for (var i = 0; i < arguments.length; i++) {
var point = arguments$1[i];
minX = Math.min(point.x, minX);
minY = Math.min(point.y, minY);
}
return new Point(minX, minY);
};
Point.max = function() {
var arguments$1 = arguments;
var maxX = MIN_NUM;
var maxY = MIN_NUM;
for (var i = 0; i < arguments.length; i++) {
var point = arguments$1[i];
maxX = Math.max(point.x, maxX);
maxY = Math.max(point.y, maxY);
}
return new Point(maxX, maxY);
};
Point.minPoint = function() {
return new Point(MIN_NUM, MIN_NUM);
};
Point.maxPoint = function() {
return new Point(MAX_NUM, MAX_NUM);
};
if (Object.defineProperties) {
Object.defineProperties(Point, {
ZERO: {
get: function() {
return new Point(0, 0);
}
}
});
}
defineAccessors(Point.prototype, [ "x", "y" ]);
ObserversMixin.extend(Point.prototype);
var Size = Class.extend({
init: function(width, height) {
this.width = width || 0;
this.height = height || 0;
},
equals: function(other) {
return other && other.width === this.width && other.height === this.height;
},
clone: function() {
return new Size(this.width, this.height);
},
toArray: function(digits) {
var doRound = defined(digits);
var width = doRound ? round(this.width, digits) : this.width;
var height = doRound ? round(this.height, digits) : this.height;
return [ width, height ];
}
});
Size.create = function(arg0, arg1) {
if (defined(arg0)) {
if (arg0 instanceof Size) {
return arg0;
} else if (arguments.length === 1 && arg0.length === 2) {
return new Size(arg0[0], arg0[1]);
}
return new Size(arg0, arg1);
}
};
if (Object.defineProperties) {
Object.defineProperties(Size, {
ZERO: {
get: function() {
return new Size(0, 0);
}
}
});
}
defineAccessors(Size.prototype, [ "width", "height" ]);
ObserversMixin.extend(Size.prototype);
var Rect = Class.extend({
init: function(origin, size) {
if (origin === void 0) { origin = new Point(); }
if (size === void 0) { size = new Size(); }
this.setOrigin(origin);
this.setSize(size);
},
clone: function() {
return new Rect(
this.origin.clone(),
this.size.clone()
);
},
equals: function(other) {
return other &&
other.origin.equals(this.origin) &&
other.size.equals(this.size);
},
setOrigin: function(value) {
this._observerField("origin", Point.create(value));
this.geometryChange();
return this;
},
getOrigin: function() {
return this.origin;
},
setSize: function(value) {
this._observerField("size", Size.create(value));
this.geometryChange();
return this;
},
getSize: function() {
return this.size;
},
width: function() {
return this.size.width;
},
height: function() {
return this.size.height;
},
topLeft: function() {
return this.origin.clone();
},
bottomRight: function() {
return this.origin.clone().translate(this.width(), this.height());
},
topRight: function() {
return this.origin.clone().translate(this.width(), 0);
},
bottomLeft: function() {
return this.origin.clone().translate(0, this.height());
},
center: function() {
return this.origin.clone().translate(this.width() / 2, this.height() / 2);
},
bbox: function(matrix) {
var tl = this.topLeft().transformCopy(matrix);
var tr = this.topRight().transformCopy(matrix);
var br = this.bottomRight().transformCopy(matrix);
var bl = this.bottomLeft().transformCopy(matrix);
return Rect.fromPoints(tl, tr, br, bl);
},
transformCopy: function(m) {
return Rect.fromPoints(
this.topLeft().transform(m),
this.bottomRight().transform(m)
);
},
expand: function(x, y) {
if (y === void 0) { y = x; }
this.size.width += 2 * x;
this.size.height += 2 * y;
this.origin.translate(-x, -y);
return this;
},
expandCopy: function(x, y) {
return this.clone().expand(x, y);
},
containsPoint: function(point) {
var origin = this.origin;
var bottomRight = this.bottomRight();
return !(point.x < origin.x || point.y < origin.y || bottomRight.x < point.x || bottomRight.y < point.y);
},
_isOnPath: function(point, width) {
var rectOuter = this.expandCopy(width, width);
var rectInner = this.expandCopy(-width, -width);
return rectOuter.containsPoint(point) && !rectInner.containsPoint(point);
}
});
Rect.fromPoints = function() {
var topLeft = Point.min.apply(null, arguments);
var bottomRight = Point.max.apply(null, arguments);
var size = new Size(
bottomRight.x - topLeft.x,
bottomRight.y - topLeft.y
);
return new Rect(topLeft, size);
};
Rect.union = function(a, b) {
return Rect.fromPoints(
Point.min(a.topLeft(), b.topLeft()),
Point.max(a.bottomRight(), b.bottomRight())
);
};
Rect.intersect = function(a, b) {
var rect1 = {
left: a.topLeft().x,
top: a.topLeft().y,
right: a.bottomRight().x,
bottom: a.bottomRight().y
};
var rect2 = {
left: b.topLeft().x,
top: b.topLeft().y,
right: b.bottomRight().x,
bottom: b.bottomRight().y
};
if (rect1.left <= rect2.right &&
rect2.left <= rect1.right &&
rect1.top <= rect2.bottom &&
rect2.top <= rect1.bottom) {
return Rect.fromPoints(
new Point(Math.max(rect1.left, rect2.left), Math.max(rect1.top, rect2.top)),
new Point(Math.min(rect1.right, rect2.right), Math.min(rect1.bottom, rect2.bottom))
);
}
};
ObserversMixin.extend(Rect.prototype);
var Transformation = Class.extend({
init: function(matrix) {
if (matrix === void 0) { matrix = Matrix.unit(); }
this._matrix = matrix;
},
clone: function() {
return new Transformation(
this._matrix.clone()
);
},
equals: function(other) {
return other &&
other._matrix.equals(this._matrix);
},
translate: function(x, y) {
this._matrix = this._matrix.multiplyCopy(Matrix.translate(x, y));
this._optionsChange();
return this;
},
scale: function(scaleX, scaleY, origin) {
if (scaleY === void 0) { scaleY = scaleX; }
if (origin === void 0) { origin = null; }
var originPoint = origin;
if (originPoint) {
originPoint = Point.create(originPoint);
this._matrix = this._matrix.multiplyCopy(Matrix.translate(originPoint.x, originPoint.y));
}
this._matrix = this._matrix.multiplyCopy(Matrix.scale(scaleX, scaleY));
if (originPoint) {
this._matrix = this._matrix.multiplyCopy(Matrix.translate(-originPoint.x, -originPoint.y));
}
this._optionsChange();
return this;
},
rotate: function(angle, origin) {
var originPoint = Point.create(origin) || Point.ZERO;
this._matrix = this._matrix.multiplyCopy(Matrix.rotate(angle, originPoint.x, originPoint.y));
this._optionsChange();
return this;
},
multiply: function(transformation) {
var matrix = toMatrix(transformation);
this._matrix = this._matrix.multiplyCopy(matrix);
this._optionsChange();
return this;
},
matrix: function(value) {
if (value) {
this._matrix = value;
this._optionsChange();
return this;
}
return this._matrix;
},
_optionsChange: function() {
this.optionsChange({
field: "transform",
value: this
});
}
});
ObserversMixin.extend(Transformation.prototype);
function transform(matrix) {
if (matrix === null) {
return null;
}
if (matrix instanceof Transformation) {
return matrix;
}
return new Transformation(matrix);
}
var Element$1 = Class.extend({
init: function(options) {
this._initOptions(options);
},
_initOptions: function(options) {
if (options === void 0) { options = {}; }
var clip = options.clip;
var transform$$1 = options.transform;
if (transform$$1) {
options.transform = transform(transform$$1);
}
if (clip && !clip.id) {
clip.id = definitionId();
}
this.options = new OptionsStore(options);
this.options.addObserver(this);
},
transform: function(value) {
if (defined(value)) {
this.options.set("transform", transform(value));
} else {
return this.options.get("transform");
}
},
parentTransform: function() {
var element = this;
var parentMatrix;
while (element.parent) {
element = element.parent;
var transformation = element.transform();
if (transformation) {
parentMatrix = transformation.matrix().multiplyCopy(parentMatrix || Matrix.unit());
}
}
if (parentMatrix) {
return transform(parentMatrix);
}
},
currentTransform: function(parentTransform) {
if (parentTransform === void 0) { parentTransform = this.parentTransform(); }
var elementTransform = this.transform();
var elementMatrix = toMatrix(elementTransform);
var parentMatrix = toMatrix(parentTransform);
var combinedMatrix;
if (elementMatrix && parentMatrix) {
combinedMatrix = parentMatrix.multiplyCopy(elementMatrix);
} else {
combinedMatrix = elementMatrix || parentMatrix;
}
if (combinedMatrix) {
return transform(combinedMatrix);
}
},
visible: function(value) {
if (defined(value)) {
this.options.set("visible", value);
return this;
}
return this.options.get("visible") !== false;
},
clip: function(value) {
var options = this.options;
if (defined(value)) {
if (value && !value.id) {
value.id = definitionId();
}
options.set("clip", value);
return this;
}
return options.get("clip");
},
opacity: function(value) {
if (defined(value)) {
this.options.set("opacity", value);
return this;
}
return valueOrDefault(this.options.get("opacity"), 1);
},
clippedBBox: function(transformation) {
var bbox = this._clippedBBox(transformation);
if (bbox) {
var clip = this.clip();
return clip ? Rect.intersect(bbox, clip.bbox(transformation)) : bbox;
}
},
containsPoint: function(point, parentTransform) {
if (this.visible()) {
var transform$$1 = this.currentTransform(parentTransform);
var transformedPoint = point;
if (transform$$1) {
transformedPoint = point.transformCopy(transform$$1.matrix().invert());
}
return (this._hasFill() && this._containsPoint(transformedPoint)) || (this._isOnPath && this._hasStroke() && this._isOnPath(transformedPoint));
}
return false;
},
_hasFill: function() {
var fill = this.options.fill;
return fill && !isTransparent(fill.color);
},
_hasStroke: function() {
var stroke = this.options.stroke;
return stroke && stroke.width > 0 && !isTransparent(stroke.color);
},
_clippedBBox: function(transformation) {
return this.bbox(transformation);
}
});
Element$1.prototype.nodeType = "Element";
ObserversMixin.extend(Element$1.prototype);
function ellipseExtremeAngles(center, rx, ry, matrix) {
var extremeX = 0;
var extremeY = 0;
if (matrix) {
extremeX = Math.atan2(matrix.c * ry, matrix.a * rx);
if (matrix.b !== 0) {
extremeY = Math.atan2(matrix.d * ry, matrix.b * rx);
}
}
return {
x: extremeX,
y: extremeY
};
}
var PI_DIV_2 = Math.PI / 2;
var Circle$2 = Class.extend({
init: function(center, radius) {
if (center === void 0) { center = new Point(); }
if (radius === void 0) { radius = 0; }
this.setCenter(center);
this.setRadius(radius);
},
setCenter: function(value) {
this._observerField("center", Point.create(value));
this.geometryChange();
return this;
},
getCenter: function() {
return this.center;
},
equals: function(other) {
return other &&
other.center.equals(this.center) &&
other.radius === this.radius;
},
clone: function() {
return new Circle$2(this.center.clone(), this.radius);
},
pointAt: function(angle) {
return this._pointAt(rad(angle));
},
bbox: function(matrix) {
var this$1 = this;
var extremeAngles = ellipseExtremeAngles(this.center, this.radius, this.radius, matrix);
var minPoint = Point.maxPoint();
var maxPoint = Point.minPoint();
for (var i = 0; i < 4; i++) {
var currentPointX = this$1._pointAt(extremeAngles.x + i * PI_DIV_2).transformCopy(matrix);
var currentPointY = this$1._pointAt(extremeAngles.y + i * PI_DIV_2).transformCopy(matrix);
var currentPoint = new Point(currentPointX.x, currentPointY.y);
minPoint = Point.min(minPoint, currentPoint);
maxPoint = Point.max(maxPoint, currentPoint);
}
return Rect.fromPoints(minPoint, maxPoint);
},
_pointAt: function(angle) {
var ref = this;
var center = ref.center;
var radius = ref.radius;
return new Point(
center.x + radius * Math.cos(angle),
center.y + radius * Math.sin(angle)
);
},
containsPoint: function(point) {
var ref = this;
var center = ref.center;
var radius = ref.radius;
var inCircle = Math.pow(point.x - center.x, 2) +
Math.pow(point.y - center.y, 2) <= Math.pow(radius, 2);
return inCircle;
},
_isOnPath: function(point, width) {
var ref = this;
var center = ref.center;
var radius = ref.radius;
var pointDistance = center.distanceTo(point);
return radius - width <= pointDistance && pointDistance <= radius + width;
}
});
defineAccessors(Circle$2.prototype, [ "radius" ]);
ObserversMixin.extend(Circle$2.prototype);
var GRADIENT = "Gradient";
var Paintable = {
extend: function(proto) {
proto.fill = this.fill;
proto.stroke = this.stroke;
},
fill: function(color, opacity) {
var options = this.options;
if (defined(color)) {
if (color && color.nodeType !== GRADIENT) {
var newFill = {
color: color
};
if (defined(opacity)) {
newFill.opacity = opacity;
}
options.set("fill", newFill);
} else {
options.set("fill", color);
}
return this;
}
return options.get("fill");
},
stroke: function(color, width, opacity) {
if (defined(color)) {
this.options.set("stroke.color", color);
if (defined(width)) {
this.options.set("stroke.width", width);
}
if (defined(opacity)) {
this.options.set("stroke.opacity", opacity);
}
return this;
}
return this.options.get("stroke");
}
};
var IDENTITY_MATRIX_HASH = Matrix.IDENTITY.toString();
var Measurable = {
extend: function(proto) {
proto.bbox = this.bbox;
proto.geometryChange = this.geometryChange;
},
bbox: function(transformation) {
var combinedMatrix = toMatrix(this.currentTransform(transformation));
var matrixHash = combinedMatrix ? combinedMatrix.toString() : IDENTITY_MATRIX_HASH;
var bbox;
if (this._bboxCache && this._matrixHash === matrixHash) {
bbox = this._bboxCache.clone();
} else {
bbox = this._bbox(combinedMatrix);
this._bboxCache = bbox ? bbox.clone() : null;
this._matrixHash = matrixHash;
}
var strokeWidth = this.options.get("stroke.width");
if (strokeWidth && bbox) {
bbox.expand(strokeWidth / 2);
}
return bbox;
},
geometryChange: function() {
delete this._bboxCache;
this.trigger("geometryChange", {
element: this
});
}
};
function geometryAccessor(name) {
var fieldName = "_" + name;
return function(value) {
if (defined(value)) {
this._observerField(fieldName, value);
this.geometryChange();
return this;
}
return this[fieldName];
};
}
function defineGeometryAccessors(fn, names) {
for (var i = 0; i < names.length; i++) {
fn[names[i]] = geometryAccessor(names[i]);
}
}
var DEFAULT_STROKE = "#000";
var Circle = Element$1.extend({
init: function(geometry, options) {
if (geometry === void 0) { geometry = new Circle$2(); }
if (options === void 0) { options = {}; }
Element$1.fn.init.call(this, options);
this.geometry(geometry);
if (!defined(this.options.stroke)) {
this.stroke(DEFAULT_STROKE);
}
},
rawBBox: function() {
return this._geometry.bbox();
},
_bbox: function(matrix) {
return this._geometry.bbox(matrix);
},
_containsPoint: function(point) {
return this.geometry().containsPoint(point);
},
_isOnPath: function(point) {
return this.geometry()._isOnPath(point, this.options.stroke.width / 2);
}
});
Circle.prototype.nodeType = "Circle";
Paintable.extend(Circle.prototype);
Measurable.extend(Circle.prototype);
defineGeometryAccessors(Circle.prototype, [ "geometry" ]);
var PRECISION = 10;
function close(a, b, tolerance) {
if (tolerance === void 0) { tolerance = PRECISION; }
return round(Math.abs(a - b), tolerance) === 0;
}
function closeOrLess(a, b, tolerance) {
return a < b || close(a, b, tolerance);
}
function lineIntersection(p0, p1, p2, p3) {
var s1x = p1.x - p0.x;
var s2x = p3.x - p2.x;
var s1y = p1.y - p0.y;
var s2y = p3.y - p2.y;
var nx = p0.x - p2.x;
var ny = p0.y - p2.y;
var d = s1x * s2y - s2x * s1y;
var s = (s1x * ny - s1y * nx) / d;
var t = (s2x * ny - s2y * nx) / d;
if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
return new Point(p0.x + t * s1x, p0.y + t * s1y);
}
}
var MAX_INTERVAL = 45;
var pow$1 = Math.pow;
var Arc$2 = Class.extend({
init: function(center, options) {
if (center === void 0) { center = new Point(); }
if (options === void 0) { options = {}; }
this.setCenter(center);
this.radiusX = options.radiusX;
this.radiusY = options.radiusY || options.radiusX;
this.startAngle = options.startAngle;
this.endAngle = options.endAngle;
this.anticlockwise = options.anticlockwise || false;
this.xRotation = options.xRotation;
},
clone: function() {
return new Arc$2(this.center, {
radiusX: this.radiusX,
radiusY: this.radiusY,
startAngle: this.startAngle,
endAngle: this.endAngle,
anticlockwise: this.anticlockwise
});
},
setCenter: function(value) {
this._observerField("center", Point.create(value));
this.geometryChange();
return this;
},
getCenter: function() {
return this.center;
},
pointAt: function(angle) {
var center = this.center;
var radian = rad(angle);
return new Point(
center.x + this.radiusX * Math.cos(radian),
center.y + this.radiusY * Math.sin(radian)
);
},
curvePoints: function() {
var this$1 = this;
var startAngle = this.startAngle;
var dir = this.anticlockwise ? -1 : 1;
var curvePoints = [ this.pointAt(startAngle) ];
var interval = this._arcInterval();
var intervalAngle = interval.endAngle - interval.startAngle;
var subIntervalsCount = Math.ceil(intervalAngle / MAX_INTERVAL);
var subIntervalAngle = intervalAngle / subIntervalsCount;
var currentAngle = startAngle;
var transformation;
if (this.xRotation) {
transformation = transform().rotate(this.xRotation, this.center);
}
for (var i = 1; i <= subIntervalsCount; i++) {
var nextAngle = currentAngle + dir * subIntervalAngle;
var points = this$1._intervalCurvePoints(currentAngle, nextAngle, transformation);
curvePoints.push(points.cp1, points.cp2, points.p2);
currentAngle = nextAngle;
}
return curvePoints;
},
bbox: function(matrix) {
var this$1 = this;
var interval = this._arcInterval();
var startAngle = interval.startAngle;
var endAngle = interval.endAngle;
var extremeAngles = ellipseExtremeAngles(this.center, this.radiusX, this.radiusY, matrix);
var extremeX = deg(extremeAngles.x);
var extremeY = deg(extremeAngles.y);
var endPoint = this.pointAt(endAngle).transformCopy(matrix);
var currentAngleX = bboxStartAngle(extremeX, startAngle);
var currentAngleY = bboxStartAngle(extremeY, startAngle);
var currentPoint = this.pointAt(startAngle).transformCopy(matrix);
var minPoint = Point.min(currentPoint, endPoint);
var maxPoint = Point.max(currentPoint, endPoint);
while (currentAngleX < endAngle || currentAngleY < endAngle) {
var currentPointX = (void 0);
if (currentAngleX < endAngle) {
currentPointX = this$1.pointAt(currentAngleX).transformCopy(matrix);
currentAngleX += 90;
}
var currentPointY = (void 0);
if (currentAngleY < endAngle) {
currentPointY = this$1.pointAt(currentAngleY).transformCopy(matrix);
currentAngleY += 90;
}
currentPoint = new Point(currentPointX.x, currentPointY.y);
minPoint = Point.min(minPoint, currentPoint);
maxPoint = Point.max(maxPoint, currentPoint);
}
return Rect.fromPoints(minPoint, maxPoint);
},
_arcInterval: function() {
var ref = this;
var startAngle = ref.startAngle;
var endAngle = ref.endAngle;
var anticlockwise = ref.anticlockwise;
if (anticlockwise) {
var oldStart = startAngle;
startAngle = endAngle;
endAngle = oldStart;
}
if (startAngle > endAngle || (anticlockwise && startAngle === endAngle)) {
endAngle += 360;
}
return {
startAngle: startAngle,
endAngle: endAngle
};
},
_intervalCurvePoints: function(startAngle, endAngle, transformation) {
var p1 = this.pointAt(startAngle);
var p2 = this.pointAt(endAngle);
var p1Derivative = this._derivativeAt(startAngle);
var p2Derivative = this._derivativeAt(endAngle);
var t = (rad(endAngle) - rad(startAngle)) / 3;
var cp1 = new Point(p1.x + t * p1Derivative.x, p1.y + t * p1Derivative.y);
var cp2 = new Point(p2.x - t * p2Derivative.x, p2.y - t * p2Derivative.y);
if (transformation) {
p1.transform(transformation);
p2.transform(transformation);
cp1.transform(transformation);
cp2.transform(transformation);
}
return {
p1: p1,
cp1: cp1,
cp2: cp2,
p2: p2
};
},
_derivativeAt: function(angle) {
var radian = rad(angle);
return new Point(-this.radiusX * Math.sin(radian), this.radiusY * Math.cos(radian));
},
containsPoint: function(point) {
var interval = this._arcInterval();
var intervalAngle = interval.endAngle - interval.startAngle;
var ref = this;
var center = ref.center;
var radiusX = ref.radiusX;
var radiusY = ref.radiusY;
var distance = center.distanceTo(point);
var angleRad = Math.atan2(point.y - center.y, point.x - center.x);
var pointRadius = (radiusX * radiusY) /
Math.sqrt(pow$1(radiusX, 2) * pow$1(Math.sin(angleRad), 2) + pow$1(radiusY, 2) * pow$1(Math.cos(angleRad), 2));
var startPoint = this.pointAt(this.startAngle).round(PRECISION);
var endPoint = this.pointAt(this.endAngle).round(PRECISION);
var intersection = lineIntersection(center, point.round(PRECISION), startPoint, endPoint);
var containsPoint;
if (intervalAngle < 180) {
containsPoint = intersection && closeOrLess(center.distanceTo(intersection), distance) && closeOrLess(distance, pointRadius);
} else {
var angle = calculateAngle(center.x, center.y, radiusX, radiusY, point.x, point.y);
if (angle !== 360) {
angle = (360 + angle) % 360;
}
var inAngleRange = interval.startAngle <= angle && angle <= interval.endAngle;
containsPoint = (inAngleRange && closeOrLess(distance, pointRadius)) || (!inAngleRange && (!intersection || intersection.equals(point)));
}
return containsPoint;
},
_isOnPath: function(point, width) {
var interval = this._arcInterval();
var center = this.center;
var angle = calculateAngle(center.x, center.y, this.radiusX, this.radiusY, point.x, point.y);
if (angle !== 360) {
angle = (360 + angle) % 360;
}
var inAngleRange = interval.startAngle <= angle && angle <= interval.endAngle;
return inAngleRange && this.pointAt(angle).distanceTo(point) <= width;
}
});
Arc$2.fromPoints = function(start, end, rx, ry, largeArc, swipe, rotation) {// eslint-disable-line max-params
var arcParameters = normalizeArcParameters({
x1: start.x,
y1: start.y,
x2: end.x,
y2: end.y,
rx: rx,
ry: ry,
largeArc: largeArc,
swipe: swipe,
rotation: rotation
});
return new Arc$2(arcParameters.center, {
startAngle: arcParameters.startAngle,
endAngle: arcParameters.endAngle,
radiusX: arcParameters.radiusX,
radiusY: arcParameters.radiusY,
xRotation: arcParameters.xRotation,
anticlockwise: swipe === 0
});
};
defineAccessors(Arc$2.prototype, [ "radiusX", "radiusY", "startAngle", "endAngle", "anticlockwise" ]);
ObserversMixin.extend(Arc$2.prototype);
function calculateAngle(cx, cy, rx, ry, x, y) {
var cos = round((x - cx) / rx, 3);
var sin = round((y - cy) / ry, 3);
return round(deg(Math.atan2(sin, cos)));
}
function normalizeArcParameters(parameters) {
var x1 = parameters.x1;
var y1 = parameters.y1;
var x2 = parameters.x2;
var y2 = parameters.y2;
var rx = parameters.rx;
var ry = parameters.ry;
var largeArc = parameters.largeArc;
var swipe = parameters.swipe;
var rotation = parameters.rotation; if (rotation === void 0) { rotation = 0; }
var radians = rad(rotation);
var cosine = Math.cos(radians);
var sine = Math.sin(radians);
var xT = cosine * (x1 - x2) / 2 + sine * (y1 - y2) / 2;
var yT = -sine * (x1 - x2) / 2 + cosine * (y1 - y2) / 2;
var sign = largeArc !== swipe ? 1 : -1;
var xt2 = Math.pow(xT, 2);
var yt2 = Math.pow(yT, 2);
var rx2 = Math.pow(rx, 2);
var ry2 = Math.pow(ry, 2);
var delta = xt2 / rx2 + yt2 / ry2;
if (delta > 1) {
delta = Math.sqrt(xt2 / rx2 + yt2 / ry2);
rx = delta * rx;
rx2 = Math.pow(rx, 2);
ry = delta * ry;
ry2 = Math.pow(ry, 2);
}
var constT = sign * Math.sqrt((rx2 * ry2 - rx2 * yt2 - ry2 * xt2) / (rx2 * yt2 + ry2 * xt2));
// due to rounding errors the value could become NaN even after radii correction
if (isNaN(constT)) {
constT = 0;
}
var cxT = constT * (rx * yT) / ry;
var cyT = - constT * (ry * xT) / rx;
var cx = cosine * cxT - sine * cyT + (x1 + x2) / 2;
var cy = sine * cxT + cosine * cyT + (y1 + y2) / 2;
var uX = (xT - cxT) / rx;
var uY = (yT - cyT) / ry;
var vX = -(xT + cxT) / rx;
var vY = -(yT + cyT) / ry;
var startAngle = (uY >= 0 ? 1 : -1) * deg(Math.acos(uX / Math.sqrt(uX * uX + uY * uY)));
var angleCosine = round((uX * vX + uY * vY) / (Math.sqrt(uX * uX + uY * uY) * Math.sqrt(vX * vX + vY * vY)), 10);
var angle = (uX * vY - uY * vX >= 0 ? 1 : -1) * deg(Math.acos(angleCosine));
if (!swipe && angle > 0) {
angle -= 360;
}
if (swipe && angle < 0) {
angle += 360;
}
var endAngle = startAngle + angle;
var signEndAngle = endAngle >= 0 ? 1 : -1;
endAngle = (Math.abs(endAngle) % 360) * signEndAngle;
return {
center: new Point(cx, cy),
startAngle: startAngle,
endAngle: endAngle,
radiusX: rx,
radiusY: ry,
xRotation: rotation
};
}
function bboxStartAngle(angle, start) {
var startAngle = angle;
while (startAngle < start) {
startAngle += 90;
}
return startAngle;
}
var push = [].push;
var pop = [].pop;
var splice = [].splice;
var shift = [].shift;
var slice = [].slice;
var unshift = [].unshift;
var ElementsArray = Class.extend({
init: function(array) {
if (array === void 0) { array = []; }
this.length = 0;
this._splice(0, array.length, array);
},
elements: function(value) {
if (value) {
this._splice(0, this.length, value);
this._change();
return this;
}
return this.slice(0);
},
push: function() {
var elements = arguments;
var result = push.apply(this, elements);
this._add(elements);
return result;
},
slice: function() {
return slice.call(this);
},
pop: function() {
var length = this.length;
var result = pop.apply(this);
if (length) {
this._remove([ result ]);
}
return result;
},
splice: function(index, howMany) {
var elements = slice.call(arguments, 2);
var result = this._splice(index, howMany, elements);
this._change();
return result;
},
shift: function() {
var length = this.length;
var result = shift.apply(this);
if (length) {
this._remove([ result ]);
}
return result;
},
unshift: function() {
var elements = arguments;
var result = unshift.apply(this, elements);
this._add(elements);
return result;
},
indexOf: function(element) {
var this$1 = this;
var length = this.length;
for (var idx = 0; idx < length; idx++) {
if (this$1[idx] === element) {
return idx;
}
}
return -1;
},
_splice: function(index, howMany, elements) {
var result = splice.apply(this, [ index, howMany ].concat(elements));
this._clearObserver(result);
this._setObserver(elements);
return result;
},
_add: function(elements) {
this._setObserver(elements);
this._change();
},
_remove: function(elements) {
this._clearObserver(elements);
this._change();
},
_setObserver: function(elements) {
var this$1 = this;
for (var idx = 0; idx < elements.length; idx++) {
elements[idx].addObserver(this$1);
}
},
_clearObserver: function(elements) {
var this$1 = this;
for (var idx = 0; idx < elements.length; idx++) {
elements[idx].removeObserver(this$1);
}
},
_change: function() {}
});
ObserversMixin.extend(ElementsArray.prototype);
var GeometryElementsArray = ElementsArray.extend({
_change: function() {
this.geometryChange();
}
});
function pointAccessor(name) {
var fieldName = "_" + name;
return function(value) {
if (defined(value)) {
this._observerField(fieldName, Point.create(value));
this.geometryChange();
return this;
}
return this[fieldName];
};
}
function definePointAccessors(fn, names) {
for (var i = 0; i < names.length; i++) {
fn[names[i]] = pointAccessor(names[i]);
}
}
function isOutOfEndPoint(endPoint, controlPoint, point) {
var angle = deg(Math.atan2(controlPoint.y - endPoint.y, controlPoint.x - endPoint.x));
var rotatedPoint = point.transformCopy(transform().rotate(-angle, endPoint));
return rotatedPoint.x < endPoint.x;
}
function calculateCurveAt(t, field, points) {
var t1 = 1 - t;
return Math.pow(t1, 3) * points[0][field] +
3 * Math.pow(t1, 2) * t * points[1][field] +
3 * Math.pow(t, 2) * t1 * points[2][field] +
Math.pow(t, 3) * points[3][field];
}
function toCubicPolynomial(points, field) {
return [ -points[0][field] + 3 * points[1][field] - 3 * points[2][field] + points[3][field],
3 * (points[0][field] - 2 * points[1][field] + points[2][field]),
3 * (-points[0][field] + points[1][field]),
points[0][field]
];
}
var ComplexNumber = Class.extend({
init: function(real, img) {
if (real === void 0) { real = 0; }
if (img === void 0) { img = 0; }
this.real = real;
this.img = img;
},
add: function(cNumber) {
return new ComplexNumber(round(this.real + cNumber.real, PRECISION), round(this.img + cNumber.img, PRECISION));
},
addConstant: function(value) {
return new ComplexNumber(this.real + value, this.img);
},
negate: function() {
return new ComplexNumber(-this.real, -this.img);
},
multiply: function(cNumber) {
return new ComplexNumber(this.real * cNumber.real - this.img * cNumber.img,
this.real * cNumber.img + this.img * cNumber.real);
},
multiplyConstant: function(value) {
return new ComplexNumber(this.real * value, this.img * value);
},
nthRoot: function(n) {
var rad$$1 = Math.atan2(this.img, this.real);
var r = Math.sqrt(Math.pow(this.img, 2) + Math.pow(this.real, 2));
var nthR = Math.pow(r, 1 / n);
return new ComplexNumber(nthR * Math.cos(rad$$1 / n), nthR * Math.sin(rad$$1 / n)); //Moivre's formula
},
equals: function(cNumber) {
return this.real === cNumber.real && this.img === cNumber.img;
},
isReal: function() {
return this.img === 0;
}
});
function numberSign(x) {
return x < 0 ? -1 : 1;
}
function solveQuadraticEquation(a, b, c) {
var squareRoot = Math.sqrt(Math.pow(b, 2) - 4 * a * c);
return [
(-b + squareRoot) / (2 * a),
(-b - squareRoot) / (2 * a)
];
}
//Cardano's formula
function solveCubicEquation(a, b, c, d) {
if (a === 0) {
return solveQuadraticEquation(b, c, d);
}
var p = (3 * a * c - Math.pow(b, 2)) / (3 * Math.pow(a, 2));
var q = (2 * Math.pow(b, 3) - 9 * a * b * c + 27 * Math.pow(a, 2) * d) / (27 * Math.pow(a, 3));
var Q = Math.pow(p / 3, 3) + Math.pow(q / 2, 2);
var i = new ComplexNumber(0,1);
var b3a = -b / (3 * a);
var x1, x2, y1, y2, y3, z1, z2;
if (Q < 0) {
x1 = new ComplexNumber(-q / 2, Math.sqrt(-Q)).nthRoot(3);
x2 = new ComplexNumber(-q / 2, - Math.sqrt(-Q)).nthRoot(3);
} else {
x1 = -q / 2 + Math.sqrt(Q);
x1 = new ComplexNumber(numberSign(x1) * Math.pow(Math.abs(x1), 1 / 3));
x2 = -q / 2 - Math.sqrt(Q);
x2 = new ComplexNumber(numberSign(x2) * Math.pow(Math.abs(x2), 1 / 3));
}
y1 = x1.add(x2);
z1 = x1.add(x2).multiplyConstant(-1 / 2);
z2 = x1.add(x2.negate()).multiplyConstant(Math.sqrt(3) / 2);
y2 = z1.add(i.multiply(z2));
y3 = z1.add(i.negate().multiply(z2));
var result = [];
if (y1.isReal()) {
result.push(round(y1.real + b3a, PRECISION));
}
if (y2.isReal()) {
result.push(round(y2.real + b3a, PRECISION));
}
if (y3.isReal()) {
result.push(round(y3.real + b3a, PRECISION));
}
return result;
}
function hasRootsInRange(points, point, field, rootField, range) {
var polynomial = toCubicPolynomial(points, rootField);
var roots = solveCubicEquation(polynomial[0], polynomial[1], polynomial[2], polynomial[3] - point[rootField]);
var intersection;
for (var idx = 0; idx < roots.length; idx++) {
if (0 <= roots[idx] && roots[idx] <= 1) {
intersection = calculateCurveAt(roots[idx], field, points);
if (Math.abs(intersection - point[field]) <= range) {
return true;
}
}
}
}
function curveIntersectionsCount(points, point, bbox) {
var polynomial = toCubicPolynomial(points, "x");
var roots = solveCubicEquation(polynomial[0], polynomial[1], polynomial[2], polynomial[3] - point.x);
var rayIntersection, intersectsRay;
var count = 0;
for (var i = 0; i < roots.length; i++) {
rayIntersection = calculateCurveAt(roots[i], "y", points);
intersectsRay = close(rayIntersection, point.y) || rayIntersection > point.y;
if (intersectsRay && (((roots[i] === 0 || roots[i] === 1) && bbox.bottomRight().x > point.x) || (0 < roots[i] && roots[i] < 1))) {
count++;
}
}
return count;
}
function lineIntersectionsCount(a, b, point) {
var intersects;
if (a.x !== b.x) {
var minX = Math.min(a.x, b.x);
var maxX = Math.max(a.x, b.x);
var minY = Math.min(a.y, b.y);
var maxY = Math.max(a.y, b.y);
var inRange = minX <= point.x && point.x < maxX;
if (minY === maxY) {
intersects = point.y <= minY && inRange;
} else {
intersects = inRange && (((maxY - minY) * ((a.x - b.x) * (a.y - b.y) > 0 ? point.x - minX : maxX - point.x)) / (maxX - minX) + minY - point.y) >= 0;
}
}
return intersects ? 1 : 0;
}
var Segment = Class.extend({
init: function(anchor, controlIn, controlOut) {
this.anchor(anchor || new Point());
this.controlIn(controlIn);
this.controlOut(controlOut);
},
bboxTo: function(toSegment, matrix) {
var segmentAnchor = this.anchor().transformCopy(matrix);
var toSegmentAnchor = toSegment.anchor().transformCopy(matrix);
var rect;
if (this.controlOut() && toSegment.controlIn()) {
rect = this._curveBoundingBox(
segmentAnchor, this.controlOut().transformCopy(matrix),
toSegment.controlIn().transformCopy(matrix), toSegmentAnchor
);
} else {
rect = this._lineBoundingBox(segmentAnchor, toSegmentAnchor);
}
return rect;
},
_lineBoundingBox: function(p1, p2) {
return Rect.fromPoints(p1, p2);
},
_curveBoundingBox: function(p1, cp1, cp2, p2) {
var points = [ p1, cp1, cp2, p2 ];
var extremesX = this._curveExtremesFor(points, "x");
var extremesY = this._curveExtremesFor(points, "y");
var xLimits = arrayLimits([ extremesX.min, extremesX.max, p1.x, p2.x ]);
var yLimits = arrayLimits([ extremesY.min, extremesY.max, p1.y, p2.y ]);
return Rect.fromPoints(new Point(xLimits.min, yLimits.min), new Point(xLimits.max, yLimits.max));
},
_curveExtremesFor: function(points, field) {
var extremes = this._curveExtremes(
points[0][field], points[1][field],
points[2][field], points[3][field]
);
return {
min: calculateCurveAt(extremes.min, field, points),
max: calculateCurveAt(extremes.max, field, points)
};
},
_curveExtremes: function(x1, x2, x3, x4) {
var a = x1 - 3 * x2 + 3 * x3 - x4;
var b = - 2 * (x1 - 2 * x2 + x3);
var c = x1 - x2;
var sqrt = Math.sqrt(b * b - 4 * a * c);
var t1 = 0;
var t2 = 1;
if (a === 0) {
if (b !== 0) {
t1 = t2 = -c / b;
}
} else if (!isNaN(sqrt)) {
t1 = (- b + sqrt) / (2 * a);
t2 = (- b - sqrt) / (2 * a);
}
var min = Math.max(Math.min(t1, t2), 0);
if (min < 0 || min > 1) {
min = 0;
}
var max = Math.min(Math.max(t1, t2), 1);
if (max > 1 || max < 0) {
max = 1;
}
return {
min: min,
max: max
};
},
_intersectionsTo: function(segment, point) {
var intersectionsCount;
if (this.controlOut() && segment.controlIn()) {
intersectionsCount = curveIntersectionsCount([ this.anchor(), this.controlOut(), segment.controlIn(), segment.anchor() ], point, this.bboxTo(segment));
} else {
intersectionsCount = lineIntersectionsCount(this.anchor(), segment.anchor(), point);
}
return intersectionsCount;
},
_isOnCurveTo: function(segment, point, width, endSegment) {
var bbox = this.bboxTo(segment).expand(width, width);
if (bbox.containsPoint(point)) {
var p1 = this.anchor();
var p2 = this.controlOut();
var p3 = segment.controlIn();
var p4 = segment.anchor();
if (endSegment === "start" && p1.distanceTo(point) <= width) {
return !isOutOfEndPoint(p1, p2, point);
} else if (endSegment === "end" && p4.distanceTo(point) <= width) {
return !isOutOfEndPoint(p4, p3, point);
}
//the approach is not entirely correct but is close and the alternatives are solving a 6th degree polynomial or testing the segment points
var points = [ p1, p2, p3, p4 ];
if (hasRootsInRange(points, point, "x", "y", width) || hasRootsInRange(points, point, "y", "x", width)) {
return true;
}
var rotation = transform().rotate(45, point);
var rotatedPoints = [ p1.transformCopy(rotation), p2.transformCopy(rotation), p3.transformCopy(rotation), p4.transformCopy(rotation) ];
return hasRootsInRange(rotatedPoints, point, "x", "y", width) || hasRootsInRange(rotatedPoints, point, "y", "x", width);
}
},
_isOnLineTo: function(segment, point, width) {
var p1 = this.anchor();
var p2 = segment.anchor();
var angle = deg(Math.atan2(p2.y - p1.y, p2.x - p1.x));
var rect = new Rect([ p1.x, p1.y - width / 2 ], [ p1.distanceTo(p2), width ]);
return rect.containsPoint(point.transformCopy(transform().rotate(-angle, p1)));
},
_isOnPathTo: function(segment, point, width, endSegment) {
var isOnPath;
if (this.controlOut() && segment.controlIn()) {
isOnPath = this._isOnCurveTo(segment, point, width / 2, endSegment);
} else {
isOnPath = this._isOnLineTo(segment, point, width);
}
return isOnPath;
}
});
definePointAccessors(Segment.prototype, [ "anchor", "controlIn", "controlOut" ]);
ObserversMixin.extend(Segment.prototype);
function arrayLimits(arr) {
var length = arr.length;
var min = MAX_NUM;
var max = MIN_NUM;
for (var i = 0; i < length; i ++) {
max = Math.max(max, arr[i]);
min = Math.min(min, arr[i]);
}
return {
min: min,
max: max
};
}
function elementsBoundingBox(elements, applyTransform, transformation) {
var boundingBox;
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
if (element.visible()) {
var elementBoundingBox = applyTransform ? element.bbox(transformation) : element.rawBBox();
if (elementBoundingBox) {
if (boundingBox) {
boundingBox = Rect.union(boundingBox, elementBoundingBox);
} else {
boundingBox = elementBoundingBox;
}
}
}
}
return boundingBox;
}
function elementsClippedBoundingBox(elements, transformation) {
var boundingBox;
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
if (element.visible()) {
var elementBoundingBox = element.clippedBBox(transformation);
if (elementBoundingBox) {
if (boundingBox) {
boundingBox = Rect.union(boundingBox, elementBoundingBox);
} else {
boundingBox = elementBoundingBox;
}
}
}
}
return boundingBox;
}
var MultiPath = Element$1.extend({
init: function(options) {
Element$1.fn.init.call(this, options);
this.paths = new GeometryElementsArray();
this.paths.addObserver(this);
if (!defined(this.options.stroke)) {
this.stroke("#000");
}
},
moveTo: function(x, y) {
var path = new Path();
path.moveTo(x, y);
this.paths.push(path);
return this;
},
lineTo: function(x, y) {
if (this.paths.length > 0) {
last(this.paths).lineTo(x, y);
}
return this;
},
curveTo: function(controlOut, controlIn, point) {
if (this.paths.length > 0) {
last(this.paths).curveTo(controlOut, controlIn, point);
}
return this;
},
arc: function(startAngle, endAngle, radiusX, radiusY, anticlockwise) {
if (this.paths.length > 0) {
last(this.paths).arc(startAngle, endAngle, radiusX, radiusY, anticlockwise);
}
return this;
},
arcTo: function(end, rx, ry, largeArc, swipe, rotation) {
if (this.paths.length > 0) {
last(this.paths).arcTo(end, rx, ry, largeArc, swipe, rotation);
}
return this;
},
close: function() {
if (this.paths.length > 0) {
last(this.paths).close();
}
return this;
},
_bbox: function(matrix) {
return elementsBoundingBox(this.paths, true, matrix);
},
rawBBox: function() {
return elementsBoundingBox(this.paths, false);
},
_containsPoint: function(point) {
var paths = this.paths;
for (var idx = 0; idx < paths.length; idx++) {
if (paths[idx]._containsPoint(point)) {
return true;
}
}
return false;
},
_isOnPath: function(point) {
var paths = this.paths;
var width = this.options.stroke.width;
for (var idx = 0; idx < paths.length; idx++) {
if (paths[idx]._isOnPath(point, width)) {
return true;
}
}
return false;
},
_clippedBBox: function(transformation) {
return elementsClippedBoundingBox(this.paths, this.currentTransform(transformation));
}
});
MultiPath.prototype.nodeType = "MultiPath";
Paintable.extend(MultiPath.prototype);
Measurable.extend(MultiPath.prototype);
var ShapeMap = {
l: function(path, options) {
var parameters = options.parameters;
var position = options.position;
for (var i = 0; i < parameters.length; i += 2) {
var point = new Point(parameters[i], parameters[i + 1]);
if (options.isRelative) {
point.translateWith(position);
}
path.lineTo(point.x, point.y);
position.x = point.x;
position.y = point.y;
}
},
c: function(path, options) {
var parameters = options.parameters;
var position = options.position;
for (var i = 0; i < parameters.length; i += 6) {
var controlOut = new Point(parameters[i], parameters[i + 1]);
var controlIn = new Point(parameters[i + 2], parameters[i + 3]);
var point = new Point(parameters[i + 4], parameters[i + 5]);
if (options.isRelative) {
controlIn.translateWith(position);
controlOut.translateWith(position);
point.translateWith(position);
}
path.curveTo(controlOut, controlIn, point);
position.x = point.x;
position.y = point.y;
}
},
v: function(path, options) {
var value = options.isRelative ? 0 : options.position.x;
toLineParamaters(options.parameters, true, value);
this.l(path, options);
},
h: function(path, options) {
var value = options.isRelative ? 0 : options.position.y;
toLineParamaters(options.parameters, false, value);
this.l(path, options);
},
a: function(path, options) {
var parameters = options.parameters;
var position = options.position;
for (var i = 0; i < parameters.length; i += 7) {
var radiusX = parameters[i];
var radiusY = parameters[i + 1];
var rotation = parameters[i + 2];
var largeArc = parameters[i + 3];
var swipe = parameters[i + 4];
var endPoint = new Point(parameters[i + 5], parameters[i + 6]);
if (options.isRelative) {
endPoint.translateWith(position);
}
if (position.x !== endPoint.x || position.y !== endPoint.y) {
path.arcTo(endPoint, radiusX, radiusY, largeArc, swipe, rotation);
position.x = endPoint.x;
position.y = endPoint.y;
}
}
},
s: function(path, options) {
var parameters = options.parameters;
var position = options.position;
var previousCommand = options.previousCommand;
var lastControlIn;
if (previousCommand === "s" || previousCommand === "c") {
lastControlIn = last(last(path.paths).segments).controlIn();
}
for (var i = 0; i < parameters.length; i += 4) {
var controlIn = new Point(parameters[i], parameters[i + 1]);
var endPoint = new Point(parameters[i + 2], parameters[i + 3]);
var controlOut = (void 0);
if (options.isRelative) {
controlIn.translateWith(position);
endPoint.translateWith(position);
}
if (lastControlIn) {
controlOut = reflectionPoint(lastControlIn, position);
} else {
controlOut = position.clone();
}
lastControlIn = controlIn;
path.curveTo(controlOut, controlIn, endPoint);
position.x = endPoint.x;
position.y = endPoint.y;
}
},
q: function(path, options) {
var parameters = options.parameters;
var position = options.position;
for (var i = 0; i < parameters.length; i += 4) {
var controlPoint = new Point(parameters[i], parameters[i + 1]);
var endPoint = new Point(parameters[i + 2], parameters[i + 3]);
if (options.isRelative) {
controlPoint.translateWith(position);
endPoint.translateWith(position);
}
var cubicControlPoints = quadraticToCubicControlPoints(position, controlPoint, endPoint);
path.curveTo(cubicControlPoints.controlOut, cubicControlPoints.controlIn, endPoint);
position.x = endPoint.x;
position.y = endPoint.y;
}
},
t: function(path, options) {
var parameters = options.parameters;
var position = options.position;
var previousCommand = options.previousCommand;
var controlPoint;
if (previousCommand === "q" || previousCommand === "t") {
var lastSegment = last(last(path.paths).segments);
controlPoint = lastSegment.controlIn().clone()
.translateWith(position.scaleCopy(-1 / 3))
.scale(3 / 2);
}
for (var i = 0; i < parameters.length; i += 2) {
var endPoint = new Point(parameters[i], parameters[i + 1]);
if (options.isRelative) {
endPoint.translateWith(position);
}
if (controlPoint) {
controlPoint = reflectionPoint(controlPoint, position);
} else {
controlPoint = position.clone();
}
var cubicControlPoints = quadraticToCubicControlPoints(position, controlPoint, endPoint);
path.curveTo(cubicControlPoints.controlOut, cubicControlPoints.controlIn, endPoint);
position.x = endPoint.x;
position.y = endPoint.y;
}
}
};
function toLineParamaters(parameters, isVertical, value) {
var insertPosition = isVertical ? 0 : 1;
for (var i = 0; i < parameters.length; i += 2) {
parameters.splice(i + insertPosition, 0, value);
}
}
function reflectionPoint(point, center) {
if (point && center) {
return center.scaleCopy(2).translate(-point.x, -point.y);
}
}
var third = 1 / 3;
function quadraticToCubicControlPoints(position, controlPoint, endPoint) {
var scaledPoint = controlPoint.clone().scale(2 / 3);
return {
controlOut: scaledPoint.clone().translateWith(position.scaleCopy(third)),
controlIn: scaledPoint.translateWith(endPoint.scaleCopy(third))
};
}
var SEGMENT_REGEX = /([a-df-z]{1})([^a-df-z]*)(z)?/gi;
var SPLIT_REGEX = /[,\s]?([+\-]?(?:\d*\.\d+|\d+)(?:[eE][+\-]?\d+)?)/g;
var MOVE = "m";
var CLOSE = "z";
function parseParameters(str) {
var parameters = [];
str.replace(SPLIT_REGEX, function(match, number) {
parameters.push(parseFloat(number));
});
return parameters;
}
var PathParser = Class.extend({
parse: function(str, options) {
var multiPath = new MultiPath(options);
var position = new Point();
var previousCommand;
str.replace(SEGMENT_REGEX, function (match, element, params, closePath) {
var command = element.toLowerCase();
var isRelative = command === element;
var parameters = parseParameters(params.trim());
if (command === MOVE) {
if (isRelative) {
position.x += parameters[0];
position.y += parameters[1];
} else {
position.x = parameters[0];
position.y = parameters[1];
}
multiPath.moveTo(position.x, position.y);
if (parameters.length > 2) {
command = "l";
parameters.splice(0, 2);
}
}
if (ShapeMap[command]) {
ShapeMap[command](
multiPath, {
parameters: parameters,
position: position,
isRelative: isRelative,
previousCommand: previousCommand
}
);
if (closePath && closePath.toLowerCase() === CLOSE) {
multiPath.close();
}
} else if (command !== MOVE) {
throw new Error("Error while parsing SVG path. Unsupported command: " + command);
}
previousCommand = command;
});
return multiPath;
}
});
PathParser.current = new PathParser();
var Path = Element$1.extend({
init: function(options) {
Element$1.fn.init.call(this, options);
this.segments = new GeometryElementsArray();
this.segments.addObserver(this);
if (!defined(this.options.stroke)) {
this.stroke("#000");
if (!defined(this.options.stroke.lineJoin)) {
this.options.set("stroke.lineJoin", "miter");
}
}
},
moveTo: function(x, y) {
this.suspend();
this.segments.elements([]);
this.resume();
this.lineTo(x, y);
return this;
},
lineTo: function(x, y) {
var point = defined(y) ? new Point(x, y) : x;
var segment = new Segment(point);
this.segments.push(segment);
return this;
},
curveTo: function(controlOut, controlIn, point) {
if (this.segments.length > 0) {
var lastSegment = last(this.segments);
var segment = new Segment(point, controlIn);
this.suspend();
lastSegment.controlOut(controlOut);
this.resume();
this.segments.push(segment);
}
return this;
},
arc: function(startAngle, endAngle, radiusX, radiusY, anticlockwise) {
if (this.segments.length > 0) {
var lastSegment = last(this.segments);
var anchor = lastSegment.anchor();
var start = rad(startAngle);
var center = new Point(anchor.x - radiusX * Math.cos(start),
anchor.y - radiusY * Math.sin(start));
var arc = new Arc$2(center, {
startAngle: startAngle,
endAngle: endAngle,
radiusX: radiusX,
radiusY: radiusY,
anticlockwise: anticlockwise
});
this._addArcSegments(arc);
}
return this;
},
arcTo: function(end, rx, ry, largeArc, swipe, rotation) {
if (this.segments.length > 0) {
var lastSegment = last(this.segments);
var anchor = lastSegment.anchor();
var arc = Arc$2.fromPoints(anchor, end, rx, ry, largeArc, swipe, rotation);
this._addArcSegments(arc);
}
return this;
},
_addArcSegments: function(arc) {
var this$1 = this;
this.suspend();
var curvePoints = arc.curvePoints();
for (var i = 1; i < curvePoints.length; i += 3) {
this$1.curveTo(curvePoints[i], curvePoints[i + 1], curvePoints[i + 2]);
}
this.resume();
this.geometryChange();
},
close: function() {
this.options.closed = true;
this.geometryChange();
return this;
},
rawBBox: function() {
return this._bbox();
},
_containsPoint: function(point) {
var segments = this.segments;
var length = segments.length;
var intersectionsCount = 0;
var previous, current;
for (var idx = 1; idx < length; idx++) {
previous = segments[idx - 1];
current = segments[idx];
intersectionsCount += previous._intersectionsTo(current, point);
}
if (this.options.closed || !segments[0].anchor().equals(segments[length - 1].anchor())) {
intersectionsCount += lineIntersectionsCount(segments[0].anchor(), segments[length - 1].anchor(), point);
}
return intersectionsCount % 2 !== 0;
},
_isOnPath: function(point, width) {
var segments = this.segments;
var length = segments.length;
var pathWidth = width || this.options.stroke.width;
if (length > 1) {
if (segments[0]._isOnPathTo(segments[1], point, pathWidth, "start")) {
return true;
}
for (var idx = 2; idx <= length - 2; idx++) {
if (segments[idx - 1]._isOnPathTo(segments[idx], point, pathWidth)) {
return true;
}
}
if (segments[length - 2]._isOnPathTo(segments[length - 1], point, pathWidth, "end")) {
return true;
}
}
return false;
},
_bbox: function(matrix) {
var segments = this.segments;
var length = segments.length;
var boundingBox;
if (length === 1) {
var anchor = segments[0].anchor().transformCopy(matrix);
boundingBox = new Rect(anchor, Size.ZERO);
} else if (length > 0) {
for (var i = 1; i < length; i++) {
var segmentBox = segments[i - 1].bboxTo(segments[i], matrix);
if (boundingBox) {
boundingBox = Rect.union(boundingBox, segmentBox);
} else {
boundingBox = segmentBox;
}
}
}
return boundingBox;
}
});
Path.fromRect = function(rect, options) {
return new Path(options)
.moveTo(rect.topLeft())
.lineTo(rect.topRight())
.lineTo(rect.bottomRight())
.lineTo(rect.bottomLeft())
.close();
};
Path.fromPoints = function(points, options) {
if (points) {
var path = new Path(options);
for (var i = 0; i < points.length; i++) {
var point = Point.create(points[i]);
if (point) {
if (i === 0) {
path.moveTo(point);
} else {
path.lineTo(point);
}
}
}
return path;
}
};
Path.fromArc = function(arc, options) {
var path = new Path(options);
var startAngle = arc.startAngle;
var start = arc.pointAt(startAngle);
path.moveTo(start.x, start.y);
path.arc(startAngle, arc.endAngle, arc.radiusX, arc.radiusY, arc.anticlockwise);
return path;
};
Path.prototype.nodeType = "Path";
Paintable.extend(Path.prototype);
Measurable.extend(Path.prototype);
Path.parse = function(str, options) {
return PathParser.current.parse(str, options);
};
var DEFAULT_STROKE$1 = "#000";
var Arc = Element$1.extend({
init: function(geometry, options) {
if (geometry === void 0) { geometry = new Arc$2(); }
if (options === void 0) { options = {}; }
Element$1.fn.init.call(this, options);
this.geometry(geometry);
if (!defined(this.options.stroke)) {
this.stroke(DEFAULT_STROKE$1);
}
},
_bbox: function(matrix) {
return this._geometry.bbox(matrix);
},
rawBBox: function() {
return this.geometry().bbox();
},
toPath: function() {
var path = new Path();
var curvePoints = this.geometry().curvePoints();
if (curvePoints.length > 0) {
path.moveTo(curvePoints[0].x, curvePoints[0].y);
for (var i = 1; i < curvePoints.length; i += 3) {
path.curveTo(curvePoints[i], curvePoints[i + 1], curvePoints[i + 2]);
}
}
return path;
},
_containsPoint: function(point) {
return this.geometry().containsPoint(point);
},
_isOnPath: function(point) {
return this.geometry()._isOnPath(point, this.options.stroke.width / 2);
}
});
Arc.prototype.nodeType = "Arc";
Paintable.extend(Arc.prototype);
Measurable.extend(Arc.prototype);
defineGeometryAccessors(Arc.prototype, [ "geometry" ]);
var DEFAULT_FONT = "12px sans-serif";
var DEFAULT_FILL = "#000";
var Text = Element$1.extend({
init: function(content, position, options) {
if (position === void 0) { position = new Point(); }
if (options === void 0) { options = {}; }
Element$1.fn.init.call(this, options);
this.content(content);
this.position(position);
if (!this.options.font) {
this.options.font = DEFAULT_FONT;
}
if (!defined(this.options.fill)) {
this.fill(DEFAULT_FILL);
}
},
content: function(value) {
if (defined(value)) {
this.options.set("content", value);
return this;
}
return this.options.get("content");
},
measure: function() {
var metrics = kendoUtil.measureText(this.content(), {
font: this.options.get("font")
});
return metrics;
},
rect: function() {
var size = this.measure();
var pos = this.position().clone();
return new Rect(pos, [ size.width, size.height ]);
},
bbox: function(transformation) {
var combinedMatrix = toMatrix(this.currentTransform(transformation));
return this.rect().bbox(combinedMatrix);
},
rawBBox: function() {
return this.rect().bbox();
},
_containsPoint: function(point) {
return this.rect().containsPoint(point);
}
});
Text.prototype.nodeType = "Text";
Paintable.extend(Text.prototype);
definePointAccessors(Text.prototype, [ "position" ]);
var Image$1 = Element$1.extend({
init: function(src, rect, options) {
if (rect === void 0) { rect = new Rect(); }
if (options === void 0) { options = {}; }
Element$1.fn.init.call(this, options);
this.src(src);
this.rect(rect);
},
src: function(value) {
if (defined(value)) {
this.options.set("src", value);
return this;
}
return this.options.get("src");
},
bbox: function(transformation) {
var combinedMatrix = toMatrix(this.currentTransform(transformation));
return this._rect.bbox(combinedMatrix);
},
rawBBox: function() {
return this._rect.bbox();
},
_containsPoint: function(point) {
return this._rect.containsPoint(point);
},
_hasFill: function() {
return this.src();
}
});
Image$1.prototype.nodeType = "Image";
defineGeometryAccessors(Image$1.prototype, [ "rect" ]);
var Traversable = {
extend: function(proto, childrenField) {
proto.traverse = function(callback) {
var children = this[childrenField];
for (var i = 0; i < children.length; i++) {
var child = children[i];
if (child.traverse) {
child.traverse(callback);
} else {
callback(child);
}
}
return this;
};
}
};
var Group = Element$1.extend({
init: function(options) {
Element$1.fn.init.call(this, options);
this.children = [];
},
childrenChange: function(action, items, index) {
this.trigger("childrenChange",{
action: action,
items: items,
index: index
});
},
append: function() {
append(this.children, arguments);
this._reparent(arguments, this);
this.childrenChange("add", arguments);
return this;
},
insert: function(index, element) {
this.children.splice(index, 0, element);
element.parent = this;
this.childrenChange("add", [ element ], index);
return this;
},
insertAt: function(element, index) {
return this.insert(index, element);
},
remove: function(element) {
var index = this.children.indexOf(element);
if (index >= 0) {
this.children.splice(index, 1);
element.parent = null;
this.childrenChange("remove", [ element ], index);
}
return this;
},
removeAt: function(index) {
if (0 <= index && index < this.children.length) {
var element = this.children[index];
this.children.splice(index, 1);
element.parent = null;
this.childrenChange("remove", [ element ], index);
}
return this;
},
clear: function() {
var items = this.children;
this.children = [];
this._reparent(items, null);
this.childrenChange("remove", items, 0);
return this;
},
bbox: function(transformation) {
return elementsBoundingBox(this.children, true, this.currentTransform(transformation));
},
rawBBox: function() {
return elementsBoundingBox(this.children, false);
},
_clippedBBox: function(transformation) {
return elementsClippedBoundingBox(this.children, this.currentTransform(transformation));
},
currentTransform: function(transformation) {
return Element$1.prototype.currentTransform.call(this, transformation) || null;
},
containsPoint: function(point, parentTransform) {
if (this.visible()) {
var children = this.children;
var transform = this.currentTransform(parentTransform);
for (var idx = 0; idx < children.length; idx++) {
if (children[idx].containsPoint(point, transform)) {
return true;
}
}
}
return false;
},
_reparent: function(elements, newParent) {
var this$1 = this;
for (var i = 0; i < elements.length; i++) {
var child = elements[i];
var parent = child.parent;
if (parent && parent !== this$1 && parent.remove) {
parent.remove(child);
}
child.parent = newParent;
}
}
});
Group.prototype.nodeType = "Group";
Traversable.extend(Group.prototype, "children");
function translateToPoint(point, bbox, element) {
var transofrm = element.transform() || transform();
var matrix = transofrm.matrix();
matrix.e += point.x - bbox.origin.x;
matrix.f += point.y - bbox.origin.y;
transofrm.matrix(matrix);
element.transform(transofrm);
}
function alignStart(size, rect, align, axis, sizeField) {
var start;
if (align === "start") {
start = rect.origin[axis];
} else if (align === "end") {
start = rect.origin[axis] + rect.size[sizeField] - size;
} else {
start = rect.origin[axis] + (rect.size[sizeField] - size) / 2;
}
return start;
}
function alignStartReverse(size, rect, align, axis, sizeField) {
var start;
if (align === "start") {
start = rect.origin[axis] + rect.size[sizeField] - size;
} else if (align === "end") {
start = rect.origin[axis];
} else {
start = rect.origin[axis] + (rect.size[sizeField] - size) / 2;
}
return start;
}
var DEFAULT_OPTIONS = {
alignContent: "start",
justifyContent: "start",
alignItems: "start",
spacing: 0,
orientation: "horizontal",
lineSpacing: 0,
wrap: true,
revers: false
};
var forEach = function (elements, callback) {
elements.forEach(callback);
};
var forEachReverse = function (elements, callback) {
var length = elements.length;
for (var idx = length - 1; idx >= 0; idx--) {
callback(elements[idx], idx);
}
};
var Layout = Group.extend({
init: function(rect, options) {
Group.fn.init.call(this, $.extend({}, DEFAULT_OPTIONS, options));
this._rect = rect;
this._fieldMap = {};
},
rect: function(value) {
if (value) {
this._rect = value;
return this;
}
return this._rect;
},
_initMap: function() {
var options = this.options;
var fieldMap = this._fieldMap;
if (options.orientation === "horizontal") {
fieldMap.sizeField = "width";
fieldMap.groupsSizeField = "height";
fieldMap.groupAxis = "x";
fieldMap.groupsAxis = "y";
} else {
fieldMap.sizeField = "height";
fieldMap.groupsSizeField = "width";
fieldMap.groupAxis = "y";
fieldMap.groupsAxis = "x";
}
if (options.reverse) {
this.forEach = forEachReverse;
this.justifyAlign = alignStartReverse;
} else {
this.forEach = forEach;
this.justifyAlign = alignStart;
}
},
reflow: function() {
var this$1 = this;
if (!this._rect || this.children.length === 0) {
return;
}
this._initMap();
if (this.options.transform) {
this.transform(null);
}
var options = this.options;
var rect = this._rect;
var ref = this._initGroups();
var groups = ref.groups;
var groupsSize = ref.groupsSize;
var ref$1 = this._fieldMap;
var sizeField = ref$1.sizeField;
var groupsSizeField = ref$1.groupsSizeField;
var groupAxis = ref$1.groupAxis;
var groupsAxis = ref$1.groupsAxis;
var groupOrigin = new Point();
var elementOrigin = new Point();
var size = new Size();
var groupStart = alignStart(groupsSize, rect, options.alignContent, groupsAxis, groupsSizeField);
var elementStart, group, groupBox;
var arrangeElements = function (bbox, idx) {
var element = group.elements[idx];
elementOrigin[groupAxis] = elementStart;
elementOrigin[groupsAxis] = alignStart(bbox.size[groupsSizeField], groupBox, options.alignItems, groupsAxis, groupsSizeField);
translateToPoint(elementOrigin, bbox, element);
elementStart += bbox.size[sizeField] + options.spacing;
};
for (var groupIdx = 0; groupIdx < groups.length; groupIdx++) {
group = groups[groupIdx];
groupOrigin[groupAxis] = elementStart = this$1.justifyAlign(group.size, rect, options.justifyContent, groupAxis, sizeField);
groupOrigin[groupsAxis] = groupStart;
size[sizeField] = group.size;
size[groupsSizeField] = group.lineSize;
groupBox = new Rect(groupOrigin, size);
this$1.forEach(group.bboxes, arrangeElements);
groupStart += group.lineSize + options.lineSpacing;
}
if (!options.wrap && group.size > rect.size[sizeField]) {
var scale = rect.size[sizeField] / groupBox.size[sizeField];
var scaledStart = groupBox.topLeft().scale(scale, scale);
var scaledSize = groupBox.size[groupsSizeField] * scale;
var newStart = alignStart(scaledSize, rect, options.alignContent, groupsAxis, groupsSizeField);
var transform$$1 = transform();
if (groupAxis === "x") {
transform$$1.translate(rect.origin.x - scaledStart.x, newStart - scaledStart.y);
} else {
transform$$1.translate(newStart - scaledStart.x, rect.origin.y - scaledStart.y);
}
transform$$1.scale(scale, scale);
this.transform(transform$$1);
}
},
_initGroups: function() {
var this$1 = this;
var ref = this;
var options = ref.options;
var children = ref.children;
var lineSpacing = options.lineSpacing;
var wrap = options.wrap;
var spacing = options.spacing;
var sizeField = this._fieldMap.sizeField;
var group = this._newGroup();
var groups = [];
var addGroup = function() {
groups.push(group);
groupsSize += group.lineSize + lineSpacing;
};
var groupsSize = -lineSpacing;
for (var idx = 0; idx < children.length; idx++) {
var element = children[idx];
var bbox = children[idx].clippedBBox();
if (element.visible() && bbox) {
if (wrap && group.size + bbox.size[sizeField] + spacing > this$1._rect.size[sizeField]) {
if (group.bboxes.length === 0) {
this$1._addToGroup(group, bbox, element);
addGroup();
group = this$1._newGroup();
} else {
addGroup();
group = this$1._newGroup();
this$1._addToGroup(group, bbox, element);
}
} else {
this$1._addToGroup(group, bbox, element);
}
}
}
if (group.bboxes.length) {
addGroup();
}
return {
groups: groups,
groupsSize: groupsSize
};
},
_addToGroup: function(group, bbox, element) {
group.size += bbox.size[this._fieldMap.sizeField] + this.options.spacing;
group.lineSize = Math.max(bbox.size[this._fieldMap.groupsSizeField], group.lineSize);
group.bboxes.push(bbox);
group.elements.push(element);
},
_newGroup: function() {
return {
lineSize: 0,
size: -this.options.spacing,
bboxes: [],
elements: []
};
}
});
var Rect$2 = Element$1.extend({
init: function(geometry, options) {
if (geometry === void 0) { geometry = new Rect(); }
if (options === void 0) { options = {}; }
Element$1.fn.init.call(this, options);
this.geometry(geometry);
if (!defined(this.options.stroke)) {
this.stroke("#000");
}
},
_bbox: function(matrix) {
return this._geometry.bbox(matrix);
},
rawBBox: function() {
return this._geometry.bbox();
},
_containsPoint: function(point) {
return this._geometry.containsPoint(point);
},
_isOnPath: function(point) {
return this.geometry()._isOnPath(point, this.options.stroke.width / 2);
}
});
Rect$2.prototype.nodeType = "Rect";
Paintable.extend(Rect$2.prototype);
Measurable.extend(Rect$2.prototype);
defineGeometryAccessors(Rect$2.prototype, [ "geometry" ]);
function alignElements(elements, rect, alignment, axis, sizeField) {
for (var idx = 0; idx < elements.length; idx++) {
var bbox = elements[idx].clippedBBox();
if (bbox) {
var point = bbox.origin.clone();
point[axis] = alignStart(bbox.size[sizeField], rect, alignment || "start", axis, sizeField);
translateToPoint(point, bbox, elements[idx]);
}
}
}
function align(elements, rect, alignment) {
alignElements(elements, rect, alignment, "x", "width");
}
function vAlign(elements, rect, alignment) {
alignElements(elements, rect, alignment, "y", "height");
}
function stackElements(elements, stackAxis, otherAxis, sizeField) {
if (elements.length > 1) {
var origin = new Point();
var previousBBox = elements[0].bbox;
for (var idx = 1; idx < elements.length; idx++) {
var element = elements[idx].element;
var bbox = elements[idx].bbox;
origin[stackAxis] = previousBBox.origin[stackAxis] + previousBBox.size[sizeField];
origin[otherAxis] = bbox.origin[otherAxis];
translateToPoint(origin, bbox, element);
bbox.origin[stackAxis] = origin[stackAxis];
previousBBox = bbox;
}
}
}
function createStackElements(elements) {
var stackElements = [];
for (var idx = 0; idx < elements.length; idx++) {
var element = elements[idx];
var bbox = element.clippedBBox();
if (bbox) {
stackElements.push({
element: element,
bbox: bbox
});
}
}
return stackElements;
}
function stack(elements) {
stackElements(createStackElements(elements), "x", "y", "width");
}
function vStack(elements) {
stackElements(createStackElements(elements), "y", "x", "height");
}
function getStacks(elements, rect, sizeField) {
var maxSize = rect.size[sizeField];
var stacks = [];
var stack = [];
var stackSize = 0;
var element, bbox;
var addElementToStack = function() {
stack.push({
element: element,
bbox: bbox
});
};
for (var idx = 0; idx < elements.length; idx++) {
element = elements[idx];
bbox = element.clippedBBox();
if (bbox) {
var size = bbox.size[sizeField];
if (stackSize + size > maxSize) {
if (stack.length) {
stacks.push(stack);
stack = [];
addElementToStack();
stackSize = size;
} else {
addElementToStack();
stacks.push(stack);
stack = [];
stackSize = 0;
}
} else {
addElementToStack();
stackSize += size;
}
}
}
if (stack.length) {
stacks.push(stack);
}
return stacks;
}
function wrapElements(elements, rect, axis, otherAxis, sizeField) {
var stacks = getStacks(elements, rect, sizeField);
var origin = rect.origin.clone();
var result = [];
for (var idx = 0; idx < stacks.length; idx++) {
var stack = stacks[idx];
var startElement = stack[0];
origin[otherAxis] = startElement.bbox.origin[otherAxis];
translateToPoint(origin, startElement.bbox, startElement.element);
startElement.bbox.origin[axis] = origin[axis];
stackElements(stack, axis, otherAxis, sizeField);
result.push([]);
for (var elementIdx = 0; elementIdx < stack.length; elementIdx++) {
result[idx].push(stack[elementIdx].element);
}
}
return result;
}
function wrap(elements, rect) {
return wrapElements(elements, rect, "x", "y", "width");
}
function vWrap(elements, rect) {
return wrapElements(elements, rect, "y", "x", "height");
}
function fit(element, rect) {
var bbox = element.clippedBBox();
if (bbox) {
var elementSize = bbox.size;
var rectSize = rect.size;
if (rectSize.width < elementSize.width || rectSize.height < elementSize.height) {
var scale = Math.min(rectSize.width / elementSize.width, rectSize.height / elementSize.height);
var transform$$1 = element.transform() || transform();
transform$$1.scale(scale, scale);
element.transform(transform$$1);
}
}
}
var StopsArray = ElementsArray.extend({
_change: function() {
this.optionsChange({
field: "stops"
});
}
});
function optionsAccessor(name) {
return function(value) {
if (defined(value)) {
this.options.set(name, value);
return this;
}
return this.options.get(name);
};
}
function defineOptionsAccessors(fn, names) {
for (var i = 0; i < names.length; i++) {
fn[names[i]] = optionsAccessor(names[i]);
}
}
var GradientStop = Class.extend({
init: function(offset, color, opacity) {
this.options = new OptionsStore({
offset: offset,
color: color,
opacity: defined(opacity) ? opacity : 1
});
this.options.addObserver(this);
}
});
GradientStop.create = function(arg) {
if (defined(arg)) {
var stop;
if (arg instanceof GradientStop) {
stop = arg;
} else if (arg.length > 1) {
stop = new GradientStop(arg[0], arg[1], arg[2]);
} else {
stop = new GradientStop(arg.offset, arg.color, arg.opacity);
}
return stop;
}
};
defineOptionsAccessors(GradientStop.prototype, [ "offset", "color", "opacity" ]);
ObserversMixin.extend(GradientStop.prototype);
var Gradient = Class.extend({
init: function(options) {
if (options === void 0) { options = {}; }
this.stops = new StopsArray(this._createStops(options.stops));
this.stops.addObserver(this);
this._userSpace = options.userSpace;
this.id = definitionId();
},
userSpace: function(value) {
if (defined(value)) {
this._userSpace = value;
this.optionsChange();
return this;
}
return this._userSpace;
},
_createStops: function(stops) {
if (stops === void 0) { stops = []; }
var result = [];
for (var idx = 0; idx < stops.length; idx++) {
result.push(GradientStop.create(stops[idx]));
}
return result;
},
addStop: function(offset, color, opacity) {
this.stops.push(new GradientStop(offset, color, opacity));
},
removeStop: function(stop) {
var index = this.stops.indexOf(stop);
if (index >= 0) {
this.stops.splice(index, 1);
}
}
});
Gradient.prototype.nodeType = "Gradient";
ObserversMixin.extend(Gradient.prototype);
$.extend(Gradient.prototype, {
optionsChange: function(e) {
this.trigger("optionsChange", {
field: "gradient" + (e ? "." + e.field : ""),
value: this
});
},
geometryChange: function() {
this.optionsChange();
}
});
var LinearGradient = Gradient.extend({
init: function(options) {
if (options === void 0) { options = {}; }
Gradient.fn.init.call(this, options);
this.start(options.start || new Point());
this.end(options.end || new Point(1, 0));
}
});
definePointAccessors(LinearGradient.prototype, [ "start", "end" ]);
var RadialGradient = Gradient.extend({
init: function(options) {
if (options === void 0) { options = {}; }
Gradient.fn.init.call(this, options);
this.center(options.center || new Point());
this._radius = defined(options.radius) ? options.radius : 1;
this._fallbackFill = options.fallbackFill;
},
radius: function(value) {
if (defined(value)) {
this._radius = value;
this.geometryChange();
return this;
}
return this._radius;
},
fallbackFill: function(value) {
if (defined(value)) {
this._fallbackFill = value;
this.optionsChange();
return this;
}
return this._fallbackFill;
}
});
definePointAccessors(RadialGradient.prototype, [ "center" ]);
function swing(position) {
return 0.5 - Math.cos(position * Math.PI) / 2;
}
function linear(position) {
return position;
}
function easeOutElastic(position, time, start, diff) {
var s = 1.70158,
p = 0,
a = diff;
if (position === 0) {
return start;
}
if (position === 1) {
return start + diff;
}
if (!p) {
p = 0.5;
}
if (a < Math.abs(diff)) {
a = diff;
s = p / 4;
} else {
s = p / (2 * Math.PI) * Math.asin(diff / a);
}
return a * Math.pow(2, -10 * position) *
Math.sin((Number(position) - s) * (1.1 * Math.PI) / p) + diff + start;
}
var easingFunctions = {
swing: swing,
linear: linear,
easeOutElastic: easeOutElastic
};
var AnimationFactory = Class.extend({
init: function() {
this._items = [];
},
register: function(name, type) {
this._items.push({
name: name,
type: type
});
},
create: function(element, options) {
var items = this._items;
var match;
if (options && options.type) {
var type = options.type.toLowerCase();
for (var i = 0; i < items.length; i++) {
if (items[i].name.toLowerCase() === type) {
match = items[i];
break;
}
}
}
if (match) {
return new match.type(element, options);
}
}
});
AnimationFactory.current = new AnimationFactory();
var now = Date.now || function() {
return new Date().getTime();
};
var Animation = Class.extend({
init: function(element, options) {
this.options = $.extend({}, this.options, options);
this.element = element;
},
setup: function() {},
step: function() {},
play: function() {
var this$1 = this;
var options = this.options;
var duration = options.duration;
var delay = options.delay; if (delay === void 0) { delay = 0; }
var easing = easingFunctions[options.easing];
var start = now() + delay;
var finish = start + duration;
if (duration === 0) {
this.step(1);
this.abort();
} else {
setTimeout(function () {
var loop = function () {
if (this$1._stopped) {
return;
}
var wallTime = now();
var time = limitValue(wallTime - start, 0, duration);
var position = time / duration;
var easingPosition = easing(position, time, 0, 1, duration);
this$1.step(easingPosition);
if (wallTime < finish) {
kendo.animationFrame(loop);
} else {
this$1.abort();
}
};
loop();
}, delay);
}
},
abort: function() {
this._stopped = true;
},
destroy: function() {
this.abort();
}
});
Animation.prototype.options = {
duration: 500,
easing: "swing"
};
Animation.create = function(type, element, options) {
return AnimationFactory.current.create(type, element, options);
};
var SurfaceFactory = Class.extend({
init: function() {
this._items = [];
},
register: function(name, type, order) {
var items = this._items;
var first = items[0];
var entry = {
name: name,
type: type,
order: order
};
if (!first || order < first.order) {
items.unshift(entry);
} else {
items.push(entry);
}
},
create: function(element, options) {
var items = this._items;
var match = items[0];
if (options && options.type) {
var preferred = options.type.toLowerCase();
for (var i = 0; i < items.length; i++) {
if (items[i].name === preferred) {
match = items[i];
break;
}
}
}
if (match) {
return new match.type(element, options);
}
kendo.logToConsole(
"Warning: Unable to create Kendo UI Drawing Surface. Possible causes:\n" +
"- The browser does not support SVG and Canvas. User agent: " + (navigator.userAgent));
}
});
SurfaceFactory.current = new SurfaceFactory();
var events = [
"click",
"mouseenter",
"mouseleave",
"mousemove",
"resize"
];
var Surface = kendo.Observable.extend({
init: function(element, options) {
kendo.Observable.fn.init.call(this);
this.options = $.extend({}, options);
this.element = element;
this.element._kendoExportVisual = this.exportVisual.bind(this);
this._click = this._handler("click");
this._mouseenter = this._handler("mouseenter");
this._mouseleave = this._handler("mouseleave");
this._mousemove = this._handler("mousemove");
this._visual = new Group();
elementSize(element, this.options);
this.bind(events, this.options);
this._enableTracking();
},
draw: function(element) {
this._visual.children.push(element);
},
clear: function() {
this._visual.children = [];
},
destroy: function() {
this._visual = null;
this.element._kendoExportVisual = null;
this.unbind();
},
eventTarget: function(e) {
var this$1 = this;
var domNode = eventElement(e);
var node;
while (!node && domNode) {
node = domNode._kendoNode;
if (domNode === this$1.element) {
break;
}
domNode = domNode.parentElement;
}
if (node) {
return node.srcElement;
}
},
exportVisual: function() {
return this._visual;
},
getSize: function() {
return elementSize(this.element);
},
currentSize: function(size) {
if (size) {
this._size = size;
} else {
return this._size;
}
},
setSize: function(size) {
elementSize(this.element, size);
this.currentSize(size);
this._resize();
},
resize: function(force) {
var size = this.getSize();
var currentSize = this.currentSize();
if (force || (size.width > 0 || size.height > 0) && (!currentSize || size.width !== currentSize.width || size.height !== currentSize.height)) {
this.currentSize(size);
this._resize(size, force);
this.trigger("resize", size);
}
},
size: function(value) {
if (!value) {
return this.getSize();
}
this.setSize(value);
},
suspendTracking: function() {
this._suspendedTracking = true;
},
resumeTracking: function() {
this._suspendedTracking = false;
},
_enableTracking: function() {},
_resize: function() {},
_handler: function(eventName) {
var this$1 = this;
return function (e) {
var node = this$1.eventTarget(e);
if (node && !this$1._suspendedTracking) {
this$1.trigger(eventName, {
element: node,
originalEvent: e,
type: eventName
});
}
};
},
_elementOffset: function() {
var element = this.element;
var ref = elementStyles(element, [ "paddingLeft", "paddingTop" ]);
var paddingLeft = ref.paddingLeft;
var paddingTop = ref.paddingTop;
var ref$1 = elementOffset(element);
var left = ref$1.left;
var top = ref$1.top;
return {
left: left + parseInt(paddingLeft, 10),
top: top + parseInt(paddingTop, 10)
};
},
_surfacePoint: function(e) {
var offset = this._elementOffset();
var coord = eventCoordinates(e);
var x = coord.x - offset.left;
var y = coord.y - offset.top;
return new Point(x, y);
}
});
Surface.create = function(element, options) {
return SurfaceFactory.current.create(element, options);
};
Surface.support = {};
var BaseNode = Class.extend({
init: function(srcElement) {
this.childNodes = [];
this.parent = null;
if (srcElement) {
this.srcElement = srcElement;
this.observe();
}
},
destroy: function() {
var this$1 = this;
if (this.srcElement) {
this.srcElement.removeObserver(this);
}
var children = this.childNodes;
for (var i = 0; i < children.length; i++) {
this$1.childNodes[i].destroy();
}
this.parent = null;
},
load: function() {},
observe: function() {
if (this.srcElement) {
this.srcElement.addObserver(this);
}
},
append: function(node) {
this.childNodes.push(node);
node.parent = this;
},
insertAt: function(node, pos) {
this.childNodes.splice(pos, 0, node);
node.parent = this;
},
remove: function(index, count) {
var this$1 = this;
var end = index + count;
for (var i = index; i < end; i++) {
this$1.childNodes[i].removeSelf();
}
this.childNodes.splice(index, count);
},
removeSelf: function() {
this.clear();
this.destroy();
},
clear: function() {
this.remove(0, this.childNodes.length);
},
invalidate: function() {
if (this.parent) {
this.parent.invalidate();
}
},
geometryChange: function() {
this.invalidate();
},
optionsChange: function() {
this.invalidate();
},
childrenChange: function(e) {
if (e.action === "add") {
this.load(e.items, e.index);
} else if (e.action === "remove") {
this.remove(e.index, e.items.length);
}
this.invalidate();
}
});
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;
}
}
var NODE_MAP = {};
var SVG_NS = "http://www.w3.org/2000/svg";
var NONE = "none";
var renderSVG = function(container, svg) {
container.innerHTML = svg;
};
if (typeof document !== "undefined") {
var testFragment = "<svg xmlns='" + SVG_NS + "'></svg>";
var testContainer = document.createElement("div");
var hasParser = typeof DOMParser !== "undefined";
testContainer.innerHTML = testFragment;
if (hasParser && testContainer.firstChild.namespaceURI !== SVG_NS) {
renderSVG = function(container, svg) {
var parser = new DOMParser();
var chartDoc = parser.parseFromString(svg, "text/xml");
var importedDoc = document.adoptNode(chartDoc.documentElement);
container.innerHTML = "";
container.appendChild(importedDoc);
};
}
}
var renderSVG$1 = renderSVG;
var TRANSFORM = "transform";
var DefinitionMap = {
clip: "clip-path",
fill: "fill"
};
function isDefinition(type, value) {
return type === "clip" || (type === "fill" && (!value || value.nodeType === "Gradient"));
}
function baseUrl() {
var base = document.getElementsByTagName("base")[0];
var href = document.location.href;
var url = "";
if (base && !supportBrowser.msie) {
var hashIndex = href.indexOf("#");
if (hashIndex !== -1) {
href = href.substring(0, hashIndex);
}
url = href;
}
return url;
}
var Node = BaseNode.extend({
init: function(srcElement, options) {
BaseNode.fn.init.call(this, srcElement);
this.definitions = {};
this.options = options;
},
destroy: function() {
if (this.element) {
this.element._kendoNode = null;
this.element = null;
}
this.clearDefinitions();
BaseNode.fn.destroy.call(this);
},
load: function(elements, pos) {
var this$1 = this;
for (var i = 0; i < elements.length; i++) {
var srcElement = elements[i];
var children = srcElement.children;
var childNode = new NODE_MAP[srcElement.nodeType](srcElement, this$1.options);
if (defined(pos)) {
this$1.insertAt(childNode, pos);
} else {
this$1.append(childNode);
}
childNode.createDefinitions();
if (children && children.length > 0) {
childNode.load(children);
}
var element = this$1.element;
if (element) {
childNode.attachTo(element, pos);
}
}
},
root: function() {
var root = this;
while (root.parent) {
root = root.parent;
}
return root;
},
attachTo: function(domElement, pos) {
var container = document.createElement("div");
renderSVG$1(container,
"<svg xmlns='" + SVG_NS + "' version='1.1'>" +
this.render() +
"</svg>"
);
var element = container.firstChild.firstChild;
if (element) {
if (defined(pos)) {
domElement.insertBefore(element, domElement.childNodes[pos] || null);
} else {
domElement.appendChild(element);
}
this.setElement(element);
}
},
setElement: function(element) {
if (this.element) {
this.element._kendoNode = null;
}
this.element = element;
this.element._kendoNode = this;
var nodes = this.childNodes;
for (var i = 0; i < nodes.length; i++) {
var childElement = element.childNodes[i];
nodes[i].setElement(childElement);
}
},
clear: function() {
this.clearDefinitions();
if (this.element) {
this.element.innerHTML = "";
}
var children = this.childNodes;
for (var i = 0; i < children.length; i++) {
children[i].destroy();
}
this.childNodes = [];
},
removeSelf: function() {
if (this.element) {
var parentNode = this.element.parentNode;
if (parentNode) {
parentNode.removeChild(this.element);
}
this.element = null;
}
BaseNode.fn.removeSelf.call(this);
},
template: function() {
return this.renderChildren();
},
render: function() {
return this.template();
},
renderChildren: function() {
var nodes = this.childNodes;
var output = "";
for (var i = 0; i < nodes.length; i++) {
output += nodes[i].render();
}
return output;
},
optionsChange: function(e) {
var field = e.field;
var value = e.value;
if (field === "visible") {
this.css("display", value ? "" : NONE);
} else if (DefinitionMap[field] && isDefinition(field, value)) {
this.updateDefinition(field, value);
} else if (field === "opacity") {
this.attr("opacity", value);
} else if (field === "cursor") {
this.css("cursor", value);
} else if (field === "id") {
if (value) {
this.attr("id", value);
} else {
this.removeAttr("id");
}
}
BaseNode.fn.optionsChange.call(this, e);
},
attr: function(name, value) {
if (this.element) {
this.element.setAttribute(name, value);
}
},
allAttr: function(attrs) {
var this$1 = this;
for (var i = 0; i < attrs.length; i++) {
this$1.attr(attrs[i][0], attrs[i][1]);
}
},
css: function(name, value) {
if (this.element) {
this.element.style[name] = value;
}
},
allCss: function(styles) {
var this$1 = this;
for (var i = 0; i < styles.length; i++) {
this$1.css(styles[i][0], styles[i][1]);
}
},
removeAttr: function(name) {
if (this.element) {
this.element.removeAttribute(name);
}
},
mapTransform: function(transform) {
var attrs = [];
if (transform) {
attrs.push([
TRANSFORM,
"matrix(" + transform.matrix().toString(6) + ")"
]);
}
return attrs;
},
renderTransform: function() {
return renderAllAttr(
this.mapTransform(this.srcElement.transform())
);
},
transformChange: function(value) {
if (value) {
this.allAttr(this.mapTransform(value));
} else {
this.removeAttr(TRANSFORM);
}
},
mapStyle: function() {
var options = this.srcElement.options;
var style = [ [ "cursor", options.cursor ] ];
if (options.visible === false) {
style.push([ "display", NONE ]);
}
return style;
},
renderStyle: function() {
return renderAttr("style", renderStyle(this.mapStyle(true)));
},
renderOpacity: function() {
return renderAttr("opacity", this.srcElement.options.opacity);
},
renderId: function() {
return renderAttr("id", this.srcElement.options.id);
},
createDefinitions: function() {
var srcElement = this.srcElement;
var definitions = this.definitions;
if (srcElement) {
var options = srcElement.options;
var hasDefinitions;
for (var field in DefinitionMap) {
var definition = options.get(field);
if (definition && isDefinition(field, definition)) {
definitions[field] = definition;
hasDefinitions = true;
}
}
if (hasDefinitions) {
this.definitionChange({
action: "add",
definitions: definitions
});
}
}
},
definitionChange: function(e) {
if (this.parent) {
this.parent.definitionChange(e);
}
},
updateDefinition: function(type, value) {
var definitions = this.definitions;
var current = definitions[type];
var attr = DefinitionMap[type];
var definition = {};
if (current) {
definition[type] = current;
this.definitionChange({
action: "remove",
definitions: definition
});
delete definitions[type];
}
if (!value) {
if (current) {
this.removeAttr(attr);
}
} else {
definition[type] = value;
this.definitionChange({
action: "add",
definitions: definition
});
definitions[type] = value;
this.attr(attr, this.refUrl(value.id));
}
},
clearDefinitions: function() {
var definitions = this.definitions;
this.definitionChange({
action: "remove",
definitions: definitions
});
this.definitions = {};
},
renderDefinitions: function() {
return renderAllAttr(this.mapDefinitions());
},
mapDefinitions: function() {
var this$1 = this;
var definitions = this.definitions;
var attrs = [];
for (var field in definitions) {
attrs.push([ DefinitionMap[field], this$1.refUrl(definitions[field].id) ]);
}
return attrs;
},
refUrl: function(id) {
var skipBaseHref = (this.options || {}).skipBaseHref;
var baseHref = this.baseUrl().replace(/'/g, "\\'");
var base = skipBaseHref ? '' : baseHref;
return ("url(" + base + "#" + id + ")");
},
baseUrl: function() {
return baseUrl();
}
});
var GradientStopNode = Node.extend({
template: function() {
return ("<stop " + (this.renderOffset()) + " " + (this.renderStyle()) + " />");
},
renderOffset: function() {
return renderAttr("offset", this.srcElement.offset());
},
mapStyle: function() {
var srcElement = this.srcElement;
return [
[ "stop-color", srcElement.color() ],
[ "stop-opacity", srcElement.opacity() ]
];
},
optionsChange: function(e) {
if (e.field === "offset") {
this.attr(e.field, e.value);
} else if (e.field === "color" || e.field === "opacity") {
this.css("stop-" + e.field, e.value);
}
}
});
var GradientNode = Node.extend({
init: function(srcElement) {
Node.fn.init.call(this, srcElement);
this.id = srcElement.id;
this.loadStops();
},
loadStops: function() {
var this$1 = this;
var stops = this.srcElement.stops;
var element = this.element;
for (var idx = 0; idx < stops.length; idx++) {
var stopNode = new GradientStopNode(stops[idx]);
this$1.append(stopNode);
if (element) {
stopNode.attachTo(element);
}
}
},
optionsChange: function(e) {
if (e.field === "gradient.stops") {
BaseNode.prototype.clear.call(this);
this.loadStops();
} else if (e.field === "gradient") {
this.allAttr(this.mapCoordinates());
}
},
renderCoordinates: function() {
return renderAllAttr(this.mapCoordinates());
},
mapSpace: function() {
return [ "gradientUnits", this.srcElement.userSpace() ? "userSpaceOnUse" : "objectBoundingBox" ];
}
});
var LinearGradientNode = GradientNode.extend({
template: function() {
return ("<linearGradient id='" + (this.id) + "' " + (this.renderCoordinates()) + ">" + (this.renderChildren()) + "</linearGradient>");
},
mapCoordinates: function() {
var srcElement = this.srcElement;
var start = srcElement.start();
var end = srcElement.end();
var attrs = [
[ "x1", start.x ],
[ "y1", start.y ],
[ "x2", end.x ],
[ "y2", end.y ],
this.mapSpace()
];
return attrs;
}
});
var RadialGradientNode = GradientNode.extend({
template: function() {
return ("<radialGradient id='" + (this.id) + "' " + (this.renderCoordinates()) + ">" + (this.renderChildren()) + "</radialGradient>");
},
mapCoordinates: function() {
var srcElement = this.srcElement;
var center = srcElement.center();
var radius = srcElement.radius();
var attrs = [
[ "cx", center.x ],
[ "cy", center.y ],
[ "r", radius ],
this.mapSpace()
];
return attrs;
}
});
var ClipNode = Node.extend({
init: function(srcElement) {
Node.fn.init.call(this);
this.srcElement = srcElement;
this.id = srcElement.id;
this.load([ srcElement ]);
},
template: function() {
return ("<clipPath id='" + (this.id) + "'>" + (this.renderChildren()) + "</clipPath>");
}
});
var DefinitionNode = Node.extend({
init: function() {
Node.fn.init.call(this);
this.definitionMap = {};
},
attachTo: function(domElement) {
this.element = domElement;
},
template: function() {
return ("<defs>" + (this.renderChildren()) + "</defs>");
},
definitionChange: function(e) {
var definitions = e.definitions;
var action = e.action;
if (action === "add") {
this.addDefinitions(definitions);
} else if (action === "remove") {
this.removeDefinitions(definitions);
}
},
createDefinition: function(type, item) {
var nodeType;
if (type === "clip") {
nodeType = ClipNode;
} else if (type === "fill") {
if (item instanceof LinearGradient) {
nodeType = LinearGradientNode;
} else if (item instanceof RadialGradient) {
nodeType = RadialGradientNode;
}
}
return new nodeType(item);
},
addDefinitions: function(definitions) {
var this$1 = this;
for (var field in definitions) {
this$1.addDefinition(field, definitions[field]);
}
},
addDefinition: function(type, srcElement) {
var ref = this;
var element = ref.element;
var definitionMap = ref.definitionMap;
var id = srcElement.id;
var mapItem = definitionMap[id];
if (!mapItem) {
var node = this.createDefinition(type, srcElement);
definitionMap[id] = {
element: node,
count: 1
};
this.append(node);
if (element) {
node.attachTo(this.element);
}
} else {
mapItem.count++;
}
},
removeDefinitions: function(definitions) {
var this$1 = this;
for (var field in definitions) {
this$1.removeDefinition(definitions[field]);
}
},
removeDefinition: function(srcElement) {
var definitionMap = this.definitionMap;
var id = srcElement.id;
var mapItem = definitionMap[id];
if (mapItem) {
mapItem.count--;
if (mapItem.count === 0) {
this.remove(this.childNodes.indexOf(mapItem.element), 1);
delete definitionMap[id];
}
}
}
});
var RootNode = Node.extend({
init: function(options) {
Node.fn.init.call(this);
this.options = options;
this.defs = new DefinitionNode();
},
attachTo: function(domElement) {
this.element = domElement;
this.defs.attachTo(domElement.firstElementChild);
},
clear: function() {
BaseNode.prototype.clear.call(this);
},
template: function() {
return this.defs.render() + this.renderChildren();
},
definitionChange: function(e) {
this.defs.definitionChange(e);
}
});
var RTL = 'rtl';
function alignToScreen(element) {
var ctm;
try {
ctm = element.getScreenCTM ? element.getScreenCTM() : null;
} catch (e) { } // eslint-disable-line no-empty
if (ctm) {
var left = - ctm.e % 1;
var top = - ctm.f % 1;
var style = element.style;
if (left !== 0 || top !== 0) {
style.left = left + "px";
style.top = top + "px";
}
}
}
var Surface$1 = Surface.extend({
init: function(element, options) {
Surface.fn.init.call(this, element, options);
this._root = new RootNode($.extend({
rtl: elementStyles(element, 'direction').direction === RTL
}, this.options));
renderSVG$1(this.element, this._template());
this._rootElement = this.element.firstElementChild;
alignToScreen(this._rootElement);
this._root.attachTo(this._rootElement);
bindEvents(this.element, {
click: this._click,
mouseover: this._mouseenter,
mouseout: this._mouseleave,
mousemove: this._mousemove
});
this.resize();
},
destroy: function() {
if (this._root) {
this._root.destroy();
this._root = null;
this._rootElement = null;
unbindEvents(this.element, {
click: this._click,
mouseover: this._mouseenter,
mouseout: this._mouseleave,
mousemove: this._mousemove
});
}
Surface.fn.destroy.call(this);
},
translate: function(offset) {
var viewBox = (Math.round(offset.x)) + " " + (Math.round(offset.y)) + " " + (this._size.width) + " " + (this._size.height);
this._offset = offset;
this._rootElement.setAttribute("viewBox", viewBox);
},
draw: function(element) {
Surface.fn.draw.call(this, element);
this._root.load([ element ]);
},
clear: function() {
Surface.fn.clear.call(this);
this._root.clear();
},
svg: function() {
return "<?xml version='1.0' ?>" + this._template();
},
exportVisual: function() {
var ref = this;
var visual = ref._visual;
var offset = ref._offset;
if (offset) {
var wrap = new Group();
wrap.children.push(visual);
wrap.transform(
transform().translate(-offset.x, -offset.y)
);
visual = wrap;
}
return visual;
},
_resize: function() {
if (this._offset) {
this.translate(this._offset);
}
},
_template: function() {
return ("<svg style='width: 100%; height: 100%; overflow: hidden;' xmlns='" + SVG_NS + "' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.1'>" + (this._root.render()) + "</svg>");
}
});
Surface$1.prototype.type = "svg";
if (typeof document !== "undefined" && document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1")) {
Surface.support.svg = true;
SurfaceFactory.current.register("svg", Surface$1, 10);
}
var GroupNode = Node.extend({
template: function() {
return ("<g" + (this.renderId() + this.renderTransform() + this.renderStyle() + this.renderOpacity() + this.renderDefinitions()) + ">" + (this.renderChildren()) + "</g>");
},
optionsChange: function(e) {
if (e.field === "transform") {
this.transformChange(e.value);
}
Node.fn.optionsChange.call(this, e);
}
});
NODE_MAP.Group = GroupNode;
var DASH_ARRAYS = {
dot: [ 1.5, 3.5 ],
dash: [ 4, 3.5 ],
longdash: [ 8, 3.5 ],
dashdot: [ 3.5, 3.5, 1.5, 3.5 ],
longdashdot: [ 8, 3.5, 1.5, 3.5 ],
longdashdotdot: [ 8, 3.5, 1.5, 3.5, 1.5, 3.5 ]
};
var SOLID = "solid";
var BUTT = "butt";
var ATTRIBUTE_MAP = {
"fill.opacity": "fill-opacity",
"stroke.color": "stroke",
"stroke.width": "stroke-width",
"stroke.opacity": "stroke-opacity"
};
var SPACE = " ";
var PathNode = Node.extend({
geometryChange: function() {
this.attr("d", this.renderData());
this.invalidate();
},
optionsChange: function(e) {
switch (e.field) {
case "fill":
if (e.value) {
this.allAttr(this.mapFill(e.value));
} else {
this.removeAttr("fill");
}
break;
case "fill.color":
this.allAttr(this.mapFill({ color: e.value }));
break;
case "stroke":
if (e.value) {
this.allAttr(this.mapStroke(e.value));
} else {
this.removeAttr("stroke");
}
break;
case "transform":
this.transformChange(e.value);
break;
default:
var name = ATTRIBUTE_MAP[e.field];
if (name) {
this.attr(name, e.value);
}
break;
}
Node.fn.optionsChange.call(this, e);
},
content: function() {
if (this.element) {
this.element.textContent = this.srcElement.content();
}
},
renderData: function() {
return this.printPath(this.srcElement);
},
printPath: function(path) {
var this$1 = this;
var segments = path.segments;
var length = segments.length;
if (length > 0) {
var parts = [];
var output, currentType;
for (var i = 1; i < length; i++) {
var segmentType = this$1.segmentType(segments[i - 1], segments[i]);
if (segmentType !== currentType) {
currentType = segmentType;
parts.push(segmentType);
}
if (segmentType === "L") {
parts.push(this$1.printPoints(segments[i].anchor()));
} else {
parts.push(this$1.printPoints(segments[i - 1].controlOut(), segments[i].controlIn(), segments[i].anchor()));
}
}
output = "M" + this.printPoints(segments[0].anchor()) + SPACE + parts.join(SPACE);
if (path.options.closed) {
output += "Z";
}
return output;
}
},
printPoints: function() {
var points = arguments;
var length = points.length;
var result = [];
for (var i = 0; i < length; i++) {
result.push(points[i].toString(3));
}
return result.join(" ");
},
segmentType: function(segmentStart, segmentEnd) {
return segmentStart.controlOut() && segmentEnd.controlIn() ? "C" : "L";
},
mapStroke: function(stroke) {
var attrs = [];
if (stroke && !isTransparent(stroke.color)) {
attrs.push([ "stroke", stroke.color ]);
attrs.push([ "stroke-width", stroke.width ]);
attrs.push([ "stroke-linecap", this.renderLinecap(stroke) ]);
attrs.push([ "stroke-linejoin", stroke.lineJoin ]);
if (defined(stroke.opacity)) {
attrs.push([ "stroke-opacity", stroke.opacity ]);
}
if (defined(stroke.dashType)) {
attrs.push([ "stroke-dasharray", this.renderDashType(stroke) ]);
}
} else {
attrs.push([ "stroke", NONE ]);
}
return attrs;
},
renderStroke: function() {
return renderAllAttr(
this.mapStroke(this.srcElement.options.stroke)
);
},
renderDashType: function(stroke) {
var dashType = stroke.dashType;
var width = stroke.width; if (width === void 0) { width = 1; }
if (dashType && dashType !== SOLID) {
var dashArray = DASH_ARRAYS[dashType.toLowerCase()];
var result = [];
for (var i = 0; i < dashArray.length; i++) {
result.push(dashArray[i] * width);
}
return result.join(" ");
}
},
renderLinecap: function(stroke) {
var dashType = stroke.dashType;
var lineCap = stroke.lineCap;
return (dashType && dashType !== "solid") ? BUTT : lineCap;
},
mapFill: function(fill) {
var attrs = [];
if (!(fill && fill.nodeType === "Gradient")) {
if (fill && !isTransparent(fill.color)) {
attrs.push([ "fill", fill.color ]);
if (defined(fill.opacity)) {
attrs.push([ "fill-opacity", fill.opacity ]);
}
} else {
attrs.push([ "fill", NONE ]);
}
}
return attrs;
},
renderFill: function() {
return renderAllAttr(
this.mapFill(this.srcElement.options.fill)
);
},
template: function() {
return "<path " + (this.renderId()) + " " + (this.renderStyle()) + " " + (this.renderOpacity()) + " " + (renderAttr('d', this.renderData())) +
"" + (this.renderStroke()) + (this.renderFill()) + (this.renderDefinitions()) + (this.renderTransform()) + "></path>";
}
});
NODE_MAP.Path = PathNode;
var ArcNode = PathNode.extend({
renderData: function() {
return this.printPath(this.srcElement.toPath());
}
});
NODE_MAP.Arc = ArcNode;
var CircleNode = PathNode.extend({
geometryChange: function() {
var center = this.center();
this.attr("cx", center.x);
this.attr("cy", center.y);
this.attr("r", this.radius());
this.invalidate();
},
center: function() {
return this.srcElement.geometry().center;
},
radius: function() {
return this.srcElement.geometry().radius;
},
template: function() {
return "<circle " + (this.renderId()) + " " + (this.renderStyle()) + " " + (this.renderOpacity()) +
"cx='" + (this.center().x) + "' cy='" + (this.center().y) + "' r='" + (this.radius()) + "'" +
(this.renderStroke()) + " " + (this.renderFill()) + " " + (this.renderDefinitions()) +
(this.renderTransform()) + " ></circle>";
}
});
NODE_MAP.Circle = CircleNode;
var RectNode = PathNode.extend({
geometryChange: function() {
var geometry = this.srcElement.geometry();
this.attr("x", geometry.origin.x);
this.attr("y", geometry.origin.y);
this.attr("width", geometry.size.width);
this.attr("height", geometry.size.height);
this.invalidate();
},
size: function() {
return this.srcElement.geometry().size;
},
origin: function() {
return this.srcElement.geometry().origin;
},
template: function() {
return "<rect " + (this.renderId()) + " " + (this.renderStyle()) + " " + (this.renderOpacity()) + " x='" + (this.origin().x) + "' y='" + (this.origin().y) + "' " +
"width='" + (this.size().width) + "' height='" + (this.size().height) + "' " + (this.renderStroke()) + " " +
(this.renderFill()) + " " + (this.renderDefinitions()) + " " + (this.renderTransform()) + " />";
}
});
NODE_MAP.Rect = RectNode;
var ImageNode = PathNode.extend({
geometryChange: function() {
this.allAttr(this.mapPosition());
this.invalidate();
},
optionsChange: function(e) {
if (e.field === "src") {
this.allAttr(this.mapSource());
}
PathNode.fn.optionsChange.call(this, e);
},
mapPosition: function() {
var rect = this.srcElement.rect();
var tl = rect.topLeft();
return [
[ "x", tl.x ],
[ "y", tl.y ],
[ "width", rect.width() + "px" ],
[ "height", rect.height() + "px" ]
];
},
renderPosition: function() {
return renderAllAttr(this.mapPosition());
},
mapSource: function(encode) {
var src = this.srcElement.src();
if (encode) {
src = kendo.htmlEncode(src);
}
return [ [ "xlink:href", src ] ];
},
renderSource: function() {
return renderAllAttr(this.mapSource(true));
},
template: function() {
return "<image preserveAspectRatio='none' " + (this.renderId()) + " " + (this.renderStyle()) + " " + (this.renderTransform()) + " " + (this.renderOpacity()) +
(this.renderPosition()) + " " + (this.renderSource()) + " " + (this.renderDefinitions()) + ">" +
"</image>";
}
});
NODE_MAP.Image = ImageNode;
var ENTITY_REGEX = /&(?:[a-zA-Z]+|#\d+);/g;
function decodeEntities(text) {
if (!text || typeof text !== "string" || !ENTITY_REGEX.test(text)) {
return text;
}
var element = decodeEntities._element;
ENTITY_REGEX.lastIndex = 0;
return text.replace(ENTITY_REGEX, function (match) {
element.innerHTML = match;
return element.textContent || element.innerText;
});
}
if (typeof document !== "undefined") {
decodeEntities._element = document.createElement("span");
}
var TextNode = PathNode.extend({
geometryChange: function() {
var pos = this.pos();
this.attr("x", pos.x);
this.attr("y", pos.y);
this.invalidate();
},
optionsChange: function(e) {
if (e.field === "font") {
this.attr("style", renderStyle(this.mapStyle()));
this.geometryChange();
} else if (e.field === "content") {
PathNode.fn.content.call(this, this.srcElement.content());
}
PathNode.fn.optionsChange.call(this, e);
},
mapStyle: function(encode) {
var style = PathNode.fn.mapStyle.call(this, encode);
var font = this.srcElement.options.font;
if (encode) {
font = kendo.htmlEncode(font);
}
style.push([ "font", font ], [ "white-space", "pre" ]);
return style;
},
pos: function() {
var pos = this.srcElement.position();
var size = this.srcElement.measure();
return pos.clone().setY(pos.y + size.baseline);
},
renderContent: function() {
var content = this.srcElement.content();
content = decodeEntities(content);
content = kendo.htmlEncode(content);
return kendoUtil.normalizeText(content);
},
renderTextAnchor: function() {
var anchor;
if ((this.options || {}).rtl && !(supportBrowser.msie || supportBrowser.edge)) {
anchor = 'end';
}
return renderAttr("text-anchor", anchor);
},
template: function() {
return "<text " + (this.renderId()) + " " + (this.renderTextAnchor()) + " " + (this.renderStyle()) + " " + (this.renderOpacity()) +
"x='" + (this.pos().x) + "' y='" + (this.pos().y) + "' " + (this.renderStroke()) + " " + (this.renderTransform()) + " " + (this.renderDefinitions()) +
(this.renderFill()) + ">" + (this.renderContent()) + "</text>";
}
});
NODE_MAP.Text = TextNode;
var MultiPathNode = PathNode.extend({
renderData: function() {
var this$1 = this;
var paths = this.srcElement.paths;
if (paths.length > 0) {
var result = [];
for (var i = 0; i < paths.length; i++) {
result.push(this$1.printPath(paths[i]));
}
return result.join(" ");
}
}
});
NODE_MAP.MultiPath = MultiPathNode;
var geometry = {
Circle: Circle$2,
Arc: Arc$2,
Rect: Rect,
Point: Point,
Segment: Segment,
Matrix: Matrix,
Size: Size,
toMatrix: toMatrix,
Transformation: Transformation,
transform: transform
};
function exportGroup(group) {
var root = new RootNode({
skipBaseHref: true
});
var bbox = group.clippedBBox();
var rootGroup = group;
if (bbox) {
var origin = bbox.getOrigin();
var exportRoot = new Group();
exportRoot.transform(transform().translate(-origin.x, -origin.y));
exportRoot.children.push(group);
rootGroup = exportRoot;
}
root.load([ rootGroup ]);
var svg = "<?xml version='1.0' ?><svg xmlns='" + SVG_NS + "' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.1'>" + (root.render()) + "</svg>";
root.destroy();
return svg;
}
var svg = {
Surface: Surface$1,
RootNode: RootNode,
Node: Node,
GroupNode: GroupNode,
ArcNode: ArcNode,
CircleNode: CircleNode,
RectNode: RectNode,
ImageNode: ImageNode,
TextNode: TextNode,
PathNode: PathNode,
MultiPathNode: MultiPathNode,
DefinitionNode: DefinitionNode,
ClipNode: ClipNode,
GradientStopNode: GradientStopNode,
LinearGradientNode: LinearGradientNode,
RadialGradientNode: RadialGradientNode,
exportGroup: exportGroup
};
var NODE_MAP$2 = {};
function renderPath(ctx, path) {
var segments = path.segments;
if (segments.length === 0) {
return;
}
var segment = segments[0];
var anchor = segment.anchor();
ctx.moveTo(anchor.x, anchor.y);
for (var i = 1; i < segments.length; i++) {
segment = segments[i];
anchor = segment.anchor();
var prevSeg = segments[i - 1];
var prevOut = prevSeg.controlOut();
var controlIn = segment.controlIn();
if (prevOut && controlIn) {
ctx.bezierCurveTo(prevOut.x, prevOut.y,
controlIn.x, controlIn.y,
anchor.x, anchor.y);
} else {
ctx.lineTo(anchor.x, anchor.y);
}
}
if (path.options.closed) {
ctx.closePath();
}
}
var Node$2 = BaseNode.extend({
init: function(srcElement) {
BaseNode.fn.init.call(this, srcElement);
if (srcElement) {
this.initClip();
}
},
initClip: function() {
var clip = this.srcElement.clip();
if (clip) {
this.clip = clip;
clip.addObserver(this);
}
},
clear: function() {
if (this.srcElement) {
this.srcElement.removeObserver(this);
}
this.clearClip();
BaseNode.fn.clear.call(this);
},
clearClip: function() {
if (this.clip) {
this.clip.removeObserver(this);
delete this.clip;
}
},
setClip: function(ctx) {
if (this.clip) {
ctx.beginPath();
renderPath(ctx, this.clip);
ctx.clip();
}
},
optionsChange: function(e) {
if (e.field === "clip") {
this.clearClip();
this.initClip();
}
BaseNode.fn.optionsChange.call(this, e);
},
setTransform: function(ctx) {
if (this.srcElement) {
var transform = this.srcElement.transform();
if (transform) {
ctx.transform.apply(ctx, transform.matrix().toArray(6));
}
}
},
loadElements: function(elements, pos, cors) {
var this$1 = this;
for (var i = 0; i < elements.length; i++) {
var srcElement = elements[i];
var children = srcElement.children;
var childNode = new NODE_MAP$2[srcElement.nodeType](srcElement, cors);
if (children && children.length > 0) {
childNode.load(children, pos, cors);
}
if (defined(pos)) {
this$1.insertAt(childNode, pos);
} else {
this$1.append(childNode);
}
}
},
load: function(elements, pos, cors) {
this.loadElements(elements, pos, cors);
this.invalidate();
},
setOpacity: function(ctx) {
if (this.srcElement) {
var opacity = this.srcElement.opacity();
if (defined(opacity)) {
this.globalAlpha(ctx, opacity);
}
}
},
globalAlpha: function(ctx, value) {
var opactity = value;
if (opactity && ctx.globalAlpha) {
opactity *= ctx.globalAlpha;
}
ctx.globalAlpha = opactity;
},
visible: function() {
var src = this.srcElement;
return !src || (src && src.options.visible !== false);
}
});
var GroupNode$2 = Node$2.extend({
renderTo: function(ctx) {
if (!this.visible()) {
return;
}
ctx.save();
this.setTransform(ctx);
this.setClip(ctx);
this.setOpacity(ctx);
var childNodes = this.childNodes;
for (var i = 0; i < childNodes.length; i++) {
var child = childNodes[i];
if (child.visible()) {
child.renderTo(ctx);
}
}
ctx.restore();
}
});
Traversable.extend(GroupNode$2.prototype, "childNodes");
NODE_MAP$2.Group = GroupNode$2;
var FRAME_DELAY = 1000 / 60;
var RootNode$2 = GroupNode$2.extend({
init: function(canvas) {
GroupNode$2.fn.init.call(this);
this.canvas = canvas;
this.ctx = canvas.getContext("2d");
var invalidateHandler = this._invalidate.bind(this);
this.invalidate = kendo.throttle(function () {
kendo.animationFrame(invalidateHandler);
}, FRAME_DELAY);
},
destroy: function() {
GroupNode$2.fn.destroy.call(this);
this.canvas = null;
this.ctx = null;
},
load: function(elements, pos, cors) {
this.loadElements(elements, pos, cors);
this._invalidate();
},
_invalidate: function() {
if (!this.ctx) {
return;
}
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.renderTo(this.ctx);
}
});
Traversable.extend(RootNode$2.prototype, "childNodes");
var QuadRoot = Class.extend({
init: function() {
this.shapes = [];
},
_add: function(shape, bbox) {
this.shapes.push({
bbox: bbox,
shape: shape
});
shape._quadNode = this;
},
pointShapes: function(point) {
var shapes = this.shapes;
var length = shapes.length;
var result = [];
for (var idx = 0; idx < length; idx++) {
if (shapes[idx].bbox.containsPoint(point)) {
result.push(shapes[idx].shape);
}
}
return result;
},
insert: function(shape, bbox) {
this._add(shape, bbox);
},
remove: function(shape) {
var shapes = this.shapes;
var length = shapes.length;
for (var idx = 0; idx < length; idx++) {
if (shapes[idx].shape === shape) {
shapes.splice(idx, 1);
break;
}
}
}
});
var QuadNode = QuadRoot.extend({
init: function(rect) {
QuadRoot.fn.init.call(this);
this.children = [];
this.rect = rect;
},
inBounds: function(rect) {
var nodeRect = this.rect;
var nodeBottomRight = nodeRect.bottomRight();
var bottomRight = rect.bottomRight();
var inBounds = nodeRect.origin.x <= rect.origin.x && nodeRect.origin.y <= rect.origin.y && bottomRight.x <= nodeBottomRight.x &&
bottomRight.y <= nodeBottomRight.y;
return inBounds;
},
pointShapes: function(point) {
var children = this.children;
var length = children.length;
var result = QuadRoot.fn.pointShapes.call(this, point);
for (var idx = 0; idx < length; idx++) {
append(result, children[idx].pointShapes(point));
}
return result;
},
insert: function(shape, bbox) {
var children = this.children;
var inserted = false;
if (this.inBounds(bbox)) {
if (this.shapes.length < 4) {
this._add(shape, bbox);
} else {
if (!children.length) {
this._initChildren();
}
for (var idx = 0; idx < children.length; idx++) {
if (children[idx].insert(shape, bbox)) {
inserted = true;
break;
}
}
if (!inserted) {
this._add(shape, bbox);
}
}
inserted = true;
}
return inserted;
},
_initChildren: function() {
var ref = this;
var rect = ref.rect;
var children = ref.children;
var center = rect.center();
var halfWidth = rect.width() / 2;
var halfHeight = rect.height() / 2;
children.push(
new QuadNode(new Rect([ rect.origin.x, rect.origin.y ], [ halfWidth, halfHeight ])),
new QuadNode(new Rect([ center.x, rect.origin.y ], [ halfWidth, halfHeight ])),
new QuadNode(new Rect([ rect.origin.x, center.y ], [ halfWidth, halfHeight ])),
new QuadNode(new Rect([ center.x, center.y ], [ halfWidth, halfHeight ]))
);
}
});
var ROOT_SIZE = 3000;
var LEVEL_STEP = 10000;
var MAX_LEVEL = 75;
var ShapesQuadTree = Class.extend({
init: function() {
this.initRoots();
},
initRoots: function() {
this.rootMap = {};
this.root = new QuadRoot();
this.rootElements = [];
},
clear: function() {
var this$1 = this;
var rootElements = this.rootElements;
for (var idx = 0; idx < rootElements.length; idx++) {
this$1.remove(rootElements[idx]);
}
this.initRoots();
},
pointShape: function(point) {
var sectorRoot = ( this.rootMap[ Math.floor( point.x / ROOT_SIZE ) ] || {} )[ Math.floor( point.y / ROOT_SIZE ) ];
var result = this.root.pointShapes(point);
if (sectorRoot) {
result = result.concat(sectorRoot.pointShapes(point));
}
this.assignZindex(result);
result.sort(zIndexComparer);
for (var idx = 0; idx < result.length; idx++) {
if (result[idx].containsPoint(point)) {
return result[idx];
}
}
},
assignZindex: function(elements) {
var this$1 = this;
for (var idx = 0; idx < elements.length; idx++) {
var element = elements[idx];
var zIndex = 0;
var levelWeight = Math.pow(LEVEL_STEP, MAX_LEVEL);
var parents = [];
while (element) {
parents.push(element);
element = element.parent;
}
while (parents.length) {
element = parents.pop();
zIndex += ((element.parent ? element.parent.children : this$1.rootElements).indexOf(element) + 1) * levelWeight;
levelWeight /= LEVEL_STEP;
}
elements[idx]._zIndex = zIndex;
}
},
optionsChange: function(e) {
if (e.field === "transform" || e.field === "stroke.width") {
this.bboxChange(e.element);
}
},
geometryChange: function(e) {
this.bboxChange(e.element);
},
bboxChange: function(element) {
var this$1 = this;
if (element.nodeType === "Group") {
for (var idx = 0; idx < element.children.length; idx++) {
this$1.bboxChange(element.children[idx]);
}
} else {
if (element._quadNode) {
element._quadNode.remove(element);
}
this._insertShape(element);
}
},
add: function(elements) {
var elementsArray = Array.isArray(elements) ? elements.slice(0) : [ elements ];
append(this.rootElements, elementsArray);
this._insert(elementsArray);
},
childrenChange: function(e) {
var this$1 = this;
if (e.action === "remove") {
for (var idx = 0; idx < e.items.length; idx++) {
this$1.remove(e.items[idx]);
}
} else {
this._insert(Array.prototype.slice.call(e.items, 0));
}
},
_insert: function(elements) {
var this$1 = this;
var element;
while (elements.length > 0) {
element = elements.pop();
element.addObserver(this$1);
if (element.nodeType === "Group") {
append(elements, element.children);
} else {
this$1._insertShape(element);
}
}
},
_insertShape: function(shape) {
var bbox = shape.bbox();
if (bbox) {
var sectors = this.getSectors(bbox);
var x = sectors[0][0];
var y = sectors[1][0];
if (this.inRoot(sectors)) {
this.root.insert(shape, bbox);
} else {
var rootMap = this.rootMap;
if (!rootMap[x]) {
rootMap[x] = {};
}
if (!rootMap[x][y]) {
rootMap[x][y] = new QuadNode(
new Rect([ x * ROOT_SIZE, y * ROOT_SIZE ], [ ROOT_SIZE, ROOT_SIZE ])
);
}
rootMap[x][y].insert(shape, bbox);
}
}
},
remove: function(element) {
var this$1 = this;
element.removeObserver(this);
if (element.nodeType === "Group") {
var children = element.children;
for (var idx = 0; idx < children.length; idx++) {
this$1.remove(children[idx]);
}
} else if (element._quadNode) {
element._quadNode.remove(element);
delete element._quadNode;
}
},
inRoot: function(sectors) {
return sectors[0].length > 1 || sectors[1].length > 1;
},
getSectors: function(rect) {
var bottomRight = rect.bottomRight();
var bottomX = Math.floor(bottomRight.x / ROOT_SIZE);
var bottomY = Math.floor(bottomRight.y / ROOT_SIZE);
var sectors = [ [], [] ];
for (var x = Math.floor(rect.origin.x / ROOT_SIZE); x <= bottomX; x++) {
sectors[0].push(x);
}
for (var y = Math.floor(rect.origin.y / ROOT_SIZE); y <= bottomY; y++) {
sectors[1].push(y);
}
return sectors;
}
});
function zIndexComparer(x1, x2) {
if (x1._zIndex < x2._zIndex) {
return 1;
}
if (x1._zIndex > x2._zIndex) {
return -1;
}
return 0;
}
var SurfaceCursor = Class.extend({
init: function(surface) {
surface.bind("mouseenter", this._mouseenter.bind(this));
surface.bind("mouseleave", this._mouseleave.bind(this));
this.element = surface.element;
},
clear: function() {
this._resetCursor();
},
destroy: function() {
this._resetCursor();
delete this.element;
},
_mouseenter: function(e) {
var cursor = this._shapeCursor(e);
if (!cursor) {
this._resetCursor();
} else {
if (!this._current) {
this._defaultCursor = this._getCursor();
}
this._setCursor(cursor);
}
},
_mouseleave: function() {
this._resetCursor();
},
_shapeCursor: function(e) {
var shape = e.element;
while (shape && !defined(shape.options.cursor)) {
shape = shape.parent;
}
if (shape) {
return shape.options.cursor;
}
},
_getCursor: function() {
if (this.element) {
return this.element.style.cursor;
}
},
_setCursor: function(cursor) {
if (this.element) {
this.element.style.cursor = cursor;
this._current = cursor;
}
},
_resetCursor: function() {
if (this._current) {
this._setCursor(this._defaultCursor || "");
delete this._current;
}
}
});
var Surface$3 = Surface.extend({
init: function(element, options) {
Surface.fn.init.call(this, element, options);
this.element.innerHTML = this._template(this);
var canvas = this.element.firstElementChild;
var size = elementSize(element);
canvas.width = size.width;
canvas.height = size.height;
this._rootElement = canvas;
this._root = new RootNode$2(canvas);
this._mouseTrackHandler = this._trackMouse.bind(this);
bindEvents(this.element, {
click: this._mouseTrackHandler,
mousemove: this._mouseTrackHandler
});
},
destroy: function() {
Surface.fn.destroy.call(this);
if (this._root) {
this._root.destroy();
this._root = null;
}
if (this._searchTree) {
this._searchTree.clear();
delete this._searchTree;
}
if (this._cursor) {
this._cursor.destroy();
delete this._cursor;
}
unbindEvents(this.element, {
click: this._mouseTrackHandler,
mousemove: this._mouseTrackHandler
});
},
draw: function(element) {
Surface.fn.draw.call(this, element);
this._root.load([ element ], undefined, this.options.cors);
if (this._searchTree) {
this._searchTree.add([ element ]);
}
},
clear: function() {
Surface.fn.clear.call(this);
this._root.clear();
if (this._searchTree) {
this._searchTree.clear();
}
if (this._cursor) {
this._cursor.clear();
}
},
eventTarget: function(e) {
if (this._searchTree) {
var point = this._surfacePoint(e);
var shape = this._searchTree.pointShape(point);
return shape;
}
},
image: function() {
var ref = this;
var root = ref._root;
var rootElement = ref._rootElement;
var loadingStates = [];
root.traverse(function (childNode) {
if (childNode.loading) {
loadingStates.push(childNode.loading);
}
});
var promise = createPromise();
var resolveDataURL = function () {
root._invalidate();
try {
var data = rootElement.toDataURL();
promise.resolve(data);
} catch (e) {
promise.reject(e);
}
};
promiseAll(loadingStates).then(resolveDataURL, resolveDataURL);
return promise;
},
suspendTracking: function() {
Surface.fn.suspendTracking.call(this);
if (this._searchTree) {
this._searchTree.clear();
delete this._searchTree;
}
},
resumeTracking: function() {
Surface.fn.resumeTracking.call(this);
if (!this._searchTree) {
this._searchTree = new ShapesQuadTree();
var childNodes = this._root.childNodes;
var rootElements = [];
for (var idx = 0; idx < childNodes.length; idx++) {
rootElements.push(childNodes[idx].srcElement);
}
this._searchTree.add(rootElements);
}
},
_resize: function() {
this._rootElement.width = this._size.width;
this._rootElement.height = this._size.height;
this._root.invalidate();
},
_template: function() {
return "<canvas style='width: 100%; height: 100%;'></canvas>";
},
_enableTracking: function() {
this._searchTree = new ShapesQuadTree();
this._cursor = new SurfaceCursor(this);
Surface.fn._enableTracking.call(this);
},
_trackMouse: function(e) {
if (this._suspendedTracking) {
return;
}
var shape = this.eventTarget(e);
if (e.type !== "click") {
var currentShape = this._currentShape;
if (currentShape && currentShape !== shape) {
this.trigger("mouseleave", {
element: currentShape,
originalEvent: e,
type: "mouseleave"
});
}
if (shape && currentShape !== shape) {
this.trigger("mouseenter", {
element: shape,
originalEvent: e,
type: "mouseenter"
});
}
this.trigger("mousemove", {
element: shape,
originalEvent: e,
type: "mousemove"
});
this._currentShape = shape;
} else if (shape) {
this.trigger("click", {
element: shape,
originalEvent: e,
type: "click"
});
}
}
});
Surface$3.prototype.type = "canvas";
if (typeof document !== "undefined" && document.createElement("canvas").getContext) {
Surface.support.canvas = true;
SurfaceFactory.current.register("canvas", Surface$3, 20);
}
function addGradientStops(gradient, stops) {
for (var idx = 0; idx < stops.length; idx++) {
var stop = stops[idx];
var color = kendo.parseColor(stop.color());
color.a *= stop.opacity();
gradient.addColorStop(stop.offset(), color.toCssRgba());
}
}
var PathNode$2 = Node$2.extend({
renderTo: function(ctx) {
ctx.save();
this.setTransform(ctx);
this.setClip(ctx);
this.setOpacity(ctx);
ctx.beginPath();
this.renderPoints(ctx, this.srcElement);
this.setLineDash(ctx);
this.setLineCap(ctx);
this.setLineJoin(ctx);
this.setFill(ctx);
this.setStroke(ctx);
ctx.restore();
},
setFill: function(ctx) {
var fill = this.srcElement.options.fill;
var hasFill = false;
if (fill) {
if (fill.nodeType === "Gradient") {
this.setGradientFill(ctx, fill);
hasFill = true;
} else if (!isTransparent(fill.color)) {
ctx.fillStyle = fill.color;
ctx.save();
this.globalAlpha(ctx, fill.opacity);
ctx.fill();
ctx.restore();
hasFill = true;
}
}
return hasFill;
},
setGradientFill: function(ctx, fill) {
var bbox = this.srcElement.rawBBox();
var gradient;
if (fill instanceof LinearGradient) {
var start = fill.start();
var end = fill.end();
gradient = ctx.createLinearGradient(start.x, start.y, end.x, end.y);
} else if (fill instanceof RadialGradient) {
var center = fill.center();
gradient = ctx.createRadialGradient(center.x, center.y, 0, center.x, center.y, fill.radius());
}
addGradientStops(gradient, fill.stops);
ctx.save();
if (!fill.userSpace()) {
ctx.transform(bbox.width(), 0, 0, bbox.height(), bbox.origin.x, bbox.origin.y);
}
ctx.fillStyle = gradient;
ctx.fill();
ctx.restore();
},
setStroke: function(ctx) {
var stroke = this.srcElement.options.stroke;
if (stroke && !isTransparent(stroke.color) && stroke.width > 0) {
ctx.strokeStyle = stroke.color;
ctx.lineWidth = valueOrDefault(stroke.width, 1);
ctx.save();
this.globalAlpha(ctx, stroke.opacity);
ctx.stroke();
ctx.restore();
return true;
}
},
dashType: function() {
var stroke = this.srcElement.options.stroke;
if (stroke && stroke.dashType) {
return stroke.dashType.toLowerCase();
}
},
setLineDash: function(ctx) {
var dashType = this.dashType();
if (dashType && dashType !== SOLID) {
var dashArray = DASH_ARRAYS[dashType];
if (ctx.setLineDash) {
ctx.setLineDash(dashArray);
} else {
ctx.mozDash = dashArray;
ctx.webkitLineDash = dashArray;
}
}
},
setLineCap: function(ctx) {
var dashType = this.dashType();
var stroke = this.srcElement.options.stroke;
if (dashType && dashType !== SOLID) {
ctx.lineCap = BUTT;
} else if (stroke && stroke.lineCap) {
ctx.lineCap = stroke.lineCap;
}
},
setLineJoin: function(ctx) {
var stroke = this.srcElement.options.stroke;
if (stroke && stroke.lineJoin) {
ctx.lineJoin = stroke.lineJoin;
}
},
renderPoints: function(ctx, path) {
renderPath(ctx, path);
}
});
NODE_MAP$2.Path = PathNode$2;
var ArcNode$2 = PathNode$2.extend({
renderPoints: function(ctx) {
var path = this.srcElement.toPath();
renderPath(ctx, path);
}
});
NODE_MAP$2.Arc = ArcNode$2;
var CircleNode$2 = PathNode$2.extend({
renderPoints: function(ctx) {
var ref = this.srcElement.geometry();
var center = ref.center;
var radius = ref.radius;
ctx.arc(center.x, center.y, radius, 0, Math.PI * 2);
}
});
NODE_MAP$2.Circle = CircleNode$2;
var RectNode$2 = PathNode$2.extend({
renderPoints: function(ctx) {
var ref = this.srcElement.geometry();
var origin = ref.origin;
var size = ref.size;
ctx.rect(origin.x, origin.y, size.width, size.height);
}
});
NODE_MAP$2.Rect = RectNode$2;
var ImageNode$2 = PathNode$2.extend({
init: function(srcElement, cors) {
PathNode$2.fn.init.call(this, srcElement);
this.onLoad = this.onLoad.bind(this);
this.onError = this.onError.bind(this);
this.loading = createPromise();
var img = this.img = new Image();
if (cors && !(/^data:/i.test(srcElement.src()))) {
img.crossOrigin = cors;
}
img.src = srcElement.src();
if (img.complete) {
this.onLoad();
} else {
img.onload = this.onLoad;
img.onerror = this.onError;
}
},
renderTo: function(ctx) {
if (this.loading.state() === "resolved") {
ctx.save();
this.setTransform(ctx);
this.setClip(ctx);
this.drawImage(ctx);
ctx.restore();
}
},
optionsChange: function(e) {
if (e.field === "src") {
this.loading = createPromise();
this.img.src = this.srcElement.src();
} else {
PathNode$2.fn.optionsChange.call(this, e);
}
},
onLoad: function() {
this.loading.resolve();
this.invalidate();
},
onError: function() {
this.loading.reject(new Error(
"Unable to load image '" + this.img.src +
"'. Check for connectivity and verify CORS headers."
));
},
drawImage: function(ctx) {
var rect = this.srcElement.rect();
var topLeft = rect.topLeft();
ctx.drawImage(
this.img, topLeft.x, topLeft.y, rect.width(), rect.height()
);
}
});
NODE_MAP$2.Image = ImageNode$2;
var TextNode$2 = PathNode$2.extend({
renderTo: function(ctx) {
var text = this.srcElement;
var pos = text.position();
var size = text.measure();
ctx.save();
this.setTransform(ctx);
this.setClip(ctx);
this.setOpacity(ctx);
ctx.beginPath();
ctx.font = text.options.font;
ctx.textAlign = 'left';
if (this.setFill(ctx)) {
ctx.fillText(text.content(), pos.x, pos.y + size.baseline);
}
if (this.setStroke(ctx)) {
this.setLineDash(ctx);
ctx.strokeText(text.content(), pos.x, pos.y + size.baseline);
}
ctx.restore();
}
});
NODE_MAP$2.Text = TextNode$2;
var MultiPathNode$2 = PathNode$2.extend({
renderPoints: function(ctx) {
var paths = this.srcElement.paths;
for (var i = 0; i < paths.length; i++) {
renderPath(ctx, paths[i]);
}
}
});
NODE_MAP$2.MultiPath = MultiPathNode$2;
var canvas = {
Surface: Surface$3,
RootNode: RootNode$2,
Node: Node$2,
GroupNode: GroupNode$2,
ArcNode: ArcNode$2,
CircleNode: CircleNode$2,
RectNode: RectNode$2,
ImageNode: ImageNode$2,
TextNode: TextNode$2,
PathNode: PathNode$2,
MultiPathNode: MultiPathNode$2
};
function exportImage(group, options) {
var defaults = {
width: "800px", height: "600px",
cors: "Anonymous"
};
var exportRoot = group;
var bbox = group.clippedBBox();
if (bbox) {
var origin = bbox.getOrigin();
exportRoot = new Group();
exportRoot.transform(transform().translate(-origin.x, -origin.y));
exportRoot.children.push(group);
var size = bbox.getSize();
defaults.width = size.width + "px";
defaults.height = size.height + "px";
}
var surfaceOptions = $.extend(defaults, options);
var container = document.createElement("div");
var style = container.style;
style.display = "none";
style.width = surfaceOptions.width;
style.height = surfaceOptions.height;
document.body.appendChild(container);
var surface = new Surface$3(container, surfaceOptions);
surface.suspendTracking();
surface.draw(exportRoot);
var promise = surface.image();
var destroy = function () {
surface.destroy();
document.body.removeChild(container);
};
promise.then(destroy, destroy);
return promise;
}
function exportSVG(group, options) {
var svg = exportGroup(group);
if (!options || !options.raw) {
svg = "data:image/svg+xml;base64," + encodeBase64(svg);
}
return createPromise().resolve(svg);
}
/* eslint-disable no-multi-spaces, key-spacing, indent, camelcase, space-before-blocks, eqeqeq, brace-style */
/* eslint-disable space-infix-ops, space-before-function-paren, array-bracket-spacing, object-curly-spacing */
/* eslint-disable no-nested-ternary, max-params, default-case, no-else-return, no-empty, yoda */
/* eslint-disable no-param-reassign, no-var, block-scoped-var */
var browser = supportBrowser;
/*
XXX: to test:
- cloneNodes function:
- drawing document containing canvas with page breaking
- drawing document with named radio <input>-s (should not clear selection)
- IE9/IE10 don't support el.dataset; do they copy user data?
- repeating table headers/footers on page breaking
- forceBreak, keepTogether
- avoidLinks
*/
/* -----[ local vars ]----- */
function slice$1(thing) {
return Array.prototype.slice.call(thing);
}
var KENDO_PSEUDO_ELEMENT = "KENDO-PSEUDO-ELEMENT";
var IMAGE_CACHE = {};
var nodeInfo = {};
nodeInfo._root = nodeInfo;
/* -----[ Custom Text node to speed up rendering in kendo.pdf ]----- */
var inBrowser = typeof window !== 'undefined';
var microsoft = inBrowser ? browser.msie || browser.edge : false;
var TextRect = Text.extend({
init: function(str, rect, options) {
Text.fn.init.call(this, str, rect.getOrigin(), options);
this._pdfRect = rect;
},
rect: function() {
// this is the crux of it: we can avoid a call to
// measure(), which is what the base class does, since we
// already know the rect. measure() is s-l-o-w.
return this._pdfRect;
},
rawBBox: function() {
// also let's avoid creating a new rectangle.
return this._pdfRect;
}
});
function addClass(el, cls) {
if (el.classList) {
el.classList.add(cls);
} else {
el.className += " " + cls;
}
}
function removeClass(el, cls) {
if (el.classList) {
el.classList.remove(cls);
} else {
el.className = el.className.split(/\s+/).reduce(function(a, word){
if (word != cls) {
a.push(word);
}
return a;
}, []).join(" ");
}
}
function setCSS(el, styles) {
Object.keys(styles).forEach(function(key){
el.style[key] = styles[key];
});
}
var matches = typeof Element !== "undefined" && Element.prototype && (function(p){
if (p.matches) {
return function(el, selector) { return el.matches(selector); };
}
if (p.webkitMatchesSelector) {
return function(el, selector) { return el.webkitMatchesSelector(selector); };
}
if (p.mozMatchesSelector) {
return function(el, selector) { return el.mozMatchesSelector(selector); };
}
if (p.msMatchesSelector) {
return function(el, selector) { return el.msMatchesSelector(selector); };
}
return function(s) {
return [].indexOf.call(document.querySelectorAll(s), this) !== -1;
};
})(Element.prototype);
function closest(el, selector) {
if (el.closest) {
return el.closest(selector);
}
// IE: stringifying rather than simply comparing with `document`,
// which is not iframe-proof and fails in editor export —
// https://github.com/telerik/kendo/issues/6721
while (el && !/^\[object (?:HTML)?Document\]$/.test(String(el))) {
if (el.nodeType == 1 /* Element */ && matches(el, selector)) {
return el;
}
el = el.parentNode;
}
}
// clone nodes ourselves, so that we redraw <canvas> (DOM or
// jQuery clone will not)
var cloneNodes = (function($){
if ($) {
// if we have Kendo and jQuery, use this version as it will
// maintain proper links between cloned element and Kendo
// widgets (i.e. it clones jQuery data(), which isn't the same
// as element's data attributes).
// https://github.com/telerik/kendo-ui-core/issues/2750
return function cloneNodes(el) {
var clone = el.cloneNode(false);
if (el.nodeType == 1 /* Element */) {
var $el = $(el), $clone = $(clone), i;
var data = $el.data();
for (i in data) {
$clone.data(i, data[i]);
}
if (/^canvas$/i.test(el.tagName)) {
clone.getContext("2d").drawImage(el, 0, 0);
} else if (/^(?:input|select|textarea|option)$/i.test(el.tagName)) {
// drop the name attributes so that we don't affect the selection of the
// original nodes (i.e. checked status of radio buttons) when we insert our copy
// into the DOM. https://github.com/telerik/kendo/issues/5409
clone.removeAttribute("id");
clone.removeAttribute("name");
clone.value = el.value;
clone.checked = el.checked;
clone.selected = el.selected;
}
for (i = el.firstChild; i; i = i.nextSibling) {
clone.appendChild(cloneNodes(i));
}
}
return clone;
};
} else {
// the no-jQuery version
return function cloneNodes(el) {
var clone = (function dive(node){
var clone = node.cloneNode(false);
if (node._kendoExportVisual) {
clone._kendoExportVisual = node._kendoExportVisual;
}
for (var i = node.firstChild; i; i = i.nextSibling) {
clone.appendChild(dive(i));
}
return clone;
})(el);
// re-draw canvases - https://github.com/telerik/kendo/issues/4872
var canvases = el.querySelectorAll("canvas");
if (canvases.length) {
slice$1(clone.querySelectorAll("canvas")).forEach(function (canvas$$1, i) {
canvas$$1.getContext("2d").drawImage(canvases[i], 0, 0);
});
}
// remove "name" attributes from <input> elements -
// https://github.com/telerik/kendo/issues/5409
var orig = el.querySelectorAll("input, select, textarea, option");
slice$1(clone.querySelectorAll("input, select, textarea, option")).forEach(function (el, i) {
el.removeAttribute("id");
el.removeAttribute("name");
el.value = orig[i].value;
el.checked = orig[i].checked;
el.selected = orig[i].selected;
});
return clone;
};
}
})(typeof window !== "undefined" && window.kendo && window.kendo.jQuery);
function getXY(thing) {
if (typeof thing == "number") {
return { x: thing, y: thing };
}
if (Array.isArray(thing)) {
return { x: thing[0], y: thing[1] };
}
return { x: thing.x, y: thing.y };
}
function drawDOM(element, options) {
if (!options) {
options = {};
}
var promise = createPromise();
if (!element) {
return promise.reject("No element to export");
}
if (typeof window.getComputedStyle != "function") {
throw new Error("window.getComputedStyle is missing. You are using an unsupported browser, or running in IE8 compatibility mode. Drawing HTML is supported in Chrome, Firefox, Safari and IE9+.");
}
kendo.pdf.defineFont(getFontFaces(element.ownerDocument));
var scale = getXY(options.scale || 1);
function doOne(element) {
var group = new Group();
// translate to start of page
var pos = element.getBoundingClientRect();
setTransform(group, [
scale.x,
0,
0,
scale.y,
(-pos.left * scale.x),
(-pos.top * scale.y)
]);
nodeInfo._clipbox = false;
nodeInfo._matrix = Matrix.unit();
nodeInfo._stackingContext = {
element: element,
group: group
};
if (options.avoidLinks === true) {
nodeInfo._avoidLinks = "a";
} else {
nodeInfo._avoidLinks = options.avoidLinks;
}
addClass(element, "k-pdf-export");
renderElement(element, group);
removeClass(element, "k-pdf-export");
return group;
}
cacheImages(element, function(){
var forceBreak = options && options.forcePageBreak;
var hasPaperSize = options && options.paperSize && options.paperSize != "auto";
var paperOptions = kendo.pdf.getPaperOptions(function(key, def){
if (key == "paperSize") {
// PDF.getPaperOptions croaks on "auto", just pass dummy A4 as we might
// still be interested in margins.
return hasPaperSize ? options[key] : "A4";
}
return key in options ? options[key] : def;
});
var pageWidth = hasPaperSize && paperOptions.paperSize[0];
var pageHeight = hasPaperSize && paperOptions.paperSize[1];
var margin = options.margin && paperOptions.margin;
var hasMargin = Boolean(margin);
if (forceBreak || pageHeight) {
if (!margin) {
margin = { left: 0, top: 0, right: 0, bottom: 0 };
}
// we want paper size and margin to be unaffected by
// scaling in the output, so we have to reverse-scale
// before our calculations begin.
if (pageWidth) { pageWidth /= scale.x; }
if (pageHeight) { pageHeight /= scale.y; }
margin.left /= scale.x;
margin.right /= scale.x;
margin.top /= scale.y;
margin.bottom /= scale.y;
var group = new Group({
pdf: {
multiPage : true,
paperSize : hasPaperSize ? paperOptions.paperSize : "auto",
_ignoreMargin : hasMargin // HACK! see exportPDF in pdf/drawing.js
}
});
handlePageBreaks(
function(x) {
if (options.progress) {
var canceled = false, pageNum = 0;
(function next(){
if (pageNum < x.pages.length) {
var page = doOne(x.pages[pageNum]);
group.append(page);
options.progress({
page: page,
pageNum: ++pageNum,
totalPages: x.pages.length,
cancel: function() {
canceled = true;
}
});
if (!canceled) {
setTimeout(next);
} else {
// XXX: should we also fail() the deferred object?
x.container.parentNode.removeChild(x.container);
}
} else {
x.container.parentNode.removeChild(x.container);
promise.resolve(group);
}
})();
} else {
x.pages.forEach(function(page){
group.append(doOne(page));
});
x.container.parentNode.removeChild(x.container);
promise.resolve(group);
}
},
element,
forceBreak,
pageWidth ? pageWidth - margin.left - margin.right : null,
pageHeight ? pageHeight - margin.top - margin.bottom : null,
margin,
options
);
} else {
promise.resolve(doOne(element));
}
});
function makeTemplate(template$$1) {
if (template$$1 != null) {
if (typeof template$$1 == "string") {
template$$1 = kendo.template(template$$1.replace(/^\s+|\s+$/g, ""));
}
if (typeof template$$1 == "function") {
return function(data) {
var el = template$$1(data);
if (el && typeof el == "string") {
var div = document.createElement("div");
div.innerHTML = el;
el = div.firstElementChild;
}
return el;
};
}
// assumed DOM element
return function() {
return template$$1.cloneNode(true);
};
}
}
function handlePageBreaks(callback, element, forceBreak, pageWidth, pageHeight, margin, options) {
var template$$1 = makeTemplate(options.template);
var doc = element.ownerDocument;
var pages = [];
var copy = options._destructive ? element : cloneNodes(element);
var container = doc.createElement("KENDO-PDF-DOCUMENT");
var adjust = 0;
// make sure <tfoot> elements are at the end (Grid widget
// places TFOOT before TBODY, tricking our algorithm to
// insert a page break right after the header).
// https://github.com/telerik/kendo/issues/4699
slice$1(copy.querySelectorAll("tfoot")).forEach(function(tfoot){
tfoot.parentNode.appendChild(tfoot);
});
// remember the index of each LI from an ordered list.
// we'll use it to reconstruct the proper numbering.
slice$1(copy.querySelectorAll("ol")).forEach(function(ol){
slice$1(ol.children).forEach(function(li, index){
li.setAttribute("kendo-split-index", index);
});
});
setCSS(container, {
display : "block",
position : "absolute",
boxSizing : "content-box",
left : "-10000px",
top : "-10000px"
});
if (pageWidth) {
// subtle: if we don't set the width *and* margins here, the layout in this
// container will be different from the one in our final page elements, and we'll
// split at the wrong places.
setCSS(container, {
width : pageWidth + "px",
paddingLeft : margin.left + "px",
paddingRight : margin.right + "px"
});
// when the first element has a margin-top (i.e. a <h1>) the page will be
// inadvertently enlarged by that number (the browser will report the container's
// bounding box top to start at the element's top, rather than including its
// margin). Adding overflow: hidden seems to fix it.
//
// to understand the difference, try the following snippets in your browser:
//
// 1. <div style="background: yellow">
// <h1 style="margin: 3em">Foo</h1>
// </div>
//
// 2. <div style="background: yellow; overflow: hidden">
// <h1 style="margin: 3em">Foo</h1>
// </div>
//
// this detail is not important when automatic page breaking is not requested, hence
// doing it only if pageWidth is defined.
setCSS(copy, { overflow: "hidden" });
}
element.parentNode.insertBefore(container, element);
container.appendChild(copy);
// we need the timeouts here, so that images dimensions are
// properly computed in DOM when we start our thing.
if (options.beforePageBreak) {
setTimeout(function(){
options.beforePageBreak(container, doPageBreak);
}, 15);
} else {
setTimeout(doPageBreak, 15);
}
function doPageBreak() {
if (forceBreak != "-" || pageHeight) {
splitElement(copy);
}
{
var page = makePage();
copy.parentNode.insertBefore(page, copy);
page.appendChild(copy);
}
if (template$$1) {
pages.forEach(function(page, i){
var el = template$$1({
element : page,
pageNum : i + 1,
totalPages : pages.length
});
if (el) {
page.appendChild(el);
}
});
}
cacheImages(pages, function() {
// Even though we already cached images, they simply won't be available
// immediately in the newly created DOM. Previously we'd allow a 10ms timeout,
// but that's arbitrary and clearly not working in all cases
// (https://github.com/telerik/kendo/issues/5399), so this function will wait
// for their .complete attribute.
whenImagesAreActuallyLoaded(pages, function(){
callback({ pages: pages, container: container });
});
});
}
function keepTogether(el) {
if (options.keepTogether && matches(el, options.keepTogether) && el.offsetHeight <= pageHeight - adjust) {
return true;
}
var tag = el.tagName;
if (/^h[1-6]$/i.test(tag) && el.offsetHeight >= pageHeight - adjust) {
return false;
}
return (el.getAttribute("data-kendo-chart") ||
/^(?:img|tr|thead|th|tfoot|iframe|svg|object|canvas|input|textarea|select|video|h[1-6])/i.test(el.tagName));
}
function splitElement(element) {
if (element.tagName == "TABLE") {
setCSS(element, { tableLayout: "fixed" });
}
if (keepTogether(element)) {
return;
}
var style = getComputedStyle(element);
var bottomPadding = parseFloat(getPropertyValue(style, "padding-bottom"));
var bottomBorder = parseFloat(getPropertyValue(style, "border-bottom-width"));
var saveAdjust = adjust;
adjust += bottomPadding + bottomBorder;
var isFirst = true;
for (var el = element.firstChild; el; el = el.nextSibling) {
if (el.nodeType == 1 /* Element */) {
isFirst = false;
if (matches(el, forceBreak)) {
breakAtElement(el);
continue;
}
if (!pageHeight) {
// we're in "manual breaks mode"
splitElement(el);
continue;
}
if (!/^(?:static|relative)$/.test(getPropertyValue(getComputedStyle(el), "position"))) {
continue;
}
var fall = fallsOnMargin(el);
if (fall == 1) {
// element starts on next page, break before anyway.
breakAtElement(el);
}
else if (fall) {
// elements ends up on next page, or possibly doesn't fit on a page at
// all. break before it anyway if it's an <img> or <tr>, otherwise
// attempt to split.
if (keepTogether(el)) {
breakAtElement(el);
} else {
splitElement(el);
}
}
else {
splitElement(el);
}
}
else if (el.nodeType == 3 /* Text */ && pageHeight) {
splitText(el, isFirst);
isFirst = false;
}
}
adjust = saveAdjust;
}
function firstInParent(el) {
var p = el.parentNode, first = p.firstChild;
if (el === first) {
return true;
}
if (el === p.children[0]) {
if (first.nodeType == 7 /* comment */ ||
first.nodeType == 8 /* processing instruction */) {
return true;
}
if (first.nodeType == 3 /* text */) {
// if whitespace only we can probably consider it's first
return !/\S/.test(first.data);
}
}
return false;
}
function breakAtElement(el) {
if (el.nodeType == 1 && el !== copy && firstInParent(el)) {
return breakAtElement(el.parentNode);
}
var table, colgroup, thead, grid, gridHead;
table = closest(el, "table");
colgroup = table && table.querySelector("colgroup");
if (options.repeatHeaders) {
thead = table && table.querySelector("thead");
// If we break page in a Kendo Grid, repeat its header. This ugly hack is
// necessary because a scrollable grid will keep the header in a separate
// <table> element from its content.
//
// XXX: This is likely to break as soon as the widget HTML is modified.
grid = closest(el, ".k-grid.k-widget");
if (grid && grid.querySelector(".k-auto-scrollable")) {
gridHead = grid.querySelector(".k-grid-header");
}
}
var page = makePage();
var range = doc.createRange();
range.setStartBefore(copy);
range.setEndBefore(el);
page.appendChild(range.extractContents());
copy.parentNode.insertBefore(page, copy);
preventBulletOnListItem(el.parentNode);
if (table) {
table = closest(el, "table"); // that's the <table> on next page!
if (options.repeatHeaders && thead) {
table.insertBefore(thead.cloneNode(true), table.firstChild);
}
if (colgroup) {
table.insertBefore(colgroup.cloneNode(true), table.firstChild);
}
}
if (options.repeatHeaders && gridHead) {
grid = closest(el, ".k-grid.k-widget");
grid.insertBefore(gridHead.cloneNode(true), grid.firstChild);
}
}
function makePage() {
var page = doc.createElement("KENDO-PDF-PAGE");
setCSS(page, {
display : "block",
boxSizing: "content-box",
width : pageWidth ? (pageWidth + "px") : "auto",
padding : (margin.top + "px " +
margin.right + "px " +
margin.bottom + "px " +
margin.left + "px"),
// allow absolutely positioned elements to be relative to current page
position : "relative",
// without the following we might affect layout of subsequent pages
height : pageHeight ? (pageHeight + "px") : "auto",
overflow : pageHeight || pageWidth ? "hidden" : "visible",
clear : "both"
});
// debug
// $("<div>").css({
// position : "absolute",
// left : margin.left,
// top : margin.top,
// width : pageWidth,
// height : pageHeight,
// boxSizing : "border-box",
// background: "rgba(255, 255, 0, 0.5)"
// //border : "1px solid red"
// }).appendTo(page);
if (options && options.pageClassName) {
page.className = options.pageClassName;
}
pages.push(page);
return page;
}
function fallsOnMargin(thing) {
var box = thing.getBoundingClientRect();
if (box.width === 0 || box.height === 0) {
// I'd say an element with dimensions zero fits on current page.
return 0;
}
var top = copy.getBoundingClientRect().top;
var available = pageHeight - adjust;
return (box.height > available) ? 3
: (box.top - top > available) ? 1
: (box.bottom - top > available) ? 2
: 0;
}
function splitText(node, isFirst) {
if (!/\S/.test(node.data)) {
return;
}
var len = node.data.length;
var range = doc.createRange();
range.selectNodeContents(node);
var fall = fallsOnMargin(range);
if (!fall) {
return; // the whole text fits on current page
}
var nextnode = node;
if (fall == 1) {
// starts on next page, break before anyway.
if (isFirst) {
// avoid leaving an empty <p>, <li>, etc. on previous page.
breakAtElement(node.parentNode);
} else {
breakAtElement(node);
}
}
else {
(function findEOP(min, pos, max) {
range.setEnd(node, pos);
if (min == pos || pos == max) {
return pos;
}
if (fallsOnMargin(range)) {
return findEOP(min, (min + pos) >> 1, pos);
} else {
return findEOP(pos, (pos + max) >> 1, max);
}
})(0, len >> 1, len);
if (!/\S/.test(range.toString()) && isFirst) {
// avoid leaving an empty <p>, <li>, etc. on previous page.
breakAtElement(node.parentNode);
} else {
// This is only needed for IE, but it feels cleaner to do it anyway. Without
// it, IE will truncate a very long text (playground/pdf-long-text-2.html).
nextnode = node.splitText(range.endOffset);
var page = makePage();
range.setStartBefore(copy);
page.appendChild(range.extractContents());
copy.parentNode.insertBefore(page, copy);
preventBulletOnListItem(nextnode.parentNode);
}
}
splitText(nextnode);
}
function preventBulletOnListItem(el) {
// set a hint on continued LI elements, to tell the
// renderer not to draw the bullet again.
// https://github.com/telerik/kendo-ui-core/issues/2732
var li = closest(el, "li");
if (li) {
li.setAttribute("kendo-no-bullet", "1");
preventBulletOnListItem(li.parentNode);
}
}
}
return promise;
}
drawDOM.getFontFaces = getFontFaces;
// This is needed for the Spreadsheet print functionality. Since
// there we only need to draw text, this cuts through the ceremony
// of drawDOM/renderElement and renders the text node directly.
drawDOM.drawText = function(element) {
var group = new Group();
nodeInfo._clipbox = false;
nodeInfo._matrix = Matrix.unit();
nodeInfo._stackingContext = {
element: element,
group: group
};
pushNodeInfo(element, getComputedStyle(element), group);
if (element.firstChild.nodeType == 3 /* Text */) {
// avoid the penalty of renderElement
renderText(element, element.firstChild, group);
} else {
_renderElement(element, group);
}
popNodeInfo();
return group;
};
var parseBackgroundImage = (function(){
var tok_linear_gradient = /^((-webkit-|-moz-|-o-|-ms-)?linear-gradient\s*)\(/;
//var tok_radial_gradient = /^((-webkit-|-moz-|-o-|-ms-)?radial-gradient\s*)\(/;
var tok_percent = /^([-0-9.]+%)/;
var tok_length = /^([-0-9.]+px)/;
var tok_keyword = /^(left|right|top|bottom|to|center)\W/;
var tok_angle = /^([-0-9.]+(deg|grad|rad|turn))/;
var tok_whitespace = /^(\s+)/;
var tok_popen = /^(\()/;
var tok_pclose = /^(\))/;
var tok_comma = /^(,)/;
var tok_url = /^(url)\(/;
var tok_content = /^(.*?)\)/;
var cache1 = {}, cache2 = {};
function parse(input) {
var orig = input;
if (hasOwnProperty(cache1, orig)) {
return cache1[orig];
}
function skip_ws() {
var m = tok_whitespace.exec(input);
if (m) {
input = input.substr(m[1].length);
}
}
function read(token) {
skip_ws();
var m = token.exec(input);
if (m) {
input = input.substr(m[1].length);
return m[1];
}
}
function read_stop() {
var color = kendo.parseColor(input, true);
var length, percent;
if (color) {
var match =
/^#[0-9a-f]+/i.exec(input) ||
/^rgba?\(.*?\)/i.exec(input) ||
/^..*?\b/.exec(input); // maybe named color
input = input.substr(match[0].length);
color = color.toRGB();
if (!(length = read(tok_length))) {
percent = read(tok_percent);
}
return { color: color, length: length, percent: percent };
}
}
function read_linear_gradient(propName) {
var angle;
var to1, to2;
var stops = [];
var reverse = false;
if (read(tok_popen)) {
// 1. [ <angle> || to <side-or-corner>, ]?
angle = read(tok_angle);
if (angle) {
angle = parseAngle(angle);
read(tok_comma);
}
else {
to1 = read(tok_keyword);
if (to1 == "to") {
to1 = read(tok_keyword);
} else if (to1 && /^-/.test(propName)) {
reverse = true;
}
to2 = read(tok_keyword);
read(tok_comma);
}
if (/-moz-/.test(propName) && angle == null && to1 == null) {
var x = read(tok_percent), y = read(tok_percent);
reverse = true;
if (x == "0%") {
to1 = "left";
} else if (x == "100%") {
to1 = "right";
}
if (y == "0%") {
to2 = "top";
} else if (y == "100%") {
to2 = "bottom";
}
read(tok_comma);
}
// 2. color stops
while (input && !read(tok_pclose)) {
var stop = read_stop();
if (!stop) {
break;
}
stops.push(stop);
read(tok_comma);
}
return {
type : "linear",
angle : angle,
to : to1 && to2 ? to1 + " " + to2 : to1 ? to1 : to2 ? to2 : null,
stops : stops,
reverse : reverse
};
}
}
function read_url() {
if (read(tok_popen)) {
var url = read(tok_content);
url = url.replace(/^['"]+|["']+$/g, "");
read(tok_pclose);
return { type: "url", url: url };
}
}
var tok;
if ((tok = read(tok_linear_gradient))) {
tok = read_linear_gradient(tok);
}
else if ((tok = read(tok_url))) {
tok = read_url();
}
return (cache1[orig] = tok || { type: "none" });
}
return function(input) {
if (hasOwnProperty(cache2, input)) {
return cache2[input];
}
return (cache2[input] = splitProperty(input).map(parse));
};
})();
var splitProperty = (function(){
var cache = {};
return function(input, separator) {
if (!separator) {
separator = /^\s*,\s*/;
}
var cacheKey = input + separator;
if (hasOwnProperty(cache, cacheKey)) {
return cache[cacheKey];
}
var ret = [];
var last$$1 = 0, pos = 0;
var in_paren = 0;
var in_string = false;
var m;
function looking_at(rx) {
return (m = rx.exec(input.substr(pos)));
}
function trim(str) {
return str.replace(/^\s+|\s+$/g, "");
}
while (pos < input.length) {
if (!in_string && looking_at(/^[\(\[\{]/)) {
in_paren++;
pos++;
}
else if (!in_string && looking_at(/^[\)\]\}]/)) {
in_paren--;
pos++;
}
else if (!in_string && looking_at(/^[\"\']/)) {
in_string = m[0];
pos++;
}
else if (in_string == "'" && looking_at(/^\\\'/)) {
pos += 2;
}
else if (in_string == '"' && looking_at(/^\\\"/)) {
pos += 2;
}
else if (in_string == "'" && looking_at(/^\'/)) {
in_string = false;
pos++;
}
else if (in_string == '"' && looking_at(/^\"/)) {
in_string = false;
pos++;
}
else if (looking_at(separator)) {
if (!in_string && !in_paren && pos > last$$1) {
ret.push(trim(input.substring(last$$1, pos)));
last$$1 = pos + m[0].length;
}
pos += m[0].length;
}
else {
pos++;
}
}
if (last$$1 < pos) {
ret.push(trim(input.substring(last$$1, pos)));
}
return (cache[cacheKey] = ret);
};
})();
var getFontURL = (function(cache){
return function(el){
// XXX: for IE we get here the whole cssText of the rule,
// because the computedStyle.src is empty. Next time we need
// to fix these regexps we better write a CSS parser. :-\
var url = cache[el];
if (!url) {
var m;
if ((m = /url\((['"]?)([^'")]*?)\1\)\s+format\((['"]?)truetype\3\)/.exec(el))) {
url = cache[el] = m[2];
} else if ((m = /url\((['"]?)([^'")]*?\.ttf)\1\)/.exec(el))) {
url = cache[el] = m[2];
}
}
return url;
};
})(Object.create ? Object.create(null) : {});
var getFontHeight = (function(cache){
return function(font) {
var height = cache[font];
if (height == null) {
height = cache[font] = kendoUtil.measureText("Mapq", { font: font }).height;
}
return height;
};
})(Object.create ? Object.create(null) : {});
function getFontFaces(doc) {
if (doc == null) {
doc = document;
}
var result = {};
for (var i = 0; i < doc.styleSheets.length; ++i) {
doStylesheet(doc.styleSheets[i]);
}
return result;
function doStylesheet(ss) {
if (ss) {
var rules = null;
try {
rules = ss.cssRules;
} catch (ex) {}
if (rules) {
addRules(ss, rules);
}
}
}
function findFonts(rule) {
var src = getPropertyValue(rule.style, "src");
if (src) {
return splitProperty(src).reduce(function(a, el){
var font = getFontURL(el);
if (font) {
a.push(font);
}
return a;
}, []);
} else {
// Internet Explorer
// XXX: this is gross. should work though for valid CSS.
var font = getFontURL(rule.cssText);
return font ? [ font ] : [];
}
}
function addRules(styleSheet, rules) {
for (var i = 0; i < rules.length; ++i) {
var r = rules[i];
switch (r.type) {
case 3: // CSSImportRule
doStylesheet(r.styleSheet);
break;
case 5: // CSSFontFaceRule
var style = r.style;
var family = splitProperty(getPropertyValue(style, "font-family"));
var bold = /^([56789]00|bold)$/i.test(getPropertyValue(style, "font-weight"));
var italic = "italic" == getPropertyValue(style, "font-style");
var src = findFonts(r);
if (src.length > 0) {
addRule(styleSheet, family, bold, italic, src[0]);
}
}
}
}
function addRule(styleSheet, names, bold, italic, url) {
// We get full resolved absolute URLs in Chrome, but sadly
// not in Firefox.
if (!(/^data:/i.test(url))) {
if (!(/^[^\/:]+:\/\//.test(url) || /^\//.test(url))) {
url = String(styleSheet.href).replace(/[^\/]*$/, "") + url;
}
}
names.forEach(function(name){
name = name.replace(/^(['"]?)(.*?)\1$/, "$2"); // it's quoted
if (bold) {
name += "|bold";
}
if (italic) {
name += "|italic";
}
result[name] = url;
});
}
}
function hasOwnProperty(obj, key) {
return Object.prototype.hasOwnProperty.call(obj, key);
}
function getCounter(name) {
name = "_counter_" + name;
return nodeInfo[name];
}
function getAllCounters(name) {
var values = [], p = nodeInfo;
name = "_counter_" + name;
while (p) {
if (hasOwnProperty(p, name)) {
values.push(p[name]);
}
p = Object.getPrototypeOf(p);
}
return values.reverse();
}
function incCounter(name, inc) {
var p = nodeInfo;
name = "_counter_" + name;
while (p && !hasOwnProperty(p, name)) {
p = Object.getPrototypeOf(p);
}
if (!p) {
p = nodeInfo._root;
}
p[name] = (p[name] || 0) + (inc == null ? 1 : inc);
}
function resetCounter(name, val) {
name = "_counter_" + name;
nodeInfo[name] = val == null ? 0 : val;
}
function doCounters(a, f, def) {
for (var i = 0; i < a.length;) {
var name = a[i++];
var val = parseFloat(a[i]);
if (isNaN(val)) {
f(name, def);
} else {
f(name, val);
++i;
}
}
}
function updateCounters(style) {
var counterReset = getPropertyValue(style, "counter-reset");
if (counterReset) {
doCounters(splitProperty(counterReset, /^\s+/), resetCounter, 0);
}
var counterIncrement = getPropertyValue(style, "counter-increment");
if (counterIncrement) {
doCounters(splitProperty(counterIncrement, /^\s+/), incCounter, 1);
}
}
function parseColor$1(str, css) {
var color = kendo.parseColor(str, true);
if (color) {
color = color.toRGB();
if (css) {
color = color.toCssRgba();
} else if (color.a === 0) {
color = null;
}
}
return color;
}
function whenImagesAreActuallyLoaded(elements, callback) {
var pending = 0;
elements.forEach(function(el){
var images = el.querySelectorAll("img");
for (var i = 0; i < images.length; ++i) {
var img = images[i];
if (!img.complete) {
pending++;
img.onload = img.onerror = next;
}
}
});
if (!pending) {
next();
}
function next() {
if (--pending <= 0) {
callback();
}
}
}
function cacheImages(element, callback) {
var urls = [];
function add(url) {
if (!IMAGE_CACHE[url]) {
IMAGE_CACHE[url] = true;
urls.push(url);
}
}
function dive(element){
if (/^img$/i.test(element.tagName)) {
add(element.src);
}
parseBackgroundImage(
getPropertyValue(
getComputedStyle(element), "background-image"
)
).forEach(function(bg){
if (bg.type == "url") {
add(bg.url);
}
});
if (element.children) {
slice$1(element.children).forEach(dive);
}
}
if (Array.isArray(element)) {
element.forEach(dive);
} else {
dive(element);
}
var count = urls.length;
function next() {
if (--count <= 0) {
callback();
}
}
if (count === 0) {
next();
}
urls.forEach(function(url){
var img = IMAGE_CACHE[url] = new window.Image();
if (!(/^data:/i.test(url))) {
img.crossOrigin = "Anonymous";
}
img.src = url;
if (img.complete) {
next();
} else {
img.onload = next;
img.onerror = function() {
IMAGE_CACHE[url] = null;
next();
};
}
});
}
function alphaNumeral(n) {
var result = "";
do {
var r = n % 26;
result = String.fromCharCode(97 + r) + result;
n = Math.floor(n / 26);
} while (n > 0);
return result;
}
function pushNodeInfo(element, style, group) {
nodeInfo = Object.create(nodeInfo);
nodeInfo[element.tagName.toLowerCase()] = {
element: element,
style: style
};
var decoration = getPropertyValue(style, "text-decoration");
if (decoration && decoration != "none") {
var color = getPropertyValue(style, "color");
decoration.split(/\s+/g).forEach(function(name){
if (!nodeInfo[name]) {
nodeInfo[name] = color;
}
});
}
if (createsStackingContext(style)) {
nodeInfo._stackingContext = {
element: element,
group: group
};
}
}
function popNodeInfo() {
nodeInfo = Object.getPrototypeOf(nodeInfo);
}
function updateClipbox(path) {
if (nodeInfo._clipbox != null) {
var box = path.bbox(nodeInfo._matrix);
if (nodeInfo._clipbox) {
nodeInfo._clipbox = Rect.intersect(nodeInfo._clipbox, box);
} else {
nodeInfo._clipbox = box;
}
}
}
function emptyClipbox() {
var cb = nodeInfo._clipbox;
if (cb == null) {
return true;
}
if (cb) {
return cb.width() === 0 || cb.height() === 0;
}
}
function createsStackingContext(style) {
function prop(name) { return getPropertyValue(style, name); }
if (prop("transform") != "none" ||
prop("position") != "static" ||
prop("z-index") != "auto" ||
prop("opacity") < 1) {
return true;
}
}
function getComputedStyle(element, pseudoElt) {
return window.getComputedStyle(element, pseudoElt || null);
}
function getPropertyValue(style, prop, defa) {
var val = style.getPropertyValue(prop);
if (val == null || val === "") {
if (browser.webkit) {
val = style.getPropertyValue("-webkit-" + prop );
} else if (browser.mozilla) {
val = style.getPropertyValue("-moz-" + prop );
} else if (browser.opera) {
val = style.getPropertyValue("-o-" + prop);
} else if (microsoft) {
val = style.getPropertyValue("-ms-" + prop);
}
}
if (arguments.length > 2 && (val == null || val === "")) {
return defa;
} else {
return val;
}
}
function pleaseSetPropertyValue(style, prop, value, important) {
style.setProperty(prop, value, important);
if (browser.webkit) {
style.setProperty("-webkit-" + prop, value, important);
} else if (browser.mozilla) {
style.setProperty("-moz-" + prop, value, important);
} else if (browser.opera) {
style.setProperty("-o-" + prop, value, important);
} else if (microsoft) {
style.setProperty("-ms-" + prop, value, important);
prop = "ms" + prop.replace(/(^|-)([a-z])/g, function(s, p1, p2){
return p1 + p2.toUpperCase();
});
style[prop] = value;
}
}
function getBorder(style, side) {
side = "border-" + side;
return {
width: parseFloat(getPropertyValue(style, side + "-width")),
style: getPropertyValue(style, side + "-style"),
color: parseColor$1(getPropertyValue(style, side + "-color"), true)
};
}
function saveStyle(element, func) {
var prev = element.style.cssText;
var result = func();
element.style.cssText = prev;
return result;
}
function getBorderRadius(style, side) {
var r = getPropertyValue(style, "border-" + side + "-radius").split(/\s+/g).map(parseFloat);
if (r.length == 1) {
r.push(r[0]);
}
return sanitizeRadius({ x: r[0], y: r[1] });
}
function getContentBox(element) {
var box = element.getBoundingClientRect();
box = innerBox(box, "border-*-width", element);
box = innerBox(box, "padding-*", element);
return box;
}
function innerBox(box, prop, element) {
var style, wt, wr, wb, wl;
if (typeof prop == "string") {
style = getComputedStyle(element);
wt = parseFloat(getPropertyValue(style, prop.replace("*", "top")));
wr = parseFloat(getPropertyValue(style, prop.replace("*", "right")));
wb = parseFloat(getPropertyValue(style, prop.replace("*", "bottom")));
wl = parseFloat(getPropertyValue(style, prop.replace("*", "left")));
}
else if (typeof prop == "number") {
wt = wr = wb = wl = prop;
}
return {
top : box.top + wt,
right : box.right - wr,
bottom : box.bottom - wb,
left : box.left + wl,
width : box.right - box.left - wr - wl,
height : box.bottom - box.top - wb - wt
};
}
function getTransform(style) {
var transform$$1 = getPropertyValue(style, "transform");
if (transform$$1 == "none") {
return null;
}
var matrix = /^\s*matrix\(\s*(.*?)\s*\)\s*$/.exec(transform$$1);
if (matrix) {
var origin = getPropertyValue(style, "transform-origin");
matrix = matrix[1].split(/\s*,\s*/g).map(parseFloat);
origin = origin.split(/\s+/g).map(parseFloat);
return {
matrix: matrix,
origin: origin
};
}
}
function radiansToDegrees(radians) {
return ((180 * radians) / Math.PI) % 360;
}
function parseAngle(angle) {
var num = parseFloat(angle);
if (/grad$/.test(angle)) {
return Math.PI * num / 200;
}
else if (/rad$/.test(angle)) {
return num;
}
else if (/turn$/.test(angle)) {
return Math.PI * num * 2;
}
else if (/deg$/.test(angle)) {
return Math.PI * num / 180;
}
}
function setTransform(shape, m) {
m = new Matrix(m[0], m[1], m[2], m[3], m[4], m[5]);
shape.transform(m);
return m;
}
function setClipping(shape, clipPath) {
shape.clip(clipPath);
}
function addArcToPath(path, x, y, options) {
var points = new Arc$2([ x, y ], options).curvePoints(), i = 1;
while (i < points.length) {
path.curveTo(points[i++], points[i++], points[i++]);
}
}
function sanitizeRadius(r) {
if (r.x <= 0 || r.y <= 0) {
r.x = r.y = 0;
}
return r;
}
function adjustBorderRadiusForBox(box, rTL, rTR, rBR, rBL) {
// adjust border radiuses such that the sum of adjacent
// radiuses is not bigger than the length of the side.
// seems the correct algorithm is variant (3) from here:
// http://www.w3.org/Style/CSS/Tracker/issues/29?changelog
var tl_x = Math.max(0, rTL.x), tl_y = Math.max(0, rTL.y);
var tr_x = Math.max(0, rTR.x), tr_y = Math.max(0, rTR.y);
var br_x = Math.max(0, rBR.x), br_y = Math.max(0, rBR.y);
var bl_x = Math.max(0, rBL.x), bl_y = Math.max(0, rBL.y);
var f = Math.min(
box.width / (tl_x + tr_x),
box.height / (tr_y + br_y),
box.width / (br_x + bl_x),
box.height / (bl_y + tl_y)
);
if (f < 1) {
tl_x *= f; tl_y *= f;
tr_x *= f; tr_y *= f;
br_x *= f; br_y *= f;
bl_x *= f; bl_y *= f;
}
return {
tl: { x: tl_x, y: tl_y },
tr: { x: tr_x, y: tr_y },
br: { x: br_x, y: br_y },
bl: { x: bl_x, y: bl_y }
};
}
function elementRoundBox(element, box, type) {
var style = getComputedStyle(element);
var rTL = getBorderRadius(style, "top-left");
var rTR = getBorderRadius(style, "top-right");
var rBL = getBorderRadius(style, "bottom-left");
var rBR = getBorderRadius(style, "bottom-right");
if (type == "padding" || type == "content") {
var bt = getBorder(style, "top");
var br = getBorder(style, "right");
var bb = getBorder(style, "bottom");
var bl = getBorder(style, "left");
rTL.x -= bl.width; rTL.y -= bt.width;
rTR.x -= br.width; rTR.y -= bt.width;
rBR.x -= br.width; rBR.y -= bb.width;
rBL.x -= bl.width; rBL.y -= bb.width;
if (type == "content") {
var pt = parseFloat(getPropertyValue(style, "padding-top"));
var pr = parseFloat(getPropertyValue(style, "padding-right"));
var pb = parseFloat(getPropertyValue(style, "padding-bottom"));
var pl = parseFloat(getPropertyValue(style, "padding-left"));
rTL.x -= pl; rTL.y -= pt;
rTR.x -= pr; rTR.y -= pt;
rBR.x -= pr; rBR.y -= pb;
rBL.x -= pl; rBL.y -= pb;
}
}
if (typeof type == "number") {
rTL.x -= type; rTL.y -= type;
rTR.x -= type; rTR.y -= type;
rBR.x -= type; rBR.y -= type;
rBL.x -= type; rBL.y -= type;
}
return roundBox(box, rTL, rTR, rBR, rBL);
}
// Create a drawing.Path for a rounded rectangle. Receives the
// bounding box and the border-radiuses in CSS order (top-left,
// top-right, bottom-right, bottom-left). The radiuses must be
// objects containing x (horiz. radius) and y (vertical radius).
function roundBox(box, rTL0, rTR0, rBR0, rBL0) {
var tmp = adjustBorderRadiusForBox(box, rTL0, rTR0, rBR0, rBL0);
var rTL = tmp.tl;
var rTR = tmp.tr;
var rBR = tmp.br;
var rBL = tmp.bl;
var path = new Path({ fill: null, stroke: null });
path.moveTo(box.left, box.top + rTL.y);
if (rTL.x) {
addArcToPath(path, box.left + rTL.x, box.top + rTL.y, {
startAngle: -180,
endAngle: -90,
radiusX: rTL.x,
radiusY: rTL.y
});
}
path.lineTo(box.right - rTR.x, box.top);
if (rTR.x) {
addArcToPath(path, box.right - rTR.x, box.top + rTR.y, {
startAngle: -90,
endAngle: 0,
radiusX: rTR.x,
radiusY: rTR.y
});
}
path.lineTo(box.right, box.bottom - rBR.y);
if (rBR.x) {
addArcToPath(path, box.right - rBR.x, box.bottom - rBR.y, {
startAngle: 0,
endAngle: 90,
radiusX: rBR.x,
radiusY: rBR.y
});
}
path.lineTo(box.left + rBL.x, box.bottom);
if (rBL.x) {
addArcToPath(path, box.left + rBL.x, box.bottom - rBL.y, {
startAngle: 90,
endAngle: 180,
radiusX: rBL.x,
radiusY: rBL.y
});
}
return path.close();
}
function formatCounter(val, style) {
var str = String(parseFloat(val));
switch (style) {
case "decimal-leading-zero":
if (str.length < 2) {
str = "0" + str;
}
return str;
case "lower-roman":
return arabicToRoman(val).toLowerCase();
case "upper-roman":
return arabicToRoman(val).toUpperCase();
case "lower-latin":
case "lower-alpha":
return alphaNumeral(val - 1);
case "upper-latin":
case "upper-alpha":
return alphaNumeral(val - 1).toUpperCase();
default:
return str;
}
}
function evalPseudoElementContent(element, content) {
function displayCounter(name, style, separator) {
if (!separator) {
return formatCounter(getCounter(name) || 0, style);
}
separator = separator.replace(/^\s*(["'])(.*)\1\s*$/, "$2");
return getAllCounters(name).map(function(val){
return formatCounter(val, style);
}).join(separator);
}
var a = splitProperty(content, /^\s+/);
var result = [], m;
a.forEach(function(el){
var tmp;
if ((m = /^\s*(["'])(.*)\1\s*$/.exec(el))) {
result.push(m[2].replace(/\\([0-9a-f]{4})/gi, function(s, p){
return String.fromCharCode(parseInt(p, 16));
}));
}
else if ((m = /^\s*counter\((.*?)\)\s*$/.exec(el))) {
tmp = splitProperty(m[1]);
result.push(displayCounter(tmp[0], tmp[1]));
}
else if ((m = /^\s*counters\((.*?)\)\s*$/.exec(el))) {
tmp = splitProperty(m[1]);
result.push(displayCounter(tmp[0], tmp[2], tmp[1]));
}
else if ((m = /^\s*attr\((.*?)\)\s*$/.exec(el))) {
result.push(element.getAttribute(m[1]) || "");
}
else {
result.push(el);
}
});
return result.join("");
}
function getCssText(style) {
if (style.cssText) {
return style.cssText;
}
// Status: NEW. Report year: 2002. Current year: 2014.
// Nice played, Mozillians.
// https://bugzilla.mozilla.org/show_bug.cgi?id=137687
var result = [];
for (var i = 0; i < style.length; ++i) {
result.push(style[i] + ": " + getPropertyValue(style, style[i]));
}
return result.join(";\n");
}
function _renderWithPseudoElements(element, group) {
if (element.tagName == KENDO_PSEUDO_ELEMENT) {
_renderElement(element, group);
return;
}
var fake = [];
function pseudo(kind, place) {
var style = getComputedStyle(element, kind), content = style.content;
updateCounters(style);
if (content && content != "normal" && content != "none" && style.width != "0px") {
var psel = element.ownerDocument.createElement(KENDO_PSEUDO_ELEMENT);
psel.style.cssText = getCssText(style);
psel.textContent = evalPseudoElementContent(element, content);
element.insertBefore(psel, place);
fake.push(psel);
}
}
pseudo(":before", element.firstChild);
pseudo(":after", null);
if (fake.length > 0) {
var saveClass = element.className;
element.className += " kendo-pdf-hide-pseudo-elements";
_renderElement(element, group);
element.className = saveClass;
fake.forEach(function(el){ element.removeChild(el); });
} else {
_renderElement(element, group);
}
}
function _renderElement(element, group) {
var style = getComputedStyle(element);
var top = getBorder(style, "top");
var right = getBorder(style, "right");
var bottom = getBorder(style, "bottom");
var left = getBorder(style, "left");
var rTL0 = getBorderRadius(style, "top-left");
var rTR0 = getBorderRadius(style, "top-right");
var rBL0 = getBorderRadius(style, "bottom-left");
var rBR0 = getBorderRadius(style, "bottom-right");
var dir = getPropertyValue(style, "direction");
var backgroundColor = getPropertyValue(style, "background-color");
backgroundColor = parseColor$1(backgroundColor);
var backgroundImage = parseBackgroundImage( getPropertyValue(style, "background-image") );
var backgroundRepeat = splitProperty( getPropertyValue(style, "background-repeat") );
var backgroundPosition = splitProperty( getPropertyValue(style, "background-position") );
var backgroundOrigin = splitProperty( getPropertyValue(style, "background-origin") );
var backgroundSize = splitProperty( getPropertyValue(style, "background-size") );
// IE shrinks the text with text-overflow: ellipsis,
// apparently because the returned bounding box for the range
// is limited to the visible area minus space for the dots,
// instead of being the full width of the text.
//
// https://github.com/telerik/kendo/issues/5232
// https://github.com/telerik/kendo-ui-core/issues/1868
//
// We have to test it here rather than in renderText because
// text-overflow: ellipsis could be set on a parent element (not
// necessarily the one containing the text); in this case,
// getComputedStyle(elementWithTheText) will return "clip", not
// "ellipsis" (which is probably a bug, but oh well...)
var textOverflow, saveTextOverflow;
if (microsoft) {
textOverflow = style.textOverflow; // computed style
if (textOverflow == "ellipsis") {
saveTextOverflow = element.style.textOverflow; // own style.
element.style.textOverflow = "clip";
}
}
if (browser.msie && browser.version < 10) {
// IE9 hacks. getPropertyValue won't return the correct
// value. Sucks that we have to do it here, I'd prefer to
// move it in getPropertyValue, but we don't have the
// element.
backgroundPosition = splitProperty(element.currentStyle.backgroundPosition);
}
var innerbox = innerBox(element.getBoundingClientRect(), "border-*-width", element);
// CSS "clip" property - if present, replace the group with a
// new one which is clipped. This must happen before drawing
// the borders and background.
(function(){
var clip = getPropertyValue(style, "clip");
var m = /^\s*rect\((.*)\)\s*$/.exec(clip);
if (m) {
var a = m[1].split(/[ ,]+/g);
var top = a[0] == "auto" ? innerbox.top : parseFloat(a[0]) + innerbox.top;
var right = a[1] == "auto" ? innerbox.right : parseFloat(a[1]) + innerbox.left;
var bottom = a[2] == "auto" ? innerbox.bottom : parseFloat(a[2]) + innerbox.top;
var left = a[3] == "auto" ? innerbox.left : parseFloat(a[3]) + innerbox.left;
var tmp = new Group();
var clipPath = new Path()
.moveTo(left, top)
.lineTo(right, top)
.lineTo(right, bottom)
.lineTo(left, bottom)
.close();
setClipping(tmp, clipPath);
group.append(tmp);
group = tmp;
updateClipbox(clipPath);
}
})();
var boxes, i, cells;
var display = getPropertyValue(style, "display");
if (display == "table-row") {
// because of rowspan/colspan, we shouldn't draw background of table row elements on the
// box given by its getBoundingClientRect, because if we do we risk overwritting a
// previously rendered cell. https://github.com/telerik/kendo/issues/4881
boxes = [];
for (i = 0, cells = element.children; i < cells.length; ++i) {
boxes.push(cells[i].getBoundingClientRect());
}
} else {
boxes = element.getClientRects();
if (boxes.length == 1) {
// Workaround the missing borders in Chrome! getClientRects() boxes contains values
// rounded to integer. getBoundingClientRect() appears to work fine. We still need
// getClientRects() to support cases where there are more boxes (continued inline
// elements that might have border/background).
boxes = [ element.getBoundingClientRect() ];
}
}
// This function workarounds another Chrome bug, where boxes returned for a table with
// border-collapse: collapse will overlap the table border. Our rendering is not perfect in
// such case anyway, but with this is better than without it.
boxes = adjustBoxes(boxes);
for (i = 0; i < boxes.length; ++i) {
drawOneBox(boxes[i], i === 0, i == boxes.length - 1);
}
// Render links as separate groups. We can't use boxes returned by element's getClientRects
// because if display type is "inline" (default for <a>), boxes will not include the height of
// images inside. https://github.com/telerik/kendo-ui-core/issues/3359
if (element.tagName == "A" && element.href && !/^#?$/.test(element.getAttribute("href"))) {
if (!nodeInfo._avoidLinks || !matches(element, nodeInfo._avoidLinks)) {
var r = document.createRange();
r.selectNodeContents(element);
slice$1(r.getClientRects()).forEach(function(box){
var g = new Group();
g._pdfLink = {
url : element.href,
top : box.top,
right : box.right,
bottom : box.bottom,
left : box.left
};
group.append(g);
});
}
}
if (boxes.length > 0 && display == "list-item" && !element.getAttribute("kendo-no-bullet")) {
drawBullet(boxes[0]);
}
// overflow: hidden/auto - if present, replace the group with
// a new one clipped by the inner box.
(function(){
function clipit() {
var clipPath = elementRoundBox(element, innerbox, "padding");
var tmp = new Group();
setClipping(tmp, clipPath);
group.append(tmp);
group = tmp;
updateClipbox(clipPath);
}
if (isFormField(element)) {
clipit();
} else if (/^(hidden|auto|scroll)/.test(getPropertyValue(style, "overflow"))) {
clipit();
} else if (/^(hidden|auto|scroll)/.test(getPropertyValue(style, "overflow-x"))) {
clipit();
} else if (/^(hidden|auto|scroll)/.test(getPropertyValue(style, "overflow-y"))) {
clipit();
}
})();
if (!maybeRenderWidget(element, group)) {
renderContents(element, group);
}
if (microsoft && textOverflow == "ellipsis") {
element.style.textOverflow = saveTextOverflow;
}
return group; // only utility functions after this line.
function adjustBoxes(boxes) {
if (/^td$/i.test(element.tagName)) {
var table = nodeInfo.table;
if (table && getPropertyValue(table.style, "border-collapse") == "collapse") {
var tableBorderLeft = getBorder(table.style, "left").width;
var tableBorderTop = getBorder(table.style, "top").width;
// check if we need to adjust
if (tableBorderLeft === 0 && tableBorderTop === 0) {
return boxes; // nope
}
var tableBox = table.element.getBoundingClientRect();
var firstCell = table.element.rows[0].cells[0];
var firstCellBox = firstCell.getBoundingClientRect();
if (firstCellBox.top == tableBox.top || firstCellBox.left == tableBox.left) {
return slice$1(boxes).map(function(box){
return {
left : box.left + tableBorderLeft,
top : box.top + tableBorderTop,
right : box.right + tableBorderLeft,
bottom : box.bottom + tableBorderTop,
height : box.height,
width : box.width
};
});
}
}
}
return boxes;
}
// this function will be called to draw each border. it
// draws starting at origin and the resulted path must be
// translated/rotated to be placed in the proper position.
//
// arguments are named as if it draws the top border:
//
// - `len` the length of the edge
// - `Wtop` the width of the edge (i.e. border-top-width)
// - `Wleft` the width of the left edge (border-left-width)
// - `Wright` the width of the right edge
// - `rl` and `rl` -- the border radius on the left and right
// (objects containing x and y, for horiz/vertical radius)
// - `transform` -- transformation to apply
//
function drawEdge(color, len, Wtop, Wleft, Wright, rl, rr, transform$$1) {
if (Wtop <= 0) {
return;
}
var path, edge = new Group();
setTransform(edge, transform$$1);
group.append(edge);
sanitizeRadius(rl);
sanitizeRadius(rr);
// draw main border. this is the area without the rounded corners
path = new Path({
fill: { color: color },
stroke: null
});
edge.append(path);
path.moveTo(rl.x ? Math.max(rl.x, Wleft) : 0, 0)
.lineTo(len - (rr.x ? Math.max(rr.x, Wright) : 0), 0)
.lineTo(len - Math.max(rr.x, Wright), Wtop)
.lineTo(Math.max(rl.x, Wleft), Wtop)
.close();
if (rl.x) {
drawRoundCorner(Wleft, rl, [ -1, 0, 0, 1, rl.x, 0 ]);
}
if (rr.x) {
drawRoundCorner(Wright, rr, [ 1, 0, 0, 1, len - rr.x, 0 ]);
}
// draws one round corner, starting at origin (needs to be
// translated/rotated to be placed properly).
function drawRoundCorner(Wright, r, transform$$1) {
var angle = Math.PI/2 * Wright / (Wright + Wtop);
// not sanitizing this one, because negative values
// are useful to fill the box correctly.
var ri = {
x: r.x - Wright,
y: r.y - Wtop
};
var path = new Path({
fill: { color: color },
stroke: null
}).moveTo(0, 0);
setTransform(path, transform$$1);
addArcToPath(path, 0, r.y, {
startAngle: -90,
endAngle: -radiansToDegrees(angle),
radiusX: r.x,
radiusY: r.y
});
if (ri.x > 0 && ri.y > 0) {
path.lineTo(ri.x * Math.cos(angle), r.y - ri.y * Math.sin(angle));
addArcToPath(path, 0, r.y, {
startAngle: -radiansToDegrees(angle),
endAngle: -90,
radiusX: ri.x,
radiusY: ri.y,
anticlockwise: true
});
}
else if (ri.x > 0) {
path.lineTo(ri.x, Wtop)
.lineTo(0, Wtop);
}
else {
path.lineTo(ri.x, Wtop)
.lineTo(ri.x, 0);
}
edge.append(path.close());
}
}
function drawBackground(box) {
var background = new Group();
setClipping(background, roundBox(box, rTL0, rTR0, rBR0, rBL0));
group.append(background);
if (backgroundColor) {
var path = new Path({
fill: { color: backgroundColor.toCssRgba() },
stroke: null
});
path.moveTo(box.left, box.top)
.lineTo(box.right, box.top)
.lineTo(box.right, box.bottom)
.lineTo(box.left, box.bottom)
.close();
background.append(path);
}
for (var i = backgroundImage.length; --i >= 0;) {
drawOneBackground(
background, box,
backgroundImage[i],
backgroundRepeat[i % backgroundRepeat.length],
backgroundPosition[i % backgroundPosition.length],
backgroundOrigin[i % backgroundOrigin.length],
backgroundSize[i % backgroundSize.length]
);
}
}
function drawOneBackground(group, box, background, backgroundRepeat, backgroundPosition, backgroundOrigin, backgroundSize) {
if (!background || (background == "none")) {
return;
}
if (background.type == "url") {
// SVG taints the canvas, can't draw it.
if (/^url\(\"data:image\/svg/i.test(background.url)) {
return;
}
var img = IMAGE_CACHE[background.url];
if (img && img.width > 0 && img.height > 0) {
drawBackgroundImage(group, box, img.width, img.height, function(group, rect){
group.append(new Image$1(background.url, rect));
});
}
} else if (background.type == "linear") {
drawBackgroundImage(group, box, box.width, box.height, gradientRenderer(background));
} else {
return;
}
function drawBackgroundImage(group, box, img_width, img_height, renderBG) {
var aspect_ratio = img_width / img_height, f;
// for background-origin: border-box the box is already appropriate
var orgBox = box;
if (backgroundOrigin == "content-box") {
orgBox = innerBox(orgBox, "border-*-width", element);
orgBox = innerBox(orgBox, "padding-*", element);
} else if (backgroundOrigin == "padding-box") {
orgBox = innerBox(orgBox, "border-*-width", element);
}
if (!/^\s*auto(\s+auto)?\s*$/.test(backgroundSize)) {
if (backgroundSize == "contain") {
f = Math.min(orgBox.width / img_width,
orgBox.height / img_height);
img_width *= f;
img_height *= f;
}
else if (backgroundSize == "cover") {
f = Math.max(orgBox.width / img_width,
orgBox.height / img_height);
img_width *= f;
img_height *= f;
}
else {
var size = backgroundSize.split(/\s+/g);
// compute width
if (/%$/.test(size[0])) {
img_width = orgBox.width * parseFloat(size[0]) / 100;
} else {
img_width = parseFloat(size[0]);
}
// compute height
if (size.length == 1 || size[1] == "auto") {
img_height = img_width / aspect_ratio;
} else if (/%$/.test(size[1])) {
img_height = orgBox.height * parseFloat(size[1]) / 100;
} else {
img_height = parseFloat(size[1]);
}
}
}
var pos = String(backgroundPosition);
// IE sometimes reports single-word positions
// https://github.com/telerik/kendo-ui-core/issues/2786
//
// it seems to switch to percentages when the horizontal
// position is not "center", therefore we don't handle
// multi-word cases here. All other browsers return
// percentages or pixels instead of keywords. At least
// for now...
switch (pos) {
case "bottom" : pos = "50% 100%"; break;
case "top" : pos = "50% 0"; break;
case "left" : pos = "0 50%"; break;
case "right" : pos = "100% 50%"; break;
case "center" : pos = "50% 50%"; break;
}
pos = pos.split(/\s+/);
if (pos.length == 1) {
pos[1] = "50%";
}
if (/%$/.test(pos[0])) {
pos[0] = parseFloat(pos[0]) / 100 * (orgBox.width - img_width);
} else {
pos[0] = parseFloat(pos[0]);
}
if (/%$/.test(pos[1])) {
pos[1] = parseFloat(pos[1]) / 100 * (orgBox.height - img_height);
} else {
pos[1] = parseFloat(pos[1]);
}
var rect = new Rect([ orgBox.left + pos[0], orgBox.top + pos[1] ], [ img_width, img_height ]);
// XXX: background-repeat could be implemented more
// efficiently as a fill pattern (at least for PDF
// output, probably SVG too).
function rewX() {
while (rect.origin.x > box.left) {
rect.origin.x -= img_width;
}
}
function rewY() {
while (rect.origin.y > box.top) {
rect.origin.y -= img_height;
}
}
function repeatX() {
while (rect.origin.x < box.right) {
renderBG(group, rect.clone());
rect.origin.x += img_width;
}
}
if (backgroundRepeat == "no-repeat") {
renderBG(group, rect);
}
else if (backgroundRepeat == "repeat-x") {
rewX();
repeatX();
}
else if (backgroundRepeat == "repeat-y") {
rewY();
while (rect.origin.y < box.bottom) {
renderBG(group, rect.clone());
rect.origin.y += img_height;
}
}
else if (backgroundRepeat == "repeat") {
rewX();
rewY();
var origin = rect.origin.clone();
while (rect.origin.y < box.bottom) {
rect.origin.x = origin.x;
repeatX();
rect.origin.y += img_height;
}
}
}
}
function drawBullet() {
var listStyleType = getPropertyValue(style, "list-style-type");
if (listStyleType == "none") {
return;
}
var listStylePosition = getPropertyValue(style, "list-style-position");
function _drawBullet(f) {
saveStyle(element, function(){
element.style.position = "relative";
var bullet = element.ownerDocument.createElement(KENDO_PSEUDO_ELEMENT);
bullet.style.position = "absolute";
bullet.style.boxSizing = "border-box";
if (listStylePosition == "outside") {
bullet.style.width = "6em";
bullet.style.left = "-6.8em";
bullet.style.textAlign = "right";
} else {
bullet.style.left = "0px";
}
f(bullet);
element.insertBefore(bullet, element.firstChild);
renderElement(bullet, group);
element.removeChild(bullet);
});
}
function elementIndex(f) {
var a = element.parentNode.children;
var k = element.getAttribute("kendo-split-index");
if (k != null) {
return f(k|0, a.length);
}
for (var i = 0; i < a.length; ++i) {
if (a[i] === element) {
return f(i, a.length);
}
}
}
switch (listStyleType) {
case "circle":
case "disc":
case "square":
_drawBullet(function(bullet){
// XXX: the science behind these values is called "trial and error".
bullet.style.fontSize = "60%";
bullet.style.lineHeight = "200%";
bullet.style.paddingRight = "0.5em";
bullet.style.fontFamily = "DejaVu Serif";
bullet.innerHTML = {
"disc" : "\u25cf",
"circle" : "\u25ef",
"square" : "\u25a0"
}[listStyleType];
});
break;
case "decimal":
case "decimal-leading-zero":
_drawBullet(function(bullet){
elementIndex(function(idx){
++idx;
if (listStyleType == "decimal-leading-zero" && idx < 10) {
idx = "0" + idx;
}
bullet.innerHTML = idx + ".";
});
});
break;
case "lower-roman":
case "upper-roman":
_drawBullet(function(bullet){
elementIndex(function(idx){
idx = arabicToRoman(idx + 1);
if (listStyleType == "upper-roman") {
idx = idx.toUpperCase();
}
bullet.innerHTML = idx + ".";
});
});
break;
case "lower-latin":
case "lower-alpha":
case "upper-latin":
case "upper-alpha":
_drawBullet(function(bullet){
elementIndex(function(idx){
idx = alphaNumeral(idx);
if (/^upper/i.test(listStyleType)) {
idx = idx.toUpperCase();
}
bullet.innerHTML = idx + ".";
});
});
break;
}
}
// draws a single border box
function drawOneBox(box, isFirst, isLast) {
if (box.width === 0 || box.height === 0) {
return;
}
drawBackground(box);
var shouldDrawLeft = (left.width > 0 && ((isFirst && dir == "ltr") || (isLast && dir == "rtl")));
var shouldDrawRight = (right.width > 0 && ((isLast && dir == "ltr") || (isFirst && dir == "rtl")));
// The most general case is that the 4 borders have different widths and border
// radiuses. The way that is handled is by drawing 3 Paths for each border: the
// straight line, and two round corners which represent half of the entire rounded
// corner. To simplify code those shapes are drawed at origin (by the drawEdge
// function), then translated/rotated into the right position.
//
// However, this leads to poor results due to rounding in the simpler cases where
// borders are straight lines. Therefore we handle a few such cases separately with
// straight lines. C^wC^wC^w -- nope, scratch that. poor rendering was because of a bug
// in Chrome (getClientRects() returns rounded integer values rather than exact floats.
// web dev is still a ghetto.)
// first, just in case there is no border...
if (top.width === 0 && left.width === 0 && right.width === 0 && bottom.width === 0) {
return;
}
// START paint borders
// if all borders have equal colors...
if (top.color == right.color && top.color == bottom.color && top.color == left.color) {
// if same widths too, we can draw the whole border by stroking a single path.
if (top.width == right.width && top.width == bottom.width && top.width == left.width)
{
if (shouldDrawLeft && shouldDrawRight) {
// reduce box by half the border width, so we can draw it by stroking.
box = innerBox(box, top.width/2);
// adjust the border radiuses, again by top.width/2, and make the path element.
var path = elementRoundBox(element, box, top.width/2);
path.options.stroke = {
color: top.color,
width: top.width
};
group.append(path);
return;
}
}
}
// if border radiuses are zero and widths are at most one pixel, we can again use simple
// paths.
if (rTL0.x === 0 && rTR0.x === 0 && rBR0.x === 0 && rBL0.x === 0) {
// alright, 1.9px will do as well. the difference in color blending should not be
// noticeable.
if (top.width < 2 && left.width < 2 && right.width < 2 && bottom.width < 2) {
// top border
if (top.width > 0) {
group.append(
new Path({
stroke: { width: top.width, color: top.color }
})
.moveTo(box.left, box.top + top.width/2)
.lineTo(box.right, box.top + top.width/2)
);
}
// bottom border
if (bottom.width > 0) {
group.append(
new Path({
stroke: { width: bottom.width, color: bottom.color }
})
.moveTo(box.left, box.bottom - bottom.width/2)
.lineTo(box.right, box.bottom - bottom.width/2)
);
}
// left border
if (shouldDrawLeft) {
group.append(
new Path({
stroke: { width: left.width, color: left.color }
})
.moveTo(box.left + left.width/2, box.top)
.lineTo(box.left + left.width/2, box.bottom)
);
}
// right border
if (shouldDrawRight) {
group.append(
new Path({
stroke: { width: right.width, color: right.color }
})
.moveTo(box.right - right.width/2, box.top)
.lineTo(box.right - right.width/2, box.bottom)
);
}
return;
}
}
// END paint borders
var tmp = adjustBorderRadiusForBox(box, rTL0, rTR0, rBR0, rBL0);
var rTL = tmp.tl;
var rTR = tmp.tr;
var rBR = tmp.br;
var rBL = tmp.bl;
// top border
drawEdge(top.color,
box.width, top.width, left.width, right.width,
rTL, rTR,
[ 1, 0, 0, 1, box.left, box.top ]);
// bottom border
drawEdge(bottom.color,
box.width, bottom.width, right.width, left.width,
rBR, rBL,
[ -1, 0, 0, -1, box.right, box.bottom ]);
// for left/right borders we need to invert the border-radiuses
function inv(p) {
return { x: p.y, y: p.x };
}
// left border
drawEdge(left.color,
box.height, left.width, bottom.width, top.width,
inv(rBL), inv(rTL),
[ 0, -1, 1, 0, box.left, box.bottom ]);
// right border
drawEdge(right.color,
box.height, right.width, top.width, bottom.width,
inv(rTR), inv(rBR),
[ 0, 1, -1, 0, box.right, box.top ]);
}
}
function gradientRenderer(gradient) {
return function(group, rect) {
var width = rect.width(), height = rect.height();
switch (gradient.type) {
case "linear":
// figure out the angle.
var angle = gradient.angle != null ? gradient.angle : Math.PI;
switch (gradient.to) {
case "top":
angle = 0;
break;
case "left":
angle = -Math.PI / 2;
break;
case "bottom":
angle = Math.PI;
break;
case "right":
angle = Math.PI / 2;
break;
case "top left": case "left top":
angle = -Math.atan2(height, width);
break;
case "top right": case "right top":
angle = Math.atan2(height, width);
break;
case "bottom left": case "left bottom":
angle = Math.PI + Math.atan2(height, width);
break;
case "bottom right": case "right bottom":
angle = Math.PI - Math.atan2(height, width);
break;
}
if (gradient.reverse) {
angle -= Math.PI;
}
// limit the angle between 0..2PI
angle %= 2 * Math.PI;
if (angle < 0) {
angle += 2 * Math.PI;
}
// compute gradient's start/end points. here len is the length of the gradient line
// and x,y is the end point relative to the center of the rectangle in conventional
// (math) axis direction.
// this is the original (unscaled) length of the gradient line. needed to deal with
// absolutely positioned color stops. formula from the CSS spec:
// http://dev.w3.org/csswg/css-images-3/#linear-gradient-syntax
var pxlen = Math.abs(width * Math.sin(angle)) + Math.abs(height * Math.cos(angle));
// The math below is pretty simple, but it took a while to figure out. We compute x
// and y, the *end* of the gradient line. However, we want to transform them into
// element-based coordinates (SVG's gradientUnits="objectBoundingBox"). That means,
// x=0 is the left edge, x=1 is the right edge, y=0 is the top edge and y=1 is the
// bottom edge.
//
// A naive approach would use the original angle for these calculations. Say we'd
// like to draw a gradient angled at 45deg in a 100x400 box. When we use
// objectBoundingBox, the renderer will draw it in a 1x1 *square* box, and then
// scale that to the desired dimensions. The 45deg angle will look more like 70deg
// after scaling. SVG (http://www.w3.org/TR/SVG/pservers.html#LinearGradients) says
// the following:
//
// When gradientUnits="objectBoundingBox" and 'gradientTransform' is the
// identity matrix, the normal of the linear gradient is perpendicular to the
// gradient vector in object bounding box space (i.e., the abstract coordinate
// system where (0,0) is at the top/left of the object bounding box and (1,1) is
// at the bottom/right of the object bounding box). When the object's bounding
// box is not square, the gradient normal which is initially perpendicular to
// the gradient vector within object bounding box space may render
// non-perpendicular relative to the gradient vector in user space. If the
// gradient vector is parallel to one of the axes of the bounding box, the
// gradient normal will remain perpendicular. This transformation is due to
// application of the non-uniform scaling transformation from bounding box space
// to user space.
//
// which is an extremely long and confusing way to tell what I just said above.
//
// For this reason we need to apply the reverse scaling to the original angle, so
// that when it'll finally be rendered it'll actually be at the desired slope. Now
// I'll let you figure out the math yourself.
var scaledAngle = Math.atan(width * Math.tan(angle) / height);
var sin = Math.sin(scaledAngle), cos = Math.cos(scaledAngle);
var len = Math.abs(sin) + Math.abs(cos);
var x = len/2 * sin;
var y = len/2 * cos;
// Because of the arctangent, our scaledAngle ends up between -PI/2..PI/2, possibly
// losing the intended direction of the gradient. The following fixes it.
if (angle > Math.PI/2 && angle <= 3*Math.PI/2) {
x = -x;
y = -y;
}
// compute the color stops.
var implicit = [], right = 0;
var stops = gradient.stops.map(function(s, i){
var offset = s.percent;
if (offset) {
offset = parseFloat(offset) / 100;
} else if (s.length) {
offset = parseFloat(s.length) / pxlen;
} else if (i === 0) {
offset = 0;
} else if (i == gradient.stops.length - 1) {
offset = 1;
}
var stop = {
color: s.color.toCssRgba(),
offset: offset
};
if (offset != null) {
right = offset;
// fix implicit offsets
implicit.forEach(function(s, i){
var stop = s.stop;
stop.offset = s.left + (right - s.left) * (i + 1) / (implicit.length + 1);
});
implicit = [];
} else {
implicit.push({ left: right, stop: stop });
}
return stop;
});
var start = [ 0.5 - x, 0.5 + y ];
var end = [ 0.5 + x, 0.5 - y ];
// finally, draw it.
group.append(
Path.fromRect(rect)
.stroke(null)
.fill(new LinearGradient({
start : start,
end : end,
stops : stops,
userSpace : false
}))
);
break;
case "radial":
// XXX:
if (window.console && window.console.log) {
window.console.log("Radial gradients are not yet supported in HTML renderer");
}
break;
}
};
}
function maybeRenderWidget(element, group) {
var visual;
if (element._kendoExportVisual) {
visual = element._kendoExportVisual();
} else if (window.kendo && window.kendo.jQuery && element.getAttribute(window.kendo.attr("role"))) {
var widget = window.kendo.widgetInstance(window.kendo.jQuery(element));
if (widget && (widget.exportDOMVisual || widget.exportVisual)) {
if (widget.exportDOMVisual) {
visual = widget.exportDOMVisual();
} else {
visual = widget.exportVisual();
}
}
}
if (!visual) {
return false;
}
var wrap$$1 = new Group();
wrap$$1.children.push(visual);
var bbox = element.getBoundingClientRect();
wrap$$1.transform(transform().translate(bbox.left, bbox.top));
group.append(wrap$$1);
return true;
}
function renderImage(element, url, group) {
var box = getContentBox(element);
var rect = new Rect([ box.left, box.top ], [ box.width, box.height ]);
var image = new Image$1(url, rect);
setClipping(image, elementRoundBox(element, box, "content"));
group.append(image);
}
function zIndexSort(a, b) {
var sa = getComputedStyle(a);
var sb = getComputedStyle(b);
var za = parseFloat(getPropertyValue(sa, "z-index"));
var zb = parseFloat(getPropertyValue(sb, "z-index"));
var pa = getPropertyValue(sa, "position");
var pb = getPropertyValue(sb, "position");
if (isNaN(za) && isNaN(zb)) {
if ((/static|absolute/.test(pa)) && (/static|absolute/.test(pb))) {
return 0;
}
if (pa == "static") {
return -1;
}
if (pb == "static") {
return 1;
}
return 0;
}
if (isNaN(za)) {
return zb === 0 ? 0 : zb > 0 ? -1 : 1;
}
if (isNaN(zb)) {
return za === 0 ? 0 : za > 0 ? 1 : -1;
}
return parseFloat(za) - parseFloat(zb);
}
function isFormField(element) {
return /^(?:textarea|select|input)$/i.test(element.tagName);
}
function getSelectedOption(element) {
if (element.selectedOptions && element.selectedOptions.length > 0) {
return element.selectedOptions[0];
}
return element.options[element.selectedIndex];
}
function renderCheckbox(element, group) {
var style = getComputedStyle(element);
var color = getPropertyValue(style, "color");
var box = element.getBoundingClientRect();
if (element.type == "checkbox") {
group.append(
Path.fromRect(
new Rect([ box.left+1, box.top+1 ],
[ box.width-2, box.height-2 ])
).stroke(color, 1)
);
if (element.checked) {
// fill a rectangle inside? looks kinda ugly.
// group.append(
// Path.fromRect(
// new geo.Rect([ box.left+4, box.top+4 ],
// [ box.width-8, box.height-8])
// ).fill(color).stroke(null)
// );
// let's draw a checkmark instead. artistic, eh?
group.append(
new Path()
.stroke(color, 1.2)
.moveTo(box.left + 0.22 * box.width,
box.top + 0.55 * box.height)
.lineTo(box.left + 0.45 * box.width,
box.top + 0.75 * box.height)
.lineTo(box.left + 0.78 * box.width,
box.top + 0.22 * box.width)
);
}
} else {
group.append(
new Circle(
new Circle$2([
(box.left + box.right) / 2,
(box.top + box.bottom) / 2
], Math.min(box.width-2, box.height-2) / 2)
).stroke(color, 1)
);
if (element.checked) {
group.append(
new Circle(
new Circle$2([
(box.left + box.right) / 2,
(box.top + box.bottom) / 2
], Math.min(box.width-8, box.height-8) / 2)
).fill(color).stroke(null)
);
}
}
}
function renderFormField(element, group) {
var tag = element.tagName.toLowerCase();
if (tag == "input" && (element.type == "checkbox" || element.type == "radio")) {
return renderCheckbox(element, group);
}
var p = element.parentNode;
var doc = element.ownerDocument;
var el = doc.createElement(KENDO_PSEUDO_ELEMENT);
var option;
el.style.cssText = getCssText(getComputedStyle(element));
if (tag == "input") {
el.style.whiteSpace = "pre";
}
if (tag == "select" || tag == "textarea") {
el.style.overflow = "auto";
}
if (tag == "select") {
if (element.multiple) {
for (var i = 0; i < element.options.length; ++i) {
option = doc.createElement(KENDO_PSEUDO_ELEMENT);
option.style.cssText = getCssText(getComputedStyle(element.options[i]));
option.style.display = "block"; // IE9 messes up without this
option.textContent = element.options[i].textContent;
el.appendChild(option);
}
} else {
option = getSelectedOption(element);
if (option) {
el.textContent = option.textContent;
}
}
} else {
el.textContent = element.value;
}
p.insertBefore(el, element);
el.scrollLeft = element.scrollLeft;
el.scrollTop = element.scrollTop;
// must temporarily hide the original element, otherwise it
// may affect layout of the fake element we want to render.
element.style.display = "none";
renderContents(el, group);
element.style.display = "";
p.removeChild(el);
}
function renderContents(element, group) {
if (nodeInfo._stackingContext.element === element) {
// the group that was set in pushNodeInfo might have
// changed due to clipping/transforms, update it here.
nodeInfo._stackingContext.group = group;
}
switch (element.tagName.toLowerCase()) {
case "img":
renderImage(element, element.src, group);
break;
case "canvas":
try {
renderImage(element, element.toDataURL("image/png"), group);
} catch (ex) {
// tainted; can't draw it, ignore.
}
break;
case "textarea":
case "input":
case "select":
renderFormField(element, group);
break;
default:
var children = [], floats = [], positioned = [];
for (var i = element.firstChild; i; i = i.nextSibling) {
switch (i.nodeType) {
case 3: // Text
if (/\S/.test(i.data)) {
renderText(element, i, group);
}
break;
case 1: // Element
var style = getComputedStyle(i);
var floating = getPropertyValue(style, "float");
var position = getPropertyValue(style, "position");
if (position != "static") {
positioned.push(i);
}
else if (floating != "none") {
floats.push(i);
} else {
children.push(i);
}
break;
}
}
mergeSort(children, zIndexSort).forEach(function(el){ renderElement(el, group); });
mergeSort(floats, zIndexSort).forEach(function(el){ renderElement(el, group); });
mergeSort(positioned, zIndexSort).forEach(function(el){ renderElement(el, group); });
}
}
function renderText(element, node, group) {
if (emptyClipbox()) {
return;
}
var style = getComputedStyle(element);
if (parseFloat(getPropertyValue(style, "text-indent")) < -500) {
// assume it should not be displayed. the slider's
// draggable handle displays a Drag text for some reason,
// having text-indent: -3333px.
return;
}
var text = node.data;
var start = 0;
var end = text.search(/\S\s*$/) + 1;
if (!end) {
return; // whitespace-only node
}
var fontSize = getPropertyValue(style, "font-size");
var lineHeight = getPropertyValue(style, "line-height");
// simply getPropertyValue("font") doesn't work in Firefox :-\
var font = [
getPropertyValue(style, "font-style"),
getPropertyValue(style, "font-variant"),
getPropertyValue(style, "font-weight"),
fontSize, // no need for line height here; it breaks layout in FF
getPropertyValue(style, "font-family")
].join(" ");
fontSize = parseFloat(fontSize);
lineHeight = parseFloat(lineHeight);
if (fontSize === 0) {
return;
}
var color = getPropertyValue(style, "color");
var range = element.ownerDocument.createRange();
var align$$1 = getPropertyValue(style, "text-align");
var isJustified = align$$1 == "justify";
var columnCount = getPropertyValue(style, "column-count", 1);
var whiteSpace = getPropertyValue(style, "white-space");
var textTransform = getPropertyValue(style, "text-transform");
// A line of 500px, with a font of 12px, contains an average of 80 characters, but since we
// err, we'd like to guess a bigger number rather than a smaller one. Multiplying by 5
// seems to be a good option.
var estimateLineLength = element.getBoundingClientRect().width / fontSize * 5;
if (estimateLineLength === 0) {
estimateLineLength = 500;
}
// we'll maintain this so we can workaround bugs in Chrome's Range.getClientRects
// https://github.com/telerik/kendo/issues/5740
var prevLineBottom = null;
var underline = nodeInfo["underline"];
var lineThrough = nodeInfo["line-through"];
var overline = nodeInfo["overline"];
var hasDecoration = underline || lineThrough || overline;
// doChunk returns true when all text has been rendered
while (!doChunk()) {}
if (hasDecoration) {
range.selectNode(node);
slice$1(range.getClientRects()).forEach(decorate);
}
return; // only function declarations after this line
function actuallyGetRangeBoundingRect(range) {
// XXX: to be revised when this Chrome bug is fixed:
// https://bugs.chromium.org/p/chromium/issues/detail?id=612459
if (microsoft || browser.chrome) {
// Workaround browser bugs: IE and Chrome would sometimes
// return 0 or 1-width rectangles before or after the main
// one. https://github.com/telerik/kendo/issues/4674
// Actually Chrome 50 got worse, since the rectangles can now have the width of a
// full character, making it hard to tell whether it's a bogus rectangle or valid
// selection location. The workaround is to ignore rectangles that fall on the
// previous line. https://github.com/telerik/kendo/issues/5740
var rectangles = range.getClientRects(), box = {
top : Infinity,
right : -Infinity,
bottom : -Infinity,
left : Infinity
}, done = false;
for (var i = 0; i < rectangles.length; ++i) {
var b = rectangles[i];
if (b.width <= 1 || b.bottom === prevLineBottom) {
continue; // bogus rectangle
}
box.left = Math.min(b.left , box.left);
box.top = Math.min(b.top , box.top);
box.right = Math.max(b.right , box.right);
box.bottom = Math.max(b.bottom , box.bottom);
done = true;
}
if (!done) {
return range.getBoundingClientRect();
}
box.width = box.right - box.left;
box.height = box.bottom - box.top;
return box;
}
return range.getBoundingClientRect();
}
// Render a chunk of text, typically one line (but for justified text we render each word as
// a separate Text object, because spacing is variable). Returns true when it finished the
// current node. After each chunk it updates `start` to just after the last rendered
// character.
function doChunk() {
var origStart = start;
var box, pos = text.substr(start).search(/\S/);
start += pos;
if (pos < 0 || start >= end) {
return true;
}
// Select a single character to determine the height of a line of text. The box.bottom
// will be essential for us to figure out where the next line begins.
range.setStart(node, start);
range.setEnd(node, start + 1);
box = actuallyGetRangeBoundingRect(range);
// for justified text we must split at each space, because space has variable width.
var found = false;
if (isJustified || columnCount > 1) {
pos = text.substr(start).search(/\s/);
if (pos >= 0) {
// we can only split there if it's on the same line, otherwise we'll fall back
// to the default mechanism (see findEOL below).
range.setEnd(node, start + pos);
var r = actuallyGetRangeBoundingRect(range);
if (r.bottom == box.bottom) {
box = r;
found = true;
start += pos;
}
}
}
if (!found) {
// This code does three things: (1) it selects one line of text in `range`, (2) it
// leaves the bounding rect of that line in `box` and (3) it returns the position
// just after the EOL. We know where the line starts (`start`) but we don't know
// where it ends. To figure this out, we select a piece of text and look at the
// bottom of the bounding box. If it changes, we have more than one line selected
// and should retry with a smaller selection.
//
// To speed things up, we first try to select all text in the node (`start` ->
// `end`). If there's more than one line there, then select only half of it. And
// so on. When we find a value for `end` that fits in one line, we try increasing
// it (also in halves) until we get to the next line. The algorithm stops when the
// right side of the bounding box does not change.
//
// One more thing to note is that everything happens in a single Text DOM node.
// There's no other tags inside it, therefore the left/top coordinates of the
// bounding box will not change.
pos = (function findEOL(min, eol, max){
range.setEnd(node, eol);
var r = actuallyGetRangeBoundingRect(range);
if (r.bottom != box.bottom && min < eol) {
return findEOL(min, (min + eol) >> 1, eol);
} else if (r.right != box.right) {
box = r;
if (eol < max) {
return findEOL(eol, (eol + max) >> 1, max);
} else {
return eol;
}
} else {
return eol;
}
})(start, Math.min(end, start + estimateLineLength), end);
if (pos == start) {
// if EOL is at the start, then no more text fits on this line. Skip the
// remainder of this node entirely to avoid a stack overflow.
return true;
}
start = pos;
pos = range.toString().search(/\s+$/);
if (pos === 0) {
return false; // whitespace only; we should not get here.
}
if (pos > 0) {
// eliminate trailing whitespace
range.setEnd(node, range.startOffset + pos);
box = actuallyGetRangeBoundingRect(range);
}
}
// another workaround for IE: if we rely on getBoundingClientRect() we'll overlap with the bullet for LI
// elements. Calling getClientRects() and using the *first* rect appears to give us the correct location.
// Note: not to be used in Chrome as it randomly returns a zero-width rectangle from the previous line.
if (microsoft) {
box = range.getClientRects()[0];
}
var str = range.toString();
if (!/^(?:pre|pre-wrap)$/i.test(whiteSpace)) {
// node with non-significant space -- collapse whitespace.
str = str.replace(/\s+/g, " ");
}
else if (/\t/.test(str)) {
// with significant whitespace we need to do something about literal TAB characters.
// There's no TAB glyph in a font so they would be rendered in PDF as an empty box,
// and the whole text will stretch to fill the original width. The core PDF lib
// does not have sufficient context to deal with it.
// calculate the starting column here, since we initially discarded any whitespace.
var cc = 0;
for (pos = origStart; pos < range.startOffset; ++pos) {
var code = text.charCodeAt(pos);
if (code == 9) {
// when we meet a TAB we must round up to the next tab stop.
// in all browsers TABs seem to be 8 characters.
cc += 8 - cc % 8;
} else if (code == 10 || code == 13) {
// just in case we meet a newline we must restart.
cc = 0;
} else {
// ordinary character --> advance one column
cc++;
}
}
// based on starting column, replace any TAB characters in the string we actually
// have to display with spaces so that they align to columns multiple of 8.
while ((pos = str.search("\t")) >= 0) {
var indent = " ".substr(0, 8 - (cc + pos) % 8);
str = str.substr(0, pos) + indent + str.substr(pos + 1);
}
}
if (!found) {
prevLineBottom = box.bottom;
}
drawText(str, box);
}
function drawText(str, box) {
// In IE the box height will be approximately lineHeight, while in
// other browsers it'll (correctly) be the height of the bounding
// box for the current text/font. Which is to say, IE sucks again.
// The only good solution I can think of is to measure the text
// ourselves and center the bounding box.
if (microsoft && !isNaN(lineHeight)) {
var height = getFontHeight(font);
var top = (box.top + box.bottom - height) / 2;
box = {
top : top,
right : box.right,
bottom : top + height,
left : box.left,
height : height,
width : box.right - box.left
};
}
// var path = new Path({ stroke: { color: "red" }});
// path.moveTo(box.left, box.top)
// .lineTo(box.right, box.top)
// .lineTo(box.right, box.bottom)
// .lineTo(box.left, box.bottom)
// .close();
// group.append(path);
switch (textTransform) {
case "uppercase":
str = str.toUpperCase();
break;
case "lowercase":
str = str.toLowerCase();
break;
case "capitalize":
str = str.replace(/(?:^|\s)\S/g, function (l) { return l.toUpperCase(); });
break;
}
var text = new TextRect(
str, new Rect([ box.left, box.top ],
[ box.width, box.height ]),
{
font: font,
fill: { color: color }
}
);
group.append(text);
}
function decorate(box) {
line(underline, box.bottom);
line(lineThrough, box.bottom - box.height / 2.7);
line(overline, box.top);
function line(color, ypos) {
if (color) {
var width = fontSize / 12;
var path = new Path({ stroke: {
width: width,
color: color
}});
ypos -= width;
path.moveTo(box.left, ypos)
.lineTo(box.right, ypos);
group.append(path);
}
}
}
}
function groupInStackingContext(element, group, zIndex) {
var main;
if (zIndex != "auto") {
// use the current stacking context
main = nodeInfo._stackingContext.group;
zIndex = parseFloat(zIndex);
} else {
// normal flow — use given container. we still have to
// figure out where should we insert this element with the
// assumption that its z-index is zero, as the group might
// already contain elements with higher z-index.
main = group;
zIndex = 0;
}
var a = main.children;
for (var i = 0; i < a.length; ++i) {
if (a[i]._dom_zIndex != null && a[i]._dom_zIndex > zIndex) {
break;
}
}
var tmp = new Group();
main.insert(i, tmp);
tmp._dom_zIndex = zIndex;
if (main !== group) {
// console.log("Placing", element, "in", nodeInfo._stackingContext.element, "at position", i, " / ", a.length);
// console.log(a.slice(i+1));
// if (nodeInfo._matrix) {
// tmp.transform(nodeInfo._matrix);
// }
if (nodeInfo._clipbox) {
var m = nodeInfo._matrix.invert();
var r = nodeInfo._clipbox.transformCopy(m);
setClipping(tmp, Path.fromRect(r));
// console.log(r);
// tmp.append(Path.fromRect(r));
// tmp.append(new Text(element.className || element.id, r.topLeft()));
}
}
return tmp;
}
function renderElement(element, container) {
var style = getComputedStyle(element);
updateCounters(style);
if (/^(style|script|link|meta|iframe|svg|col|colgroup)$/i.test(element.tagName)) {
return;
}
if (nodeInfo._clipbox == null) {
return;
}
var opacity = parseFloat(getPropertyValue(style, "opacity"));
var visibility = getPropertyValue(style, "visibility");
var display = getPropertyValue(style, "display");
if (opacity === 0 || visibility == "hidden" || display == "none") {
return;
}
var tr = getTransform(style);
var group;
var zIndex = getPropertyValue(style, "z-index");
if ((tr || opacity < 1) && zIndex == "auto") {
zIndex = 0;
}
group = groupInStackingContext(element, container, zIndex);
// XXX: remove at some point
// group._pdfElement = element;
// group.options._pdfDebug = "";
// if (element.id) {
// group.options._pdfDebug = "#" + element.id;
// }
// if (element.className) {
// group.options._pdfDebug += "." + element.className.split(" ").join(".");
// }
if (opacity < 1) {
group.opacity(opacity * group.opacity());
}
pushNodeInfo(element, style, group);
if (!tr) {
_renderWithPseudoElements(element, group);
}
else {
saveStyle(element, function(){
// must clear transform, so getBoundingClientRect returns correct values.
pleaseSetPropertyValue(element.style, "transform", "none", "important");
// must also clear transitions, so correct values are returned *immediately*
pleaseSetPropertyValue(element.style, "transition", "none", "important");
// the presence of any transform makes it behave like it had position: relative,
// because why not.
// http://meyerweb.com/eric/thoughts/2011/09/12/un-fixing-fixed-elements-with-css-transforms/
if (getPropertyValue(style, "position") == "static") {
// but only if it's not already positioned. :-/
pleaseSetPropertyValue(element.style, "position", "relative", "important");
}
// must translate to origin before applying the CSS
// transformation, then translate back.
var bbox = element.getBoundingClientRect();
var x = bbox.left + tr.origin[0];
var y = bbox.top + tr.origin[1];
var m = [ 1, 0, 0, 1, -x, -y ];
m = mmul(m, tr.matrix);
m = mmul(m, [ 1, 0, 0, 1, x, y ]);
m = setTransform(group, m);
nodeInfo._matrix = nodeInfo._matrix.multiplyCopy(m);
_renderWithPseudoElements(element, group);
});
}
popNodeInfo();
//drawDebugBox(element.getBoundingClientRect(), container);
}
// function drawDebugBox(box, group, color) {
// var path = Path.fromRect(new geo.Rect([ box.left, box.top ], [ box.width, box.height ]));
// if (color) {
// path.stroke(color);
// }
// group.append(path);
// }
// function dumpTextNode(node) {
// var txt = node.data.replace(/^\s+/, "");
// if (txt.length < 100) {
// console.log(node.data.length + ": |" + txt);
// } else {
// console.log(node.data.length + ": |" + txt.substr(0, 50) + "|...|" + txt.substr(-50));
// }
// }
function mmul(a, b) {
var a1 = a[0], b1 = a[1], c1 = a[2], d1 = a[3], e1 = a[4], f1 = a[5];
var a2 = b[0], b2 = b[1], c2 = b[2], d2 = b[3], e2 = b[4], f2 = b[5];
return [
a1*a2 + b1*c2, a1*b2 + b1*d2,
c1*a2 + d1*c2, c1*b2 + d1*d2,
e1*a2 + f1*c2 + e2, e1*b2 + f1*d2 + f2
];
}
var drawing = {
svg: svg,
canvas: canvas,
util: util,
PathParser: PathParser,
Surface: Surface,
BaseNode: BaseNode,
SurfaceFactory: SurfaceFactory,
OptionsStore: OptionsStore,
exportImage: exportImage,
exportSVG: exportSVG,
QuadNode: QuadNode,
ShapesQuadTree: ShapesQuadTree,
ObserversMixin: ObserversMixin,
Element: Element$1,
Circle: Circle,
Arc: Arc,
Path: Path,
MultiPath: MultiPath,
Text: Text,
Image: Image$1,
Group: Group,
Layout: Layout,
Rect: Rect$2,
align: align,
vAlign: vAlign,
stack: stack,
vStack: vStack,
wrap: wrap,
vWrap: vWrap,
fit: fit,
LinearGradient: LinearGradient,
RadialGradient: RadialGradient,
GradientStop: GradientStop,
Gradient: Gradient,
Animation: Animation,
AnimationFactory: AnimationFactory,
drawDOM: drawDOM
};
kendo.deepExtend(kendo, {
drawing: drawing,
geometry: geometry
});
kendo.drawing.Segment = kendo.geometry.Segment;
kendo.dataviz.drawing = kendo.drawing;
kendo.dataviz.geometry = kendo.geometry;
kendo.drawing.util.measureText = kendo.util.measureText;
kendo.drawing.util.objectKey = kendo.util.objectKey;
kendo.drawing.Color = kendo.Color;
kendo.util.encodeBase64 = kendo.drawing.util.encodeBase64;
})(window.kendo.jQuery);
}, __webpack_require__(3));
/***/ }),
/***/ 922:
/***/ (function(module, exports) {
module.exports = require("./util");
/***/ }),
/***/ 923:
/***/ (function(module, exports) {
module.exports = require("../kendo.color");
/***/ }),
/***/ 924:
/***/ (function(module, exports) {
module.exports = require("../util/text-metrics");
/***/ })
/******/ });