/** * Kendo UI v2016.1.112 (http://www.telerik.com/kendo-ui) * Copyright 2016 Telerik AD. All rights reserved. * * Kendo UI commercial licenses may be obtained at * http://www.telerik.com/purchase/license-agreement/kendo-ui-complete * If you do not own a commercial license, this file shall be governed by the trial license terms. */ (function (f, define) { define('util/main', ['kendo.core'], f); }(function () { (function () { var math = Math, kendo = window.kendo, deepExtend = kendo.deepExtend; var DEG_TO_RAD = math.PI / 180, MAX_NUM = Number.MAX_VALUE, MIN_NUM = -Number.MAX_VALUE, UNDEFINED = 'undefined'; function defined(value) { return typeof value !== UNDEFINED; } function round(value, precision) { var power = pow(precision); return math.round(value * power) / power; } function pow(p) { if (p) { return math.pow(10, p); } else { return 1; } } function limitValue(value, min, max) { return math.max(math.min(value, max), min); } function rad(degrees) { return degrees * DEG_TO_RAD; } function deg(radians) { return radians / DEG_TO_RAD; } function isNumber(val) { return typeof val === 'number' && !isNaN(val); } function valueOrDefault(value, defaultValue) { return defined(value) ? value : defaultValue; } function sqr(value) { return value * value; } function objectKey(object) { var parts = []; for (var key in object) { parts.push(key + object[key]); } return parts.sort().join(''); } function hashKey(str) { var hash = 2166136261; for (var i = 0; i < str.length; ++i) { hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24); hash ^= str.charCodeAt(i); } return hash >>> 0; } function hashObject(object) { return hashKey(objectKey(object)); } var now = Date.now; if (!now) { now = function () { return new Date().getTime(); }; } function arrayLimits(arr) { var length = arr.length, i, min = MAX_NUM, max = MIN_NUM; for (i = 0; i < length; i++) { max = math.max(max, arr[i]); min = math.min(min, arr[i]); } return { min: min, max: max }; } function arrayMin(arr) { return arrayLimits(arr).min; } function arrayMax(arr) { return arrayLimits(arr).max; } function sparseArrayMin(arr) { return sparseArrayLimits(arr).min; } function sparseArrayMax(arr) { return sparseArrayLimits(arr).max; } function sparseArrayLimits(arr) { var min = MAX_NUM, max = MIN_NUM; for (var i = 0, length = arr.length; i < length; i++) { var n = arr[i]; if (n !== null && isFinite(n)) { min = math.min(min, n); max = math.max(max, n); } } return { min: min === MAX_NUM ? undefined : min, max: max === MIN_NUM ? undefined : max }; } function last(array) { if (array) { return array[array.length - 1]; } } function append(first, second) { first.push.apply(first, second); return first; } function renderTemplate(text) { return kendo.template(text, { useWithBlock: false, paramName: 'd' }); } function renderAttr(name, value) { return defined(value) && value !== null ? ' ' + name + '=\'' + value + '\' ' : ''; } function renderAllAttr(attrs) { var output = ''; for (var i = 0; i < attrs.length; i++) { output += renderAttr(attrs[i][0], attrs[i][1]); } return output; } function renderStyle(attrs) { var output = ''; for (var i = 0; i < attrs.length; i++) { var value = attrs[i][1]; if (defined(value)) { output += attrs[i][0] + ':' + value + ';'; } } if (output !== '') { return output; } } function renderSize(size) { if (typeof size !== 'string') { size += 'px'; } return size; } function renderPos(pos) { var result = []; if (pos) { var parts = kendo.toHyphens(pos).split('-'); for (var i = 0; i < parts.length; i++) { result.push('k-pos-' + parts[i]); } } return result.join(' '); } function isTransparent(color) { return color === '' || color === null || color === 'none' || color === 'transparent' || !defined(color); } function arabicToRoman(n) { var literals = { 1: 'i', 10: 'x', 100: 'c', 2: 'ii', 20: 'xx', 200: 'cc', 3: 'iii', 30: 'xxx', 300: 'ccc', 4: 'iv', 40: 'xl', 400: 'cd', 5: 'v', 50: 'l', 500: 'd', 6: 'vi', 60: 'lx', 600: 'dc', 7: 'vii', 70: 'lxx', 700: 'dcc', 8: 'viii', 80: 'lxxx', 800: 'dccc', 9: 'ix', 90: 'xc', 900: 'cm', 1000: 'm' }; var values = [ 1000, 900, 800, 700, 600, 500, 400, 300, 200, 100, 90, 80, 70, 60, 50, 40, 30, 20, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 ]; var roman = ''; while (n > 0) { if (n < values[0]) { values.shift(); } else { roman += literals[values[0]]; n -= values[0]; } } return roman; } function romanToArabic(r) { r = r.toLowerCase(); var digits = { i: 1, v: 5, x: 10, l: 50, c: 100, d: 500, m: 1000 }; var value = 0, prev = 0; for (var i = 0; i < r.length; ++i) { var v = digits[r.charAt(i)]; if (!v) { return null; } value += v; if (v > prev) { value -= 2 * prev; } prev = v; } return value; } function memoize(f) { var cache = Object.create(null); return function () { var id = ''; for (var i = arguments.length; --i >= 0;) { id += ':' + arguments[i]; } if (id in cache) { return cache[id]; } return f.apply(this, arguments); }; } function ucs2decode(string) { var output = [], counter = 0, length = string.length, value, extra; while (counter < length) { value = string.charCodeAt(counter++); if (value >= 55296 && value <= 56319 && counter < length) { extra = string.charCodeAt(counter++); if ((extra & 64512) == 56320) { output.push(((value & 1023) << 10) + (extra & 1023) + 65536); } else { output.push(value); counter--; } } else { output.push(value); } } return output; } function ucs2encode(array) { return array.map(function (value) { var output = ''; if (value > 65535) { value -= 65536; output += String.fromCharCode(value >>> 10 & 1023 | 55296); value = 56320 | value & 1023; } output += String.fromCharCode(value); return output; }).join(''); } deepExtend(kendo, { util: { MAX_NUM: MAX_NUM, MIN_NUM: MIN_NUM, append: append, arrayLimits: arrayLimits, arrayMin: arrayMin, arrayMax: arrayMax, defined: defined, deg: deg, hashKey: hashKey, hashObject: hashObject, isNumber: isNumber, isTransparent: isTransparent, last: last, limitValue: limitValue, now: now, objectKey: objectKey, round: round, rad: rad, renderAttr: renderAttr, renderAllAttr: renderAllAttr, renderPos: renderPos, renderSize: renderSize, renderStyle: renderStyle, renderTemplate: renderTemplate, sparseArrayLimits: sparseArrayLimits, sparseArrayMin: sparseArrayMin, sparseArrayMax: sparseArrayMax, sqr: sqr, valueOrDefault: valueOrDefault, romanToArabic: romanToArabic, arabicToRoman: arabicToRoman, memoize: memoize, ucs2encode: ucs2encode, ucs2decode: ucs2decode } }); kendo.drawing.util = kendo.util; kendo.dataviz.util = kendo.util; }()); return window.kendo; }, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) { (a3 || a2)(); })); (function (f, define) { define('util/text-metrics', [ 'kendo.core', 'util/main' ], f); }(function () { (function ($) { var doc = document, kendo = window.kendo, Class = kendo.Class, util = kendo.util, defined = util.defined; var LRUCache = Class.extend({ init: function (size) { this._size = size; this._length = 0; this._map = {}; }, put: function (key, value) { var lru = this, map = lru._map, entry = { key: key, value: value }; map[key] = entry; if (!lru._head) { lru._head = lru._tail = entry; } else { lru._tail.newer = entry; entry.older = lru._tail; lru._tail = entry; } if (lru._length >= lru._size) { map[lru._head.key] = null; lru._head = lru._head.newer; lru._head.older = null; } else { lru._length++; } }, get: function (key) { var lru = this, entry = lru._map[key]; if (entry) { if (entry === lru._head && entry !== lru._tail) { lru._head = entry.newer; lru._head.older = null; } if (entry !== lru._tail) { if (entry.older) { entry.older.newer = entry.newer; entry.newer.older = entry.older; } entry.older = lru._tail; entry.newer = null; lru._tail.newer = entry; lru._tail = entry; } return entry.value; } } }); var defaultMeasureBox = $('
')[0]; var TextMetrics = Class.extend({ init: function (options) { this._cache = new LRUCache(1000); this._initOptions(options); }, options: { baselineMarkerSize: 1 }, measure: function (text, style, box) { var styleKey = util.objectKey(style), cacheKey = util.hashKey(text + styleKey), cachedResult = this._cache.get(cacheKey); if (cachedResult) { return cachedResult; } var size = { width: 0, height: 0, baseline: 0 }; var measureBox = box ? box : defaultMeasureBox; var baselineMarker = this._baselineMarker().cloneNode(false); for (var key in style) { var value = style[key]; if (defined(value)) { measureBox.style[key] = value; } } $(measureBox).text(text); measureBox.appendChild(baselineMarker); doc.body.appendChild(measureBox); if ((text + '').length) { size.width = measureBox.offsetWidth - this.options.baselineMarkerSize; size.height = measureBox.offsetHeight; size.baseline = baselineMarker.offsetTop + this.options.baselineMarkerSize; } if (size.width > 0 && size.height > 0) { this._cache.put(cacheKey, size); } measureBox.parentNode.removeChild(measureBox); return size; }, _baselineMarker: function () { return $('')[0]; } }); TextMetrics.current = new TextMetrics(); function measureText(text, style, measureBox) { return TextMetrics.current.measure(text, style, measureBox); } kendo.util.TextMetrics = TextMetrics; kendo.util.LRUCache = LRUCache; kendo.util.measureText = measureText; }(window.kendo.jQuery)); }, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) { (a3 || a2)(); })); (function (f, define) { define('util/base64', ['util/main'], f); }(function () { (function () { var kendo = window.kendo, deepExtend = kendo.deepExtend, fromCharCode = String.fromCharCode; var KEY_STR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; function encodeBase64(input) { var output = ''; var chr1, chr2, chr3, enc1, enc2, enc3, enc4; var i = 0; input = encodeUTF8(input); while (i < input.length) { chr1 = input.charCodeAt(i++); chr2 = input.charCodeAt(i++); chr3 = input.charCodeAt(i++); enc1 = chr1 >> 2; enc2 = (chr1 & 3) << 4 | chr2 >> 4; enc3 = (chr2 & 15) << 2 | chr3 >> 6; enc4 = chr3 & 63; if (isNaN(chr2)) { enc3 = enc4 = 64; } else if (isNaN(chr3)) { enc4 = 64; } output = output + KEY_STR.charAt(enc1) + KEY_STR.charAt(enc2) + KEY_STR.charAt(enc3) + KEY_STR.charAt(enc4); } return output; } function encodeUTF8(input) { var output = ''; for (var i = 0; i < input.length; i++) { var c = input.charCodeAt(i); if (c < 128) { output += fromCharCode(c); } else if (c < 2048) { output += fromCharCode(192 | c >>> 6); output += fromCharCode(128 | c & 63); } else if (c < 65536) { output += fromCharCode(224 | c >>> 12); output += fromCharCode(128 | c >>> 6 & 63); output += fromCharCode(128 | c & 63); } } return output; } deepExtend(kendo.util, { encodeBase64: encodeBase64, encodeUTF8: encodeUTF8 }); }()); return window.kendo; }, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) { (a3 || a2)(); })); (function (f, define) { define('mixins/observers', ['kendo.core'], f); }(function () { (function ($) { var math = Math, kendo = window.kendo, deepExtend = kendo.deepExtend, inArray = $.inArray; var ObserversMixin = { observers: function () { this._observers = this._observers || []; return this._observers; }, addObserver: function (element) { if (!this._observers) { this._observers = [element]; } else { this._observers.push(element); } return this; }, removeObserver: function (element) { var observers = this.observers(); var index = inArray(element, observers); if (index != -1) { observers.splice(index, 1); } return this; }, trigger: function (methodName, event) { var observers = this._observers; var observer; var idx; if (observers && !this._suspended) { for (idx = 0; idx < observers.length; idx++) { observer = observers[idx]; if (observer[methodName]) { observer[methodName](event); } } } return this; }, optionsChange: function (e) { this.trigger('optionsChange', e); }, geometryChange: function (e) { this.trigger('geometryChange', e); }, suspend: function () { this._suspended = (this._suspended || 0) + 1; return this; }, resume: function () { this._suspended = math.max((this._suspended || 0) - 1, 0); return this; }, _observerField: function (field, value) { if (this[field]) { this[field].removeObserver(this); } this[field] = value; value.addObserver(this); } }; deepExtend(kendo, { mixins: { ObserversMixin: ObserversMixin } }); }(window.kendo.jQuery)); return window.kendo; }, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) { (a3 || a2)(); })); (function (f, define) { define('kendo.dataviz.chart.polar', [ 'kendo.dataviz.chart', 'kendo.drawing' ], f); }(function () { var __meta__ = { id: 'dataviz.chart.polar', name: 'Polar Charts', category: 'dataviz', depends: ['dataviz.chart'], hidden: true }; (function ($, undefined) { var math = Math, kendo = window.kendo, deepExtend = kendo.deepExtend, util = kendo.util, append = util.append, draw = kendo.drawing, geom = kendo.geometry, dataviz = kendo.dataviz, AreaSegment = dataviz.AreaSegment, Axis = dataviz.Axis, AxisGroupRangeTracker = dataviz.AxisGroupRangeTracker, BarChart = dataviz.BarChart, Box2D = dataviz.Box2D, CategoryAxis = dataviz.CategoryAxis, CategoricalChart = dataviz.CategoricalChart, CategoricalPlotArea = dataviz.CategoricalPlotArea, ChartElement = dataviz.ChartElement, CurveProcessor = dataviz.CurveProcessor, DonutSegment = dataviz.DonutSegment, LineChart = dataviz.LineChart, LineSegment = dataviz.LineSegment, LogarithmicAxis = dataviz.LogarithmicAxis, NumericAxis = dataviz.NumericAxis, PlotAreaBase = dataviz.PlotAreaBase, PlotAreaFactory = dataviz.PlotAreaFactory, Point2D = dataviz.Point2D, Ring = dataviz.Ring, ScatterChart = dataviz.ScatterChart, ScatterLineChart = dataviz.ScatterLineChart, SeriesBinder = dataviz.SeriesBinder, ShapeBuilder = dataviz.ShapeBuilder, SplineSegment = dataviz.SplineSegment, SplineAreaSegment = dataviz.SplineAreaSegment, getSpacing = dataviz.getSpacing, filterSeriesByType = dataviz.filterSeriesByType, limitValue = util.limitValue, round = dataviz.round; var ARC = 'arc', BLACK = '#000', COORD_PRECISION = dataviz.COORD_PRECISION, DEFAULT_PADDING = 0.15, DEG_TO_RAD = math.PI / 180, GAP = 'gap', INTERPOLATE = 'interpolate', LOGARITHMIC = 'log', PLOT_AREA_CLICK = 'plotAreaClick', POLAR_AREA = 'polarArea', POLAR_LINE = 'polarLine', POLAR_SCATTER = 'polarScatter', RADAR_AREA = 'radarArea', RADAR_COLUMN = 'radarColumn', RADAR_LINE = 'radarLine', SMOOTH = 'smooth', X = 'x', Y = 'y', ZERO = 'zero', POLAR_CHARTS = [ POLAR_AREA, POLAR_LINE, POLAR_SCATTER ], RADAR_CHARTS = [ RADAR_AREA, RADAR_COLUMN, RADAR_LINE ]; var GridLinesMixin = { createGridLines: function (altAxis) { var axis = this, options = axis.options, radius = math.abs(axis.box.center().y - altAxis.lineBox().y1), majorAngles, minorAngles, skipMajor = false, gridLines = []; if (options.majorGridLines.visible) { majorAngles = axis.majorGridLineAngles(altAxis); skipMajor = true; gridLines = axis.renderMajorGridLines(majorAngles, radius, options.majorGridLines); } if (options.minorGridLines.visible) { minorAngles = axis.minorGridLineAngles(altAxis, skipMajor); append(gridLines, axis.renderMinorGridLines(minorAngles, radius, options.minorGridLines, altAxis, skipMajor)); } return gridLines; }, renderMajorGridLines: function (angles, radius, options) { return this.renderGridLines(angles, radius, options); }, renderMinorGridLines: function (angles, radius, options, altAxis, skipMajor) { var radiusCallback = this.radiusCallback && this.radiusCallback(radius, altAxis, skipMajor); return this.renderGridLines(angles, radius, options, radiusCallback); }, renderGridLines: function (angles, radius, options, radiusCallback) { var style = { stroke: { width: options.width, color: options.color, dashType: options.dashType } }; var center = this.box.center(); var circle = new geom.Circle([ center.x, center.y ], radius); var container = this.gridLinesVisual(); for (var i = 0; i < angles.length; i++) { var line = new draw.Path(style); if (radiusCallback) { circle.radius = radiusCallback(angles[i]); } line.moveTo(circle.center).lineTo(circle.pointAt(angles[i])); container.append(line); } return container.children; }, gridLineAngles: function (altAxis, size, skip, step, skipAngles) { var axis = this, divs = axis.intervals(size, skip, step, skipAngles), options = altAxis.options, altAxisVisible = options.visible && (options.line || {}).visible !== false; return $.map(divs, function (d) { var alpha = axis.intervalAngle(d); if (!altAxisVisible || alpha !== 90) { return alpha; } }); } }; var RadarCategoryAxis = CategoryAxis.extend({ options: { startAngle: 90, labels: { margin: getSpacing(10) }, majorGridLines: { visible: true }, justified: true }, range: function () { return { min: 0, max: this.options.categories.length }; }, reflow: function (box) { this.box = box; this.reflowLabels(); }, lineBox: function () { return this.box; }, reflowLabels: function () { var axis = this, labelOptions = axis.options.labels, skip = labelOptions.skip || 0, step = labelOptions.step || 1, measureBox = new Box2D(), labels = axis.labels, labelBox, i; for (i = 0; i < labels.length; i++) { labels[i].reflow(measureBox); labelBox = labels[i].box; labels[i].reflow(axis.getSlot(skip + i * step).adjacentBox(0, labelBox.width(), labelBox.height())); } }, intervals: function (size, skip, step, skipAngles) { var axis = this, options = axis.options, categories = options.categories.length, angle = 0, divCount = categories / size || 1, divAngle = 360 / divCount, divs = [], i; skip = skip || 0; step = step || 1; for (i = skip; i < divCount; i += step) { if (options.reverse) { angle = 360 - i * divAngle; } else { angle = i * divAngle; } angle = round(angle, COORD_PRECISION) % 360; if (!(skipAngles && dataviz.inArray(angle, skipAngles))) { divs.push(angle); } } return divs; }, majorIntervals: function () { return this.intervals(1); }, minorIntervals: function () { return this.intervals(0.5); }, intervalAngle: function (interval) { return (360 + interval + this.options.startAngle) % 360; }, majorAngles: function () { return $.map(this.majorIntervals(), $.proxy(this.intervalAngle, this)); }, createLine: function () { return []; }, majorGridLineAngles: function (altAxis) { var majorGridLines = this.options.majorGridLines; return this.gridLineAngles(altAxis, 1, majorGridLines.skip, majorGridLines.step); }, minorGridLineAngles: function (altAxis, skipMajor) { var options = this.options; var minorGridLines = options.minorGridLines; var majorGridLines = options.majorGridLines; var majorGridLineAngles = skipMajor ? this.intervals(1, majorGridLines.skip, majorGridLines.step) : null; return this.gridLineAngles(altAxis, 0.5, minorGridLines.skip, minorGridLines.step, majorGridLineAngles); }, radiusCallback: function (radius, altAxis, skipMajor) { if (altAxis.options.type !== ARC) { var minorAngle = 360 / (this.options.categories.length * 2); var minorRadius = math.cos(minorAngle * DEG_TO_RAD) * radius; var majorAngles = this.majorAngles(); var radiusCallback = function (angle) { if (!skipMajor && dataviz.inArray(angle, majorAngles)) { return radius; } else { return minorRadius; } }; return radiusCallback; } }, createPlotBands: function () { var axis = this, options = axis.options, plotBands = options.plotBands || [], i, band, slot, singleSlot, head, tail; var group = this._plotbandGroup = new draw.Group({ zIndex: -1 }); for (i = 0; i < plotBands.length; i++) { band = plotBands[i]; slot = axis.plotBandSlot(band); singleSlot = axis.getSlot(band.from); head = band.from - math.floor(band.from); slot.startAngle += head * singleSlot.angle; tail = math.ceil(band.to) - band.to; slot.angle -= (tail + head) * singleSlot.angle; var ring = ShapeBuilder.current.createRing(slot, { fill: { color: band.color, opacity: band.opacity }, stroke: { opacity: band.opacity } }); group.append(ring); } axis.appendVisual(group); }, plotBandSlot: function (band) { return this.getSlot(band.from, band.to - 1); }, getSlot: function (from, to) { var axis = this, options = axis.options, justified = options.justified, box = axis.box, divs = axis.majorAngles(), totalDivs = divs.length, slots, slotAngle = 360 / totalDivs, slotStart, angle; if (options.reverse && !justified) { from = (from + 1) % totalDivs; } from = limitValue(math.floor(from), 0, totalDivs - 1); slotStart = divs[from]; if (justified) { slotStart = slotStart - slotAngle / 2; if (slotStart < 0) { slotStart += 360; } } to = limitValue(math.ceil(to || from), from, totalDivs - 1); slots = to - from + 1; angle = slotAngle * slots; return new Ring(box.center(), 0, box.height() / 2, slotStart, angle); }, slot: function (from, to) { var slot = this.getSlot(from, to); var startAngle = slot.startAngle + 180; var endAngle = startAngle + slot.angle; return new geom.Arc([ slot.c.x, slot.c.y ], { startAngle: startAngle, endAngle: endAngle, radiusX: slot.r, radiusY: slot.r }); }, pointCategoryIndex: function (point) { var axis = this, index = null, i, length = axis.options.categories.length, slot; for (i = 0; i < length; i++) { slot = axis.getSlot(i); if (slot.containsPoint(point)) { index = i; break; } } return index; } }); deepExtend(RadarCategoryAxis.fn, GridLinesMixin); var RadarNumericAxisMixin = { options: { majorGridLines: { visible: true } }, createPlotBands: function () { var axis = this, options = axis.options, plotBands = options.plotBands || [], type = options.majorGridLines.type, altAxis = axis.plotArea.polarAxis, majorAngles = altAxis.majorAngles(), center = altAxis.box.center(), i, band, bandStyle, slot, ring; var group = this._plotbandGroup = new draw.Group({ zIndex: -1 }); for (i = 0; i < plotBands.length; i++) { band = plotBands[i]; bandStyle = { fill: { color: band.color, opacity: band.opacity }, stroke: { opacity: band.opacity } }; slot = axis.getSlot(band.from, band.to, true); ring = new Ring(center, center.y - slot.y2, center.y - slot.y1, 0, 360); var shape; if (type === ARC) { shape = ShapeBuilder.current.createRing(ring, bandStyle); } else { shape = draw.Path.fromPoints(axis.plotBandPoints(ring, majorAngles), bandStyle).close(); } group.append(shape); } axis.appendVisual(group); }, plotBandPoints: function (ring, angles) { var innerPoints = [], outerPoints = []; var center = [ ring.c.x, ring.c.y ]; var innerCircle = new geom.Circle(center, ring.ir); var outerCircle = new geom.Circle(center, ring.r); for (var i = 0; i < angles.length; i++) { innerPoints.push(innerCircle.pointAt(angles[i])); outerPoints.push(outerCircle.pointAt(angles[i])); } innerPoints.reverse(); innerPoints.push(innerPoints[0]); outerPoints.push(outerPoints[0]); return outerPoints.concat(innerPoints); }, createGridLines: function (altAxis) { var axis = this, options = axis.options, majorTicks = axis.radarMajorGridLinePositions(), majorAngles = altAxis.majorAngles(), minorTicks, center = altAxis.box.center(), gridLines = []; if (options.majorGridLines.visible) { gridLines = axis.renderGridLines(center, majorTicks, majorAngles, options.majorGridLines); } if (options.minorGridLines.visible) { minorTicks = axis.radarMinorGridLinePositions(); append(gridLines, axis.renderGridLines(center, minorTicks, majorAngles, options.minorGridLines)); } return gridLines; }, renderGridLines: function (center, ticks, angles, options) { var tickRadius, tickIx, angleIx; var style = { stroke: { width: options.width, color: options.color, dashType: options.dashType } }; var container = this.gridLinesVisual(); for (tickIx = 0; tickIx < ticks.length; tickIx++) { tickRadius = center.y - ticks[tickIx]; if (tickRadius > 0) { var circle = new geom.Circle([ center.x, center.y ], tickRadius); if (options.type === ARC) { container.append(new draw.Circle(circle, style)); } else { var line = new draw.Path(style); for (angleIx = 0; angleIx < angles.length; angleIx++) { line.lineTo(circle.pointAt(angles[angleIx])); } line.close(); container.append(line); } } } return container.children; }, getValue: function (point) { var axis = this, options = axis.options, lineBox = axis.lineBox(), altAxis = axis.plotArea.polarAxis, majorAngles = altAxis.majorAngles(), center = altAxis.box.center(), r = point.distanceTo(center), distance = r; if (options.majorGridLines.type !== ARC && majorAngles.length > 1) { var dx = point.x - center.x, dy = point.y - center.y, theta = (math.atan2(dy, dx) / DEG_TO_RAD + 540) % 360; majorAngles.sort(function (a, b) { return angularDistance(a, theta) - angularDistance(b, theta); }); var midAngle = angularDistance(majorAngles[0], majorAngles[1]) / 2, alpha = angularDistance(theta, majorAngles[0]), gamma = 90 - midAngle, beta = 180 - alpha - gamma; distance = r * (math.sin(beta * DEG_TO_RAD) / math.sin(gamma * DEG_TO_RAD)); } return axis.axisType().fn.getValue.call(axis, new Point2D(lineBox.x1, lineBox.y2 - distance)); } }; var RadarNumericAxis = NumericAxis.extend({ radarMajorGridLinePositions: function () { return this.getTickPositions(this.options.majorUnit); }, radarMinorGridLinePositions: function () { var axis = this, options = axis.options, minorSkipStep = 0; if (options.majorGridLines.visible) { minorSkipStep = options.majorUnit; } return axis.getTickPositions(options.minorUnit, minorSkipStep); }, axisType: function () { return NumericAxis; } }); deepExtend(RadarNumericAxis.fn, RadarNumericAxisMixin); var RadarLogarithmicAxis = LogarithmicAxis.extend({ radarMajorGridLinePositions: function () { var axis = this, positions = []; axis.traverseMajorTicksPositions(function (position) { positions.push(position); }, axis.options.majorGridLines); return positions; }, radarMinorGridLinePositions: function () { var axis = this, positions = []; axis.traverseMinorTicksPositions(function (position) { positions.push(position); }, axis.options.minorGridLines); return positions; }, axisType: function () { return LogarithmicAxis; } }); deepExtend(RadarLogarithmicAxis.fn, RadarNumericAxisMixin); var PolarAxis = Axis.extend({ init: function (options) { var axis = this; Axis.fn.init.call(axis, options); options = axis.options; options.minorUnit = options.minorUnit || axis.options.majorUnit / 2; }, options: { type: 'polar', startAngle: 0, reverse: false, majorUnit: 60, min: 0, max: 360, labels: { margin: getSpacing(10) }, majorGridLines: { color: BLACK, visible: true, width: 1 }, minorGridLines: { color: '#aaa' } }, getDivisions: function (stepValue) { return NumericAxis.fn.getDivisions.call(this, stepValue) - 1; }, reflow: function (box) { this.box = box; this.reflowLabels(); }, reflowLabels: function () { var axis = this, options = axis.options, labelOptions = options.labels, skip = labelOptions.skip || 0, step = labelOptions.step || 1, measureBox = new Box2D(), divs = axis.intervals(options.majorUnit, skip, step), labels = axis.labels, labelBox, i; for (i = 0; i < labels.length; i++) { labels[i].reflow(measureBox); labelBox = labels[i].box; labels[i].reflow(axis.getSlot(divs[i]).adjacentBox(0, labelBox.width(), labelBox.height())); } }, lineBox: function () { return this.box; }, intervals: function (size, skip, step, skipAngles) { var axis = this, options = axis.options, divisions = axis.getDivisions(size), min = options.min, current, divs = [], i; skip = skip || 0; step = step || 1; for (i = skip; i < divisions; i += step) { current = (360 + min + i * size) % 360; if (!(skipAngles && dataviz.inArray(current, skipAngles))) { divs.push(current); } } return divs; }, majorIntervals: function () { return this.intervals(this.options.majorUnit); }, minorIntervals: function () { return this.intervals(this.options.minorUnit); }, intervalAngle: function (i) { return (540 - i - this.options.startAngle) % 360; }, majorAngles: RadarCategoryAxis.fn.majorAngles, createLine: function () { return []; }, majorGridLineAngles: function (altAxis) { var majorGridLines = this.options.majorGridLines; return this.gridLineAngles(altAxis, this.options.majorUnit, majorGridLines.skip, majorGridLines.step); }, minorGridLineAngles: function (altAxis, skipMajor) { var options = this.options; var minorGridLines = options.minorGridLines; var majorGridLines = options.majorGridLines; var majorGridLineAngles = skipMajor ? this.intervals(options.majorUnit, majorGridLines.skip, majorGridLines.step) : null; return this.gridLineAngles(altAxis, this.options.minorUnit, minorGridLines.skip, minorGridLines.step, majorGridLineAngles); }, createPlotBands: RadarCategoryAxis.fn.createPlotBands, plotBandSlot: function (band) { return this.getSlot(band.from, band.to); }, getSlot: function (a, b) { var axis = this, options = axis.options, start = options.startAngle, box = axis.box, tmp; a = limitValue(a, options.min, options.max); b = limitValue(b || a, a, options.max); if (options.reverse) { a *= -1; b *= -1; } a = (540 - a - start) % 360; b = (540 - b - start) % 360; if (b < a) { tmp = a; a = b; b = tmp; } return new Ring(box.center(), 0, box.height() / 2, a, b - a); }, slot: function (from, to) { var options = this.options; var start = 360 - options.startAngle; var slot = this.getSlot(from, to); var startAngle; var endAngle; var min; var max; if (!dataviz.util.defined(to)) { to = from; } min = math.min(from, to); max = math.max(from, to); if (options.reverse) { startAngle = min; endAngle = max; } else { startAngle = 360 - max; endAngle = 360 - min; } startAngle = (startAngle + start) % 360; endAngle = (endAngle + start) % 360; return new geom.Arc([ slot.c.x, slot.c.y ], { startAngle: startAngle, endAngle: endAngle, radiusX: slot.r, radiusY: slot.r }); }, getValue: function (point) { var axis = this, options = axis.options, center = axis.box.center(), dx = point.x - center.x, dy = point.y - center.y, theta = math.round(math.atan2(dy, dx) / DEG_TO_RAD), start = options.startAngle; if (!options.reverse) { theta *= -1; start *= -1; } return (theta + start + 360) % 360; }, range: NumericAxis.fn.range, labelsCount: NumericAxis.fn.labelsCount, createAxisLabel: NumericAxis.fn.createAxisLabel }); deepExtend(PolarAxis.fn, GridLinesMixin); var RadarClusterLayout = ChartElement.extend({ options: { gap: 1, spacing: 0 }, reflow: function (sector) { var cluster = this, options = cluster.options, children = cluster.children, gap = options.gap, spacing = options.spacing, count = children.length, slots = count + gap + spacing * (count - 1), slotAngle = sector.angle / slots, slotSector, angle = sector.startAngle + slotAngle * (gap / 2), i; for (i = 0; i < count; i++) { slotSector = sector.clone(); slotSector.startAngle = angle; slotSector.angle = slotAngle; if (children[i].sector) { slotSector.r = children[i].sector.r; } children[i].reflow(slotSector); children[i].sector = slotSector; angle += slotAngle + slotAngle * spacing; } } }); var RadarStackLayout = ChartElement.extend({ reflow: function (sector) { var stack = this, reverse = stack.options.isReversed, children = stack.children, childrenCount = children.length, childSector, i, first = reverse ? childrenCount - 1 : 0, step = reverse ? -1 : 1; stack.box = new Box2D(); for (i = first; i >= 0 && i < childrenCount; i += step) { childSector = children[i].sector; childSector.startAngle = sector.startAngle; childSector.angle = sector.angle; } } }); var RadarSegment = DonutSegment.extend({ init: function (value, options) { DonutSegment.fn.init.call(this, value, null, options); }, options: { overlay: { gradient: null }, labels: { distance: 10 } } }); var RadarBarChart = BarChart.extend({ pointType: function () { return RadarSegment; }, clusterType: function () { return RadarClusterLayout; }, stackType: function () { return RadarStackLayout; }, categorySlot: function (categoryAxis, categoryIx) { return categoryAxis.getSlot(categoryIx); }, pointSlot: function (categorySlot, valueSlot) { var slot = categorySlot.clone(), y = categorySlot.c.y; slot.r = y - valueSlot.y1; slot.ir = y - valueSlot.y2; return slot; }, reflow: CategoricalChart.fn.reflow, reflowPoint: function (point, pointSlot) { point.sector = pointSlot; point.reflow(); }, options: { clip: false, animation: { type: 'pie' } }, createAnimation: function () { this.options.animation.center = this.box.toRect().center(); BarChart.fn.createAnimation.call(this); } }); var RadarLineChart = LineChart.extend({ options: { clip: false }, pointSlot: function (categorySlot, valueSlot) { var valueRadius = categorySlot.c.y - valueSlot.y1, slot = Point2D.onCircle(categorySlot.c, categorySlot.middle(), valueRadius); return new Box2D(slot.x, slot.y, slot.x, slot.y); }, createSegment: function (linePoints, currentSeries, seriesIx) { var segment, pointType, style = currentSeries.style; if (style == SMOOTH) { pointType = SplineSegment; } else { pointType = LineSegment; } segment = new pointType(linePoints, currentSeries, seriesIx); if (linePoints.length === currentSeries.data.length) { segment.options.closed = true; } return segment; } }); var RadarAreaSegment = AreaSegment.extend({ points: function () { return LineSegment.fn.points.call(this, this.stackPoints); } }); var SplineRadarAreaSegment = SplineAreaSegment.extend({ closeFill: $.noop }); var RadarAreaChart = RadarLineChart.extend({ createSegment: function (linePoints, currentSeries, seriesIx, prevSegment) { var chart = this, options = chart.options, isStacked = options.isStacked, stackPoints, segment, style = (currentSeries.line || {}).style; if (style === SMOOTH) { segment = new SplineRadarAreaSegment(linePoints, prevSegment, isStacked, currentSeries, seriesIx); segment.options.closed = true; } else { if (isStacked && seriesIx > 0 && prevSegment) { stackPoints = prevSegment.linePoints.slice(0).reverse(); } linePoints.push(linePoints[0]); segment = new RadarAreaSegment(linePoints, stackPoints, currentSeries, seriesIx); } return segment; }, seriesMissingValues: function (series) { return series.missingValues || ZERO; } }); var PolarScatterChart = ScatterChart.extend({ pointSlot: function (slotX, slotY) { var valueRadius = slotX.c.y - slotY.y1, slot = Point2D.onCircle(slotX.c, slotX.startAngle, valueRadius); return new Box2D(slot.x, slot.y, slot.x, slot.y); }, options: { clip: false } }); var PolarLineChart = ScatterLineChart.extend({ pointSlot: PolarScatterChart.fn.pointSlot, options: { clip: false } }); var PolarAreaSegment = AreaSegment.extend({ points: function () { var segment = this, chart = segment.parent, plotArea = chart.plotArea, polarAxis = plotArea.polarAxis, center = polarAxis.box.center(), stackPoints = segment.stackPoints, points = LineSegment.fn.points.call(segment, stackPoints); points.unshift([ center.x, center.y ]); points.push([ center.x, center.y ]); return points; } }); var SplinePolarAreaSegment = SplineAreaSegment.extend({ closeFill: function (fillPath) { var center = this._polarAxisCenter(); fillPath.lineTo(center.x, center.y); }, _polarAxisCenter: function () { var chart = this.parent, plotArea = chart.plotArea, polarAxis = plotArea.polarAxis, center = polarAxis.box.center(); return center; }, strokeSegments: function () { var segments = this._strokeSegments; if (!segments) { var center = this._polarAxisCenter(), curveProcessor = new CurveProcessor(false), linePoints = LineSegment.fn.points.call(this); linePoints.push(center); segments = this._strokeSegments = curveProcessor.process(linePoints); segments.pop(); } return segments; } }); var PolarAreaChart = PolarLineChart.extend({ createSegment: function (linePoints, currentSeries, seriesIx) { var segment, style = (currentSeries.line || {}).style; if (style == SMOOTH) { segment = new SplinePolarAreaSegment(linePoints, null, false, currentSeries, seriesIx); } else { segment = new PolarAreaSegment(linePoints, [], currentSeries, seriesIx); } return segment; }, createMissingValue: function (value, missingValues) { var missingValue; if (dataviz.hasValue(value.x) && missingValues != INTERPOLATE) { missingValue = { x: value.x, y: value.y }; if (missingValues == ZERO) { missingValue.y = 0; } } return missingValue; }, seriesMissingValues: function (series) { return series.missingValues || ZERO; }, _hasMissingValuesGap: function () { var series = this.options.series; for (var idx = 0; idx < series.length; idx++) { if (this.seriesMissingValues(series[idx]) === GAP) { return true; } } }, sortPoints: function (points) { var value, point; points.sort(xComparer); if (this._hasMissingValuesGap()) { for (var idx = 0; idx < points.length; idx++) { point = points[idx]; if (point) { value = point.value; if (!dataviz.hasValue(value.y) && this.seriesMissingValues(point.series) === GAP) { delete points[idx]; } } } } return points; } }); var PolarPlotAreaBase = PlotAreaBase.extend({ init: function (series, options) { var plotArea = this; plotArea.valueAxisRangeTracker = new AxisGroupRangeTracker(); PlotAreaBase.fn.init.call(plotArea, series, options); }, render: function () { var plotArea = this; plotArea.addToLegend(plotArea.series); plotArea.createPolarAxis(); plotArea.createCharts(); plotArea.createValueAxis(); }, alignAxes: function () { var axis = this.valueAxis; var range = axis.range(); var crossingValue = axis.options.reverse ? range.max : range.min; var slot = axis.getSlot(crossingValue); var center = this.polarAxis.getSlot(0).c; var axisBox = axis.box.translate(center.x - slot.x1, center.y - slot.y1); axis.reflow(axisBox); }, createValueAxis: function () { var plotArea = this, tracker = plotArea.valueAxisRangeTracker, defaultRange = tracker.query(), range, valueAxis, axisOptions = plotArea.valueAxisOptions({ roundToMajorUnit: false, zIndex: -1 }), axisType, axisDefaultRange; if (axisOptions.type === LOGARITHMIC) { axisType = RadarLogarithmicAxis; axisDefaultRange = { min: 0.1, max: 1 }; } else { axisType = RadarNumericAxis; axisDefaultRange = { min: 0, max: 1 }; } range = tracker.query(name) || defaultRange || axisDefaultRange; if (range && defaultRange) { range.min = math.min(range.min, defaultRange.min); range.max = math.max(range.max, defaultRange.max); } valueAxis = new axisType(range.min, range.max, axisOptions); plotArea.valueAxis = valueAxis; plotArea.appendAxis(valueAxis); }, reflowAxes: function () { var plotArea = this, options = plotArea.options.plotArea, valueAxis = plotArea.valueAxis, polarAxis = plotArea.polarAxis, box = plotArea.box, defaultPadding = math.min(box.width(), box.height()) * DEFAULT_PADDING, padding = getSpacing(options.padding || {}, defaultPadding), axisBox = box.clone().unpad(padding), valueAxisBox = axisBox.clone().shrink(0, axisBox.height() / 2); polarAxis.reflow(axisBox); valueAxis.reflow(valueAxisBox); var heightDiff = valueAxis.lineBox().height() - valueAxis.box.height(); valueAxis.reflow(valueAxis.box.unpad({ top: heightDiff })); plotArea.axisBox = axisBox; plotArea.alignAxes(axisBox); }, backgroundBox: function () { return this.box; } }); var RadarPlotArea = PolarPlotAreaBase.extend({ options: { categoryAxis: { categories: [] }, valueAxis: {} }, createPolarAxis: function () { var plotArea = this, categoryAxis; categoryAxis = new RadarCategoryAxis(plotArea.options.categoryAxis); plotArea.polarAxis = categoryAxis; plotArea.categoryAxis = categoryAxis; plotArea.appendAxis(categoryAxis); }, valueAxisOptions: function (defaults) { var plotArea = this; if (plotArea._hasBarCharts) { deepExtend(defaults, { majorGridLines: { type: ARC }, minorGridLines: { type: ARC } }); } if (plotArea._isStacked100) { deepExtend(defaults, { roundToMajorUnit: false, labels: { format: 'P0' } }); } return deepExtend(defaults, plotArea.options.valueAxis); }, appendChart: CategoricalPlotArea.fn.appendChart, createCharts: function () { var plotArea = this, series = plotArea.filterVisibleSeries(plotArea.series), pane = plotArea.panes[0]; plotArea.createAreaChart(filterSeriesByType(series, [RADAR_AREA]), pane); plotArea.createLineChart(filterSeriesByType(series, [RADAR_LINE]), pane); plotArea.createBarChart(filterSeriesByType(series, [RADAR_COLUMN]), pane); }, chartOptions: function (series) { var options = { series: series }; var firstSeries = series[0]; if (firstSeries) { var filteredSeries = this.filterVisibleSeries(series); var stack = firstSeries.stack; options.isStacked = stack && filteredSeries.length > 1; options.isStacked100 = stack && stack.type === '100%' && filteredSeries.length > 1; if (options.isStacked100) { this._isStacked100 = true; } } return options; }, createAreaChart: function (series, pane) { if (series.length === 0) { return; } var areaChart = new RadarAreaChart(this, this.chartOptions(series)); this.appendChart(areaChart, pane); }, createLineChart: function (series, pane) { if (series.length === 0) { return; } var lineChart = new RadarLineChart(this, this.chartOptions(series)); this.appendChart(lineChart, pane); }, createBarChart: function (series, pane) { if (series.length === 0) { return; } var firstSeries = series[0]; var options = this.chartOptions(series); options.gap = firstSeries.gap; options.spacing = firstSeries.spacing; var barChart = new RadarBarChart(this, options); this.appendChart(barChart, pane); this._hasBarCharts = true; }, seriesCategoryAxis: function () { return this.categoryAxis; }, click: function (chart, e) { var plotArea = this, coords = chart._eventCoordinates(e), point = new Point2D(coords.x, coords.y), category, value; category = plotArea.categoryAxis.getCategory(point); value = plotArea.valueAxis.getValue(point); if (category !== null && value !== null) { chart.trigger(PLOT_AREA_CLICK, { element: $(e.target), category: category, value: value }); } }, createCrosshairs: $.noop }); var PolarPlotArea = PolarPlotAreaBase.extend({ options: { xAxis: {}, yAxis: {} }, createPolarAxis: function () { var plotArea = this, polarAxis; polarAxis = new PolarAxis(plotArea.options.xAxis); plotArea.polarAxis = polarAxis; plotArea.axisX = polarAxis; plotArea.appendAxis(polarAxis); }, valueAxisOptions: function (defaults) { var plotArea = this; return deepExtend(defaults, { majorGridLines: { type: ARC }, minorGridLines: { type: ARC } }, plotArea.options.yAxis); }, createValueAxis: function () { var plotArea = this; PolarPlotAreaBase.fn.createValueAxis.call(plotArea); plotArea.axisY = plotArea.valueAxis; }, appendChart: function (chart, pane) { var plotArea = this; plotArea.valueAxisRangeTracker.update(chart.yAxisRanges); PlotAreaBase.fn.appendChart.call(plotArea, chart, pane); }, createCharts: function () { var plotArea = this, series = plotArea.filterVisibleSeries(plotArea.series), pane = plotArea.panes[0]; plotArea.createLineChart(filterSeriesByType(series, [POLAR_LINE]), pane); plotArea.createScatterChart(filterSeriesByType(series, [POLAR_SCATTER]), pane); plotArea.createAreaChart(filterSeriesByType(series, [POLAR_AREA]), pane); }, createLineChart: function (series, pane) { if (series.length === 0) { return; } var plotArea = this, lineChart = new PolarLineChart(plotArea, { series: series }); plotArea.appendChart(lineChart, pane); }, createScatterChart: function (series, pane) { if (series.length === 0) { return; } var plotArea = this, scatterChart = new PolarScatterChart(plotArea, { series: series }); plotArea.appendChart(scatterChart, pane); }, createAreaChart: function (series, pane) { if (series.length === 0) { return; } var plotArea = this, areaChart = new PolarAreaChart(plotArea, { series: series }); plotArea.appendChart(areaChart, pane); }, click: function (chart, e) { var plotArea = this, coords = chart._eventCoordinates(e), point = new Point2D(coords.x, coords.y), xValue, yValue; xValue = plotArea.axisX.getValue(point); yValue = plotArea.axisY.getValue(point); if (xValue !== null && yValue !== null) { chart.trigger(PLOT_AREA_CLICK, { element: $(e.target), x: xValue, y: yValue }); } }, createCrosshairs: $.noop }); function xComparer(a, b) { return a.value.x - b.value.x; } function angularDistance(a, b) { return 180 - math.abs(math.abs(a - b) - 180); } PlotAreaFactory.current.register(PolarPlotArea, POLAR_CHARTS); PlotAreaFactory.current.register(RadarPlotArea, RADAR_CHARTS); SeriesBinder.current.register(POLAR_CHARTS, [ X, Y ], ['color']); SeriesBinder.current.register(RADAR_CHARTS, ['value'], ['color']); dataviz.DefaultAggregates.current.register(RADAR_CHARTS, { value: 'max', color: 'first' }); deepExtend(dataviz, { PolarAreaChart: PolarAreaChart, PolarAxis: PolarAxis, PolarLineChart: PolarLineChart, PolarPlotArea: PolarPlotArea, RadarAreaChart: RadarAreaChart, RadarBarChart: RadarBarChart, RadarCategoryAxis: RadarCategoryAxis, RadarClusterLayout: RadarClusterLayout, RadarLineChart: RadarLineChart, RadarNumericAxis: RadarNumericAxis, RadarPlotArea: RadarPlotArea, SplinePolarAreaSegment: SplinePolarAreaSegment, SplineRadarAreaSegment: SplineRadarAreaSegment, RadarStackLayout: RadarStackLayout }); }(window.kendo.jQuery)); return window.kendo; }, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) { (a3 || a2)(); }));