summaryrefslogtreecommitdiff
path: root/html/includes/js/modules
diff options
context:
space:
mode:
Diffstat (limited to 'html/includes/js/modules')
-rw-r--r--html/includes/js/modules/canvas-tools.src.js3113
-rw-r--r--html/includes/js/modules/data.src.js1025
-rw-r--r--html/includes/js/modules/drilldown.src.js606
-rw-r--r--html/includes/js/modules/exporting.src.js719
-rw-r--r--html/includes/js/modules/funnel.src.js310
-rw-r--r--html/includes/js/modules/heatmap.src.js687
-rw-r--r--html/includes/js/modules/no-data-to-display.src.js130
-rw-r--r--html/includes/js/modules/solid-gauge.src.js234
8 files changed, 0 insertions, 6824 deletions
diff --git a/html/includes/js/modules/canvas-tools.src.js b/html/includes/js/modules/canvas-tools.src.js
deleted file mode 100644
index 3725c02..0000000
--- a/html/includes/js/modules/canvas-tools.src.js
+++ /dev/null
@@ -1,3113 +0,0 @@
-/**
- * @license A class to parse color values
- * @author Stoyan Stefanov <sstoo@gmail.com>
- * @link http://www.phpied.com/rgb-color-parser-in-javascript/
- * Use it if you like it
- *
- */
-function RGBColor(color_string)
-{
- this.ok = false;
-
- // strip any leading #
- if (color_string.charAt(0) == '#') { // remove # if any
- color_string = color_string.substr(1,6);
- }
-
- color_string = color_string.replace(/ /g,'');
- color_string = color_string.toLowerCase();
-
- // before getting into regexps, try simple matches
- // and overwrite the input
- var simple_colors = {
- aliceblue: 'f0f8ff',
- antiquewhite: 'faebd7',
- aqua: '00ffff',
- aquamarine: '7fffd4',
- azure: 'f0ffff',
- beige: 'f5f5dc',
- bisque: 'ffe4c4',
- black: '000000',
- blanchedalmond: 'ffebcd',
- blue: '0000ff',
- blueviolet: '8a2be2',
- brown: 'a52a2a',
- burlywood: 'deb887',
- cadetblue: '5f9ea0',
- chartreuse: '7fff00',
- chocolate: 'd2691e',
- coral: 'ff7f50',
- cornflowerblue: '6495ed',
- cornsilk: 'fff8dc',
- crimson: 'dc143c',
- cyan: '00ffff',
- darkblue: '00008b',
- darkcyan: '008b8b',
- darkgoldenrod: 'b8860b',
- darkgray: 'a9a9a9',
- darkgreen: '006400',
- darkkhaki: 'bdb76b',
- darkmagenta: '8b008b',
- darkolivegreen: '556b2f',
- darkorange: 'ff8c00',
- darkorchid: '9932cc',
- darkred: '8b0000',
- darksalmon: 'e9967a',
- darkseagreen: '8fbc8f',
- darkslateblue: '483d8b',
- darkslategray: '2f4f4f',
- darkturquoise: '00ced1',
- darkviolet: '9400d3',
- deeppink: 'ff1493',
- deepskyblue: '00bfff',
- dimgray: '696969',
- dodgerblue: '1e90ff',
- feldspar: 'd19275',
- firebrick: 'b22222',
- floralwhite: 'fffaf0',
- forestgreen: '228b22',
- fuchsia: 'ff00ff',
- gainsboro: 'dcdcdc',
- ghostwhite: 'f8f8ff',
- gold: 'ffd700',
- goldenrod: 'daa520',
- gray: '808080',
- green: '008000',
- greenyellow: 'adff2f',
- honeydew: 'f0fff0',
- hotpink: 'ff69b4',
- indianred : 'cd5c5c',
- indigo : '4b0082',
- ivory: 'fffff0',
- khaki: 'f0e68c',
- lavender: 'e6e6fa',
- lavenderblush: 'fff0f5',
- lawngreen: '7cfc00',
- lemonchiffon: 'fffacd',
- lightblue: 'add8e6',
- lightcoral: 'f08080',
- lightcyan: 'e0ffff',
- lightgoldenrodyellow: 'fafad2',
- lightgrey: 'd3d3d3',
- lightgreen: '90ee90',
- lightpink: 'ffb6c1',
- lightsalmon: 'ffa07a',
- lightseagreen: '20b2aa',
- lightskyblue: '87cefa',
- lightslateblue: '8470ff',
- lightslategray: '778899',
- lightsteelblue: 'b0c4de',
- lightyellow: 'ffffe0',
- lime: '00ff00',
- limegreen: '32cd32',
- linen: 'faf0e6',
- magenta: 'ff00ff',
- maroon: '800000',
- mediumaquamarine: '66cdaa',
- mediumblue: '0000cd',
- mediumorchid: 'ba55d3',
- mediumpurple: '9370d8',
- mediumseagreen: '3cb371',
- mediumslateblue: '7b68ee',
- mediumspringgreen: '00fa9a',
- mediumturquoise: '48d1cc',
- mediumvioletred: 'c71585',
- midnightblue: '191970',
- mintcream: 'f5fffa',
- mistyrose: 'ffe4e1',
- moccasin: 'ffe4b5',
- navajowhite: 'ffdead',
- navy: '000080',
- oldlace: 'fdf5e6',
- olive: '808000',
- olivedrab: '6b8e23',
- orange: 'ffa500',
- orangered: 'ff4500',
- orchid: 'da70d6',
- palegoldenrod: 'eee8aa',
- palegreen: '98fb98',
- paleturquoise: 'afeeee',
- palevioletred: 'd87093',
- papayawhip: 'ffefd5',
- peachpuff: 'ffdab9',
- peru: 'cd853f',
- pink: 'ffc0cb',
- plum: 'dda0dd',
- powderblue: 'b0e0e6',
- purple: '800080',
- red: 'ff0000',
- rosybrown: 'bc8f8f',
- royalblue: '4169e1',
- saddlebrown: '8b4513',
- salmon: 'fa8072',
- sandybrown: 'f4a460',
- seagreen: '2e8b57',
- seashell: 'fff5ee',
- sienna: 'a0522d',
- silver: 'c0c0c0',
- skyblue: '87ceeb',
- slateblue: '6a5acd',
- slategray: '708090',
- snow: 'fffafa',
- springgreen: '00ff7f',
- steelblue: '4682b4',
- tan: 'd2b48c',
- teal: '008080',
- thistle: 'd8bfd8',
- tomato: 'ff6347',
- turquoise: '40e0d0',
- violet: 'ee82ee',
- violetred: 'd02090',
- wheat: 'f5deb3',
- white: 'ffffff',
- whitesmoke: 'f5f5f5',
- yellow: 'ffff00',
- yellowgreen: '9acd32'
- };
- for (var key in simple_colors) {
- if (color_string == key) {
- color_string = simple_colors[key];
- }
- }
- // emd of simple type-in colors
-
- // array of color definition objects
- var color_defs = [
- {
- re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
- example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],
- process: function (bits){
- return [
- parseInt(bits[1]),
- parseInt(bits[2]),
- parseInt(bits[3])
- ];
- }
- },
- {
- re: /^(\w{2})(\w{2})(\w{2})$/,
- example: ['#00ff00', '336699'],
- process: function (bits){
- return [
- parseInt(bits[1], 16),
- parseInt(bits[2], 16),
- parseInt(bits[3], 16)
- ];
- }
- },
- {
- re: /^(\w{1})(\w{1})(\w{1})$/,
- example: ['#fb0', 'f0f'],
- process: function (bits){
- return [
- parseInt(bits[1] + bits[1], 16),
- parseInt(bits[2] + bits[2], 16),
- parseInt(bits[3] + bits[3], 16)
- ];
- }
- }
- ];
-
- // search through the definitions to find a match
- for (var i = 0; i < color_defs.length; i++) {
- var re = color_defs[i].re;
- var processor = color_defs[i].process;
- var bits = re.exec(color_string);
- if (bits) {
- channels = processor(bits);
- this.r = channels[0];
- this.g = channels[1];
- this.b = channels[2];
- this.ok = true;
- }
-
- }
-
- // validate/cleanup values
- this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r);
- this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g);
- this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b);
-
- // some getters
- this.toRGB = function () {
- return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')';
- }
- this.toHex = function () {
- var r = this.r.toString(16);
- var g = this.g.toString(16);
- var b = this.b.toString(16);
- if (r.length == 1) r = '0' + r;
- if (g.length == 1) g = '0' + g;
- if (b.length == 1) b = '0' + b;
- return '#' + r + g + b;
- }
-
- // help
- this.getHelpXML = function () {
-
- var examples = new Array();
- // add regexps
- for (var i = 0; i < color_defs.length; i++) {
- var example = color_defs[i].example;
- for (var j = 0; j < example.length; j++) {
- examples[examples.length] = example[j];
- }
- }
- // add type-in colors
- for (var sc in simple_colors) {
- examples[examples.length] = sc;
- }
-
- var xml = document.createElement('ul');
- xml.setAttribute('id', 'rgbcolor-examples');
- for (var i = 0; i < examples.length; i++) {
- try {
- var list_item = document.createElement('li');
- var list_color = new RGBColor(examples[i]);
- var example_div = document.createElement('div');
- example_div.style.cssText =
- 'margin: 3px; '
- + 'border: 1px solid black; '
- + 'background:' + list_color.toHex() + '; '
- + 'color:' + list_color.toHex()
- ;
- example_div.appendChild(document.createTextNode('test'));
- var list_item_value = document.createTextNode(
- ' ' + examples[i] + ' -> ' + list_color.toRGB() + ' -> ' + list_color.toHex()
- );
- list_item.appendChild(example_div);
- list_item.appendChild(list_item_value);
- xml.appendChild(list_item);
-
- } catch(e){}
- }
- return xml;
-
- }
-
-}
-
-/**
- * @license canvg.js - Javascript SVG parser and renderer on Canvas
- * MIT Licensed
- * Gabe Lerner (gabelerner@gmail.com)
- * http://code.google.com/p/canvg/
- *
- * Requires: rgbcolor.js - http://www.phpied.com/rgb-color-parser-in-javascript/
- *
- */
-if(!window.console) {
- window.console = {};
- window.console.log = function(str) {};
- window.console.dir = function(str) {};
-}
-
-if(!Array.prototype.indexOf){
- Array.prototype.indexOf = function(obj){
- for(var i=0; i<this.length; i++){
- if(this[i]==obj){
- return i;
- }
- }
- return -1;
- }
-}
-
-(function(){
- // canvg(target, s)
- // empty parameters: replace all 'svg' elements on page with 'canvas' elements
- // target: canvas element or the id of a canvas element
- // s: svg string, url to svg file, or xml document
- // opts: optional hash of options
- // ignoreMouse: true => ignore mouse events
- // ignoreAnimation: true => ignore animations
- // ignoreDimensions: true => does not try to resize canvas
- // ignoreClear: true => does not clear canvas
- // offsetX: int => draws at a x offset
- // offsetY: int => draws at a y offset
- // scaleWidth: int => scales horizontally to width
- // scaleHeight: int => scales vertically to height
- // renderCallback: function => will call the function after the first render is completed
- // forceRedraw: function => will call the function on every frame, if it returns true, will redraw
- this.canvg = function (target, s, opts) {
- // no parameters
- if (target == null && s == null && opts == null) {
- var svgTags = document.getElementsByTagName('svg');
- for (var i=0; i<svgTags.length; i++) {
- var svgTag = svgTags[i];
- var c = document.createElement('canvas');
- c.width = svgTag.clientWidth;
- c.height = svgTag.clientHeight;
- svgTag.parentNode.insertBefore(c, svgTag);
- svgTag.parentNode.removeChild(svgTag);
- var div = document.createElement('div');
- div.appendChild(svgTag);
- canvg(c, div.innerHTML);
- }
- return;
- }
- opts = opts || {};
-
- if (typeof target == 'string') {
- target = document.getElementById(target);
- }
-
- // reuse class per canvas
- var svg;
- if (target.svg == null) {
- svg = build();
- target.svg = svg;
- }
- else {
- svg = target.svg;
- svg.stop();
- }
- svg.opts = opts;
-
- var ctx = target.getContext('2d');
- if (typeof(s.documentElement) != 'undefined') {
- // load from xml doc
- svg.loadXmlDoc(ctx, s);
- }
- else if (s.substr(0,1) == '<') {
- // load from xml string
- svg.loadXml(ctx, s);
- }
- else {
- // load from url
- svg.load(ctx, s);
- }
- }
-
- function build() {
- var svg = { };
-
- svg.FRAMERATE = 30;
- svg.MAX_VIRTUAL_PIXELS = 30000;
-
- // globals
- svg.init = function(ctx) {
- svg.Definitions = {};
- svg.Styles = {};
- svg.Animations = [];
- svg.Images = [];
- svg.ctx = ctx;
- svg.ViewPort = new (function () {
- this.viewPorts = [];
- this.Clear = function() { this.viewPorts = []; }
- this.SetCurrent = function(width, height) { this.viewPorts.push({ width: width, height: height }); }
- this.RemoveCurrent = function() { this.viewPorts.pop(); }
- this.Current = function() { return this.viewPorts[this.viewPorts.length - 1]; }
- this.width = function() { return this.Current().width; }
- this.height = function() { return this.Current().height; }
- this.ComputeSize = function(d) {
- if (d != null && typeof(d) == 'number') return d;
- if (d == 'x') return this.width();
- if (d == 'y') return this.height();
- return Math.sqrt(Math.pow(this.width(), 2) + Math.pow(this.height(), 2)) / Math.sqrt(2);
- }
- });
- }
- svg.init();
-
- // images loaded
- svg.ImagesLoaded = function() {
- for (var i=0; i<svg.Images.length; i++) {
- if (!svg.Images[i].loaded) return false;
- }
- return true;
- }
-
- // trim
- svg.trim = function(s) { return s.replace(/^\s+|\s+$/g, ''); }
-
- // compress spaces
- svg.compressSpaces = function(s) { return s.replace(/[\s\r\t\n]+/gm,' '); }
-
- // ajax
- svg.ajax = function(url) {
- var AJAX;
- if(window.XMLHttpRequest){AJAX=new XMLHttpRequest();}
- else{AJAX=new ActiveXObject('Microsoft.XMLHTTP');}
- if(AJAX){
- AJAX.open('GET',url,false);
- AJAX.send(null);
- return AJAX.responseText;
- }
- return null;
- }
-
- // parse xml
- svg.parseXml = function(xml) {
- if (window.DOMParser)
- {
- var parser = new DOMParser();
- return parser.parseFromString(xml, 'text/xml');
- }
- else
- {
- xml = xml.replace(/<!DOCTYPE svg[^>]*>/, '');
- var xmlDoc = new ActiveXObject('Microsoft.XMLDOM');
- xmlDoc.async = 'false';
- xmlDoc.loadXML(xml);
- return xmlDoc;
- }
- }
-
- svg.Property = function(name, value) {
- this.name = name;
- this.value = value;
-
- this.hasValue = function() {
- return (this.value != null && this.value !== '');
- }
-
- // return the numerical value of the property
- this.numValue = function() {
- if (!this.hasValue()) return 0;
-
- var n = parseFloat(this.value);
- if ((this.value + '').match(/%$/)) {
- n = n / 100.0;
- }
- return n;
- }
-
- this.valueOrDefault = function(def) {
- if (this.hasValue()) return this.value;
- return def;
- }
-
- this.numValueOrDefault = function(def) {
- if (this.hasValue()) return this.numValue();
- return def;
- }
-
- /* EXTENSIONS */
- var that = this;
-
- // color extensions
- this.Color = {
- // augment the current color value with the opacity
- addOpacity: function(opacity) {
- var newValue = that.value;
- if (opacity != null && opacity != '') {
- var color = new RGBColor(that.value);
- if (color.ok) {
- newValue = 'rgba(' + color.r + ', ' + color.g + ', ' + color.b + ', ' + opacity + ')';
- }
- }
- return new svg.Property(that.name, newValue);
- }
- }
-
- // definition extensions
- this.Definition = {
- // get the definition from the definitions table
- getDefinition: function() {
- var name = that.value.replace(/^(url\()?#([^\)]+)\)?$/, '$2');
- return svg.Definitions[name];
- },
-
- isUrl: function() {
- return that.value.indexOf('url(') == 0
- },
-
- getFillStyle: function(e) {
- var def = this.getDefinition();
-
- // gradient
- if (def != null && def.createGradient) {
- return def.createGradient(svg.ctx, e);
- }
-
- // pattern
- if (def != null && def.createPattern) {
- return def.createPattern(svg.ctx, e);
- }
-
- return null;
- }
- }
-
- // length extensions
- this.Length = {
- DPI: function(viewPort) {
- return 96.0; // TODO: compute?
- },
-
- EM: function(viewPort) {
- var em = 12;
-
- var fontSize = new svg.Property('fontSize', svg.Font.Parse(svg.ctx.font).fontSize);
- if (fontSize.hasValue()) em = fontSize.Length.toPixels(viewPort);
-
- return em;
- },
-
- // get the length as pixels
- toPixels: function(viewPort) {
- if (!that.hasValue()) return 0;
- var s = that.value+'';
- if (s.match(/em$/)) return that.numValue() * this.EM(viewPort);
- if (s.match(/ex$/)) return that.numValue() * this.EM(viewPort) / 2.0;
- if (s.match(/px$/)) return that.numValue();
- if (s.match(/pt$/)) return that.numValue() * 1.25;
- if (s.match(/pc$/)) return that.numValue() * 15;
- if (s.match(/cm$/)) return that.numValue() * this.DPI(viewPort) / 2.54;
- if (s.match(/mm$/)) return that.numValue() * this.DPI(viewPort) / 25.4;
- if (s.match(/in$/)) return that.numValue() * this.DPI(viewPort);
- if (s.match(/%$/)) return that.numValue() * svg.ViewPort.ComputeSize(viewPort);
- return that.numValue();
- }
- }
-
- // time extensions
- this.Time = {
- // get the time as milliseconds
- toMilliseconds: function() {
- if (!that.hasValue()) return 0;
- var s = that.value+'';
- if (s.match(/s$/)) return that.numValue() * 1000;
- if (s.match(/ms$/)) return that.numValue();
- return that.numValue();
- }
- }
-
- // angle extensions
- this.Angle = {
- // get the angle as radians
- toRadians: function() {
- if (!that.hasValue()) return 0;
- var s = that.value+'';
- if (s.match(/deg$/)) return that.numValue() * (Math.PI / 180.0);
- if (s.match(/grad$/)) return that.numValue() * (Math.PI / 200.0);
- if (s.match(/rad$/)) return that.numValue();
- return that.numValue() * (Math.PI / 180.0);
- }
- }
- }
-
- // fonts
- svg.Font = new (function() {
- this.Styles = ['normal','italic','oblique','inherit'];
- this.Variants = ['normal','small-caps','inherit'];
- this.Weights = ['normal','bold','bolder','lighter','100','200','300','400','500','600','700','800','900','inherit'];
-
- this.CreateFont = function(fontStyle, fontVariant, fontWeight, fontSize, fontFamily, inherit) {
- var f = inherit != null ? this.Parse(inherit) : this.CreateFont('', '', '', '', '', svg.ctx.font);
- return {
- fontFamily: fontFamily || f.fontFamily,
- fontSize: fontSize || f.fontSize,
- fontStyle: fontStyle || f.fontStyle,
- fontWeight: fontWeight || f.fontWeight,
- fontVariant: fontVariant || f.fontVariant,
- toString: function () { return [this.fontStyle, this.fontVariant, this.fontWeight, this.fontSize, this.fontFamily].join(' ') }
- }
- }
-
- var that = this;
- this.Parse = function(s) {
- var f = {};
- var d = svg.trim(svg.compressSpaces(s || '')).split(' ');
- var set = { fontSize: false, fontStyle: false, fontWeight: false, fontVariant: false }
- var ff = '';
- for (var i=0; i<d.length; i++) {
- if (!set.fontStyle && that.Styles.indexOf(d[i]) != -1) { if (d[i] != 'inherit') f.fontStyle = d[i]; set.fontStyle = true; }
- else if (!set.fontVariant && that.Variants.indexOf(d[i]) != -1) { if (d[i] != 'inherit') f.fontVariant = d[i]; set.fontStyle = set.fontVariant = true; }
- else if (!set.fontWeight && that.Weights.indexOf(d[i]) != -1) { if (d[i] != 'inherit') f.fontWeight = d[i]; set.fontStyle = set.fontVariant = set.fontWeight = true; }
- else if (!set.fontSize) { if (d[i] != 'inherit') f.fontSize = d[i].split('/')[0]; set.fontStyle = set.fontVariant = set.fontWeight = set.fontSize = true; }
- else { if (d[i] != 'inherit') ff += d[i]; }
- } if (ff != '') f.fontFamily = ff;
- return f;
- }
- });
-
- // points and paths
- svg.ToNumberArray = function(s) {
- var a = svg.trim(svg.compressSpaces((s || '').replace(/,/g, ' '))).split(' ');
- for (var i=0; i<a.length; i++) {
- a[i] = parseFloat(a[i]);
- }
- return a;
- }
- svg.Point = function(x, y) {
- this.x = x;
- this.y = y;
-
- this.angleTo = function(p) {
- return Math.atan2(p.y - this.y, p.x - this.x);
- }
-
- this.applyTransform = function(v) {
- var xp = this.x * v[0] + this.y * v[2] + v[4];
- var yp = this.x * v[1] + this.y * v[3] + v[5];
- this.x = xp;
- this.y = yp;
- }
- }
- svg.CreatePoint = function(s) {
- var a = svg.ToNumberArray(s);
- return new svg.Point(a[0], a[1]);
- }
- svg.CreatePath = function(s) {
- var a = svg.ToNumberArray(s);
- var path = [];
- for (var i=0; i<a.length; i+=2) {
- path.push(new svg.Point(a[i], a[i+1]));
- }
- return path;
- }
-
- // bounding box
- svg.BoundingBox = function(x1, y1, x2, y2) { // pass in initial points if you want
- this.x1 = Number.NaN;
- this.y1 = Number.NaN;
- this.x2 = Number.NaN;
- this.y2 = Number.NaN;
-
- this.x = function() { return this.x1; }
- this.y = function() { return this.y1; }
- this.width = function() { return this.x2 - this.x1; }
- this.height = function() { return this.y2 - this.y1; }
-
- this.addPoint = function(x, y) {
- if (x != null) {
- if (isNaN(this.x1) || isNaN(this.x2)) {
- this.x1 = x;
- this.x2 = x;
- }
- if (x < this.x1) this.x1 = x;
- if (x > this.x2) this.x2 = x;
- }
-
- if (y != null) {
- if (isNaN(this.y1) || isNaN(this.y2)) {
- this.y1 = y;
- this.y2 = y;
- }
- if (y < this.y1) this.y1 = y;
- if (y > this.y2) this.y2 = y;
- }
- }
- this.addX = function(x) { this.addPoint(x, null); }
- this.addY = function(y) { this.addPoint(null, y); }
-
- this.addBoundingBox = function(bb) {
- this.addPoint(bb.x1, bb.y1);
- this.addPoint(bb.x2, bb.y2);
- }
-
- this.addQuadraticCurve = function(p0x, p0y, p1x, p1y, p2x, p2y) {
- var cp1x = p0x + 2/3 * (p1x - p0x); // CP1 = QP0 + 2/3 *(QP1-QP0)
- var cp1y = p0y + 2/3 * (p1y - p0y); // CP1 = QP0 + 2/3 *(QP1-QP0)
- var cp2x = cp1x + 1/3 * (p2x - p0x); // CP2 = CP1 + 1/3 *(QP2-QP0)
- var cp2y = cp1y + 1/3 * (p2y - p0y); // CP2 = CP1 + 1/3 *(QP2-QP0)
- this.addBezierCurve(p0x, p0y, cp1x, cp2x, cp1y, cp2y, p2x, p2y);
- }
-
- this.addBezierCurve = function(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y) {
- // from http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
- var p0 = [p0x, p0y], p1 = [p1x, p1y], p2 = [p2x, p2y], p3 = [p3x, p3y];
- this.addPoint(p0[0], p0[1]);
- this.addPoint(p3[0], p3[1]);
-
- for (i=0; i<=1; i++) {
- var f = function(t) {
- return Math.pow(1-t, 3) * p0[i]
- + 3 * Math.pow(1-t, 2) * t * p1[i]
- + 3 * (1-t) * Math.pow(t, 2) * p2[i]
- + Math.pow(t, 3) * p3[i];
- }
-
- var b = 6 * p0[i] - 12 * p1[i] + 6 * p2[i];
- var a = -3 * p0[i] + 9 * p1[i] - 9 * p2[i] + 3 * p3[i];
- var c = 3 * p1[i] - 3 * p0[i];
-
- if (a == 0) {
- if (b == 0) continue;
- var t = -c / b;
- if (0 < t && t < 1) {
- if (i == 0) this.addX(f(t));
- if (i == 1) this.addY(f(t));
- }
- continue;
- }
-
- var b2ac = Math.pow(b, 2) - 4 * c * a;
- if (b2ac < 0) continue;
- var t1 = (-b + Math.sqrt(b2ac)) / (2 * a);
- if (0 < t1 && t1 < 1) {
- if (i == 0) this.addX(f(t1));
- if (i == 1) this.addY(f(t1));
- }
- var t2 = (-b - Math.sqrt(b2ac)) / (2 * a);
- if (0 < t2 && t2 < 1) {
- if (i == 0) this.addX(f(t2));
- if (i == 1) this.addY(f(t2));
- }
- }
- }
-
- this.isPointInBox = function(x, y) {
- return (this.x1 <= x && x <= this.x2 && this.y1 <= y && y <= this.y2);
- }
-
- this.addPoint(x1, y1);
- this.addPoint(x2, y2);
- }
-
- // transforms
- svg.Transform = function(v) {
- var that = this;
- this.Type = {}
-
- // translate
- this.Type.translate = function(s) {
- this.p = svg.CreatePoint(s);
- this.apply = function(ctx) {
- ctx.translate(this.p.x || 0.0, this.p.y || 0.0);
- }
- this.applyToPoint = function(p) {
- p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]);
- }
- }
-
- // rotate
- this.Type.rotate = function(s) {
- var a = svg.ToNumberArray(s);
- this.angle = new svg.Property('angle', a[0]);
- this.cx = a[1] || 0;
- this.cy = a[2] || 0;
- this.apply = function(ctx) {
- ctx.translate(this.cx, this.cy);
- ctx.rotate(this.angle.Angle.toRadians());
- ctx.translate(-this.cx, -this.cy);
- }
- this.applyToPoint = function(p) {
- var a = this.angle.Angle.toRadians();
- p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]);
- p.applyTransform([Math.cos(a), Math.sin(a), -Math.sin(a), Math.cos(a), 0, 0]);
- p.applyTransform([1, 0, 0, 1, -this.p.x || 0.0, -this.p.y || 0.0]);
- }
- }
-
- this.Type.scale = function(s) {
- this.p = svg.CreatePoint(s);
- this.apply = function(ctx) {
- ctx.scale(this.p.x || 1.0, this.p.y || this.p.x || 1.0);
- }
- this.applyToPoint = function(p) {
- p.applyTransform([this.p.x || 0.0, 0, 0, this.p.y || 0.0, 0, 0]);
- }
- }
-
- this.Type.matrix = function(s) {
- this.m = svg.ToNumberArray(s);
- this.apply = function(ctx) {
- ctx.transform(this.m[0], this.m[1], this.m[2], this.m[3], this.m[4], this.m[5]);
- }
- this.applyToPoint = function(p) {
- p.applyTransform(this.m);
- }
- }
-
- this.Type.SkewBase = function(s) {
- this.base = that.Type.matrix;
- this.base(s);
- this.angle = new svg.Property('angle', s);
- }
- this.Type.SkewBase.prototype = new this.Type.matrix;
-
- this.Type.skewX = function(s) {
- this.base = that.Type.SkewBase;
- this.base(s);
- this.m = [1, 0, Math.tan(this.angle.Angle.toRadians()), 1, 0, 0];
- }
- this.Type.skewX.prototype = new this.Type.SkewBase;
-
- this.Type.skewY = function(s) {
- this.base = that.Type.SkewBase;
- this.base(s);
- this.m = [1, Math.tan(this.angle.Angle.toRadians()), 0, 1, 0, 0];
- }
- this.Type.skewY.prototype = new this.Type.SkewBase;
-
- this.transforms = [];
-
- this.apply = function(ctx) {
- for (var i=0; i<this.transforms.length; i++) {
- this.transforms[i].apply(ctx);
- }
- }
-
- this.applyToPoint = function(p) {
- for (var i=0; i<this.transforms.length; i++) {
- this.transforms[i].applyToPoint(p);
- }
- }
-
- var data = svg.trim(svg.compressSpaces(v)).split(/\s(?=[a-z])/);
- for (var i=0; i<data.length; i++) {
- var type = data[i].split('(')[0];
- var s = data[i].split('(')[1].replace(')','');
- var transform = new this.Type[type](s);
- this.transforms.push(transform);
- }
- }
-
- // aspect ratio
- svg.AspectRatio = function(ctx, aspectRatio, width, desiredWidth, height, desiredHeight, minX, minY, refX, refY) {
- // aspect ratio - http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute
- aspectRatio = svg.compressSpaces(aspectRatio);
- aspectRatio = aspectRatio.replace(/^defer\s/,''); // ignore defer
- var align = aspectRatio.split(' ')[0] || 'xMidYMid';
- var meetOrSlice = aspectRatio.split(' ')[1] || 'meet';
-
- // calculate scale
- var scaleX = width / desiredWidth;
- var scaleY = height / desiredHeight;
- var scaleMin = Math.min(scaleX, scaleY);
- var scaleMax = Math.max(scaleX, scaleY);
- if (meetOrSlice == 'meet') { desiredWidth *= scaleMin; desiredHeight *= scaleMin; }
- if (meetOrSlice == 'slice') { desiredWidth *= scaleMax; desiredHeight *= scaleMax; }
-
- refX = new svg.Property('refX', refX);
- refY = new svg.Property('refY', refY);
- if (refX.hasValue() && refY.hasValue()) {
- ctx.translate(-scaleMin * refX.Length.toPixels('x'), -scaleMin * refY.Length.toPixels('y'));
- }
- else {
- // align
- if (align.match(/^xMid/) && ((meetOrSlice == 'meet' && scaleMin == scaleY) || (meetOrSlice == 'slice' && scaleMax == scaleY))) ctx.translate(width / 2.0 - desiredWidth / 2.0, 0);
- if (align.match(/YMid$/) && ((meetOrSlice == 'meet' && scaleMin == scaleX) || (meetOrSlice == 'slice' && scaleMax == scaleX))) ctx.translate(0, height / 2.0 - desiredHeight / 2.0);
- if (align.match(/^xMax/) && ((meetOrSlice == 'meet' && scaleMin == scaleY) || (meetOrSlice == 'slice' && scaleMax == scaleY))) ctx.translate(width - desiredWidth, 0);
- if (align.match(/YMax$/) && ((meetOrSlice == 'meet' && scaleMin == scaleX) || (meetOrSlice == 'slice' && scaleMax == scaleX))) ctx.translate(0, height - desiredHeight);
- }
-
- // scale
- if (align == 'none') ctx.scale(scaleX, scaleY);
- else if (meetOrSlice == 'meet') ctx.scale(scaleMin, scaleMin);
- else if (meetOrSlice == 'slice') ctx.scale(scaleMax, scaleMax);
-
- // translate
- ctx.translate(minX == null ? 0 : -minX, minY == null ? 0 : -minY);
- }
-
- // elements
- svg.Element = {}
-
- svg.Element.ElementBase = function(node) {
- this.attributes = {};
- this.styles = {};
- this.children = [];
-
- // get or create attribute
- this.attribute = function(name, createIfNotExists) {
- var a = this.attributes[name];
- if (a != null) return a;
-
- a = new svg.Property(name, '');
- if (createIfNotExists == true) this.attributes[name] = a;
- return a;
- }
-
- // get or create style, crawls up node tree
- this.style = function(name, createIfNotExists) {
- var s = this.styles[name];
- if (s != null) return s;
-
- var a = this.attribute(name);
- if (a != null && a.hasValue()) {
- return a;
- }
-
- var p = this.parent;
- if (p != null) {
- var ps = p.style(name);
- if (ps != null && ps.hasValue()) {
- return ps;
- }
- }
-
- s = new svg.Property(name, '');
- if (createIfNotExists == true) this.styles[name] = s;
- return s;
- }
-
- // base render
- this.render = function(ctx) {
- // don't render display=none
- if (this.style('display').value == 'none') return;
-
- // don't render visibility=hidden
- if (this.attribute('visibility').value == 'hidden') return;
-
- ctx.save();
- this.setContext(ctx);
- // mask
- if (this.attribute('mask').hasValue()) {
- var mask = this.attribute('mask').Definition.getDefinition();
- if (mask != null) mask.apply(ctx, this);
- }
- else if (this.style('filter').hasValue()) {
- var filter = this.style('filter').Definition.getDefinition();
- if (filter != null) filter.apply(ctx, this);
- }
- else this.renderChildren(ctx);
- this.clearContext(ctx);
- ctx.restore();
- }
-
- // base set context
- this.setContext = function(ctx) {
- // OVERRIDE ME!
- }
-
- // base clear context
- this.clearContext = function(ctx) {
- // OVERRIDE ME!
- }
-
- // base render children
- this.renderChildren = function(ctx) {
- for (var i=0; i<this.children.length; i++) {
- this.children[i].render(ctx);
- }
- }
-
- this.addChild = function(childNode, create) {
- var child = childNode;
- if (create) child = svg.CreateElement(childNode);
- child.parent = this;
- this.children.push(child);
- }
-
- if (node != null && node.nodeType == 1) { //ELEMENT_NODE
- // add children
- for (var i=0; i<node.childNodes.length; i++) {
- var childNode = node.childNodes[i];
- if (childNode.nodeType == 1) this.addChild(childNode, true); //ELEMENT_NODE
- }
-
- // add attributes
- for (var i=0; i<node.attributes.length; i++) {
- var attribute = node.attributes[i];
- this.attributes[attribute.nodeName] = new svg.Property(attribute.nodeName, attribute.nodeValue);
- }
-
- // add tag styles
- var styles = svg.Styles[node.nodeName];
- if (styles != null) {
- for (var name in styles) {
- this.styles[name] = styles[name];
- }
- }
-
- // add class styles
- if (this.attribute('class').hasValue()) {
- var classes = svg.compressSpaces(this.attribute('class').value).split(' ');
- for (var j=0; j<classes.length; j++) {
- styles = svg.Styles['.'+classes[j]];
- if (styles != null) {
- for (var name in styles) {
- this.styles[name] = styles[name];
- }
- }
- styles = svg.Styles[node.nodeName+'.'+classes[j]];
- if (styles != null) {
- for (var name in styles) {
- this.styles[name] = styles[name];
- }
- }
- }
- }
-
- // add inline styles
- if (this.attribute('style').hasValue()) {
- var styles = this.attribute('style').value.split(';');
- for (var i=0; i<styles.length; i++) {
- if (svg.trim(styles[i]) != '') {
- var style = styles[i].split(':');
- var name = svg.trim(style[0]);
- var value = svg.trim(style[1]);
- this.styles[name] = new svg.Property(name, value);
- }
- }
- }
-
- // add id
- if (this.attribute('id').hasValue()) {
- if (svg.Definitions[this.attribute('id').value] == null) {
- svg.Definitions[this.attribute('id').value] = this;
- }
- }
- }
- }
-
- svg.Element.RenderedElementBase = function(node) {
- this.base = svg.Element.ElementBase;
- this.base(node);
-
- this.setContext = function(ctx) {
- // fill
- if (this.style('fill').Definition.isUrl()) {
- var fs = this.style('fill').Definition.getFillStyle(this);
- if (fs != null) ctx.fillStyle = fs;
- }
- else if (this.style('fill').hasValue()) {
- var fillStyle = this.style('fill');
- if (this.style('fill-opacity').hasValue()) fillStyle = fillStyle.Color.addOpacity(this.style('fill-opacity').value);
- ctx.fillStyle = (fillStyle.value == 'none' ? 'rgba(0,0,0,0)' : fillStyle.value);
- }
-
- // stroke
- if (this.style('stroke').Definition.isUrl()) {
- var fs = this.style('stroke').Definition.getFillStyle(this);
- if (fs != null) ctx.strokeStyle = fs;
- }
- else if (this.style('stroke').hasValue()) {
- var strokeStyle = this.style('stroke');
- if (this.style('stroke-opacity').hasValue()) strokeStyle = strokeStyle.Color.addOpacity(this.style('stroke-opacity').value);
- ctx.strokeStyle = (strokeStyle.value == 'none' ? 'rgba(0,0,0,0)' : strokeStyle.value);
- }
- if (this.style('stroke-width').hasValue()) ctx.lineWidth = this.style('stroke-width').Length.toPixels();
- if (this.style('stroke-linecap').hasValue()) ctx.lineCap = this.style('stroke-linecap').value;
- if (this.style('stroke-linejoin').hasValue()) ctx.lineJoin = this.style('stroke-linejoin').value;
- if (this.style('stroke-miterlimit').hasValue()) ctx.miterLimit = this.style('stroke-miterlimit').value;
-
- // font
- if (typeof(ctx.font) != 'undefined') {
- ctx.font = svg.Font.CreateFont(
- this.style('font-style').value,
- this.style('font-variant').value,
- this.style('font-weight').value,
- this.style('font-size').hasValue() ? this.style('font-size').Length.toPixels() + 'px' : '',
- this.style('font-family').value).toString();
- }
-
- // transform
- if (this.attribute('transform').hasValue()) {
- var transform = new svg.Transform(this.attribute('transform').value);
- transform.apply(ctx);
- }
-
- // clip
- if (this.attribute('clip-path').hasValue()) {
- var clip = this.attribute('clip-path').Definition.getDefinition();
- if (clip != null) clip.apply(ctx);
- }
-
- // opacity
- if (this.style('opacity').hasValue()) {
- ctx.globalAlpha = this.style('opacity').numValue();
- }
- }
- }
- svg.Element.RenderedElementBase.prototype = new svg.Element.ElementBase;
-
- svg.Element.PathElementBase = function(node) {
- this.base = svg.Element.RenderedElementBase;
- this.base(node);
-
- this.path = function(ctx) {
- if (ctx != null) ctx.beginPath();
- return new svg.BoundingBox();
- }
-
- this.renderChildren = function(ctx) {
- this.path(ctx);
- svg.Mouse.checkPath(this, ctx);
- if (ctx.fillStyle != '') ctx.fill();
- if (ctx.strokeStyle != '') ctx.stroke();
-
- var markers = this.getMarkers();
- if (markers != null) {
- if (this.style('marker-start').Definition.isUrl()) {
- var marker = this.style('marker-start').Definition.getDefinition();
- marker.render(ctx, markers[0][0], markers[0][1]);
- }
- if (this.style('marker-mid').Definition.isUrl()) {
- var marker = this.style('marker-mid').Definition.getDefinition();
- for (var i=1;i<markers.length-1;i++) {
- marker.render(ctx, markers[i][0], markers[i][1]);
- }
- }
- if (this.style('marker-end').Definition.isUrl()) {
- var marker = this.style('marker-end').Definition.getDefinition();
- marker.render(ctx, markers[markers.length-1][0], markers[markers.length-1][1]);
- }
- }
- }
-
- this.getBoundingBox = function() {
- return this.path();
- }
-
- this.getMarkers = function() {
- return null;
- }
- }
- svg.Element.PathElementBase.prototype = new svg.Element.RenderedElementBase;
-
- // svg element
- svg.Element.svg = function(node) {
- this.base = svg.Element.RenderedElementBase;
- this.base(node);
-
- this.baseClearContext = this.clearContext;
- this.clearContext = function(ctx) {
- this.baseClearContext(ctx);
- svg.ViewPort.RemoveCurrent();
- }
-
- this.baseSetContext = this.setContext;
- this.setContext = function(ctx) {
- // initial values
- ctx.strokeStyle = 'rgba(0,0,0,0)';
- ctx.lineCap = 'butt';
- ctx.lineJoin = 'miter';
- ctx.miterLimit = 4;
-
- this.baseSetContext(ctx);
-
- // create new view port
- if (this.attribute('x').hasValue() && this.attribute('y').hasValue()) {
- ctx.translate(this.attribute('x').Length.toPixels('x'), this.attribute('y').Length.toPixels('y'));
- }
-
- var width = svg.ViewPort.width();
- var height = svg.ViewPort.height();
- if (typeof(this.root) == 'undefined' && this.attribute('width').hasValue() && this.attribute('height').hasValue()) {
- width = this.attribute('width').Length.toPixels('x');
- height = this.attribute('height').Length.toPixels('y');
-
- var x = 0;
- var y = 0;
- if (this.attribute('refX').hasValue() && this.attribute('refY').hasValue()) {
- x = -this.attribute('refX').Length.toPixels('x');
- y = -this.attribute('refY').Length.toPixels('y');
- }
-
- ctx.beginPath();
- ctx.moveTo(x, y);
- ctx.lineTo(width, y);
- ctx.lineTo(width, height);
- ctx.lineTo(x, height);
- ctx.closePath();
- ctx.clip();
- }
- svg.ViewPort.SetCurrent(width, height);
-
- // viewbox
- if (this.attribute('viewBox').hasValue()) {
- var viewBox = svg.ToNumberArray(this.attribute('viewBox').value);
- var minX = viewBox[0];
- var minY = viewBox[1];
- width = viewBox[2];
- height = viewBox[3];
-
- svg.AspectRatio(ctx,
- this.attribute('preserveAspectRatio').value,
- svg.ViewPort.width(),
- width,
- svg.ViewPort.height(),
- height,
- minX,
- minY,
- this.attribute('refX').value,
- this.attribute('refY').value);
-
- svg.ViewPort.RemoveCurrent();
- svg.ViewPort.SetCurrent(viewBox[2], viewBox[3]);
- }
- }
- }
- svg.Element.svg.prototype = new svg.Element.RenderedElementBase;
-
- // rect element
- svg.Element.rect = function(node) {
- this.base = svg.Element.PathElementBase;
- this.base(node);
-
- this.path = function(ctx) {
- var x = this.attribute('x').Length.toPixels('x');
- var y = this.attribute('y').Length.toPixels('y');
- var width = this.attribute('width').Length.toPixels('x');
- var height = this.attribute('height').Length.toPixels('y');
- var rx = this.attribute('rx').Length.toPixels('x');
- var ry = this.attribute('ry').Length.toPixels('y');
- if (this.attribute('rx').hasValue() && !this.attribute('ry').hasValue()) ry = rx;
- if (this.attribute('ry').hasValue() && !this.attribute('rx').hasValue()) rx = ry;
-
- if (ctx != null) {
- ctx.beginPath();
- ctx.moveTo(x + rx, y);
- ctx.lineTo(x + width - rx, y);
- ctx.quadraticCurveTo(x + width, y, x + width, y + ry)
- ctx.lineTo(x + width, y + height - ry);
- ctx.quadraticCurveTo(x + width, y + height, x + width - rx, y + height)
- ctx.lineTo(x + rx, y + height);
- ctx.quadraticCurveTo(x, y + height, x, y + height - ry)
- ctx.lineTo(x, y + ry);
- ctx.quadraticCurveTo(x, y, x + rx, y)
- ctx.closePath();
- }
-
- return new svg.BoundingBox(x, y, x + width, y + height);
- }
- }
- svg.Element.rect.prototype = new svg.Element.PathElementBase;
-
- // circle element
- svg.Element.circle = function(node) {
- this.base = svg.Element.PathElementBase;
- this.base(node);
-
- this.path = function(ctx) {
- var cx = this.attribute('cx').Length.toPixels('x');
- var cy = this.attribute('cy').Length.toPixels('y');
- var r = this.attribute('r').Length.toPixels();
-
- if (ctx != null) {
- ctx.beginPath();
- ctx.arc(cx, cy, r, 0, Math.PI * 2, true);
- ctx.closePath();
- }
-
- return new svg.BoundingBox(cx - r, cy - r, cx + r, cy + r);
- }
- }
- svg.Element.circle.prototype = new svg.Element.PathElementBase;
-
- // ellipse element
- svg.Element.ellipse = function(node) {
- this.base = svg.Element.PathElementBase;
- this.base(node);
-
- this.path = function(ctx) {
- var KAPPA = 4 * ((Math.sqrt(2) - 1) / 3);
- var rx = this.attribute('rx').Length.toPixels('x');
- var ry = this.attribute('ry').Length.toPixels('y');
- var cx = this.attribute('cx').Length.toPixels('x');
- var cy = this.attribute('cy').Length.toPixels('y');
-
- if (ctx != null) {
- ctx.beginPath();
- ctx.moveTo(cx, cy - ry);
- ctx.bezierCurveTo(cx + (KAPPA * rx), cy - ry, cx + rx, cy - (KAPPA * ry), cx + rx, cy);
- ctx.bezierCurveTo(cx + rx, cy + (KAPPA * ry), cx + (KAPPA * rx), cy + ry, cx, cy + ry);
- ctx.bezierCurveTo(cx - (KAPPA * rx), cy + ry, cx - rx, cy + (KAPPA * ry), cx - rx, cy);
- ctx.bezierCurveTo(cx - rx, cy - (KAPPA * ry), cx - (KAPPA * rx), cy - ry, cx, cy - ry);
- ctx.closePath();
- }
-
- return new svg.BoundingBox(cx - rx, cy - ry, cx + rx, cy + ry);
- }
- }
- svg.Element.ellipse.prototype = new svg.Element.PathElementBase;
-
- // line element
- svg.Element.line = function(node) {
- this.base = svg.Element.PathElementBase;
- this.base(node);
-
- this.getPoints = function() {
- return [
- new svg.Point(this.attribute('x1').Length.toPixels('x'), this.attribute('y1').Length.toPixels('y')),
- new svg.Point(this.attribute('x2').Length.toPixels('x'), this.attribute('y2').Length.toPixels('y'))];
- }
-
- this.path = function(ctx) {
- var points = this.getPoints();
-
- if (ctx != null) {
- ctx.beginPath();
- ctx.moveTo(points[0].x, points[0].y);
- ctx.lineTo(points[1].x, points[1].y);
- }
-
- return new svg.BoundingBox(points[0].x, points[0].y, points[1].x, points[1].y);
- }
-
- this.getMarkers = function() {
- var points = this.getPoints();
- var a = points[0].angleTo(points[1]);
- return [[points[0], a], [points[1], a]];
- }
- }
- svg.Element.line.prototype = new svg.Element.PathElementBase;
-
- // polyline element
- svg.Element.polyline = function(node) {
- this.base = svg.Element.PathElementBase;
- this.base(node);
-
- this.points = svg.CreatePath(this.attribute('points').value);
- this.path = function(ctx) {
- var bb = new svg.BoundingBox(this.points[0].x, this.points[0].y);
- if (ctx != null) {
- ctx.beginPath();
- ctx.moveTo(this.points[0].x, this.points[0].y);
- }
- for (var i=1; i<this.points.length; i++) {
- bb.addPoint(this.points[i].x, this.points[i].y);
- if (ctx != null) ctx.lineTo(this.points[i].x, this.points[i].y);
- }
- return bb;
- }
-
- this.getMarkers = function() {
- var markers = [];
- for (var i=0; i<this.points.length - 1; i++) {
- markers.push([this.points[i], this.points[i].angleTo(this.points[i+1])]);
- }
- markers.push([this.points[this.points.length-1], markers[markers.length-1][1]]);
- return markers;
- }
- }
- svg.Element.polyline.prototype = new svg.Element.PathElementBase;
-
- // polygon element
- svg.Element.polygon = function(node) {
- this.base = svg.Element.polyline;
- this.base(node);
-
- this.basePath = this.path;
- this.path = function(ctx) {
- var bb = this.basePath(ctx);
- if (ctx != null) {
- ctx.lineTo(this.points[0].x, this.points[0].y);
- ctx.closePath();
- }
- return bb;
- }
- }
- svg.Element.polygon.prototype = new svg.Element.polyline;
-
- // path element
- svg.Element.path = function(node) {
- this.base = svg.Element.PathElementBase;
- this.base(node);
-
- var d = this.attribute('d').value;
- // TODO: convert to real lexer based on http://www.w3.org/TR/SVG11/paths.html#PathDataBNF
- d = d.replace(/,/gm,' '); // get rid of all commas
- d = d.replace(/([MmZzLlHhVvCcSsQqTtAa])([MmZzLlHhVvCcSsQqTtAa])/gm,'$1 $2'); // separate commands from commands
- d = d.replace(/([MmZzLlHhVvCcSsQqTtAa])([MmZzLlHhVvCcSsQqTtAa])/gm,'$1 $2'); // separate commands from commands
- d = d.replace(/([MmZzLlHhVvCcSsQqTtAa])([^\s])/gm,'$1 $2'); // separate commands from points
- d = d.replace(/([^\s])([MmZzLlHhVvCcSsQqTtAa])/gm,'$1 $2'); // separate commands from points
- d = d.replace(/([0-9])([+\-])/gm,'$1 $2'); // separate digits when no comma
- d = d.replace(/(\.[0-9]*)(\.)/gm,'$1 $2'); // separate digits when no comma
- d = d.replace(/([Aa](\s+[0-9]+){3})\s+([01])\s*([01])/gm,'$1 $3 $4 '); // shorthand elliptical arc path syntax
- d = svg.compressSpaces(d); // compress multiple spaces
- d = svg.trim(d);
- this.PathParser = new (function(d) {
- this.tokens = d.split(' ');
-
- this.reset = function() {
- this.i = -1;
- this.command = '';
- this.previousCommand = '';
- this.start = new svg.Point(0, 0);
- this.control = new svg.Point(0, 0);
- this.current = new svg.Point(0, 0);
- this.points = [];
- this.angles = [];
- }
-
- this.isEnd = function() {
- return this.i >= this.tokens.length - 1;
- }
-
- this.isCommandOrEnd = function() {
- if (this.isEnd()) return true;
- return this.tokens[this.i + 1].match(/^[A-Za-z]$/) != null;
- }
-
- this.isRelativeCommand = function() {
- return this.command == this.command.toLowerCase();
- }
-
- this.getToken = function() {
- this.i = this.i + 1;
- return this.tokens[this.i];
- }
-
- this.getScalar = function() {
- return parseFloat(this.getToken());
- }
-
- this.nextCommand = function() {
- this.previousCommand = this.command;
- this.command = this.getToken();
- }
-
- this.getPoint = function() {
- var p = new svg.Point(this.getScalar(), this.getScalar());
- return this.makeAbsolute(p);
- }
-
- this.getAsControlPoint = function() {
- var p = this.getPoint();
- this.control = p;
- return p;
- }
-
- this.getAsCurrentPoint = function() {
- var p = this.getPoint();
- this.current = p;
- return p;
- }
-
- this.getReflectedControlPoint = function() {
- if (this.previousCommand.toLowerCase() != 'c' && this.previousCommand.toLowerCase() != 's') {
- return this.current;
- }
-
- // reflect point
- var p = new svg.Point(2 * this.current.x - this.control.x, 2 * this.current.y - this.control.y);
- return p;
- }
-
- this.makeAbsolute = function(p) {
- if (this.isRelativeCommand()) {
- p.x = this.current.x + p.x;
- p.y = this.current.y + p.y;
- }
- return p;
- }
-
- this.addMarker = function(p, from, priorTo) {
- // if the last angle isn't filled in because we didn't have this point yet ...
- if (priorTo != null && this.angles.length > 0 && this.angles[this.angles.length-1] == null) {
- this.angles[this.angles.length-1] = this.points[this.points.length-1].angleTo(priorTo);
- }
- this.addMarkerAngle(p, from == null ? null : from.angleTo(p));
- }
-
- this.addMarkerAngle = function(p, a) {
- this.points.push(p);
- this.angles.push(a);
- }
-
- this.getMarkerPoints = function() { return this.points; }
- this.getMarkerAngles = function() {
- for (var i=0; i<this.angles.length; i++) {
- if (this.angles[i] == null) {
- for (var j=i+1; j<this.angles.length; j++) {
- if (this.angles[j] != null) {
- this.angles[i] = this.angles[j];
- break;
- }
- }
- }
- }
- return this.angles;
- }
- })(d);
-
- this.path = function(ctx) {
- var pp = this.PathParser;
- pp.reset();
-
- var bb = new svg.BoundingBox();
- if (ctx != null) ctx.beginPath();
- while (!pp.isEnd()) {
- pp.nextCommand();
- switch (pp.command.toUpperCase()) {
- case 'M':
- var p = pp.getAsCurrentPoint();
- pp.addMarker(p);
- bb.addPoint(p.x, p.y);
- if (ctx != null) ctx.moveTo(p.x, p.y);
- pp.start = pp.current;
- while (!pp.isCommandOrEnd()) {
- var p = pp.getAsCurrentPoint();
- pp.addMarker(p, pp.start);
- bb.addPoint(p.x, p.y);
- if (ctx != null) ctx.lineTo(p.x, p.y);
- }
- break;
- case 'L':
- while (!pp.isCommandOrEnd()) {
- var c = pp.current;
- var p = pp.getAsCurrentPoint();
- pp.addMarker(p, c);
- bb.addPoint(p.x, p.y);
- if (ctx != null) ctx.lineTo(p.x, p.y);
- }
- break;
- case 'H':
- while (!pp.isCommandOrEnd()) {
- var newP = new svg.Point((pp.isRelativeCommand() ? pp.current.x : 0) + pp.getScalar(), pp.current.y);
- pp.addMarker(newP, pp.current);
- pp.current = newP;
- bb.addPoint(pp.current.x, pp.current.y);
- if (ctx != null) ctx.lineTo(pp.current.x, pp.current.y);
- }
- break;
- case 'V':
- while (!pp.isCommandOrEnd()) {
- var newP = new svg.Point(pp.current.x, (pp.isRelativeCommand() ? pp.current.y : 0) + pp.getScalar());
- pp.addMarker(newP, pp.current);
- pp.current = newP;
- bb.addPoint(pp.current.x, pp.current.y);
- if (ctx != null) ctx.lineTo(pp.current.x, pp.current.y);
- }
- break;
- case 'C':
- while (!pp.isCommandOrEnd()) {
- var curr = pp.current;
- var p1 = pp.getPoint();
- var cntrl = pp.getAsControlPoint();
- var cp = pp.getAsCurrentPoint();
- pp.addMarker(cp, cntrl, p1);
- bb.addBezierCurve(curr.x, curr.y, p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);
- if (ctx != null) ctx.bezierCurveTo(p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);
- }
- break;
- case 'S':
- while (!pp.isCommandOrEnd()) {
- var curr = pp.current;
- var p1 = pp.getReflectedControlPoint();
- var cntrl = pp.getAsControlPoint();
- var cp = pp.getAsCurrentPoint();
- pp.addMarker(cp, cntrl, p1);
- bb.addBezierCurve(curr.x, curr.y, p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);
- if (ctx != null) ctx.bezierCurveTo(p1.x, p1.y, cntrl.x, cntrl.y, cp.x, cp.y);
- }
- break;
- case 'Q':
- while (!pp.isCommandOrEnd()) {
- var curr = pp.current;
- var cntrl = pp.getAsControlPoint();
- var cp = pp.getAsCurrentPoint();
- pp.addMarker(cp, cntrl, cntrl);
- bb.addQuadraticCurve(curr.x, curr.y, cntrl.x, cntrl.y, cp.x, cp.y);
- if (ctx != null) ctx.quadraticCurveTo(cntrl.x, cntrl.y, cp.x, cp.y);
- }
- break;
- case 'T':
- while (!pp.isCommandOrEnd()) {
- var curr = pp.current;
- var cntrl = pp.getReflectedControlPoint();
- pp.control = cntrl;
- var cp = pp.getAsCurrentPoint();
- pp.addMarker(cp, cntrl, cntrl);
- bb.addQuadraticCurve(curr.x, curr.y, cntrl.x, cntrl.y, cp.x, cp.y);
- if (ctx != null) ctx.quadraticCurveTo(cntrl.x, cntrl.y, cp.x, cp.y);
- }
- break;
- case 'A':
- while (!pp.isCommandOrEnd()) {
- var curr = pp.current;
- var rx = pp.getScalar();
- var ry = pp.getScalar();
- var xAxisRotation = pp.getScalar() * (Math.PI / 180.0);
- var largeArcFlag = pp.getScalar();
- var sweepFlag = pp.getScalar();
- var cp = pp.getAsCurrentPoint();
-
- // Conversion from endpoint to center parameterization
- // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
- // x1', y1'
- var currp = new svg.Point(
- Math.cos(xAxisRotation) * (curr.x - cp.x) / 2.0 + Math.sin(xAxisRotation) * (curr.y - cp.y) / 2.0,
- -Math.sin(xAxisRotation) * (curr.x - cp.x) / 2.0 + Math.cos(xAxisRotation) * (curr.y - cp.y) / 2.0
- );
- // adjust radii
- var l = Math.pow(currp.x,2)/Math.pow(rx,2)+Math.pow(currp.y,2)/Math.pow(ry,2);
- if (l > 1) {
- rx *= Math.sqrt(l);
- ry *= Math.sqrt(l);
- }
- // cx', cy'
- var s = (largeArcFlag == sweepFlag ? -1 : 1) * Math.sqrt(
- ((Math.pow(rx,2)*Math.pow(ry,2))-(Math.pow(rx,2)*Math.pow(currp.y,2))-(Math.pow(ry,2)*Math.pow(currp.x,2))) /
- (Math.pow(rx,2)*Math.pow(currp.y,2)+Math.pow(ry,2)*Math.pow(currp.x,2))
- );
- if (isNaN(s)) s = 0;
- var cpp = new svg.Point(s * rx * currp.y / ry, s * -ry * currp.x / rx);
- // cx, cy
- var centp = new svg.Point(
- (curr.x + cp.x) / 2.0 + Math.cos(xAxisRotation) * cpp.x - Math.sin(xAxisRotation) * cpp.y,
- (curr.y + cp.y) / 2.0 + Math.sin(xAxisRotation) * cpp.x + Math.cos(xAxisRotation) * cpp.y
- );
- // vector magnitude
- var m = function(v) { return Math.sqrt(Math.pow(v[0],2) + Math.pow(v[1],2)); }
- // ratio between two vectors
- var r = function(u, v) { return (u[0]*v[0]+u[1]*v[1]) / (m(u)*m(v)) }
- // angle between two vectors
- var a = function(u, v) { return (u[0]*v[1] < u[1]*v[0] ? -1 : 1) * Math.acos(r(u,v)); }
- // initial angle
- var a1 = a([1,0], [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry]);
- // angle delta
- var u = [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry];
- var v = [(-currp.x-cpp.x)/rx,(-currp.y-cpp.y)/ry];
- var ad = a(u, v);
- if (r(u,v) <= -1) ad = Math.PI;
- if (r(u,v) >= 1) ad = 0;
-
- if (sweepFlag == 0 && ad > 0) ad = ad - 2 * Math.PI;
- if (sweepFlag == 1 && ad < 0) ad = ad + 2 * Math.PI;
-
- // for markers
- var halfWay = new svg.Point(
- centp.x - rx * Math.cos((a1 + ad) / 2),
- centp.y - ry * Math.sin((a1 + ad) / 2)
- );
- pp.addMarkerAngle(halfWay, (a1 + ad) / 2 + (sweepFlag == 0 ? 1 : -1) * Math.PI / 2);
- pp.addMarkerAngle(cp, ad + (sweepFlag == 0 ? 1 : -1) * Math.PI / 2);
-
- bb.addPoint(cp.x, cp.y); // TODO: this is too naive, make it better
- if (ctx != null) {
- var r = rx > ry ? rx : ry;
- var sx = rx > ry ? 1 : rx / ry;
- var sy = rx > ry ? ry / rx : 1;
-
- ctx.translate(centp.x, centp.y);
- ctx.rotate(xAxisRotation);
- ctx.scale(sx, sy);
- ctx.arc(0, 0, r, a1, a1 + ad, 1 - sweepFlag);
- ctx.scale(1/sx, 1/sy);
- ctx.rotate(-xAxisRotation);
- ctx.translate(-centp.x, -centp.y);
- }
- }
- break;
- case 'Z':
- if (ctx != null) ctx.closePath();
- pp.current = pp.start;
- }
- }
-
- return bb;
- }
-
- this.getMarkers = function() {
- var points = this.PathParser.getMarkerPoints();
- var angles = this.PathParser.getMarkerAngles();
-
- var markers = [];
- for (var i=0; i<points.length; i++) {
- markers.push([points[i], angles[i]]);
- }
- return markers;
- }
- }
- svg.Element.path.prototype = new svg.Element.PathElementBase;
-
- // pattern element
- svg.Element.pattern = function(node) {
- this.base = svg.Element.ElementBase;
- this.base(node);
-
- this.createPattern = function(ctx, element) {
- // render me using a temporary svg element
- var tempSvg = new svg.Element.svg();
- tempSvg.attributes['viewBox'] = new svg.Property('viewBox', this.attribute('viewBox').value);
- tempSvg.attributes['x'] = new svg.Property('x', this.attribute('x').value);
- tempSvg.attributes['y'] = new svg.Property('y', this.attribute('y').value);
- tempSvg.attributes['width'] = new svg.Property('width', this.attribute('width').value);
- tempSvg.attributes['height'] = new svg.Property('height', this.attribute('height').value);
- tempSvg.children = this.children;
-
- var c = document.createElement('canvas');
- c.width = this.attribute('width').Length.toPixels('x');
- c.height = this.attribute('height').Length.toPixels('y');
- tempSvg.render(c.getContext('2d'));
- return ctx.createPattern(c, 'repeat');
- }
- }
- svg.Element.pattern.prototype = new svg.Element.ElementBase;
-
- // marker element
- svg.Element.marker = function(node) {
- this.base = svg.Element.ElementBase;
- this.base(node);
-
- this.baseRender = this.render;
- this.render = function(ctx, point, angle) {
- ctx.translate(point.x, point.y);
- if (this.attribute('orient').valueOrDefault('auto') == 'auto') ctx.rotate(angle);
- if (this.attribute('markerUnits').valueOrDefault('strokeWidth') == 'strokeWidth') ctx.scale(ctx.lineWidth, ctx.lineWidth);
- ctx.save();
-
- // render me using a temporary svg element
- var tempSvg = new svg.Element.svg();
- tempSvg.attributes['viewBox'] = new svg.Property('viewBox', this.attribute('viewBox').value);
- tempSvg.attributes['refX'] = new svg.Property('refX', this.attribute('refX').value);
- tempSvg.attributes['refY'] = new svg.Property('refY', this.attribute('refY').value);
- tempSvg.attributes['width'] = new svg.Property('width', this.attribute('markerWidth').value);
- tempSvg.attributes['height'] = new svg.Property('height', this.attribute('markerHeight').value);
- tempSvg.attributes['fill'] = new svg.Property('fill', this.attribute('fill').valueOrDefault('black'));
- tempSvg.attributes['stroke'] = new svg.Property('stroke', this.attribute('stroke').valueOrDefault('none'));
- tempSvg.children = this.children;
- tempSvg.render(ctx);
-
- ctx.restore();
- if (this.attribute('markerUnits').valueOrDefault('strokeWidth') == 'strokeWidth') ctx.scale(1/ctx.lineWidth, 1/ctx.lineWidth);
- if (this.attribute('orient').valueOrDefault('auto') == 'auto') ctx.rotate(-angle);
- ctx.translate(-point.x, -point.y);
- }
- }
- svg.Element.marker.prototype = new svg.Element.ElementBase;
-
- // definitions element
- svg.Element.defs = function(node) {
- this.base = svg.Element.ElementBase;
- this.base(node);
-
- this.render = function(ctx) {
- // NOOP
- }
- }
- svg.Element.defs.prototype = new svg.Element.ElementBase;
-
- // base for gradients
- svg.Element.GradientBase = function(node) {
- this.base = svg.Element.ElementBase;
- this.base(node);
-
- this.gradientUnits = this.attribute('gradientUnits').valueOrDefault('objectBoundingBox');
-
- this.stops = [];
- for (var i=0; i<this.children.length; i++) {
- var child = this.children[i];
- this.stops.push(child);
- }
-
- this.getGradient = function() {
- // OVERRIDE ME!
- }
-
- this.createGradient = function(ctx, element) {
- var stopsContainer = this;
- if (this.attribute('xlink:href').hasValue()) {
- stopsContainer = this.attribute('xlink:href').Definition.getDefinition();
- }
-
- var g = this.getGradient(ctx, element);
- for (var i=0; i<stopsContainer.stops.length; i++) {
- g.addColorStop(stopsContainer.stops[i].offset, stopsContainer.stops[i].color);
- }
-
- if (this.attribute('gradientTransform').hasValue()) {
- // render as transformed pattern on temporary canvas
- var rootView = svg.ViewPort.viewPorts[0];
-
- var rect = new svg.Element.rect();
- rect.attributes['x'] = new svg.Property('x', -svg.MAX_VIRTUAL_PIXELS/3.0);
- rect.attributes['y'] = new svg.Property('y', -svg.MAX_VIRTUAL_PIXELS/3.0);
- rect.attributes['width'] = new svg.Property('width', svg.MAX_VIRTUAL_PIXELS);
- rect.attributes['height'] = new svg.Property('height', svg.MAX_VIRTUAL_PIXELS);
-
- var group = new svg.Element.g();
- group.attributes['transform'] = new svg.Property('transform', this.attribute('gradientTransform').value);
- group.children = [ rect ];
-
- var tempSvg = new svg.Element.svg();
- tempSvg.attributes['x'] = new svg.Property('x', 0);
- tempSvg.attributes['y'] = new svg.Property('y', 0);
- tempSvg.attributes['width'] = new svg.Property('width', rootView.width);
- tempSvg.attributes['height'] = new svg.Property('height', rootView.height);
- tempSvg.children = [ group ];
-
- var c = document.createElement('canvas');
- c.width = rootView.width;
- c.height = rootView.height;
- var tempCtx = c.getContext('2d');
- tempCtx.fillStyle = g;
- tempSvg.render(tempCtx);
- return tempCtx.createPattern(c, 'no-repeat');
- }
-
- return g;
- }
- }
- svg.Element.GradientBase.prototype = new svg.Element.ElementBase;
-
- // linear gradient element
- svg.Element.linearGradient = function(node) {
- this.base = svg.Element.GradientBase;
- this.base(node);
-
- this.getGradient = function(ctx, element) {
- var bb = element.getBoundingBox();
-
- var x1 = (this.gradientUnits == 'objectBoundingBox'
- ? bb.x() + bb.width() * this.attribute('x1').numValue()
- : this.attribute('x1').Length.toPixels('x'));
- var y1 = (this.gradientUnits == 'objectBoundingBox'
- ? bb.y() + bb.height() * this.attribute('y1').numValue()
- : this.attribute('y1').Length.toPixels('y'));
- var x2 = (this.gradientUnits == 'objectBoundingBox'
- ? bb.x() + bb.width() * this.attribute('x2').numValue()
- : this.attribute('x2').Length.toPixels('x'));
- var y2 = (this.gradientUnits == 'objectBoundingBox'
- ? bb.y() + bb.height() * this.attribute('y2').numValue()
- : this.attribute('y2').Length.toPixels('y'));
-
- return ctx.createLinearGradient(x1, y1, x2, y2);
- }
- }
- svg.Element.linearGradient.prototype = new svg.Element.GradientBase;
-
- // radial gradient element
- svg.Element.radialGradient = function(node) {
- this.base = svg.Element.GradientBase;
- this.base(node);
-
- this.getGradient = function(ctx, element) {
- var bb = element.getBoundingBox();
-
- var cx = (this.gradientUnits == 'objectBoundingBox'
- ? bb.x() + bb.width() * this.attribute('cx').numValue()
- : this.attribute('cx').Length.toPixels('x'));
- var cy = (this.gradientUnits == 'objectBoundingBox'
- ? bb.y() + bb.height() * this.attribute('cy').numValue()
- : this.attribute('cy').Length.toPixels('y'));
-
- var fx = cx;
- var fy = cy;
- if (this.attribute('fx').hasValue()) {
- fx = (this.gradientUnits == 'objectBoundingBox'
- ? bb.x() + bb.width() * this.attribute('fx').numValue()
- : this.attribute('fx').Length.toPixels('x'));
- }
- if (this.attribute('fy').hasValue()) {
- fy = (this.gradientUnits == 'objectBoundingBox'
- ? bb.y() + bb.height() * this.attribute('fy').numValue()
- : this.attribute('fy').Length.toPixels('y'));
- }
-
- var r = (this.gradientUnits == 'objectBoundingBox'
- ? (bb.width() + bb.height()) / 2.0 * this.attribute('r').numValue()
- : this.attribute('r').Length.toPixels());
-
- return ctx.createRadialGradient(fx, fy, 0, cx, cy, r);
- }
- }
- svg.Element.radialGradient.prototype = new svg.Element.GradientBase;
-
- // gradient stop element
- svg.Element.stop = function(node) {
- this.base = svg.Element.ElementBase;
- this.base(node);
-
- this.offset = this.attribute('offset').numValue();
-
- var stopColor = this.style('stop-color');
- if (this.style('stop-opacity').hasValue()) stopColor = stopColor.Color.addOpacity(this.style('stop-opacity').value);
- this.color = stopColor.value;
- }
- svg.Element.stop.prototype = new svg.Element.ElementBase;
-
- // animation base element
- svg.Element.AnimateBase = function(node) {
- this.base = svg.Element.ElementBase;
- this.base(node);
-
- svg.Animations.push(this);
-
- this.duration = 0.0;
- this.begin = this.attribute('begin').Time.toMilliseconds();
- this.maxDuration = this.begin + this.attribute('dur').Time.toMilliseconds();
-
- this.getProperty = function() {
- var attributeType = this.attribute('attributeType').value;
- var attributeName = this.attribute('attributeName').value;
-
- if (attributeType == 'CSS') {
- return this.parent.style(attributeName, true);
- }
- return this.parent.attribute(attributeName, true);
- };
-
- this.initialValue = null;
- this.removed = false;
-
- this.calcValue = function() {
- // OVERRIDE ME!
- return '';
- }
-
- this.update = function(delta) {
- // set initial value
- if (this.initialValue == null) {
- this.initialValue = this.getProperty().value;
- }
-
- // if we're past the end time
- if (this.duration > this.maxDuration) {
- // loop for indefinitely repeating animations
- if (this.attribute('repeatCount').value == 'indefinite') {
- this.duration = 0.0
- }
- else if (this.attribute('fill').valueOrDefault('remove') == 'remove' && !this.removed) {
- this.removed = true;
- this.getProperty().value = this.initialValue;
- return true;
- }
- else {
- return false; // no updates made
- }
- }
- this.duration = this.duration + delta;
-
- // if we're past the begin time
- var updated = false;
- if (this.begin < this.duration) {
- var newValue = this.calcValue(); // tween
-
- if (this.attribute('type').hasValue()) {
- // for transform, etc.
- var type = this.attribute('type').value;
- newValue = type + '(' + newValue + ')';
- }
-
- this.getProperty().value = newValue;
- updated = true;
- }
-
- return updated;
- }
-
- // fraction of duration we've covered
- this.progress = function() {
- return ((this.duration - this.begin) / (this.maxDuration - this.begin));
- }
- }
- svg.Element.AnimateBase.prototype = new svg.Element.ElementBase;
-
- // animate element
- svg.Element.animate = function(node) {
- this.base = svg.Element.AnimateBase;
- this.base(node);
-
- this.calcValue = function() {
- var from = this.attribute('from').numValue();
- var to = this.attribute('to').numValue();
-
- // tween value linearly
- return from + (to - from) * this.progress();
- };
- }
- svg.Element.animate.prototype = new svg.Element.AnimateBase;
-
- // animate color element
- svg.Element.animateColor = function(node) {
- this.base = svg.Element.AnimateBase;
- this.base(node);
-
- this.calcValue = function() {
- var from = new RGBColor(this.attribute('from').value);
- var to = new RGBColor(this.attribute('to').value);
-
- if (from.ok && to.ok) {
- // tween color linearly
- var r = from.r + (to.r - from.r) * this.progress();
- var g = from.g + (to.g - from.g) * this.progress();
- var b = from.b + (to.b - from.b) * this.progress();
- return 'rgb('+parseInt(r,10)+','+parseInt(g,10)+','+parseInt(b,10)+')';
- }
- return this.attribute('from').value;
- };
- }
- svg.Element.animateColor.prototype = new svg.Element.AnimateBase;
-
- // animate transform element
- svg.Element.animateTransform = function(node) {
- this.base = svg.Element.animate;
- this.base(node);
- }
- svg.Element.animateTransform.prototype = new svg.Element.animate;
-
- // font element
- svg.Element.font = function(node) {
- this.base = svg.Element.ElementBase;
- this.base(node);
-
- this.horizAdvX = this.attribute('horiz-adv-x').numValue();
-
- this.isRTL = false;
- this.isArabic = false;
- this.fontFace = null;
- this.missingGlyph = null;
- this.glyphs = [];
- for (var i=0; i<this.children.length; i++) {
- var child = this.children[i];
- if (child.type == 'font-face') {
- this.fontFace = child;
- if (child.style('font-family').hasValue()) {
- svg.Definitions[child.style('font-family').value] = this;
- }
- }
- else if (child.type == 'missing-glyph') this.missingGlyph = child;
- else if (child.type == 'glyph') {
- if (child.arabicForm != '') {
- this.isRTL = true;
- this.isArabic = true;
- if (typeof(this.glyphs[child.unicode]) == 'undefined') this.glyphs[child.unicode] = [];
- this.glyphs[child.unicode][child.arabicForm] = child;
- }
- else {
- this.glyphs[child.unicode] = child;
- }
- }
- }
- }
- svg.Element.font.prototype = new svg.Element.ElementBase;
-
- // font-face element
- svg.Element.fontface = function(node) {
- this.base = svg.Element.ElementBase;
- this.base(node);
-
- this.ascent = this.attribute('ascent').value;
- this.descent = this.attribute('descent').value;
- this.unitsPerEm = this.attribute('units-per-em').numValue();
- }
- svg.Element.fontface.prototype = new svg.Element.ElementBase;
-
- // missing-glyph element
- svg.Element.missingglyph = function(node) {
- this.base = svg.Element.path;
- this.base(node);
-
- this.horizAdvX = 0;
- }
- svg.Element.missingglyph.prototype = new svg.Element.path;
-
- // glyph element
- svg.Element.glyph = function(node) {
- this.base = svg.Element.path;
- this.base(node);
-
- this.horizAdvX = this.attribute('horiz-adv-x').numValue();
- this.unicode = this.attribute('unicode').value;
- this.arabicForm = this.attribute('arabic-form').value;
- }
- svg.Element.glyph.prototype = new svg.Element.path;
-
- // text element
- svg.Element.text = function(node) {
- this.base = svg.Element.RenderedElementBase;
- this.base(node);
-
- if (node != null) {
- // add children
- this.children = [];
- for (var i=0; i<node.childNodes.length; i++) {
- var childNode = node.childNodes[i];
- if (childNode.nodeType == 1) { // capture tspan and tref nodes
- this.addChild(childNode, true);
- }
- else if (childNode.nodeType == 3) { // capture text
- this.addChild(new svg.Element.tspan(childNode), false);
- }
- }
- }
-
- this.baseSetContext = this.setContext;
- this.setContext = function(ctx) {
- this.baseSetContext(ctx);
- if (this.style('dominant-baseline').hasValue()) ctx.textBaseline = this.style('dominant-baseline').value;
- if (this.style('alignment-baseline').hasValue()) ctx.textBaseline = this.style('alignment-baseline').value;
- }
-
- this.renderChildren = function(ctx) {
- var textAnchor = this.style('text-anchor').valueOrDefault('start');
- var x = this.attribute('x').Length.toPixels('x');
- var y = this.attribute('y').Length.toPixels('y');
- for (var i=0; i<this.children.length; i++) {
- var child = this.children[i];
-
- if (child.attribute('x').hasValue()) {
- child.x = child.attribute('x').Length.toPixels('x');
- }
- else {
- if (child.attribute('dx').hasValue()) x += child.attribute('dx').Length.toPixels('x');
- child.x = x;
- }
-
- var childLength = child.measureText(ctx);
- if (textAnchor != 'start' && (i==0 || child.attribute('x').hasValue())) { // new group?
- // loop through rest of children
- var groupLength = childLength;
- for (var j=i+1; j<this.children.length; j++) {
- var childInGroup = this.children[j];
- if (childInGroup.attribute('x').hasValue()) break; // new group
- groupLength += childInGroup.measureText(ctx);
- }
- child.x -= (textAnchor == 'end' ? groupLength : groupLength / 2.0);
- }
- x = child.x + childLength;
-
- if (child.attribute('y').hasValue()) {
- child.y = child.attribute('y').Length.toPixels('y');
- }
- else {
- if (child.attribute('dy').hasValue()) y += child.attribute('dy').Length.toPixels('y');
- child.y = y;
- }
- y = child.y;
-
- child.render(ctx);
- }
- }
- }
- svg.Element.text.prototype = new svg.Element.RenderedElementBase;
-
- // text base
- svg.Element.TextElementBase = function(node) {
- this.base = svg.Element.RenderedElementBase;
- this.base(node);
-
- this.getGlyph = function(font, text, i) {
- var c = text[i];
- var glyph = null;
- if (font.isArabic) {
- var arabicForm = 'isolated';
- if ((i==0 || text[i-1]==' ') && i<text.length-2 && text[i+1]!=' ') arabicForm = 'terminal';
- if (i>0 && text[i-1]!=' ' && i<text.length-2 && text[i+1]!=' ') arabicForm = 'medial';
- if (i>0 && text[i-1]!=' ' && (i == text.length-1 || text[i+1]==' ')) arabicForm = 'initial';
- if (typeof(font.glyphs[c]) != 'undefined') {
- glyph = font.glyphs[c][arabicForm];
- if (glyph == null && font.glyphs[c].type == 'glyph') glyph = font.glyphs[c];
- }
- }
- else {
- glyph = font.glyphs[c];
- }
- if (glyph == null) glyph = font.missingGlyph;
- return glyph;
- }
-
- this.renderChildren = function(ctx) {
- var customFont = this.parent.style('font-family').Definition.getDefinition();
- if (customFont != null) {
- var fontSize = this.parent.style('font-size').numValueOrDefault(svg.Font.Parse(svg.ctx.font).fontSize);
- var fontStyle = this.parent.style('font-style').valueOrDefault(svg.Font.Parse(svg.ctx.font).fontStyle);
- var text = this.getText();
- if (customFont.isRTL) text = text.split("").reverse().join("");
-
- var dx = svg.ToNumberArray(this.parent.attribute('dx').value);
- for (var i=0; i<text.length; i++) {
- var glyph = this.getGlyph(customFont, text, i);
- var scale = fontSize / customFont.fontFace.unitsPerEm;
- ctx.translate(this.x, this.y);
- ctx.scale(scale, -scale);
- var lw = ctx.lineWidth;
- ctx.lineWidth = ctx.lineWidth * customFont.fontFace.unitsPerEm / fontSize;
- if (fontStyle == 'italic') ctx.transform(1, 0, .4, 1, 0, 0);
- glyph.render(ctx);
- if (fontStyle == 'italic') ctx.transform(1, 0, -.4, 1, 0, 0);
- ctx.lineWidth = lw;
- ctx.scale(1/scale, -1/scale);
- ctx.translate(-this.x, -this.y);
-
- this.x += fontSize * (glyph.horizAdvX || customFont.horizAdvX) / customFont.fontFace.unitsPerEm;
- if (typeof(dx[i]) != 'undefined' && !isNaN(dx[i])) {
- this.x += dx[i];
- }
- }
- return;
- }
-
- if (ctx.strokeStyle != '') ctx.strokeText(svg.compressSpaces(this.getText()), this.x, this.y);
- if (ctx.fillStyle != '') ctx.fillText(svg.compressSpaces(this.getText()), this.x, this.y);
- }
-
- this.getText = function() {
- // OVERRIDE ME
- }
-
- this.measureText = function(ctx) {
- var customFont = this.parent.style('font-family').Definition.getDefinition();
- if (customFont != null) {
- var fontSize = this.parent.style('font-size').numValueOrDefault(svg.Font.Parse(svg.ctx.font).fontSize);
- var measure = 0;
- var text = this.getText();
- if (customFont.isRTL) text = text.split("").reverse().join("");
- var dx = svg.ToNumberArray(this.parent.attribute('dx').value);
- for (var i=0; i<text.length; i++) {
- var glyph = this.getGlyph(customFont, text, i);
- measure += (glyph.horizAdvX || customFont.horizAdvX) * fontSize / customFont.fontFace.unitsPerEm;
- if (typeof(dx[i]) != 'undefined' && !isNaN(dx[i])) {
- measure += dx[i];
- }
- }
- return measure;
- }
-
- var textToMeasure = svg.compressSpaces(this.getText());
- if (!ctx.measureText) return textToMeasure.length * 10;
-
- ctx.save();
- this.setContext(ctx);
- var width = ctx.measureText(textToMeasure).width;
- ctx.restore();
- return width;
- }
- }
- svg.Element.TextElementBase.prototype = new svg.Element.RenderedElementBase;
-
- // tspan
- svg.Element.tspan = function(node) {
- this.base = svg.Element.TextElementBase;
- this.base(node);
-
- this.text = node.nodeType == 3 ? node.nodeValue : // text
- node.childNodes.length > 0 ? node.childNodes[0].nodeValue : // element
- node.text;
- this.getText = function() {
- return this.text;
- }
- }
- svg.Element.tspan.prototype = new svg.Element.TextElementBase;
-
- // tref
- svg.Element.tref = function(node) {
- this.base = svg.Element.TextElementBase;
- this.base(node);
-
- this.getText = function() {
- var element = this.attribute('xlink:href').Definition.getDefinition();
- if (element != null) return element.children[0].getText();
- }
- }
- svg.Element.tref.prototype = new svg.Element.TextElementBase;
-
- // a element
- svg.Element.a = function(node) {
- this.base = svg.Element.TextElementBase;
- this.base(node);
-
- this.hasText = true;
- for (var i=0; i<node.childNodes.length; i++) {
- if (node.childNodes[i].nodeType != 3) this.hasText = false;
- }
-
- // this might contain text
- this.text = this.hasText ? node.childNodes[0].nodeValue : '';
- this.getText = function() {
- return this.text;
- }
-
- this.baseRenderChildren = this.renderChildren;
- this.renderChildren = function(ctx) {
- if (this.hasText) {
- // render as text element
- this.baseRenderChildren(ctx);
- var fontSize = new svg.Property('fontSize', svg.Font.Parse(svg.ctx.font).fontSize);
- svg.Mouse.checkBoundingBox(this, new svg.BoundingBox(this.x, this.y - fontSize.Length.toPixels('y'), this.x + this.measureText(ctx), this.y));
- }
- else {
- // render as temporary group
- var g = new svg.Element.g();
- g.children = this.children;
- g.parent = this;
- g.render(ctx);
- }
- }
-
- this.onclick = function() {
- window.open(this.attribute('xlink:href').value);
- }
-
- this.onmousemove = function() {
- svg.ctx.canvas.style.cursor = 'pointer';
- }
- }
- svg.Element.a.prototype = new svg.Element.TextElementBase;
-
- // image element
- svg.Element.image = function(node) {
- this.base = svg.Element.RenderedElementBase;
- this.base(node);
-
- svg.Images.push(this);
- this.img = document.createElement('img');
- this.loaded = false;
- var that = this;
- this.img.onload = function() { that.loaded = true; }
- this.img.src = this.attribute('xlink:href').value;
-
- this.renderChildren = function(ctx) {
- var x = this.attribute('x').Length.toPixels('x');
- var y = this.attribute('y').Length.toPixels('y');
-
- var width = this.attribute('width').Length.toPixels('x');
- var height = this.attribute('height').Length.toPixels('y');
- if (width == 0 || height == 0) return;
-
- ctx.save();
- ctx.translate(x, y);
- svg.AspectRatio(ctx,
- this.attribute('preserveAspectRatio').value,
- width,
- this.img.width,
- height,
- this.img.height,
- 0,
- 0);
- ctx.drawImage(this.img, 0, 0);
- ctx.restore();
- }
- }
- svg.Element.image.prototype = new svg.Element.RenderedElementBase;
-
- // group element
- svg.Element.g = function(node) {
- this.base = svg.Element.RenderedElementBase;
- this.base(node);
-
- this.getBoundingBox = function() {
- var bb = new svg.BoundingBox();
- for (var i=0; i<this.children.length; i++) {
- bb.addBoundingBox(this.children[i].getBoundingBox());
- }
- return bb;
- };
- }
- svg.Element.g.prototype = new svg.Element.RenderedElementBase;
-
- // symbol element
- svg.Element.symbol = function(node) {
- this.base = svg.Element.RenderedElementBase;
- this.base(node);
-
- this.baseSetContext = this.setContext;
- this.setContext = function(ctx) {
- this.baseSetContext(ctx);
-
- // viewbox
- if (this.attribute('viewBox').hasValue()) {
- var viewBox = svg.ToNumberArray(this.attribute('viewBox').value);
- var minX = viewBox[0];
- var minY = viewBox[1];
- width = viewBox[2];
- height = viewBox[3];
-
- svg.AspectRatio(ctx,
- this.attribute('preserveAspectRatio').value,
- this.attribute('width').Length.toPixels('x'),
- width,
- this.attribute('height').Length.toPixels('y'),
- height,
- minX,
- minY);
-
- svg.ViewPort.SetCurrent(viewBox[2], viewBox[3]);
- }
- }
- }
- svg.Element.symbol.prototype = new svg.Element.RenderedElementBase;
-
- // style element
- svg.Element.style = function(node) {
- this.base = svg.Element.ElementBase;
- this.base(node);
-
- // text, or spaces then CDATA
- var css = node.childNodes[0].nodeValue + (node.childNodes.length > 1 ? node.childNodes[1].nodeValue : '');
- css = css.replace(/(\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\/)|(^[\s]*\/\/.*)/gm, ''); // remove comments
- css = svg.compressSpaces(css); // replace whitespace
- var cssDefs = css.split('}');
- for (var i=0; i<cssDefs.length; i++) {
- if (svg.trim(cssDefs[i]) != '') {
- var cssDef = cssDefs[i].split('{');
- var cssClasses = cssDef[0].split(',');
- var cssProps = cssDef[1].split(';');
- for (var j=0; j<cssClasses.length; j++) {
- var cssClass = svg.trim(cssClasses[j]);
- if (cssClass != '') {
- var props = {};
- for (var k=0; k<cssProps.length; k++) {
- var prop = cssProps[k].indexOf(':');
- var name = cssProps[k].substr(0, prop);
- var value = cssProps[k].substr(prop + 1, cssProps[k].length - prop);
- if (name != null && value != null) {
- props[svg.trim(name)] = new svg.Property(svg.trim(name), svg.trim(value));
- }
- }
- svg.Styles[cssClass] = props;
- if (cssClass == '@font-face') {
- var fontFamily = props['font-family'].value.replace(/"/g,'');
- var srcs = props['src'].value.split(',');
- for (var s=0; s<srcs.length; s++) {
- if (srcs[s].indexOf('format("svg")') > 0) {
- var urlStart = srcs[s].indexOf('url');
- var urlEnd = srcs[s].indexOf(')', urlStart);
- var url = srcs[s].substr(urlStart + 5, urlEnd - urlStart - 6);
- var doc = svg.parseXml(svg.ajax(url));
- var fonts = doc.getElementsByTagName('font');
- for (var f=0; f<fonts.length; f++) {
- var font = svg.CreateElement(fonts[f]);
- svg.Definitions[fontFamily] = font;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- svg.Element.style.prototype = new svg.Element.ElementBase;
-
- // use element
- svg.Element.use = function(node) {
- this.base = svg.Element.RenderedElementBase;
- this.base(node);
-
- this.baseSetContext = this.setContext;
- this.setContext = function(ctx) {
- this.baseSetContext(ctx);
- if (this.attribute('x').hasValue()) ctx.translate(this.attribute('x').Length.toPixels('x'), 0);
- if (this.attribute('y').hasValue()) ctx.translate(0, this.attribute('y').Length.toPixels('y'));
- }
-
- this.getDefinition = function() {
- var element = this.attribute('xlink:href').Definition.getDefinition();
- if (this.attribute('width').hasValue()) element.attribute('width', true).value = this.attribute('width').value;
- if (this.attribute('height').hasValue()) element.attribute('height', true).value = this.attribute('height').value;
- return element;
- }
-
- this.path = function(ctx) {
- var element = this.getDefinition();
- if (element != null) element.path(ctx);
- }
-
- this.renderChildren = function(ctx) {
- var element = this.getDefinition();
- if (element != null) element.render(ctx);
- }
- }
- svg.Element.use.prototype = new svg.Element.RenderedElementBase;
-
- // mask element
- svg.Element.mask = function(node) {
- this.base = svg.Element.ElementBase;
- this.base(node);
-
- this.apply = function(ctx, element) {
- // render as temp svg
- var x = this.attribute('x').Length.toPixels('x');
- var y = this.attribute('y').Length.toPixels('y');
- var width = this.attribute('width').Length.toPixels('x');
- var height = this.attribute('height').Length.toPixels('y');
-
- // temporarily remove mask to avoid recursion
- var mask = element.attribute('mask').value;
- element.attribute('mask').value = '';
-
- var cMask = document.createElement('canvas');
- cMask.width = x + width;
- cMask.height = y + height;
- var maskCtx = cMask.getContext('2d');
- this.renderChildren(maskCtx);
-
- var c = document.createElement('canvas');
- c.width = x + width;
- c.height = y + height;
- var tempCtx = c.getContext('2d');
- element.render(tempCtx);
- tempCtx.globalCompositeOperation = 'destination-in';
- tempCtx.fillStyle = maskCtx.createPattern(cMask, 'no-repeat');
- tempCtx.fillRect(0, 0, x + width, y + height);
-
- ctx.fillStyle = tempCtx.createPattern(c, 'no-repeat');
- ctx.fillRect(0, 0, x + width, y + height);
-
- // reassign mask
- element.attribute('mask').value = mask;
- }
-
- this.render = function(ctx) {
- // NO RENDER
- }
- }
- svg.Element.mask.prototype = new svg.Element.ElementBase;
-
- // clip element
- svg.Element.clipPath = function(node) {
- this.base = svg.Element.ElementBase;
- this.base(node);
-
- this.apply = function(ctx) {
- for (var i=0; i<this.children.length; i++) {
- if (this.children[i].path) {
- this.children[i].path(ctx);
- ctx.clip();
- }
- }
- }
-
- this.render = function(ctx) {
- // NO RENDER
- }
- }
- svg.Element.clipPath.prototype = new svg.Element.ElementBase;
-
- // filters
- svg.Element.filter = function(node) {
- this.base = svg.Element.ElementBase;
- this.base(node);
-
- this.apply = function(ctx, element) {
- // render as temp svg
- var bb = element.getBoundingBox();
- var x = this.attribute('x').Length.toPixels('x');
- var y = this.attribute('y').Length.toPixels('y');
- if (x == 0 || y == 0) {
- x = bb.x1;
- y = bb.y1;
- }
- var width = this.attribute('width').Length.toPixels('x');
- var height = this.attribute('height').Length.toPixels('y');
- if (width == 0 || height == 0) {
- width = bb.width();
- height = bb.height();
- }
-
- // temporarily remove filter to avoid recursion
- var filter = element.style('filter').value;
- element.style('filter').value = '';
-
- // max filter distance
- var extraPercent = .20;
- var px = extraPercent * width;
- var py = extraPercent * height;
-
- var c = document.createElement('canvas');
- c.width = width + 2*px;
- c.height = height + 2*py;
- var tempCtx = c.getContext('2d');
- tempCtx.translate(-x + px, -y + py);
- element.render(tempCtx);
-
- // apply filters
- for (var i=0; i<this.children.length; i++) {
- this.children[i].apply(tempCtx, 0, 0, width + 2*px, height + 2*py);
- }
-
- // render on me
- ctx.drawImage(c, 0, 0, width + 2*px, height + 2*py, x - px, y - py, width + 2*px, height + 2*py);
-
- // reassign filter
- element.style('filter', true).value = filter;
- }
-
- this.render = function(ctx) {
- // NO RENDER
- }
- }
- svg.Element.filter.prototype = new svg.Element.ElementBase;
-
- svg.Element.feGaussianBlur = function(node) {
- this.base = svg.Element.ElementBase;
- this.base(node);
-
- function make_fgauss(sigma) {
- sigma = Math.max(sigma, 0.01);
- var len = Math.ceil(sigma * 4.0) + 1;
- mask = [];
- for (var i = 0; i < len; i++) {
- mask[i] = Math.exp(-0.5 * (i / sigma) * (i / sigma));
- }
- return mask;
- }
-
- function normalize(mask) {
- var sum = 0;
- for (var i = 1; i < mask.length; i++) {
- sum += Math.abs(mask[i]);
- }
- sum = 2 * sum + Math.abs(mask[0]);
- for (var i = 0; i < mask.length; i++) {
- mask[i] /= sum;
- }
- return mask;
- }
-
- function convolve_even(src, dst, mask, width, height) {
- for (var y = 0; y < height; y++) {
- for (var x = 0; x < width; x++) {
- var a = imGet(src, x, y, width, height, 3)/255;
- for (var rgba = 0; rgba < 4; rgba++) {
- var sum = mask[0] * (a==0?255:imGet(src, x, y, width, height, rgba)) * (a==0||rgba==3?1:a);
- for (var i = 1; i < mask.length; i++) {
- var a1 = imGet(src, Math.max(x-i,0), y, width, height, 3)/255;
- var a2 = imGet(src, Math.min(x+i, width-1), y, width, height, 3)/255;
- sum += mask[i] *
- ((a1==0?255:imGet(src, Math.max(x-i,0), y, width, height, rgba)) * (a1==0||rgba==3?1:a1) +
- (a2==0?255:imGet(src, Math.min(x+i, width-1), y, width, height, rgba)) * (a2==0||rgba==3?1:a2));
- }
- imSet(dst, y, x, height, width, rgba, sum);
- }
- }
- }
- }
-
- function imGet(img, x, y, width, height, rgba) {
- return img[y*width*4 + x*4 + rgba];
- }
-
- function imSet(img, x, y, width, height, rgba, val) {
- img[y*width*4 + x*4 + rgba] = val;
- }
-
- function blur(ctx, width, height, sigma)
- {
- var srcData = ctx.getImageData(0, 0, width, height);
- var mask = make_fgauss(sigma);
- mask = normalize(mask);
- tmp = [];
- convolve_even(srcData.data, tmp, mask, width, height);
- convolve_even(tmp, srcData.data, mask, height, width);
- ctx.clearRect(0, 0, width, height);
- ctx.putImageData(srcData, 0, 0);
- }
-
- this.apply = function(ctx, x, y, width, height) {
- // assuming x==0 && y==0 for now
- blur(ctx, width, height, this.attribute('stdDeviation').numValue());
- }
- }
- svg.Element.filter.prototype = new svg.Element.feGaussianBlur;
-
- // title element, do nothing
- svg.Element.title = function(node) {
- }
- svg.Element.title.prototype = new svg.Element.ElementBase;
-
- // desc element, do nothing
- svg.Element.desc = function(node) {
- }
- svg.Element.desc.prototype = new svg.Element.ElementBase;
-
- svg.Element.MISSING = function(node) {
- console.log('ERROR: Element \'' + node.nodeName + '\' not yet implemented.');
- }
- svg.Element.MISSING.prototype = new svg.Element.ElementBase;
-
- // element factory
- svg.CreateElement = function(node) {
- var className = node.nodeName.replace(/^[^:]+:/,''); // remove namespace
- className = className.replace(/\-/g,''); // remove dashes
- var e = null;
- if (typeof(svg.Element[className]) != 'undefined') {
- e = new svg.Element[className](node);
- }
- else {
- e = new svg.Element.MISSING(node);
- }
-
- e.type = node.nodeName;
- return e;
- }
-
- // load from url
- svg.load = function(ctx, url) {
- svg.loadXml(ctx, svg.ajax(url));
- }
-
- // load from xml
- svg.loadXml = function(ctx, xml) {
- svg.loadXmlDoc(ctx, svg.parseXml(xml));
- }
-
- svg.loadXmlDoc = function(ctx, dom) {
- svg.init(ctx);
-
- var mapXY = function(p) {
- var e = ctx.canvas;
- while (e) {
- p.x -= e.offsetLeft;
- p.y -= e.offsetTop;
- e = e.offsetParent;
- }
- if (window.scrollX) p.x += window.scrollX;
- if (window.scrollY) p.y += window.scrollY;
- return p;
- }
-
- // bind mouse
- if (svg.opts['ignoreMouse'] != true) {
- ctx.canvas.onclick = function(e) {
- var p = mapXY(new svg.Point(e != null ? e.clientX : event.clientX, e != null ? e.clientY : event.clientY));
- svg.Mouse.onclick(p.x, p.y);
- };
- ctx.canvas.onmousemove = function(e) {
- var p = mapXY(new svg.Point(e != null ? e.clientX : event.clientX, e != null ? e.clientY : event.clientY));
- svg.Mouse.onmousemove(p.x, p.y);
- };
- }
-
- var e = svg.CreateElement(dom.documentElement);
- e.root = true;
-
- // render loop
- var isFirstRender = true;
- var draw = function() {
- svg.ViewPort.Clear();
- if (ctx.canvas.parentNode) svg.ViewPort.SetCurrent(ctx.canvas.parentNode.clientWidth, ctx.canvas.parentNode.clientHeight);
-
- if (svg.opts['ignoreDimensions'] != true) {
- // set canvas size
- if (e.style('width').hasValue()) {
- ctx.canvas.width = e.style('width').Length.toPixels('x');
- ctx.canvas.style.width = ctx.canvas.width + 'px';
- }
- if (e.style('height').hasValue()) {
- ctx.canvas.height = e.style('height').Length.toPixels('y');
- ctx.canvas.style.height = ctx.canvas.height + 'px';
- }
- }
- var cWidth = ctx.canvas.clientWidth || ctx.canvas.width;
- var cHeight = ctx.canvas.clientHeight || ctx.canvas.height;
- svg.ViewPort.SetCurrent(cWidth, cHeight);
-
- if (svg.opts != null && svg.opts['offsetX'] != null) e.attribute('x', true).value = svg.opts['offsetX'];
- if (svg.opts != null && svg.opts['offsetY'] != null) e.attribute('y', true).value = svg.opts['offsetY'];
- if (svg.opts != null && svg.opts['scaleWidth'] != null && svg.opts['scaleHeight'] != null) {
- var xRatio = 1, yRatio = 1;
- if (e.attribute('width').hasValue()) xRatio = e.attribute('width').Length.toPixels('x') / svg.opts['scaleWidth'];
- if (e.attribute('height').hasValue()) yRatio = e.attribute('height').Length.toPixels('y') / svg.opts['scaleHeight'];
-
- e.attribute('width', true).value = svg.opts['scaleWidth'];
- e.attribute('height', true).value = svg.opts['scaleHeight'];
- e.attribute('viewBox', true).value = '0 0 ' + (cWidth * xRatio) + ' ' + (cHeight * yRatio);
- e.attribute('preserveAspectRatio', true).value = 'none';
- }
-
- // clear and render
- if (svg.opts['ignoreClear'] != true) {
- ctx.clearRect(0, 0, cWidth, cHeight);
- }
- e.render(ctx);
- if (isFirstRender) {
- isFirstRender = false;
- if (svg.opts != null && typeof(svg.opts['renderCallback']) == 'function') svg.opts['renderCallback']();
- }
- }
-
- var waitingForImages = true;
- if (svg.ImagesLoaded()) {
- waitingForImages = false;
- draw();
- }
- svg.intervalID = setInterval(function() {
- var needUpdate = false;
-
- if (waitingForImages && svg.ImagesLoaded()) {
- waitingForImages = false;
- needUpdate = true;
- }
-
- // need update from mouse events?
- if (svg.opts['ignoreMouse'] != true) {
- needUpdate = needUpdate | svg.Mouse.hasEvents();
- }
-
- // need update from animations?
- if (svg.opts['ignoreAnimation'] != true) {
- for (var i=0; i<svg.Animations.length; i++) {
- needUpdate = needUpdate | svg.Animations[i].update(1000 / svg.FRAMERATE);
- }
- }
-
- // need update from redraw?
- if (svg.opts != null && typeof(svg.opts['forceRedraw']) == 'function') {
- if (svg.opts['forceRedraw']() == true) needUpdate = true;
- }
-
- // render if needed
- if (needUpdate) {
- draw();
- svg.Mouse.runEvents(); // run and clear our events
- }
- }, 1000 / svg.FRAMERATE);
- }
-
- svg.stop = function() {
- if (svg.intervalID) {
- clearInterval(svg.intervalID);
- }
- }
-
- svg.Mouse = new (function() {
- this.events = [];
- this.hasEvents = function() { return this.events.length != 0; }
-
- this.onclick = function(x, y) {
- this.events.push({ type: 'onclick', x: x, y: y,
- run: function(e) { if (e.onclick) e.onclick(); }
- });
- }
-
- this.onmousemove = function(x, y) {
- this.events.push({ type: 'onmousemove', x: x, y: y,
- run: function(e) { if (e.onmousemove) e.onmousemove(); }
- });
- }
-
- this.eventElements = [];
-
- this.checkPath = function(element, ctx) {
- for (var i=0; i<this.events.length; i++) {
- var e = this.events[i];
- if (ctx.isPointInPath && ctx.isPointInPath(e.x, e.y)) this.eventElements[i] = element;
- }
- }
-
- this.checkBoundingBox = function(element, bb) {
- for (var i=0; i<this.events.length; i++) {
- var e = this.events[i];
- if (bb.isPointInBox(e.x, e.y)) this.eventElements[i] = element;
- }
- }
-
- this.runEvents = function() {
- svg.ctx.canvas.style.cursor = '';
-
- for (var i=0; i<this.events.length; i++) {
- var e = this.events[i];
- var element = this.eventElements[i];
- while (element) {
- e.run(element);
- element = element.parent;
- }
- }
-
- // done running, clear
- this.events = [];
- this.eventElements = [];
- }
- });
-
- return svg;
- }
-})();
-
-if (CanvasRenderingContext2D) {
- CanvasRenderingContext2D.prototype.drawSvg = function(s, dx, dy, dw, dh) {
- canvg(this.canvas, s, {
- ignoreMouse: true,
- ignoreAnimation: true,
- ignoreDimensions: true,
- ignoreClear: true,
- offsetX: dx,
- offsetY: dy,
- scaleWidth: dw,
- scaleHeight: dh
- });
- }
-}/**
- * @license Highcharts JS v4.0.4 (2014-09-02)
- * CanVGRenderer Extension module
- *
- * (c) 2011-2012 Torstein Honsi, Erik Olsson
- *
- * License: www.highcharts.com/license
- */
-
-// JSLint options:
-/*global Highcharts */
-
-(function (Highcharts) { // encapsulate
- var UNDEFINED,
- DIV = 'div',
- ABSOLUTE = 'absolute',
- RELATIVE = 'relative',
- HIDDEN = 'hidden',
- VISIBLE = 'visible',
- PX = 'px',
- css = Highcharts.css,
- CanVGRenderer = Highcharts.CanVGRenderer,
- SVGRenderer = Highcharts.SVGRenderer,
- extend = Highcharts.extend,
- merge = Highcharts.merge,
- addEvent = Highcharts.addEvent,
- createElement = Highcharts.createElement,
- discardElement = Highcharts.discardElement;
-
- // Extend CanVG renderer on demand, inherit from SVGRenderer
- extend(CanVGRenderer.prototype, SVGRenderer.prototype);
-
- // Add additional functionality:
- extend(CanVGRenderer.prototype, {
- create: function (chart, container, chartWidth, chartHeight) {
- this.setContainer(container, chartWidth, chartHeight);
- this.configure(chart);
- },
- setContainer: function (container, chartWidth, chartHeight) {
- var containerStyle = container.style,
- containerParent = container.parentNode,
- containerLeft = containerStyle.left,
- containerTop = containerStyle.top,
- containerOffsetWidth = container.offsetWidth,
- containerOffsetHeight = container.offsetHeight,
- canvas,
- initialHiddenStyle = { visibility: HIDDEN, position: ABSOLUTE };
-
- this.init.apply(this, [container, chartWidth, chartHeight]);
-
- // add the canvas above it
- canvas = createElement('canvas', {
- width: containerOffsetWidth,
- height: containerOffsetHeight
- }, {
- position: RELATIVE,
- left: containerLeft,
- top: containerTop
- }, container);
- this.canvas = canvas;
-
- // Create the tooltip line and div, they are placed as siblings to
- // the container (and as direct childs to the div specified in the html page)
- this.ttLine = createElement(DIV, null, initialHiddenStyle, containerParent);
- this.ttDiv = createElement(DIV, null, initialHiddenStyle, containerParent);
- this.ttTimer = UNDEFINED;
-
- // Move away the svg node to a new div inside the container's parent so we can hide it.
- var hiddenSvg = createElement(DIV, {
- width: containerOffsetWidth,
- height: containerOffsetHeight
- }, {
- visibility: HIDDEN,
- left: containerLeft,
- top: containerTop
- }, containerParent);
- this.hiddenSvg = hiddenSvg;
- hiddenSvg.appendChild(this.box);
- },
-
- /**
- * Configures the renderer with the chart. Attach a listener to the event tooltipRefresh.
- **/
- configure: function (chart) {
- var renderer = this,
- options = chart.options.tooltip,
- borderWidth = options.borderWidth,
- tooltipDiv = renderer.ttDiv,
- tooltipDivStyle = options.style,
- tooltipLine = renderer.ttLine,
- padding = parseInt(tooltipDivStyle.padding, 10);
-
- // Add border styling from options to the style
- tooltipDivStyle = merge(tooltipDivStyle, {
- padding: padding + PX,
- 'background-color': options.backgroundColor,
- 'border-style': 'solid',
- 'border-width': borderWidth + PX,
- 'border-radius': options.borderRadius + PX
- });
-
- // Optionally add shadow
- if (options.shadow) {
- tooltipDivStyle = merge(tooltipDivStyle, {
- 'box-shadow': '1px 1px 3px gray', // w3c
- '-webkit-box-shadow': '1px 1px 3px gray' // webkit
- });
- }
- css(tooltipDiv, tooltipDivStyle);
-
- // Set simple style on the line
- css(tooltipLine, {
- 'border-left': '1px solid darkgray'
- });
-
- // This event is triggered when a new tooltip should be shown
- addEvent(chart, 'tooltipRefresh', function (args) {
- var chartContainer = chart.container,
- offsetLeft = chartContainer.offsetLeft,
- offsetTop = chartContainer.offsetTop,
- position;
-
- // Set the content of the tooltip
- tooltipDiv.innerHTML = args.text;
-
- // Compute the best position for the tooltip based on the divs size and container size.
- position = chart.tooltip.getPosition(tooltipDiv.offsetWidth, tooltipDiv.offsetHeight, {plotX: args.x, plotY: args.y});
-
- css(tooltipDiv, {
- visibility: VISIBLE,
- left: position.x + PX,
- top: position.y + PX,
- 'border-color': args.borderColor
- });
-
- // Position the tooltip line
- css(tooltipLine, {
- visibility: VISIBLE,
- left: offsetLeft + args.x + PX,
- top: offsetTop + chart.plotTop + PX,
- height: chart.plotHeight + PX
- });
-
- // This timeout hides the tooltip after 3 seconds
- // First clear any existing timer
- if (renderer.ttTimer !== UNDEFINED) {
- clearTimeout(renderer.ttTimer);
- }
-
- // Start a new timer that hides tooltip and line
- renderer.ttTimer = setTimeout(function () {
- css(tooltipDiv, { visibility: HIDDEN });
- css(tooltipLine, { visibility: HIDDEN });
- }, 3000);
- });
- },
-
- /**
- * Extend SVGRenderer.destroy to also destroy the elements added by CanVGRenderer.
- */
- destroy: function () {
- var renderer = this;
-
- // Remove the canvas
- discardElement(renderer.canvas);
-
- // Kill the timer
- if (renderer.ttTimer !== UNDEFINED) {
- clearTimeout(renderer.ttTimer);
- }
-
- // Remove the divs for tooltip and line
- discardElement(renderer.ttLine);
- discardElement(renderer.ttDiv);
- discardElement(renderer.hiddenSvg);
-
- // Continue with base class
- return SVGRenderer.prototype.destroy.apply(renderer);
- },
-
- /**
- * Take a color and return it if it's a string, do not make it a gradient even if it is a
- * gradient. Currently canvg cannot render gradients (turns out black),
- * see: http://code.google.com/p/canvg/issues/detail?id=104
- *
- * @param {Object} color The color or config object
- */
- color: function (color, elem, prop) {
- if (color && color.linearGradient) {
- // Pick the end color and forward to base implementation
- color = color.stops[color.stops.length - 1][1];
- }
- return SVGRenderer.prototype.color.call(this, color, elem, prop);
- },
-
- /**
- * Draws the SVG on the canvas or adds a draw invokation to the deferred list.
- */
- draw: function () {
- var renderer = this;
- window.canvg(renderer.canvas, renderer.hiddenSvg.innerHTML);
- }
- });
-}(Highcharts));
diff --git a/html/includes/js/modules/data.src.js b/html/includes/js/modules/data.src.js
deleted file mode 100644
index 471307f..0000000
--- a/html/includes/js/modules/data.src.js
+++ /dev/null
@@ -1,1025 +0,0 @@
-/**
- * @license Data plugin for Highcharts
- *
- * (c) 2012-2014 Torstein Honsi
- *
- * License: www.highcharts.com/license
- */
-
-/*
- * The Highcharts Data plugin is a utility to ease parsing of input sources like
- * CSV, HTML tables or grid views into basic configuration options for use
- * directly in the Highcharts constructor.
- *
- * Demo: http://jsfiddle.net/highcharts/SnLFj/
- *
- * --- OPTIONS ---
- *
- * - columns : Array<Array<Mixed>>
- * A two-dimensional array representing the input data on tabular form. This input can
- * be used when the data is already parsed, for example from a grid view component.
- * Each cell can be a string or number. If not switchRowsAndColumns is set, the columns
- * are interpreted as series. See also the rows option.
- *
- * - complete : Function(chartOptions)
- * The callback that is evaluated when the data is finished loading, optionally from an
- * external source, and parsed. The first argument passed is a finished chart options
- * object, containing the series. Thise options
- * can be extended with additional options and passed directly to the chart constructor. This is
- * related to the parsed callback, that goes in at an earlier stage.
- *
- * - csv : String
- * A comma delimited string to be parsed. Related options are startRow, endRow, startColumn
- * and endColumn to delimit what part of the table is used. The lineDelimiter and
- * itemDelimiter options define the CSV delimiter formats.
- *
- * - dateFormat: String
- * Which of the predefined date formats in Date.prototype.dateFormats to use to parse date
- * columns, for example "dd/mm/YYYY" or "YYYY-mm-dd". Defaults to a best guess based on
- * what format gives valid dates, and prefers ordered dates.
- *
- * - endColumn : Integer
- * In tabular input data, the first row (indexed by 0) to use. Defaults to the last
- * column containing data.
- *
- * - endRow : Integer
- * In tabular input data, the last row (indexed by 0) to use. Defaults to the last row
- * containing data.
- *
- * - googleSpreadsheetKey : String
- * A Google Spreadsheet key. See https://developers.google.com/gdata/samples/spreadsheet_sample
- * for general information on GS.
- *
- * - googleSpreadsheetWorksheet : String
- * The Google Spreadsheet worksheet. The available id's can be read from
- * https://spreadsheets.google.com/feeds/worksheets/{key}/public/basic
- *
- * - itemDelimiter : String
- * Item or cell delimiter for parsing CSV. Defaults to the tab character "\t" if a tab character
- * is found in the CSV string, if not it defaults to ",".
- *
- * - lineDelimiter : String
- * Line delimiter for parsing CSV. Defaults to "\n".
- *
- * - parsed : Function
- * A callback function to access the parsed columns, the two-dimentional input data
- * array directly, before they are interpreted into series data and categories. See also
- * the complete callback, that goes in on a later stage where the raw columns are interpreted
- * into a Highcharts option structure. Return false to stop completion, or call this.complete()
- * to continue async.
- *
- * - parseDate : Function
- * A callback function to parse string representations of dates into JavaScript timestamps.
- * Return an integer on success.
- *
- * - rows : Array<Array<Mixed>>
- * The same as the columns input option, but defining rows intead of columns.
- *
- * - seriesMapping : Array<Object>
- * An array containing object with Point property names along with what column id the
- * property should be taken from.
- *
- * - startColumn : Integer
- * In tabular input data, the first column (indexed by 0) to use.
- *
- * - startRow : Integer
- * In tabular input data, the first row (indexed by 0) to use.
- *
- * - switchRowsAndColumns : Boolean
- * Switch rows and columns of the input data, so that this.columns effectively becomes the
- * rows of the data set, and the rows are interpreted as series.
- *
- * - table : String|HTMLElement
- * A HTML table or the id of such to be parsed as input data. Related options ara startRow,
- * endRow, startColumn and endColumn to delimit what part of the table is used.
- */
-
-/*
- * TODO:
- * - Handle various date formats
- * - http://jsfiddle.net/highcharts/114wejdx/
- * - http://jsfiddle.net/highcharts/ryv67bkq/
- */
-
-// JSLint options:
-/*global jQuery, HighchartsAdapter */
-
-(function (Highcharts) { // docs
-
- // Utilities
- var each = Highcharts.each,
- inArray = HighchartsAdapter.inArray,
- splat = Highcharts.splat,
- SeriesBuilder;
-
-
- // The Data constructor
- var Data = function (dataOptions, chartOptions) {
- this.init(dataOptions, chartOptions);
- };
-
- // Set the prototype properties
- Highcharts.extend(Data.prototype, {
-
- /**
- * Initialize the Data object with the given options
- */
- init: function (options, chartOptions) {
- this.options = options;
- this.chartOptions = chartOptions;
- this.columns = options.columns || this.rowsToColumns(options.rows) || [];
-
- // This is a two-dimensional array holding the raw, trimmed string values
- // with the same organisation as the columns array. It makes it possible
- // for example to revert from interpreted timestamps to string-based
- // categories.
- this.rawColumns = [];
-
- // No need to parse or interpret anything
- if (this.columns.length) {
- this.dataFound();
-
- // Parse and interpret
- } else {
-
- // Parse a CSV string if options.csv is given
- this.parseCSV();
-
- // Parse a HTML table if options.table is given
- this.parseTable();
-
- // Parse a Google Spreadsheet
- this.parseGoogleSpreadsheet();
- }
-
- },
-
- /**
- * Get the column distribution. For example, a line series takes a single column for
- * Y values. A range series takes two columns for low and high values respectively,
- * and an OHLC series takes four columns.
- */
- getColumnDistribution: function () {
- var chartOptions = this.chartOptions,
- options = this.options,
- xColumns = [],
- getValueCount = function (type) {
- return (Highcharts.seriesTypes[type || 'line'].prototype.pointArrayMap || [0]).length;
- },
- getPointArrayMap = function (type) {
- return Highcharts.seriesTypes[type || 'line'].prototype.pointArrayMap;
- },
- globalType = chartOptions && chartOptions.chart && chartOptions.chart.type,
- individualCounts = [],
- seriesBuilders = [],
- seriesIndex,
- i;
-
- each((chartOptions && chartOptions.series) || [], function (series) {
- individualCounts.push(getValueCount(series.type || globalType));
- });
-
- // Collect the x-column indexes from seriesMapping
- each((options && options.seriesMapping) || [], function (mapping) {
- xColumns.push(mapping.x || 0);
- });
-
- // If there are no defined series with x-columns, use the first column as x column
- if (xColumns.length === 0) {
- xColumns.push(0);
- }
-
- // Loop all seriesMappings and constructs SeriesBuilders from
- // the mapping options.
- each((options && options.seriesMapping) || [], function (mapping) {
- var builder = new SeriesBuilder(),
- name,
- numberOfValueColumnsNeeded = individualCounts[seriesIndex] || getValueCount(globalType),
- seriesArr = (chartOptions && chartOptions.series) || [],
- series = seriesArr[seriesIndex] || {},
- pointArrayMap = getPointArrayMap(series.type || globalType) || ['y'];
-
- // Add an x reader from the x property or from an undefined column
- // if the property is not set. It will then be auto populated later.
- builder.addColumnReader(mapping.x, 'x');
-
- // Add all column mappings
- for (name in mapping) {
- if (mapping.hasOwnProperty(name) && name !== 'x') {
- builder.addColumnReader(mapping[name], name);
- }
- }
-
- // Add missing columns
- for (i = 0; i < numberOfValueColumnsNeeded; i++) {
- if (!builder.hasReader(pointArrayMap[i])) {
- //builder.addNextColumnReader(pointArrayMap[i]);
- // Create and add a column reader for the next free column index
- builder.addColumnReader(undefined, pointArrayMap[i]);
- }
- }
-
- seriesBuilders.push(builder);
- seriesIndex++;
- });
-
- var globalPointArrayMap = getPointArrayMap(globalType);
- if (globalPointArrayMap === undefined) {
- globalPointArrayMap = ['y'];
- }
-
- this.valueCount = {
- global: getValueCount(globalType),
- xColumns: xColumns,
- individual: individualCounts,
- seriesBuilders: seriesBuilders,
- globalPointArrayMap: globalPointArrayMap
- };
- },
-
- /**
- * When the data is parsed into columns, either by CSV, table, GS or direct input,
- * continue with other operations.
- */
- dataFound: function () {
-
- if (this.options.switchRowsAndColumns) {
- this.columns = this.rowsToColumns(this.columns);
- }
-
- // Interpret the info about series and columns
- this.getColumnDistribution();
-
- // Interpret the values into right types
- this.parseTypes();
-
- // Use first row for series names?
- this.findHeaderRow();
-
- // Handle columns if a handleColumns callback is given
- if (this.parsed() !== false) {
-
- // Complete if a complete callback is given
- this.complete();
- }
-
- },
-
- /**
- * Parse a CSV input string
- */
- parseCSV: function () {
- var self = this,
- options = this.options,
- csv = options.csv,
- columns = this.columns,
- startRow = options.startRow || 0,
- endRow = options.endRow || Number.MAX_VALUE,
- startColumn = options.startColumn || 0,
- endColumn = options.endColumn || Number.MAX_VALUE,
- itemDelimiter,
- lines,
- activeRowNo = 0;
-
- if (csv) {
-
- lines = csv
- .replace(/\r\n/g, "\n") // Unix
- .replace(/\r/g, "\n") // Mac
- .split(options.lineDelimiter || "\n");
-
- itemDelimiter = options.itemDelimiter || (csv.indexOf('\t') !== -1 ? '\t' : ',');
-
- each(lines, function (line, rowNo) {
- var trimmed = self.trim(line),
- isComment = trimmed.indexOf('#') === 0,
- isBlank = trimmed === '',
- items;
-
- if (rowNo >= startRow && rowNo <= endRow && !isComment && !isBlank) {
- items = line.split(itemDelimiter);
- each(items, function (item, colNo) {
- if (colNo >= startColumn && colNo <= endColumn) {
- if (!columns[colNo - startColumn]) {
- columns[colNo - startColumn] = [];
- }
-
- columns[colNo - startColumn][activeRowNo] = item;
- }
- });
- activeRowNo += 1;
- }
- });
-
- this.dataFound();
- }
- },
-
- /**
- * Parse a HTML table
- */
- parseTable: function () {
- var options = this.options,
- table = options.table,
- columns = this.columns,
- startRow = options.startRow || 0,
- endRow = options.endRow || Number.MAX_VALUE,
- startColumn = options.startColumn || 0,
- endColumn = options.endColumn || Number.MAX_VALUE;
-
- if (table) {
-
- if (typeof table === 'string') {
- table = document.getElementById(table);
- }
-
- each(table.getElementsByTagName('tr'), function (tr, rowNo) {
- if (rowNo >= startRow && rowNo <= endRow) {
- each(tr.children, function (item, colNo) {
- if ((item.tagName === 'TD' || item.tagName === 'TH') && colNo >= startColumn && colNo <= endColumn) {
- if (!columns[colNo - startColumn]) {
- columns[colNo - startColumn] = [];
- }
-
- columns[colNo - startColumn][rowNo - startRow] = item.innerHTML;
- }
- });
- }
- });
-
- this.dataFound(); // continue
- }
- },
-
- /**
- */
- parseGoogleSpreadsheet: function () {
- var self = this,
- options = this.options,
- googleSpreadsheetKey = options.googleSpreadsheetKey,
- columns = this.columns,
- startRow = options.startRow || 0,
- endRow = options.endRow || Number.MAX_VALUE,
- startColumn = options.startColumn || 0,
- endColumn = options.endColumn || Number.MAX_VALUE,
- gr, // google row
- gc; // google column
-
- if (googleSpreadsheetKey) {
- jQuery.ajax({
- dataType: 'json',
- url: 'https://spreadsheets.google.com/feeds/cells/' +
- googleSpreadsheetKey + '/' + (options.googleSpreadsheetWorksheet || 'od6') +
- '/public/values?alt=json-in-script&callback=?',
- error: options.error,
- success: function (json) {
- // Prepare the data from the spreadsheat
- var cells = json.feed.entry,
- cell,
- cellCount = cells.length,
- colCount = 0,
- rowCount = 0,
- i;
-
- // First, find the total number of columns and rows that
- // are actually filled with data
- for (i = 0; i < cellCount; i++) {
- cell = cells[i];
- colCount = Math.max(colCount, cell.gs$cell.col);
- rowCount = Math.max(rowCount, cell.gs$cell.row);
- }
-
- // Set up arrays containing the column data
- for (i = 0; i < colCount; i++) {
- if (i >= startColumn && i <= endColumn) {
- // Create new columns with the length of either end-start or rowCount
- columns[i - startColumn] = [];
-
- // Setting the length to avoid jslint warning
- columns[i - startColumn].length = Math.min(rowCount, endRow - startRow);
- }
- }
-
- // Loop over the cells and assign the value to the right
- // place in the column arrays
- for (i = 0; i < cellCount; i++) {
- cell = cells[i];
- gr = cell.gs$cell.row - 1; // rows start at 1
- gc = cell.gs$cell.col - 1; // columns start at 1
-
- // If both row and col falls inside start and end
- // set the transposed cell value in the newly created columns
- if (gc >= startColumn && gc <= endColumn &&
- gr >= startRow && gr <= endRow) {
- columns[gc - startColumn][gr - startRow] = cell.content.$t;
- }
- }
- self.dataFound();
- }
- });
- }
- },
-
- /**
- * Find the header row. For now, we just check whether the first row contains
- * numbers or strings. Later we could loop down and find the first row with
- * numbers.
- */
- findHeaderRow: function () {
- var headerRow = 0;
- each(this.columns, function (column) {
- if (column.isNumeric && typeof column[0] !== 'string') {
- headerRow = null;
- }
- });
- this.headerRow = headerRow;
- },
-
- /**
- * Trim a string from whitespace
- */
- trim: function (str) {
- return typeof str === 'string' ? str.replace(/^\s+|\s+$/g, '') : str;
- },
-
- /**
- * Parse numeric cells in to number types and date types in to true dates.
- */
- parseTypes: function () {
- var columns = this.columns,
- rawColumns = this.rawColumns,
- col = columns.length,
- row,
- val,
- floatVal,
- trimVal,
- isXColumn,
- dateVal,
- descending,
- backup = [],
- diff,
- hasHeaderRow,
- forceCategory,
- chartOptions = this.chartOptions;
-
- while (col--) {
- row = columns[col].length;
- rawColumns[col] = [];
- isXColumn = inArray(col, this.valueCount.xColumns) !== -1;
- forceCategory = isXColumn && chartOptions && chartOptions.xAxis && splat(chartOptions.xAxis)[0].type === 'category';
- while (row--) {
- val = backup[row] || columns[col][row];
- floatVal = parseFloat(val);
- trimVal = rawColumns[col][row] = this.trim(val);
-
- // Disable number or date parsing by setting the X axis type to category
- if (forceCategory) {
- columns[col][row] = trimVal;
-
- /*jslint eqeq: true*/
- } else if (trimVal == floatVal) { // is numeric
- /*jslint eqeq: false*/
- columns[col][row] = floatVal;
-
- // If the number is greater than milliseconds in a year, assume datetime
- if (floatVal > 365 * 24 * 3600 * 1000) {
- columns[col].isDatetime = true;
- } else {
- columns[col].isNumeric = true;
- }
-
- } else { // string, continue to determine if it is a date string or really a string
- dateVal = this.parseDate(val);
- // Only allow parsing of dates if this column is an x-column
- if (isXColumn && typeof dateVal === 'number' && !isNaN(dateVal)) { // is date
- backup[row] = val;
- columns[col][row] = dateVal;
- columns[col].isDatetime = true;
-
- // Check if the dates are uniformly descending or ascending. If they
- // are not, chances are that they are a different time format, so check
- // for alternative.
- if (columns[col][row + 1] !== undefined) {
- diff = dateVal > columns[col][row + 1];
- if (diff !== descending && descending !== undefined) {
- if (this.alternativeFormat) {
- this.dateFormat = this.alternativeFormat;
- row = columns[col].length;
- this.alternativeFormat = this.dateFormats[this.dateFormat].alternative;
- } else {
- columns[col].unsorted = true;
- }
- }
- descending = diff;
- }
-
- } else { // string
- columns[col][row] = trimVal === '' ? null : trimVal;
- if (row !== 0 && (columns[col].isDatetime || columns[col].isNumeric)) {
- columns[col].mixed = true;
- }
- }
- }
- }
-
- // If strings are intermixed with numbers or dates in a parsed column, it is an indication
- // that parsing went wrong or the data was not intended to display as numbers or dates and
- // parsing is too aggressive. Fall back to categories. Demonstrated in the
- // highcharts/demo/column-drilldown sample.
- if (isXColumn && columns[col].mixed) {
- columns[col] = rawColumns[col];
- }
- }
-
- // If the 0 column is date and descending, reverse all columns.
- // TODO: probably this should apply to xColumns, not 0 column alone.
- if (columns[0].isDatetime && descending) {
- hasHeaderRow = typeof columns[0][0] !== 'number';
- for (col = 0; col < columns.length; col++) {
- columns[col].reverse();
- if (hasHeaderRow) {
- columns[col].unshift(columns[col].pop());
- }
- }
- }
- },
-
- /**
- * A collection of available date formats, extendable from the outside to support
- * custom date formats.
- */
- dateFormats: {
- 'YYYY-mm-dd': {
- regex: /^([0-9]{4})[\-\/\.]([0-9]{2})[\-\/\.]([0-9]{2})$/,
- parser: function (match) {
- return Date.UTC(+match[1], match[2] - 1, +match[3]);
- }
- },
- 'dd/mm/YYYY': {
- regex: /^([0-9]{1,2})[\-\/\.]([0-9]{1,2})[\-\/\.]([0-9]{4})$/,
- parser: function (match) {
- return Date.UTC(+match[3], match[2] - 1, +match[1]);
- },
- alternative: 'mm/dd/YYYY' // different format with the same regex
- },
- 'mm/dd/YYYY': {
- regex: /^([0-9]{1,2})[\-\/\.]([0-9]{1,2})[\-\/\.]([0-9]{4})$/,
- parser: function (match) {
- return Date.UTC(+match[3], match[1] - 1, +match[2]);
- }
- },
- 'dd/mm/YY': {
- regex: /^([0-9]{1,2})[\-\/\.]([0-9]{1,2})[\-\/\.]([0-9]{2})$/,
- parser: function (match) {
- return Date.UTC(+match[3] + 2000, match[2] - 1, +match[1]);
- },
- alternative: 'mm/dd/YY' // different format with the same regex
- },
- 'mm/dd/YY': {
- regex: /^([0-9]{1,2})[\-\/\.]([0-9]{1,2})[\-\/\.]([0-9]{2})$/,
- parser: function (match) {
- console.log(match)
- return Date.UTC(+match[3] + 2000, match[1] - 1, +match[2]);
- }
- }
- },
-
- /**
- * Parse a date and return it as a number. Overridable through options.parseDate.
- */
- parseDate: function (val) {
- var parseDate = this.options.parseDate,
- ret,
- key,
- format,
- dateFormat = this.options.dateFormat || this.dateFormat,
- match;
-
- if (parseDate) {
- ret = parseDate(val);
- }
-
- if (typeof val === 'string') {
- // Auto-detect the date format the first time
- if (!dateFormat) {
- for (key in this.dateFormats) {
- format = this.dateFormats[key];
- match = val.match(format.regex);
- if (match) {
- this.dateFormat = dateFormat = key;
- this.alternativeFormat = format.alternative;
- ret = format.parser(match);
- break;
- }
- }
- // Next time, use the one previously found
- } else {
- format = this.dateFormats[dateFormat];
- match = val.match(format.regex);
- if (match) {
- ret = format.parser(match);
- }
- }
- // Fall back to Date.parse
- if (!match) {
- match = Date.parse(val);
- // External tools like Date.js and MooTools extend Date object and
- // returns a date.
- if (typeof match === 'object' && match !== null && match.getTime) {
- ret = match.getTime() - match.getTimezoneOffset() * 60000;
-
- // Timestamp
- } else if (typeof match === 'number' && !isNaN(match)) {
- ret = match - (new Date(match)).getTimezoneOffset() * 60000;
- }
- }
- }
- return ret;
- },
-
- /**
- * Reorganize rows into columns
- */
- rowsToColumns: function (rows) {
- var row,
- rowsLength,
- col,
- colsLength,
- columns;
-
- if (rows) {
- columns = [];
- rowsLength = rows.length;
- for (row = 0; row < rowsLength; row++) {
- colsLength = rows[row].length;
- for (col = 0; col < colsLength; col++) {
- if (!columns[col]) {
- columns[col] = [];
- }
- columns[col][row] = rows[row][col];
- }
- }
- }
- return columns;
- },
-
- /**
- * A hook for working directly on the parsed columns
- */
- parsed: function () {
- if (this.options.parsed) {
- return this.options.parsed.call(this, this.columns);
- }
- },
-
- getFreeIndexes: function (numberOfColumns, seriesBuilders) {
- var s,
- i,
- freeIndexes = [],
- freeIndexValues = [],
- referencedIndexes;
-
- // Add all columns as free
- for (i = 0; i < numberOfColumns; i = i + 1) {
- freeIndexes.push(true);
- }
-
- // Loop all defined builders and remove their referenced columns
- for (s = 0; s < seriesBuilders.length; s = s + 1) {
- referencedIndexes = seriesBuilders[s].getReferencedColumnIndexes();
-
- for (i = 0; i < referencedIndexes.length; i = i + 1) {
- freeIndexes[referencedIndexes[i]] = false;
- }
- }
-
- // Collect the values for the free indexes
- for (i = 0; i < freeIndexes.length; i = i + 1) {
- if (freeIndexes[i]) {
- freeIndexValues.push(i);
- }
- }
-
- return freeIndexValues;
- },
-
- /**
- * If a complete callback function is provided in the options, interpret the
- * columns into a Highcharts options object.
- */
- complete: function () {
-
- var columns = this.columns,
- xColumns = [],
- type,
- options = this.options,
- series,
- data,
- i,
- j,
- r,
- seriesIndex,
- chartOptions,
- allSeriesBuilders = [],
- builder,
- freeIndexes,
- typeCol,
- index;
-
- xColumns.length = columns.length;
- if (options.complete || options.afterComplete) {
-
- // Get the names and shift the top row
- for (i = 0; i < columns.length; i++) {
- if (this.headerRow === 0) {
- columns[i].name = columns[i].shift();
- }
- }
-
- // Use the next columns for series
- series = [];
- freeIndexes = this.getFreeIndexes(columns.length, this.valueCount.seriesBuilders);
-
- // Populate defined series
- for (seriesIndex = 0; seriesIndex < this.valueCount.seriesBuilders.length; seriesIndex++) {
- builder = this.valueCount.seriesBuilders[seriesIndex];
-
- // If the builder can be populated with remaining columns, then add it to allBuilders
- if (builder.populateColumns(freeIndexes)) {
- allSeriesBuilders.push(builder);
- }
- }
-
- // Populate dynamic series
- while (freeIndexes.length > 0) {
- builder = new SeriesBuilder();
- builder.addColumnReader(0, 'x');
-
- // Mark index as used (not free)
- index = inArray(0, freeIndexes);
- if (index !== -1) {
- freeIndexes.splice(index, 1);
- }
-
- for (i = 0; i < this.valueCount.global; i++) {
- // Create and add a column reader for the next free column index
- builder.addColumnReader(undefined, this.valueCount.globalPointArrayMap[i]);
- }
-
- // If the builder can be populated with remaining columns, then add it to allBuilders
- if (builder.populateColumns(freeIndexes)) {
- allSeriesBuilders.push(builder);
- }
- }
-
- // Get the data-type from the first series x column
- if (allSeriesBuilders.length > 0 && allSeriesBuilders[0].readers.length > 0) {
- typeCol = columns[allSeriesBuilders[0].readers[0].columnIndex];
- if (typeCol !== undefined) {
- if (typeCol.isDatetime) {
- type = 'datetime';
- } else if (!typeCol.isNumeric) {
- type = 'category';
- }
- }
- }
- // Axis type is category, then the "x" column should be called "name"
- if (type === 'category') {
- for (seriesIndex = 0; seriesIndex < allSeriesBuilders.length; seriesIndex++) {
- builder = allSeriesBuilders[seriesIndex];
- for (r = 0; r < builder.readers.length; r++) {
- if (builder.readers[r].configName === 'x') {
- builder.readers[r].configName = 'name';
- }
- }
- }
- }
-
- // Read data for all builders
- for (seriesIndex = 0; seriesIndex < allSeriesBuilders.length; seriesIndex++) {
- builder = allSeriesBuilders[seriesIndex];
-
- // Iterate down the cells of each column and add data to the series
- data = [];
- for (j = 0; j < columns[0].length; j++) { // TODO: which column's length should we use here
- data[j] = builder.read(columns, j);
- }
-
- // Add the series
- series[seriesIndex] = {
- data: data
- };
- if (builder.name) {
- series[seriesIndex].name = builder.name;
- }
- }
-
-
-
- // Do the callback
- chartOptions = {
- xAxis: {
- type: type
- },
- series: series
- };
- if (options.complete) {
- options.complete(chartOptions);
- }
-
- // The afterComplete hook is used internally to avoid conflict with the externally
- // available complete option.
- if (options.afterComplete) {
- options.afterComplete(chartOptions);
- }
- }
- }
- });
-
- // Register the Data prototype and data function on Highcharts
- Highcharts.Data = Data;
- Highcharts.data = function (options, chartOptions) {
- return new Data(options, chartOptions);
- };
-
- // Extend Chart.init so that the Chart constructor accepts a new configuration
- // option group, data.
- Highcharts.wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, callback) {
- var chart = this;
-
- if (userOptions && userOptions.data) {
- Highcharts.data(Highcharts.extend(userOptions.data, {
-
- afterComplete: function (dataOptions) {
- var i, series;
-
- // Merge series configs
- if (userOptions.hasOwnProperty('series')) {
- if (typeof userOptions.series === 'object') {
- i = Math.max(userOptions.series.length, dataOptions.series.length);
- while (i--) {
- series = userOptions.series[i] || {};
- userOptions.series[i] = Highcharts.merge(series, dataOptions.series[i]);
- }
- } else { // Allow merging in dataOptions.series (#2856)
- delete userOptions.series;
- }
- }
-
- // Do the merge
- userOptions = Highcharts.merge(dataOptions, userOptions);
-
- proceed.call(chart, userOptions, callback);
- }
- }), userOptions);
- } else {
- proceed.call(chart, userOptions, callback);
- }
- });
-
- /**
- * Creates a new SeriesBuilder. A SeriesBuilder consists of a number
- * of ColumnReaders that reads columns and give them a name.
- * Ex: A series builder can be constructed to read column 3 as 'x' and
- * column 7 and 8 as 'y1' and 'y2'.
- * The output would then be points/rows of the form {x: 11, y1: 22, y2: 33}
- *
- * The name of the builder is taken from the second column. In the above
- * example it would be the column with index 7.
- * @constructor
- */
- SeriesBuilder = function () {
- this.readers = [];
- this.pointIsArray = true;
- };
-
- /**
- * Populates readers with column indexes. A reader can be added without
- * a specific index and for those readers the index is taken sequentially
- * from the free columns (this is handled by the ColumnCursor instance).
- * @returns {boolean}
- */
- SeriesBuilder.prototype.populateColumns = function (freeIndexes) {
- var builder = this,
- enoughColumns = true;
-
- // Loop each reader and give it an index if its missing.
- // The freeIndexes.shift() will return undefined if there
- // are no more columns.
- each(builder.readers, function (reader) {
- if (reader.columnIndex === undefined) {
- reader.columnIndex = freeIndexes.shift();
- }
- });
-
- // Now, all readers should have columns mapped. If not
- // then return false to signal that this series should
- // not be added.
- each(builder.readers, function (reader) {
- if (reader.columnIndex === undefined) {
- enoughColumns = false;
- }
- });
-
- return enoughColumns;
- };
-
- /**
- * Reads a row from the dataset and returns a point or array depending
- * on the names of the readers.
- * @param columns
- * @param rowIndex
- * @returns {Array | Object}
- */
- SeriesBuilder.prototype.read = function (columns, rowIndex) {
- var builder = this,
- pointIsArray = builder.pointIsArray,
- point = pointIsArray ? [] : {},
- columnIndexes;
-
- // Loop each reader and ask it to read its value.
- // Then, build an array or point based on the readers names.
- each(builder.readers, function (reader) {
- var value = columns[reader.columnIndex][rowIndex];
- if (pointIsArray) {
- point.push(value);
- } else {
- point[reader.configName] = value;
- }
- });
-
- // The name comes from the first column (excluding the x column)
- if (this.name === undefined && builder.readers.length >= 2) {
- columnIndexes = builder.getReferencedColumnIndexes();
- if (columnIndexes.length >= 2) {
- // remove the first one (x col)
- columnIndexes.shift();
-
- // Sort the remaining
- columnIndexes.sort();
-
- // Now use the lowest index as name column
- this.name = columns[columnIndexes.shift()].name;
- }
- }
-
- return point;
- };
-
- /**
- * Creates and adds ColumnReader from the given columnIndex and configName.
- * ColumnIndex can be undefined and in that case the reader will be given
- * an index when columns are populated.
- * @param columnIndex {Number | undefined}
- * @param configName
- */
- SeriesBuilder.prototype.addColumnReader = function (columnIndex, configName) {
- this.readers.push({
- columnIndex: columnIndex,
- configName: configName
- });
-
- if (!(configName === 'x' || configName === 'y' || configName === undefined)) {
- this.pointIsArray = false;
- }
- };
-
- /**
- * Returns an array of column indexes that the builder will use when
- * reading data.
- * @returns {Array}
- */
- SeriesBuilder.prototype.getReferencedColumnIndexes = function () {
- var i,
- referencedColumnIndexes = [],
- columnReader;
-
- for (i = 0; i < this.readers.length; i = i + 1) {
- columnReader = this.readers[i];
- if (columnReader.columnIndex !== undefined) {
- referencedColumnIndexes.push(columnReader.columnIndex);
- }
- }
-
- return referencedColumnIndexes;
- };
-
- /**
- * Returns true if the builder has a reader for the given configName.
- * @param configName
- * @returns {boolean}
- */
- SeriesBuilder.prototype.hasReader = function (configName) {
- var i, columnReader;
- for (i = 0; i < this.readers.length; i = i + 1) {
- columnReader = this.readers[i];
- if (columnReader.configName === configName) {
- return true;
- }
- }
- // Else return undefined
- };
-
-
-
-}(Highcharts));
diff --git a/html/includes/js/modules/drilldown.src.js b/html/includes/js/modules/drilldown.src.js
deleted file mode 100644
index cd3522c..0000000
--- a/html/includes/js/modules/drilldown.src.js
+++ /dev/null
@@ -1,606 +0,0 @@
-/**
- * Highcharts Drilldown plugin
- *
- * Author: Torstein Honsi
- * License: MIT License
- *
- * Demo: http://jsfiddle.net/highcharts/Vf3yT/
- */
-
-/*global HighchartsAdapter*/
-(function (H) {
-
- "use strict";
-
- var noop = function () {},
- defaultOptions = H.getOptions(),
- each = H.each,
- extend = H.extend,
- format = H.format,
- pick = H.pick,
- wrap = H.wrap,
- Chart = H.Chart,
- seriesTypes = H.seriesTypes,
- PieSeries = seriesTypes.pie,
- ColumnSeries = seriesTypes.column,
- fireEvent = HighchartsAdapter.fireEvent,
- inArray = HighchartsAdapter.inArray,
- dupes = [];
-
- // Utilities
- function tweenColors(startColor, endColor, pos) {
- var rgba = [
- Math.round(startColor[0] + (endColor[0] - startColor[0]) * pos),
- Math.round(startColor[1] + (endColor[1] - startColor[1]) * pos),
- Math.round(startColor[2] + (endColor[2] - startColor[2]) * pos),
- startColor[3] + (endColor[3] - startColor[3]) * pos
- ];
- return 'rgba(' + rgba.join(',') + ')';
- }
-
- // Add language
- extend(defaultOptions.lang, {
- drillUpText: '◁ Back to {series.name}'
- });
- defaultOptions.drilldown = {
- activeAxisLabelStyle: {
- cursor: 'pointer',
- color: '#0d233a',
- fontWeight: 'bold',
- textDecoration: 'underline'
- },
- activeDataLabelStyle: {
- cursor: 'pointer',
- color: '#0d233a',
- fontWeight: 'bold',
- textDecoration: 'underline'
- },
- animation: {
- duration: 500
- },
- drillUpButton: {
- position: {
- align: 'right',
- x: -10,
- y: 10
- }
- // relativeTo: 'plotBox'
- // theme
- }
- };
-
- /**
- * A general fadeIn method
- */
- H.SVGRenderer.prototype.Element.prototype.fadeIn = function (animation) {
- this
- .attr({
- opacity: 0.1,
- visibility: 'inherit'
- })
- .animate({
- opacity: pick(this.newOpacity, 1) // newOpacity used in maps
- }, animation || {
- duration: 250
- });
- };
-
- Chart.prototype.addSeriesAsDrilldown = function (point, ddOptions) {
- this.addSingleSeriesAsDrilldown(point, ddOptions);
- this.applyDrilldown();
- };
- Chart.prototype.addSingleSeriesAsDrilldown = function (point, ddOptions) {
- var oldSeries = point.series,
- xAxis = oldSeries.xAxis,
- yAxis = oldSeries.yAxis,
- newSeries,
- color = point.color || oldSeries.color,
- pointIndex,
- levelSeries = [],
- levelSeriesOptions = [],
- level,
- levelNumber;
-
- levelNumber = oldSeries.levelNumber || 0;
-
- ddOptions = extend({
- color: color
- }, ddOptions);
- pointIndex = inArray(point, oldSeries.points);
-
- // Record options for all current series
- each(oldSeries.chart.series, function (series) {
- if (series.xAxis === xAxis) {
- levelSeries.push(series);
- levelSeriesOptions.push(series.userOptions);
- series.levelNumber = series.levelNumber || levelNumber; // #3182
- }
- });
-
- // Add a record of properties for each drilldown level
- level = {
- levelNumber: levelNumber,
- seriesOptions: oldSeries.userOptions,
- levelSeriesOptions: levelSeriesOptions,
- levelSeries: levelSeries,
- shapeArgs: point.shapeArgs,
- bBox: point.graphic.getBBox(),
- color: color,
- lowerSeriesOptions: ddOptions,
- pointOptions: oldSeries.options.data[pointIndex],
- pointIndex: pointIndex,
- oldExtremes: {
- xMin: xAxis && xAxis.userMin,
- xMax: xAxis && xAxis.userMax,
- yMin: yAxis && yAxis.userMin,
- yMax: yAxis && yAxis.userMax
- }
- };
-
- // Generate and push it to a lookup array
- if (!this.drilldownLevels) {
- this.drilldownLevels = [];
- }
- this.drilldownLevels.push(level);
-
- newSeries = level.lowerSeries = this.addSeries(ddOptions, false);
- newSeries.levelNumber = levelNumber + 1;
- if (xAxis) {
- xAxis.oldPos = xAxis.pos;
- xAxis.userMin = xAxis.userMax = null;
- yAxis.userMin = yAxis.userMax = null;
- }
-
- // Run fancy cross-animation on supported and equal types
- if (oldSeries.type === newSeries.type) {
- newSeries.animate = newSeries.animateDrilldown || noop;
- newSeries.options.animation = true;
- }
- };
-
- Chart.prototype.applyDrilldown = function () {
- var drilldownLevels = this.drilldownLevels,
- levelToRemove;
-
- if (drilldownLevels && drilldownLevels.length > 0) { // #3352, async loading
- levelToRemove = drilldownLevels[drilldownLevels.length - 1].levelNumber;
- each(this.drilldownLevels, function (level) {
- if (level.levelNumber === levelToRemove) {
- each(level.levelSeries, function (series) {
- if (series.levelNumber === levelToRemove) { // Not removed, not added as part of a multi-series drilldown
- series.remove(false);
- }
- });
- }
- });
- }
-
- this.redraw();
- this.showDrillUpButton();
- };
-
- Chart.prototype.getDrilldownBackText = function () {
- var drilldownLevels = this.drilldownLevels,
- lastLevel;
- if (drilldownLevels && drilldownLevels.length > 0) { // #3352, async loading
- lastLevel = drilldownLevels[drilldownLevels.length - 1];
- lastLevel.series = lastLevel.seriesOptions;
- return format(this.options.lang.drillUpText, lastLevel);
- }
-
- };
-
- Chart.prototype.showDrillUpButton = function () {
- var chart = this,
- backText = this.getDrilldownBackText(),
- buttonOptions = chart.options.drilldown.drillUpButton,
- attr,
- states;
-
-
- if (!this.drillUpButton) {
- attr = buttonOptions.theme;
- states = attr && attr.states;
-
- this.drillUpButton = this.renderer.button(
- backText,
- null,
- null,
- function () {
- chart.drillUp();
- },
- attr,
- states && states.hover,
- states && states.select
- )
- .attr({
- align: buttonOptions.position.align,
- zIndex: 9
- })
- .add()
- .align(buttonOptions.position, false, buttonOptions.relativeTo || 'plotBox');
- } else {
- this.drillUpButton.attr({
- text: backText
- })
- .align();
- }
- };
-
- Chart.prototype.drillUp = function () {
- var chart = this,
- drilldownLevels = chart.drilldownLevels,
- levelNumber = drilldownLevels[drilldownLevels.length - 1].levelNumber,
- i = drilldownLevels.length,
- chartSeries = chart.series,
- seriesI = chartSeries.length,
- level,
- oldSeries,
- newSeries,
- oldExtremes,
- addSeries = function (seriesOptions) {
- var addedSeries;
- each(chartSeries, function (series) {
- if (series.userOptions === seriesOptions) {
- addedSeries = series;
- }
- });
-
- addedSeries = addedSeries || chart.addSeries(seriesOptions, false);
- if (addedSeries.type === oldSeries.type && addedSeries.animateDrillupTo) {
- addedSeries.animate = addedSeries.animateDrillupTo;
- }
- if (seriesOptions === level.seriesOptions) {
- newSeries = addedSeries;
- }
- };
-
- while (i--) {
-
- level = drilldownLevels[i];
- if (level.levelNumber === levelNumber) {
- drilldownLevels.pop();
-
- // Get the lower series by reference or id
- oldSeries = level.lowerSeries;
- if (!oldSeries.chart) { // #2786
- while (seriesI--) {
- if (chartSeries[seriesI].options.id === level.lowerSeriesOptions.id) {
- oldSeries = chartSeries[seriesI];
- break;
- }
- }
- }
- oldSeries.xData = []; // Overcome problems with minRange (#2898)
-
- each(level.levelSeriesOptions, addSeries);
-
- fireEvent(chart, 'drillup', { seriesOptions: level.seriesOptions });
-
- if (newSeries.type === oldSeries.type) {
- newSeries.drilldownLevel = level;
- newSeries.options.animation = chart.options.drilldown.animation;
-
- if (oldSeries.animateDrillupFrom) {
- oldSeries.animateDrillupFrom(level);
- }
- }
- newSeries.levelNumber = levelNumber;
-
- oldSeries.remove(false);
-
- // Reset the zoom level of the upper series
- if (newSeries.xAxis) {
- oldExtremes = level.oldExtremes;
- newSeries.xAxis.setExtremes(oldExtremes.xMin, oldExtremes.xMax, false);
- newSeries.yAxis.setExtremes(oldExtremes.yMin, oldExtremes.yMax, false);
- }
- }
- }
-
- this.redraw();
-
- if (this.drilldownLevels.length === 0) {
- this.drillUpButton = this.drillUpButton.destroy();
- } else {
- this.drillUpButton.attr({
- text: this.getDrilldownBackText()
- })
- .align();
- }
-
- dupes.length = []; // #3315
- };
-
-
- ColumnSeries.prototype.supportsDrilldown = true;
-
- /**
- * When drilling up, keep the upper series invisible until the lower series has
- * moved into place
- */
- ColumnSeries.prototype.animateDrillupTo = function (init) {
- if (!init) {
- var newSeries = this,
- level = newSeries.drilldownLevel;
-
- each(this.points, function (point) {
- point.graphic.hide();
- if (point.dataLabel) {
- point.dataLabel.hide();
- }
- if (point.connector) {
- point.connector.hide();
- }
- });
-
-
- // Do dummy animation on first point to get to complete
- setTimeout(function () {
- each(newSeries.points, function (point, i) {
- // Fade in other points
- var verb = i === (level && level.pointIndex) ? 'show' : 'fadeIn',
- inherit = verb === 'show' ? true : undefined;
- point.graphic[verb](inherit);
- if (point.dataLabel) {
- point.dataLabel[verb](inherit);
- }
- if (point.connector) {
- point.connector[verb](inherit);
- }
- });
- }, Math.max(this.chart.options.drilldown.animation.duration - 50, 0));
-
- // Reset
- this.animate = noop;
- }
-
- };
-
- ColumnSeries.prototype.animateDrilldown = function (init) {
- var series = this,
- drilldownLevels = this.chart.drilldownLevels,
- animateFrom = this.chart.drilldownLevels[this.chart.drilldownLevels.length - 1].shapeArgs,
- animationOptions = this.chart.options.drilldown.animation;
-
- if (!init) {
- each(drilldownLevels, function (level) {
- if (series.userOptions === level.lowerSeriesOptions) {
- animateFrom = level.shapeArgs;
- }
- });
-
- animateFrom.x += (this.xAxis.oldPos - this.xAxis.pos);
-
- each(this.points, function (point) {
- if (point.graphic) {
- point.graphic
- .attr(animateFrom)
- .animate(point.shapeArgs, animationOptions);
- }
- if (point.dataLabel) {
- point.dataLabel.fadeIn(animationOptions);
- }
- });
- this.animate = null;
- }
-
- };
-
- /**
- * When drilling up, pull out the individual point graphics from the lower series
- * and animate them into the origin point in the upper series.
- */
- ColumnSeries.prototype.animateDrillupFrom = function (level) {
- var animationOptions = this.chart.options.drilldown.animation,
- group = this.group,
- series = this;
-
- // Cancel mouse events on the series group (#2787)
- each(series.trackerGroups, function (key) {
- if (series[key]) { // we don't always have dataLabelsGroup
- series[key].on('mouseover');
- }
- });
-
-
- delete this.group;
- each(this.points, function (point) {
- var graphic = point.graphic,
- startColor = H.Color(point.color).rgba,
- endColor = H.Color(level.color).rgba,
- complete = function () {
- graphic.destroy();
- if (group) {
- group = group.destroy();
- }
- };
-
- if (graphic) {
-
- delete point.graphic;
-
- if (animationOptions) {
- /*jslint unparam: true*/
- graphic.animate(level.shapeArgs, H.merge(animationOptions, {
- step: function (val, fx) {
- if (fx.prop === 'start' && startColor.length === 4 && endColor.length === 4) {
- this.attr({
- fill: tweenColors(startColor, endColor, fx.pos)
- });
- }
- },
- complete: complete
- }));
- /*jslint unparam: false*/
- } else {
- graphic.attr(level.shapeArgs);
- complete();
- }
- }
- });
- };
-
- if (PieSeries) {
- extend(PieSeries.prototype, {
- supportsDrilldown: true,
- animateDrillupTo: ColumnSeries.prototype.animateDrillupTo,
- animateDrillupFrom: ColumnSeries.prototype.animateDrillupFrom,
-
- animateDrilldown: function (init) {
- var level = this.chart.drilldownLevels[this.chart.drilldownLevels.length - 1],
- animationOptions = this.chart.options.drilldown.animation,
- animateFrom = level.shapeArgs,
- start = animateFrom.start,
- angle = animateFrom.end - start,
- startAngle = angle / this.points.length,
- startColor = H.Color(level.color).rgba;
-
- if (!init) {
- each(this.points, function (point, i) {
- var endColor = H.Color(point.color).rgba;
-
- /*jslint unparam: true*/
- point.graphic
- .attr(H.merge(animateFrom, {
- start: start + i * startAngle,
- end: start + (i + 1) * startAngle
- }))[animationOptions ? 'animate' : 'attr'](point.shapeArgs, H.merge(animationOptions, {
- step: function (val, fx) {
- if (fx.prop === 'start' && startColor.length === 4 && endColor.length === 4) {
- this.attr({
- fill: tweenColors(startColor, endColor, fx.pos)
- });
- }
- }
- }));
- /*jslint unparam: false*/
- });
- this.animate = null;
- }
- }
- });
- }
-
- H.Point.prototype.doDrilldown = function (_holdRedraw) {
- var series = this.series,
- chart = series.chart,
- drilldown = chart.options.drilldown,
- i = (drilldown.series || []).length,
- seriesOptions;
-
- while (i-- && !seriesOptions) {
- if (drilldown.series[i].id === this.drilldown && inArray(this.drilldown, dupes) === -1) {
- seriesOptions = drilldown.series[i];
- dupes.push(this.drilldown);
- }
- }
-
- // Fire the event. If seriesOptions is undefined, the implementer can check for
- // seriesOptions, and call addSeriesAsDrilldown async if necessary.
- fireEvent(chart, 'drilldown', {
- point: this,
- seriesOptions: seriesOptions
- });
-
- if (seriesOptions) {
- if (_holdRedraw) {
- chart.addSingleSeriesAsDrilldown(this, seriesOptions);
- } else {
- chart.addSeriesAsDrilldown(this, seriesOptions);
- }
- }
-
- };
-
- wrap(H.Point.prototype, 'init', function (proceed, series, options, x) {
- var point = proceed.call(this, series, options, x),
- chart = series.chart,
- tick = series.xAxis && series.xAxis.ticks[x],
- tickLabel = tick && tick.label;
-
- if (point.drilldown) {
-
- // Add the click event to the point
- H.addEvent(point, 'click', function () {
- point.doDrilldown();
- });
- /*wrap(point, 'importEvents', function (proceed) { // wrapping importEvents makes point.click event work
- if (!this.hasImportedEvents) {
- proceed.call(this);
- H.addEvent(this, 'click', function () {
- this.doDrilldown();
- });
- }
- });*/
-
- // Make axis labels clickable
- if (tickLabel) {
- if (!tickLabel.basicStyles) {
- tickLabel.basicStyles = H.merge(tickLabel.styles);
- }
- tickLabel
- .addClass('highcharts-drilldown-axis-label')
- .css(chart.options.drilldown.activeAxisLabelStyle)
- .on('click', function () {
- each(tickLabel.ddPoints, function (point) {
- if (point.doDrilldown) {
- point.doDrilldown(true);
- }
- });
- chart.applyDrilldown();
- });
- if (!tickLabel.ddPoints) {
- tickLabel.ddPoints = [];
- }
- tickLabel.ddPoints.push(point);
-
- }
- } else if (tickLabel && tickLabel.basicStyles) {
- tickLabel.styles = {}; // reset for full overwrite of styles
- tickLabel.css(tickLabel.basicStyles);
- }
-
- return point;
- });
-
- wrap(H.Series.prototype, 'drawDataLabels', function (proceed) {
- var css = this.chart.options.drilldown.activeDataLabelStyle;
-
- proceed.call(this);
-
- each(this.points, function (point) {
- if (point.drilldown && point.dataLabel) {
- point.dataLabel
- .attr({
- 'class': 'highcharts-drilldown-data-label'
- })
- .css(css)
- .on('click', function () {
- point.doDrilldown();
- });
- }
- });
- });
-
- // Mark the trackers with a pointer
- var type,
- drawTrackerWrapper = function (proceed) {
- proceed.call(this);
- each(this.points, function (point) {
- if (point.drilldown && point.graphic) {
- point.graphic
- .attr({
- 'class': 'highcharts-drilldown-point'
- })
- .css({ cursor: 'pointer' });
- }
- });
- };
- for (type in seriesTypes) {
- if (seriesTypes[type].prototype.supportsDrilldown) {
- wrap(seriesTypes[type].prototype, 'drawTracker', drawTrackerWrapper);
- }
- }
-
-}(Highcharts));
diff --git a/html/includes/js/modules/exporting.src.js b/html/includes/js/modules/exporting.src.js
deleted file mode 100644
index 2111990..0000000
--- a/html/includes/js/modules/exporting.src.js
+++ /dev/null
@@ -1,719 +0,0 @@
-/**
- * @license Highcharts JS v4.0.4 (2014-09-02)
- * Exporting module
- *
- * (c) 2010-2014 Torstein Honsi
- *
- * License: www.highcharts.com/license
- */
-
-// JSLint options:
-/*global Highcharts, document, window, Math, setTimeout */
-
-(function (Highcharts) { // encapsulate
-
-// create shortcuts
-var Chart = Highcharts.Chart,
- addEvent = Highcharts.addEvent,
- removeEvent = Highcharts.removeEvent,
- createElement = Highcharts.createElement,
- discardElement = Highcharts.discardElement,
- css = Highcharts.css,
- merge = Highcharts.merge,
- each = Highcharts.each,
- extend = Highcharts.extend,
- math = Math,
- mathMax = math.max,
- doc = document,
- win = window,
- isTouchDevice = Highcharts.isTouchDevice,
- M = 'M',
- L = 'L',
- DIV = 'div',
- HIDDEN = 'hidden',
- NONE = 'none',
- PREFIX = 'highcharts-',
- ABSOLUTE = 'absolute',
- PX = 'px',
- UNDEFINED,
- symbols = Highcharts.Renderer.prototype.symbols,
- defaultOptions = Highcharts.getOptions(),
- buttonOffset;
-
- // Add language
- extend(defaultOptions.lang, {
- printChart: 'Print chart',
- downloadPNG: 'Download PNG image',
- downloadJPEG: 'Download JPEG image',
- downloadPDF: 'Download PDF document',
- downloadSVG: 'Download SVG vector image',
- contextButtonTitle: 'Chart context menu'
- });
-
-// Buttons and menus are collected in a separate config option set called 'navigation'.
-// This can be extended later to add control buttons like zoom and pan right click menus.
-defaultOptions.navigation = {
- menuStyle: {
- border: '1px solid #A0A0A0',
- background: '#FFFFFF',
- padding: '5px 0'
- },
- menuItemStyle: {
- padding: '0 10px',
- background: NONE,
- color: '#303030',
- fontSize: isTouchDevice ? '14px' : '11px'
- },
- menuItemHoverStyle: {
- background: '#4572A5',
- color: '#FFFFFF'
- },
-
- buttonOptions: {
- symbolFill: '#E0E0E0',
- symbolSize: 14,
- symbolStroke: '#666',
- symbolStrokeWidth: 3,
- symbolX: 12.5,
- symbolY: 10.5,
- align: 'right',
- buttonSpacing: 3,
- height: 22,
- // text: null,
- theme: {
- fill: 'white', // capture hover
- stroke: 'none'
- },
- verticalAlign: 'top',
- width: 24
- }
-};
-
-
-
-// Add the export related options
-defaultOptions.exporting = {
- //enabled: true,
- //filename: 'chart',
- type: 'image/png',
- url: 'http://export.highcharts.com/',
- //width: undefined,
- //scale: 2
- buttons: {
- contextButton: {
- menuClassName: PREFIX + 'contextmenu',
- //x: -10,
- symbol: 'menu',
- _titleKey: 'contextButtonTitle',
- menuItems: [{
- textKey: 'printChart',
- onclick: function () {
- this.print();
- }
- }, {
- separator: true
- }, {
- textKey: 'downloadPNG',
- onclick: function () {
- this.exportChart();
- }
- }, {
- textKey: 'downloadJPEG',
- onclick: function () {
- this.exportChart({
- type: 'image/jpeg'
- });
- }
- }, {
- textKey: 'downloadPDF',
- onclick: function () {
- this.exportChart({
- type: 'application/pdf'
- });
- }
- }, {
- textKey: 'downloadSVG',
- onclick: function () {
- this.exportChart({
- type: 'image/svg+xml'
- });
- }
- }
- // Enable this block to add "View SVG" to the dropdown menu
- /*
- ,{
-
- text: 'View SVG',
- onclick: function () {
- var svg = this.getSVG()
- .replace(/</g, '\n&lt;')
- .replace(/>/g, '&gt;');
-
- doc.body.innerHTML = '<pre>' + svg + '</pre>';
- }
- } // */
- ]
- }
- }
-};
-
-// Add the Highcharts.post utility
-Highcharts.post = function (url, data, formAttributes) {
- var name,
- form;
-
- // create the form
- form = createElement('form', merge({
- method: 'post',
- action: url,
- enctype: 'multipart/form-data'
- }, formAttributes), {
- display: NONE
- }, doc.body);
-
- // add the data
- for (name in data) {
- createElement('input', {
- type: HIDDEN,
- name: name,
- value: data[name]
- }, null, form);
- }
-
- // submit
- form.submit();
-
- // clean up
- discardElement(form);
-};
-
-extend(Chart.prototype, {
-
- /**
- * Return an SVG representation of the chart
- *
- * @param additionalOptions {Object} Additional chart options for the generated SVG representation
- */
- getSVG: function (additionalOptions) {
- var chart = this,
- chartCopy,
- sandbox,
- svg,
- seriesOptions,
- sourceWidth,
- sourceHeight,
- cssWidth,
- cssHeight,
- options = merge(chart.options, additionalOptions); // copy the options and add extra options
-
- // IE compatibility hack for generating SVG content that it doesn't really understand
- if (!doc.createElementNS) {
- /*jslint unparam: true*//* allow unused parameter ns in function below */
- doc.createElementNS = function (ns, tagName) {
- return doc.createElement(tagName);
- };
- /*jslint unparam: false*/
- }
-
- // create a sandbox where a new chart will be generated
- sandbox = createElement(DIV, null, {
- position: ABSOLUTE,
- top: '-9999em',
- width: chart.chartWidth + PX,
- height: chart.chartHeight + PX
- }, doc.body);
-
- // get the source size
- cssWidth = chart.renderTo.style.width;
- cssHeight = chart.renderTo.style.height;
- sourceWidth = options.exporting.sourceWidth ||
- options.chart.width ||
- (/px$/.test(cssWidth) && parseInt(cssWidth, 10)) ||
- 600;
- sourceHeight = options.exporting.sourceHeight ||
- options.chart.height ||
- (/px$/.test(cssHeight) && parseInt(cssHeight, 10)) ||
- 400;
-
- // override some options
- extend(options.chart, {
- animation: false,
- renderTo: sandbox,
- forExport: true,
- width: sourceWidth,
- height: sourceHeight
- });
- options.exporting.enabled = false; // hide buttons in print
-
- // prepare for replicating the chart
- options.series = [];
- each(chart.series, function (serie) {
- seriesOptions = merge(serie.options, {
- animation: false, // turn off animation
- enableMouseTracking: false,
- showCheckbox: false,
- visible: serie.visible
- });
-
- if (!seriesOptions.isInternal) { // used for the navigator series that has its own option set
- options.series.push(seriesOptions);
- }
- });
-
- // generate the chart copy
- chartCopy = new Highcharts.Chart(options, chart.callback);
-
- // reflect axis extremes in the export
- each(['xAxis', 'yAxis'], function (axisType) {
- each(chart[axisType], function (axis, i) {
- var axisCopy = chartCopy[axisType][i],
- extremes = axis.getExtremes(),
- userMin = extremes.userMin,
- userMax = extremes.userMax;
-
- if (axisCopy && (userMin !== UNDEFINED || userMax !== UNDEFINED)) {
- axisCopy.setExtremes(userMin, userMax, true, false);
- }
- });
- });
-
- // get the SVG from the container's innerHTML
- svg = chartCopy.container.innerHTML;
-
- // free up memory
- options = null;
- chartCopy.destroy();
- discardElement(sandbox);
-
- // sanitize
- svg = svg
- .replace(/zIndex="[^"]+"/g, '')
- .replace(/isShadow="[^"]+"/g, '')
- .replace(/symbolName="[^"]+"/g, '')
- .replace(/jQuery[0-9]+="[^"]+"/g, '')
- .replace(/url\([^#]+#/g, 'url(#')
- .replace(/<svg /, '<svg xmlns:xlink="http://www.w3.org/1999/xlink" ')
- .replace(/ href=/g, ' xlink:href=')
- .replace(/\n/, ' ')
- // Any HTML added to the container after the SVG (#894)
- .replace(/<\/svg>.*?$/, '</svg>')
- // Batik doesn't support rgba fills and strokes (#3095)
- .replace(/(fill|stroke)="rgba\(([ 0-9]+,[ 0-9]+,[ 0-9]+),([ 0-9\.]+)\)"/g, '$1="rgb($2)" $1-opacity="$3"')
- /* This fails in IE < 8
- .replace(/([0-9]+)\.([0-9]+)/g, function(s1, s2, s3) { // round off to save weight
- return s2 +'.'+ s3[0];
- })*/
-
- // Replace HTML entities, issue #347
- .replace(/&nbsp;/g, '\u00A0') // no-break space
- .replace(/&shy;/g, '\u00AD') // soft hyphen
-
- // IE specific
- .replace(/<IMG /g, '<image ')
- .replace(/height=([^" ]+)/g, 'height="$1"')
- .replace(/width=([^" ]+)/g, 'width="$1"')
- .replace(/hc-svg-href="([^"]+)">/g, 'xlink:href="$1"/>')
- .replace(/id=([^" >]+)/g, 'id="$1"')
- .replace(/class=([^" >]+)/g, 'class="$1"')
- .replace(/ transform /g, ' ')
- .replace(/:(path|rect)/g, '$1')
- .replace(/style="([^"]+)"/g, function (s) {
- return s.toLowerCase();
- });
-
- // IE9 beta bugs with innerHTML. Test again with final IE9.
- svg = svg.replace(/(url\(#highcharts-[0-9]+)&quot;/g, '$1')
- .replace(/&quot;/g, "'");
-
- return svg;
- },
-
- /**
- * Submit the SVG representation of the chart to the server
- * @param {Object} options Exporting options. Possible members are url, type, width and formAttributes.
- * @param {Object} chartOptions Additional chart options for the SVG representation of the chart
- */
- exportChart: function (options, chartOptions) {
- options = options || {};
-
- var chart = this,
- chartExportingOptions = chart.options.exporting,
- svg = chart.getSVG(merge(
- { chart: { borderRadius: 0 } },
- chartExportingOptions.chartOptions,
- chartOptions,
- {
- exporting: {
- sourceWidth: options.sourceWidth || chartExportingOptions.sourceWidth,
- sourceHeight: options.sourceHeight || chartExportingOptions.sourceHeight
- }
- }
- ));
-
- // merge the options
- options = merge(chart.options.exporting, options);
-
- // do the post
- Highcharts.post(options.url, {
- filename: options.filename || 'chart',
- type: options.type,
- width: options.width || 0, // IE8 fails to post undefined correctly, so use 0
- scale: options.scale || 2,
- svg: svg
- }, options.formAttributes);
-
- },
-
- /**
- * Print the chart
- */
- print: function () {
-
- var chart = this,
- container = chart.container,
- origDisplay = [],
- origParent = container.parentNode,
- body = doc.body,
- childNodes = body.childNodes;
-
- if (chart.isPrinting) { // block the button while in printing mode
- return;
- }
-
- chart.isPrinting = true;
-
- // hide all body content
- each(childNodes, function (node, i) {
- if (node.nodeType === 1) {
- origDisplay[i] = node.style.display;
- node.style.display = NONE;
- }
- });
-
- // pull out the chart
- body.appendChild(container);
-
- // print
- win.focus(); // #1510
- win.print();
-
- // allow the browser to prepare before reverting
- setTimeout(function () {
-
- // put the chart back in
- origParent.appendChild(container);
-
- // restore all body content
- each(childNodes, function (node, i) {
- if (node.nodeType === 1) {
- node.style.display = origDisplay[i];
- }
- });
-
- chart.isPrinting = false;
-
- }, 1000);
-
- },
-
- /**
- * Display a popup menu for choosing the export type
- *
- * @param {String} className An identifier for the menu
- * @param {Array} items A collection with text and onclicks for the items
- * @param {Number} x The x position of the opener button
- * @param {Number} y The y position of the opener button
- * @param {Number} width The width of the opener button
- * @param {Number} height The height of the opener button
- */
- contextMenu: function (className, items, x, y, width, height, button) {
- var chart = this,
- navOptions = chart.options.navigation,
- menuItemStyle = navOptions.menuItemStyle,
- chartWidth = chart.chartWidth,
- chartHeight = chart.chartHeight,
- cacheName = 'cache-' + className,
- menu = chart[cacheName],
- menuPadding = mathMax(width, height), // for mouse leave detection
- boxShadow = '3px 3px 10px #888',
- innerMenu,
- hide,
- hideTimer,
- menuStyle,
- docMouseUpHandler = function (e) {
- if (!chart.pointer.inClass(e.target, className)) {
- hide();
- }
- };
-
- // create the menu only the first time
- if (!menu) {
-
- // create a HTML element above the SVG
- chart[cacheName] = menu = createElement(DIV, {
- className: className
- }, {
- position: ABSOLUTE,
- zIndex: 1000,
- padding: menuPadding + PX
- }, chart.container);
-
- innerMenu = createElement(DIV, null,
- extend({
- MozBoxShadow: boxShadow,
- WebkitBoxShadow: boxShadow,
- boxShadow: boxShadow
- }, navOptions.menuStyle), menu);
-
- // hide on mouse out
- hide = function () {
- css(menu, { display: NONE });
- if (button) {
- button.setState(0);
- }
- chart.openMenu = false;
- };
-
- // Hide the menu some time after mouse leave (#1357)
- addEvent(menu, 'mouseleave', function () {
- hideTimer = setTimeout(hide, 500);
- });
- addEvent(menu, 'mouseenter', function () {
- clearTimeout(hideTimer);
- });
-
-
- // Hide it on clicking or touching outside the menu (#2258, #2335, #2407)
- addEvent(document, 'mouseup', docMouseUpHandler);
- addEvent(chart, 'destroy', function () {
- removeEvent(document, 'mouseup', docMouseUpHandler);
- });
-
-
- // create the items
- each(items, function (item) {
- if (item) {
- var element = item.separator ?
- createElement('hr', null, null, innerMenu) :
- createElement(DIV, {
- onmouseover: function () {
- css(this, navOptions.menuItemHoverStyle);
- },
- onmouseout: function () {
- css(this, menuItemStyle);
- },
- onclick: function () {
- hide();
- item.onclick.apply(chart, arguments);
- },
- innerHTML: item.text || chart.options.lang[item.textKey]
- }, extend({
- cursor: 'pointer'
- }, menuItemStyle), innerMenu);
-
-
- // Keep references to menu divs to be able to destroy them
- chart.exportDivElements.push(element);
- }
- });
-
- // Keep references to menu and innerMenu div to be able to destroy them
- chart.exportDivElements.push(innerMenu, menu);
-
- chart.exportMenuWidth = menu.offsetWidth;
- chart.exportMenuHeight = menu.offsetHeight;
- }
-
- menuStyle = { display: 'block' };
-
- // if outside right, right align it
- if (x + chart.exportMenuWidth > chartWidth) {
- menuStyle.right = (chartWidth - x - width - menuPadding) + PX;
- } else {
- menuStyle.left = (x - menuPadding) + PX;
- }
- // if outside bottom, bottom align it
- if (y + height + chart.exportMenuHeight > chartHeight && button.alignOptions.verticalAlign !== 'top') {
- menuStyle.bottom = (chartHeight - y - menuPadding) + PX;
- } else {
- menuStyle.top = (y + height - menuPadding) + PX;
- }
-
- css(menu, menuStyle);
- chart.openMenu = true;
- },
-
- /**
- * Add the export button to the chart
- */
- addButton: function (options) {
- var chart = this,
- renderer = chart.renderer,
- btnOptions = merge(chart.options.navigation.buttonOptions, options),
- onclick = btnOptions.onclick,
- menuItems = btnOptions.menuItems,
- symbol,
- button,
- symbolAttr = {
- stroke: btnOptions.symbolStroke,
- fill: btnOptions.symbolFill
- },
- symbolSize = btnOptions.symbolSize || 12;
- if (!chart.btnCount) {
- chart.btnCount = 0;
- }
-
- // Keeps references to the button elements
- if (!chart.exportDivElements) {
- chart.exportDivElements = [];
- chart.exportSVGElements = [];
- }
-
- if (btnOptions.enabled === false) {
- return;
- }
-
-
- var attr = btnOptions.theme,
- states = attr.states,
- hover = states && states.hover,
- select = states && states.select,
- callback;
-
- delete attr.states;
-
- if (onclick) {
- callback = function () {
- onclick.apply(chart, arguments);
- };
-
- } else if (menuItems) {
- callback = function () {
- chart.contextMenu(
- button.menuClassName,
- menuItems,
- button.translateX,
- button.translateY,
- button.width,
- button.height,
- button
- );
- button.setState(2);
- };
- }
-
-
- if (btnOptions.text && btnOptions.symbol) {
- attr.paddingLeft = Highcharts.pick(attr.paddingLeft, 25);
-
- } else if (!btnOptions.text) {
- extend(attr, {
- width: btnOptions.width,
- height: btnOptions.height,
- padding: 0
- });
- }
-
- button = renderer.button(btnOptions.text, 0, 0, callback, attr, hover, select)
- .attr({
- title: chart.options.lang[btnOptions._titleKey],
- 'stroke-linecap': 'round'
- });
- button.menuClassName = options.menuClassName || PREFIX + 'menu-' + chart.btnCount++;
-
- if (btnOptions.symbol) {
- symbol = renderer.symbol(
- btnOptions.symbol,
- btnOptions.symbolX - (symbolSize / 2),
- btnOptions.symbolY - (symbolSize / 2),
- symbolSize,
- symbolSize
- )
- .attr(extend(symbolAttr, {
- 'stroke-width': btnOptions.symbolStrokeWidth || 1,
- zIndex: 1
- })).add(button);
- }
-
- button.add()
- .align(extend(btnOptions, {
- width: button.width,
- x: Highcharts.pick(btnOptions.x, buttonOffset) // #1654
- }), true, 'spacingBox');
-
- buttonOffset += (button.width + btnOptions.buttonSpacing) * (btnOptions.align === 'right' ? -1 : 1);
-
- chart.exportSVGElements.push(button, symbol);
-
- },
-
- /**
- * Destroy the buttons.
- */
- destroyExport: function (e) {
- var chart = e.target,
- i,
- elem;
-
- // Destroy the extra buttons added
- for (i = 0; i < chart.exportSVGElements.length; i++) {
- elem = chart.exportSVGElements[i];
-
- // Destroy and null the svg/vml elements
- if (elem) { // #1822
- elem.onclick = elem.ontouchstart = null;
- chart.exportSVGElements[i] = elem.destroy();
- }
- }
-
- // Destroy the divs for the menu
- for (i = 0; i < chart.exportDivElements.length; i++) {
- elem = chart.exportDivElements[i];
-
- // Remove the event handler
- removeEvent(elem, 'mouseleave');
-
- // Remove inline events
- chart.exportDivElements[i] = elem.onmouseout = elem.onmouseover = elem.ontouchstart = elem.onclick = null;
-
- // Destroy the div by moving to garbage bin
- discardElement(elem);
- }
- }
-});
-
-
-symbols.menu = function (x, y, width, height) {
- var arr = [
- M, x, y + 2.5,
- L, x + width, y + 2.5,
- M, x, y + height / 2 + 0.5,
- L, x + width, y + height / 2 + 0.5,
- M, x, y + height - 1.5,
- L, x + width, y + height - 1.5
- ];
- return arr;
-};
-
-// Add the buttons on chart load
-Chart.prototype.callbacks.push(function (chart) {
- var n,
- exportingOptions = chart.options.exporting,
- buttons = exportingOptions.buttons;
-
- buttonOffset = 0;
-
- if (exportingOptions.enabled !== false) {
-
- for (n in buttons) {
- chart.addButton(buttons[n]);
- }
-
- // Destroy the export elements at chart destroy
- addEvent(chart, 'destroy', chart.destroyExport);
- }
-
-});
-
-
-}(Highcharts));
diff --git a/html/includes/js/modules/funnel.src.js b/html/includes/js/modules/funnel.src.js
deleted file mode 100644
index 102d0ad..0000000
--- a/html/includes/js/modules/funnel.src.js
+++ /dev/null
@@ -1,310 +0,0 @@
-/**
- * @license
- * Highcharts funnel module
- *
- * (c) 2010-2014 Torstein Honsi
- *
- * License: www.highcharts.com/license
- */
-
-/*global Highcharts */
-(function (Highcharts) {
-
-'use strict';
-
-// create shortcuts
-var defaultOptions = Highcharts.getOptions(),
- defaultPlotOptions = defaultOptions.plotOptions,
- seriesTypes = Highcharts.seriesTypes,
- merge = Highcharts.merge,
- noop = function () {},
- each = Highcharts.each;
-
-// set default options
-defaultPlotOptions.funnel = merge(defaultPlotOptions.pie, {
- animation: false,
- center: ['50%', '50%'],
- width: '90%',
- neckWidth: '30%',
- height: '100%',
- neckHeight: '25%',
- reversed: false,
- dataLabels: {
- //position: 'right',
- connectorWidth: 1,
- connectorColor: '#606060'
- },
- size: true, // to avoid adapting to data label size in Pie.drawDataLabels
- states: {
- select: {
- color: '#C0C0C0',
- borderColor: '#000000',
- shadow: false
- }
- }
-});
-
-
-seriesTypes.funnel = Highcharts.extendClass(seriesTypes.pie, {
-
- type: 'funnel',
- animate: noop,
- singularTooltips: true,
-
- /**
- * Overrides the pie translate method
- */
- translate: function () {
-
- var
- // Get positions - either an integer or a percentage string must be given
- getLength = function (length, relativeTo) {
- return (/%$/).test(length) ?
- relativeTo * parseInt(length, 10) / 100 :
- parseInt(length, 10);
- },
-
- sum = 0,
- series = this,
- chart = series.chart,
- options = series.options,
- reversed = options.reversed,
- plotWidth = chart.plotWidth,
- plotHeight = chart.plotHeight,
- cumulative = 0, // start at top
- center = options.center,
- centerX = getLength(center[0], plotWidth),
- centerY = getLength(center[1], plotHeight),
- width = getLength(options.width, plotWidth),
- tempWidth,
- getWidthAt,
- height = getLength(options.height, plotHeight),
- neckWidth = getLength(options.neckWidth, plotWidth),
- neckHeight = getLength(options.neckHeight, plotHeight),
- neckY = height - neckHeight,
- data = series.data,
- path,
- fraction,
- half = options.dataLabels.position === 'left' ? 1 : 0,
-
- x1,
- y1,
- x2,
- x3,
- y3,
- x4,
- y5;
-
- // Return the width at a specific y coordinate
- series.getWidthAt = getWidthAt = function (y) {
- return y > height - neckHeight || height === neckHeight ?
- neckWidth :
- neckWidth + (width - neckWidth) * ((height - neckHeight - y) / (height - neckHeight));
- };
- series.getX = function (y, half) {
- return centerX + (half ? -1 : 1) * ((getWidthAt(reversed ? plotHeight - y : y) / 2) + options.dataLabels.distance);
- };
-
- // Expose
- series.center = [centerX, centerY, height];
- series.centerX = centerX;
-
- /*
- * Individual point coordinate naming:
- *
- * x1,y1 _________________ x2,y1
- * \ /
- * \ /
- * \ /
- * \ /
- * \ /
- * x3,y3 _________ x4,y3
- *
- * Additional for the base of the neck:
- *
- * | |
- * | |
- * | |
- * x3,y5 _________ x4,y5
- */
-
-
-
-
- // get the total sum
- each(data, function (point) {
- sum += point.y;
- });
-
- each(data, function (point) {
- // set start and end positions
- y5 = null;
- fraction = sum ? point.y / sum : 0;
- y1 = centerY - height / 2 + cumulative * height;
- y3 = y1 + fraction * height;
- //tempWidth = neckWidth + (width - neckWidth) * ((height - neckHeight - y1) / (height - neckHeight));
- tempWidth = getWidthAt(y1);
- x1 = centerX - tempWidth / 2;
- x2 = x1 + tempWidth;
- tempWidth = getWidthAt(y3);
- x3 = centerX - tempWidth / 2;
- x4 = x3 + tempWidth;
-
- // the entire point is within the neck
- if (y1 > neckY) {
- x1 = x3 = centerX - neckWidth / 2;
- x2 = x4 = centerX + neckWidth / 2;
-
- // the base of the neck
- } else if (y3 > neckY) {
- y5 = y3;
-
- tempWidth = getWidthAt(neckY);
- x3 = centerX - tempWidth / 2;
- x4 = x3 + tempWidth;
-
- y3 = neckY;
- }
-
- if (reversed) {
- y1 = height - y1;
- y3 = height - y3;
- y5 = (y5 ? height - y5 : null);
- }
- // save the path
- path = [
- 'M',
- x1, y1,
- 'L',
- x2, y1,
- x4, y3
- ];
- if (y5) {
- path.push(x4, y5, x3, y5);
- }
- path.push(x3, y3, 'Z');
-
- // prepare for using shared dr
- point.shapeType = 'path';
- point.shapeArgs = { d: path };
-
-
- // for tooltips and data labels
- point.percentage = fraction * 100;
- point.plotX = centerX;
- point.plotY = (y1 + (y5 || y3)) / 2;
-
- // Placement of tooltips and data labels
- point.tooltipPos = [
- centerX,
- point.plotY
- ];
-
- // Slice is a noop on funnel points
- point.slice = noop;
-
- // Mimicking pie data label placement logic
- point.half = half;
-
- cumulative += fraction;
- });
- },
- /**
- * Draw a single point (wedge)
- * @param {Object} point The point object
- * @param {Object} color The color of the point
- * @param {Number} brightness The brightness relative to the color
- */
- drawPoints: function () {
- var series = this,
- options = series.options,
- chart = series.chart,
- renderer = chart.renderer;
-
- each(series.data, function (point) {
-
- var graphic = point.graphic,
- shapeArgs = point.shapeArgs;
-
- if (!graphic) { // Create the shapes
- point.graphic = renderer.path(shapeArgs).
- attr({
- fill: point.color,
- stroke: options.borderColor,
- 'stroke-width': options.borderWidth
- }).
- add(series.group);
-
- } else { // Update the shapes
- graphic.animate(shapeArgs);
- }
- });
- },
-
- /**
- * Funnel items don't have angles (#2289)
- */
- sortByAngle: function (points) {
- points.sort(function (a, b) {
- return a.plotY - b.plotY;
- });
- },
-
- /**
- * Extend the pie data label method
- */
- drawDataLabels: function () {
- var data = this.data,
- labelDistance = this.options.dataLabels.distance,
- leftSide,
- sign,
- point,
- i = data.length,
- x,
- y;
-
- // In the original pie label anticollision logic, the slots are distributed
- // from one labelDistance above to one labelDistance below the pie. In funnels
- // we don't want this.
- this.center[2] -= 2 * labelDistance;
-
- // Set the label position array for each point.
- while (i--) {
- point = data[i];
- leftSide = point.half;
- sign = leftSide ? 1 : -1;
- y = point.plotY;
- x = this.getX(y, leftSide);
-
- // set the anchor point for data labels
- point.labelPos = [
- 0, // first break of connector
- y, // a/a
- x + (labelDistance - 5) * sign, // second break, right outside point shape
- y, // a/a
- x + labelDistance * sign, // landing point for connector
- y, // a/a
- leftSide ? 'right' : 'left', // alignment
- 0 // center angle
- ];
- }
-
- seriesTypes.pie.prototype.drawDataLabels.call(this);
- }
-
-});
-
-/**
- * Pyramid series type.
- * A pyramid series is a special type of funnel, without neck and reversed by default.
- */
-defaultOptions.plotOptions.pyramid = Highcharts.merge(defaultOptions.plotOptions.funnel, {
- neckWidth: '0%',
- neckHeight: '0%',
- reversed: true
-});
-Highcharts.seriesTypes.pyramid = Highcharts.extendClass(Highcharts.seriesTypes.funnel, {
- type: 'pyramid'
-});
-
-}(Highcharts));
diff --git a/html/includes/js/modules/heatmap.src.js b/html/includes/js/modules/heatmap.src.js
deleted file mode 100644
index 253ca2b..0000000
--- a/html/includes/js/modules/heatmap.src.js
+++ /dev/null
@@ -1,687 +0,0 @@
-/**
- * @license Highcharts JS v4.0.4 (2014-09-02)
- *
- * (c) 2011-2014 Torstein Honsi
- *
- * License: www.highcharts.com/license
- */
-
-/*global HighchartsAdapter*/
-(function (Highcharts) {
-
-
-var UNDEFINED,
- Axis = Highcharts.Axis,
- Chart = Highcharts.Chart,
- Color = Highcharts.Color,
- Legend = Highcharts.Legend,
- LegendSymbolMixin = Highcharts.LegendSymbolMixin,
- Series = Highcharts.Series,
- SVGRenderer = Highcharts.SVGRenderer,
-
- defaultOptions = Highcharts.getOptions(),
- each = Highcharts.each,
- extend = Highcharts.extend,
- extendClass = Highcharts.extendClass,
- merge = Highcharts.merge,
- pick = Highcharts.pick,
- numberFormat = Highcharts.numberFormat,
- seriesTypes = Highcharts.seriesTypes,
- wrap = Highcharts.wrap,
- noop = function () {};
-
-
-
-
-/**
- * The ColorAxis object for inclusion in gradient legends
- */
-var ColorAxis = Highcharts.ColorAxis = function () {
- this.isColorAxis = true;
- this.init.apply(this, arguments);
-};
-extend(ColorAxis.prototype, Axis.prototype);
-extend(ColorAxis.prototype, {
- defaultColorAxisOptions: {
- lineWidth: 0,
- gridLineWidth: 1,
- tickPixelInterval: 72,
- startOnTick: true,
- endOnTick: true,
- offset: 0,
- marker: {
- animation: {
- duration: 50
- },
- color: 'gray',
- width: 0.01
- },
- labels: {
- overflow: 'justify'
- },
- minColor: '#EFEFFF',
- maxColor: '#003875',
- tickLength: 5
- },
- init: function (chart, userOptions) {
- var horiz = chart.options.legend.layout !== 'vertical',
- options;
-
- // Build the options
- options = merge(this.defaultColorAxisOptions, {
- side: horiz ? 2 : 1,
- reversed: !horiz
- }, userOptions, {
- isX: horiz,
- opposite: !horiz,
- showEmpty: false,
- title: null,
- isColor: true
- });
-
- Axis.prototype.init.call(this, chart, options);
-
- // Base init() pushes it to the xAxis array, now pop it again
- //chart[this.isXAxis ? 'xAxis' : 'yAxis'].pop();
-
- // Prepare data classes
- if (userOptions.dataClasses) {
- this.initDataClasses(userOptions);
- }
- this.initStops(userOptions);
-
- // Override original axis properties
- this.isXAxis = true;
- this.horiz = horiz;
- this.zoomEnabled = false;
- },
-
- /*
- * Return an intermediate color between two colors, according to pos where 0
- * is the from color and 1 is the to color
- */
- tweenColors: function (from, to, pos) {
- // Check for has alpha, because rgba colors perform worse due to lack of
- // support in WebKit.
- var hasAlpha = (to.rgba[3] !== 1 || from.rgba[3] !== 1);
- return (hasAlpha ? 'rgba(' : 'rgb(') +
- Math.round(to.rgba[0] + (from.rgba[0] - to.rgba[0]) * (1 - pos)) + ',' +
- Math.round(to.rgba[1] + (from.rgba[1] - to.rgba[1]) * (1 - pos)) + ',' +
- Math.round(to.rgba[2] + (from.rgba[2] - to.rgba[2]) * (1 - pos)) +
- (hasAlpha ? (',' + (to.rgba[3] + (from.rgba[3] - to.rgba[3]) * (1 - pos))) : '') + ')';
- },
-
- initDataClasses: function (userOptions) {
- var axis = this,
- chart = this.chart,
- dataClasses,
- colorCounter = 0,
- options = this.options,
- len = userOptions.dataClasses.length;
- this.dataClasses = dataClasses = [];
- this.legendItems = [];
-
- each(userOptions.dataClasses, function (dataClass, i) {
- var colors;
-
- dataClass = merge(dataClass);
- dataClasses.push(dataClass);
- if (!dataClass.color) {
- if (options.dataClassColor === 'category') {
- colors = chart.options.colors;
- dataClass.color = colors[colorCounter++];
- // loop back to zero
- if (colorCounter === colors.length) {
- colorCounter = 0;
- }
- } else {
- dataClass.color = axis.tweenColors(
- Color(options.minColor),
- Color(options.maxColor),
- len < 2 ? 0.5 : i / (len - 1) // #3219
- );
- }
- }
- });
- },
-
- initStops: function (userOptions) {
- this.stops = userOptions.stops || [
- [0, this.options.minColor],
- [1, this.options.maxColor]
- ];
- each(this.stops, function (stop) {
- stop.color = Color(stop[1]);
- });
- },
-
- /**
- * Extend the setOptions method to process extreme colors and color
- * stops.
- */
- setOptions: function (userOptions) {
- Axis.prototype.setOptions.call(this, userOptions);
-
- this.options.crosshair = this.options.marker;
- this.coll = 'colorAxis';
- },
-
- setAxisSize: function () {
- var symbol = this.legendSymbol,
- chart = this.chart,
- x,
- y,
- width,
- height;
-
- if (symbol) {
- this.left = x = symbol.attr('x');
- this.top = y = symbol.attr('y');
- this.width = width = symbol.attr('width');
- this.height = height = symbol.attr('height');
- this.right = chart.chartWidth - x - width;
- this.bottom = chart.chartHeight - y - height;
-
- this.len = this.horiz ? width : height;
- this.pos = this.horiz ? x : y;
- }
- },
-
- /**
- * Translate from a value to a color
- */
- toColor: function (value, point) {
- var pos,
- stops = this.stops,
- from,
- to,
- color,
- dataClasses = this.dataClasses,
- dataClass,
- i;
-
- if (dataClasses) {
- i = dataClasses.length;
- while (i--) {
- dataClass = dataClasses[i];
- from = dataClass.from;
- to = dataClass.to;
- if ((from === UNDEFINED || value >= from) && (to === UNDEFINED || value <= to)) {
- color = dataClass.color;
- if (point) {
- point.dataClass = i;
- }
- break;
- }
- }
-
- } else {
-
- if (this.isLog) {
- value = this.val2lin(value);
- }
- pos = 1 - ((this.max - value) / ((this.max - this.min) || 1));
- i = stops.length;
- while (i--) {
- if (pos > stops[i][0]) {
- break;
- }
- }
- from = stops[i] || stops[i + 1];
- to = stops[i + 1] || from;
-
- // The position within the gradient
- pos = 1 - (to[0] - pos) / ((to[0] - from[0]) || 1);
-
- color = this.tweenColors(
- from.color,
- to.color,
- pos
- );
- }
- return color;
- },
-
- getOffset: function () {
- var group = this.legendGroup,
- sideOffset = this.chart.axisOffset[this.side];
-
- if (group) {
-
- Axis.prototype.getOffset.call(this);
-
- if (!this.axisGroup.parentGroup) {
-
- // Move the axis elements inside the legend group
- this.axisGroup.add(group);
- this.gridGroup.add(group);
- this.labelGroup.add(group);
-
- this.added = true;
- }
- // Reset it to avoid color axis reserving space
- this.chart.axisOffset[this.side] = sideOffset;
- }
- },
-
- /**
- * Create the color gradient
- */
- setLegendColor: function () {
- var grad,
- horiz = this.horiz,
- options = this.options;
-
- grad = horiz ? [0, 0, 1, 0] : [0, 0, 0, 1];
- this.legendColor = {
- linearGradient: { x1: grad[0], y1: grad[1], x2: grad[2], y2: grad[3] },
- stops: options.stops || [
- [0, options.minColor],
- [1, options.maxColor]
- ]
- };
- },
-
- /**
- * The color axis appears inside the legend and has its own legend symbol
- */
- drawLegendSymbol: function (legend, item) {
- var padding = legend.padding,
- legendOptions = legend.options,
- horiz = this.horiz,
- box,
- width = pick(legendOptions.symbolWidth, horiz ? 200 : 12),
- height = pick(legendOptions.symbolHeight, horiz ? 12 : 200),
- labelPadding = pick(legendOptions.labelPadding, horiz ? 16 : 30),
- itemDistance = pick(legendOptions.itemDistance, 10);
-
- this.setLegendColor();
-
- // Create the gradient
- item.legendSymbol = this.chart.renderer.rect(
- 0,
- legend.baseline - 11,
- width,
- height
- ).attr({
- zIndex: 1
- }).add(item.legendGroup);
- box = item.legendSymbol.getBBox();
-
- // Set how much space this legend item takes up
- this.legendItemWidth = width + padding + (horiz ? itemDistance : labelPadding);
- this.legendItemHeight = height + padding + (horiz ? labelPadding : 0);
- },
- /**
- * Fool the legend
- */
- setState: noop,
- visible: true,
- setVisible: noop,
- getSeriesExtremes: function () {
- var series;
- if (this.series.length) {
- series = this.series[0];
- this.dataMin = series.valueMin;
- this.dataMax = series.valueMax;
- }
- },
- drawCrosshair: function (e, point) {
- var newCross = !this.cross,
- plotX = point && point.plotX,
- plotY = point && point.plotY,
- crossPos,
- axisPos = this.pos,
- axisLen = this.len;
-
- if (point) {
- crossPos = this.toPixels(point.value);
- if (crossPos < axisPos) {
- crossPos = axisPos - 2;
- } else if (crossPos > axisPos + axisLen) {
- crossPos = axisPos + axisLen + 2;
- }
-
- point.plotX = crossPos;
- point.plotY = this.len - crossPos;
- Axis.prototype.drawCrosshair.call(this, e, point);
- point.plotX = plotX;
- point.plotY = plotY;
-
- if (!newCross && this.cross) {
- this.cross
- .attr({
- fill: this.crosshair.color
- })
- .add(this.labelGroup);
- }
- }
- },
- getPlotLinePath: function (a, b, c, d, pos) {
- if (pos) { // crosshairs only
- return this.horiz ?
- ['M', pos - 4, this.top - 6, 'L', pos + 4, this.top - 6, pos, this.top, 'Z'] :
- ['M', this.left, pos, 'L', this.left - 6, pos + 6, this.left - 6, pos - 6, 'Z'];
- } else {
- return Axis.prototype.getPlotLinePath.call(this, a, b, c, d);
- }
- },
-
- update: function (newOptions, redraw) {
- each(this.series, function (series) {
- series.isDirtyData = true; // Needed for Axis.update when choropleth colors change
- });
- Axis.prototype.update.call(this, newOptions, redraw);
- if (this.legendItem) {
- this.setLegendColor();
- this.chart.legend.colorizeItem(this, true);
- }
- },
-
- /**
- * Get the legend item symbols for data classes
- */
- getDataClassLegendSymbols: function () {
- var axis = this,
- chart = this.chart,
- legendItems = this.legendItems,
- legendOptions = chart.options.legend,
- valueDecimals = legendOptions.valueDecimals,
- valueSuffix = legendOptions.valueSuffix || '',
- name;
-
- if (!legendItems.length) {
- each(this.dataClasses, function (dataClass, i) {
- var vis = true,
- from = dataClass.from,
- to = dataClass.to;
-
- // Assemble the default name. This can be overridden by legend.options.labelFormatter
- name = '';
- if (from === UNDEFINED) {
- name = '< ';
- } else if (to === UNDEFINED) {
- name = '> ';
- }
- if (from !== UNDEFINED) {
- name += numberFormat(from, valueDecimals) + valueSuffix;
- }
- if (from !== UNDEFINED && to !== UNDEFINED) {
- name += ' - ';
- }
- if (to !== UNDEFINED) {
- name += numberFormat(to, valueDecimals) + valueSuffix;
- }
-
- // Add a mock object to the legend items
- legendItems.push(extend({
- chart: chart,
- name: name,
- options: {},
- drawLegendSymbol: LegendSymbolMixin.drawRectangle,
- visible: true,
- setState: noop,
- setVisible: function () {
- vis = this.visible = !vis;
- each(axis.series, function (series) {
- each(series.points, function (point) {
- if (point.dataClass === i) {
- point.setVisible(vis);
- }
- });
- });
-
- chart.legend.colorizeItem(this, vis);
- }
- }, dataClass));
- });
- }
- return legendItems;
- },
- name: '' // Prevents 'undefined' in legend in IE8
-});
-
-/**
- * Handle animation of the color attributes directly
- */
-each(['fill', 'stroke'], function (prop) {
- HighchartsAdapter.addAnimSetter(prop, function (fx) {
- fx.elem.attr(prop, ColorAxis.prototype.tweenColors(Color(fx.start), Color(fx.end), fx.pos));
- });
-});
-
-/**
- * Extend the chart getAxes method to also get the color axis
- */
-wrap(Chart.prototype, 'getAxes', function (proceed) {
-
- var options = this.options,
- colorAxisOptions = options.colorAxis;
-
- proceed.call(this);
-
- this.colorAxis = [];
- if (colorAxisOptions) {
- proceed = new ColorAxis(this, colorAxisOptions); // Fake assignment for jsLint
- }
-});
-
-
-/**
- * Wrap the legend getAllItems method to add the color axis. This also removes the
- * axis' own series to prevent them from showing up individually.
- */
-wrap(Legend.prototype, 'getAllItems', function (proceed) {
- var allItems = [],
- colorAxis = this.chart.colorAxis[0];
-
- if (colorAxis) {
-
- // Data classes
- if (colorAxis.options.dataClasses) {
- allItems = allItems.concat(colorAxis.getDataClassLegendSymbols());
- // Gradient legend
- } else {
- // Add this axis on top
- allItems.push(colorAxis);
- }
-
- // Don't add the color axis' series
- each(colorAxis.series, function (series) {
- series.options.showInLegend = false;
- });
- }
-
- return allItems.concat(proceed.call(this));
-});/**
- * Mixin for maps and heatmaps
- */
-var colorSeriesMixin = {
-
- pointAttrToOptions: { // mapping between SVG attributes and the corresponding options
- stroke: 'borderColor',
- 'stroke-width': 'borderWidth',
- fill: 'color',
- dashstyle: 'dashStyle'
- },
- pointArrayMap: ['value'],
- axisTypes: ['xAxis', 'yAxis', 'colorAxis'],
- optionalAxis: 'colorAxis',
- trackerGroups: ['group', 'markerGroup', 'dataLabelsGroup'],
- getSymbol: noop,
- parallelArrays: ['x', 'y', 'value'],
- colorKey: 'value',
-
- /**
- * In choropleth maps, the color is a result of the value, so this needs translation too
- */
- translateColors: function () {
- var series = this,
- nullColor = this.options.nullColor,
- colorAxis = this.colorAxis,
- colorKey = this.colorKey;
-
- each(this.data, function (point) {
- var value = point[colorKey],
- color;
-
- color = value === null ? nullColor : (colorAxis && value !== undefined) ? colorAxis.toColor(value, point) : point.color || series.color;
-
- if (color) {
- point.color = color;
- }
- });
- }
-};
-
-
-/**
- * Wrap the buildText method and add the hook for add text stroke
- */
-wrap(SVGRenderer.prototype, 'buildText', function (proceed, wrapper) {
-
- var textStroke = wrapper.styles && wrapper.styles.HcTextStroke;
-
- proceed.call(this, wrapper);
-
- // Apply the text stroke
- if (textStroke && wrapper.applyTextStroke) {
- wrapper.applyTextStroke(textStroke);
- }
-});
-
-/**
- * Apply an outside text stroke to data labels, based on the custom CSS property, HcTextStroke.
- * Consider moving this to Highcharts core, also makes sense on stacked columns etc.
- */
-SVGRenderer.prototype.Element.prototype.applyTextStroke = function (textStroke) {
- var elem = this.element,
- tspans,
- firstChild;
-
- textStroke = textStroke.split(' ');
- tspans = elem.getElementsByTagName('tspan');
- firstChild = elem.firstChild;
-
- // In order to get the right y position of the clones,
- // copy over the y setter
- this.ySetter = this.xSetter;
-
- each([].slice.call(tspans), function (tspan, y) {
- var clone;
- if (y === 0) {
- tspan.setAttribute('x', elem.getAttribute('x'));
- if ((y = elem.getAttribute('y')) !== null) {
- tspan.setAttribute('y', y);
- }
- }
- clone = tspan.cloneNode(1);
- clone.setAttribute('stroke', textStroke[1]);
- clone.setAttribute('stroke-width', textStroke[0]);
- clone.setAttribute('stroke-linejoin', 'round');
- elem.insertBefore(clone, firstChild);
- });
-};
-/**
- * Extend the default options with map options
- */
-defaultOptions.plotOptions.heatmap = merge(defaultOptions.plotOptions.scatter, {
- animation: false,
- borderWidth: 0,
- nullColor: '#F8F8F8',
- dataLabels: {
- formatter: function () { // #2945
- return this.point.value;
- },
- verticalAlign: 'middle',
- crop: false,
- overflow: false,
- style: {
- color: 'white',
- fontWeight: 'bold',
- HcTextStroke: '1px rgba(0,0,0,0.5)'
- }
- },
- marker: null,
- tooltip: {
- pointFormat: '{point.x}, {point.y}: {point.value}<br/>'
- },
- states: {
- normal: {
- animation: true
- },
- hover: {
- brightness: 0.2
- }
- }
-});
-
-// The Heatmap series type
-seriesTypes.heatmap = extendClass(seriesTypes.scatter, merge(colorSeriesMixin, {
- type: 'heatmap',
- pointArrayMap: ['y', 'value'],
- hasPointSpecificOptions: true,
- supportsDrilldown: true,
- getExtremesFromAll: true,
- init: function () {
- seriesTypes.scatter.prototype.init.apply(this, arguments);
- this.pointRange = this.options.colsize || 1;
- this.yAxis.axisPointRange = this.options.rowsize || 1; // general point range
- },
- translate: function () {
- var series = this,
- options = series.options,
- xAxis = series.xAxis,
- yAxis = series.yAxis;
-
- series.generatePoints();
-
- each(series.points, function (point) {
- var xPad = (options.colsize || 1) / 2,
- yPad = (options.rowsize || 1) / 2,
- x1 = Math.round(xAxis.len - xAxis.translate(point.x - xPad, 0, 1, 0, 1)),
- x2 = Math.round(xAxis.len - xAxis.translate(point.x + xPad, 0, 1, 0, 1)),
- y1 = Math.round(yAxis.translate(point.y - yPad, 0, 1, 0, 1)),
- y2 = Math.round(yAxis.translate(point.y + yPad, 0, 1, 0, 1));
-
- // Set plotX and plotY for use in K-D-Tree and more
- point.plotX = (x1 + x2) / 2;
- point.plotY = (y1 + y2) / 2;
-
- point.shapeType = 'rect';
- point.shapeArgs = {
- x: Math.min(x1, x2),
- y: Math.min(y1, y2),
- width: Math.abs(x2 - x1),
- height: Math.abs(y2 - y1)
- };
- });
-
- series.translateColors();
-
- // Make sure colors are updated on colorAxis update (#2893)
- if (this.chart.hasRendered) {
- each(series.points, function (point) {
- point.shapeArgs.fill = point.options.color || point.color; // #3311
- });
- }
- },
- drawPoints: seriesTypes.column.prototype.drawPoints,
- animate: noop,
- getBox: noop,
- drawLegendSymbol: LegendSymbolMixin.drawRectangle,
-
- getExtremes: function () {
- // Get the extremes from the value data
- Series.prototype.getExtremes.call(this, this.valueData);
- this.valueMin = this.dataMin;
- this.valueMax = this.dataMax;
-
- // Get the extremes from the y data
- Series.prototype.getExtremes.call(this);
- }
-
-}));
-
-
-}(Highcharts));
diff --git a/html/includes/js/modules/no-data-to-display.src.js b/html/includes/js/modules/no-data-to-display.src.js
deleted file mode 100644
index 9badd16..0000000
--- a/html/includes/js/modules/no-data-to-display.src.js
+++ /dev/null
@@ -1,130 +0,0 @@
-/**
- * @license Highcharts JS v4.0.4 (2014-09-02)
- * Plugin for displaying a message when there is no data visible in chart.
- *
- * (c) 2010-2014 Highsoft AS
- * Author: Oystein Moseng
- *
- * License: www.highcharts.com/license
- */
-
-(function (H) {
-
- var seriesTypes = H.seriesTypes,
- chartPrototype = H.Chart.prototype,
- defaultOptions = H.getOptions(),
- extend = H.extend;
-
- // Add language option
- extend(defaultOptions.lang, {
- noData: 'No data to display'
- });
-
- // Add default display options for message
- defaultOptions.noData = {
- position: {
- x: 0,
- y: 0,
- align: 'center',
- verticalAlign: 'middle'
- },
- attr: {
- },
- style: {
- fontWeight: 'bold',
- fontSize: '12px',
- color: '#60606a'
- }
- };
-
- /**
- * Define hasData functions for series. These return true if there are data points on this series within the plot area
- */
- function hasDataPie() {
- return !!this.points.length; /* != 0 */
- }
-
- if (seriesTypes.pie) {
- seriesTypes.pie.prototype.hasData = hasDataPie;
- }
-
- if (seriesTypes.gauge) {
- seriesTypes.gauge.prototype.hasData = hasDataPie;
- }
-
- if (seriesTypes.waterfall) {
- seriesTypes.waterfall.prototype.hasData = hasDataPie;
- }
-
- H.Series.prototype.hasData = function () {
- return this.dataMax !== undefined && this.dataMin !== undefined;
- };
-
- /**
- * Display a no-data message.
- *
- * @param {String} str An optional message to show in place of the default one
- */
- chartPrototype.showNoData = function (str) {
- var chart = this,
- options = chart.options,
- text = str || options.lang.noData,
- noDataOptions = options.noData;
-
- if (!chart.noDataLabel) {
- chart.noDataLabel = chart.renderer.label(text, 0, 0, null, null, null, null, null, 'no-data')
- .attr(noDataOptions.attr)
- .css(noDataOptions.style)
- .add();
- chart.noDataLabel.align(extend(chart.noDataLabel.getBBox(), noDataOptions.position), false, 'plotBox');
- }
- };
-
- /**
- * Hide no-data message
- */
- chartPrototype.hideNoData = function () {
- var chart = this;
- if (chart.noDataLabel) {
- chart.noDataLabel = chart.noDataLabel.destroy();
- }
- };
-
- /**
- * Returns true if there are data points within the plot area now
- */
- chartPrototype.hasData = function () {
- var chart = this,
- series = chart.series,
- i = series.length;
-
- while (i--) {
- if (series[i].hasData() && !series[i].options.isInternal) {
- return true;
- }
- }
-
- return false;
- };
-
- /**
- * Show no-data message if there is no data in sight. Otherwise, hide it.
- */
- function handleNoData() {
- var chart = this;
- if (chart.hasData()) {
- chart.hideNoData();
- } else {
- chart.showNoData();
- }
- }
-
- /**
- * Add event listener to handle automatic display of no-data message
- */
- chartPrototype.callbacks.push(function (chart) {
- H.addEvent(chart, 'load', handleNoData);
- H.addEvent(chart, 'redraw', handleNoData);
- });
-
-}(Highcharts));
diff --git a/html/includes/js/modules/solid-gauge.src.js b/html/includes/js/modules/solid-gauge.src.js
deleted file mode 100644
index 6fd14c9..0000000
--- a/html/includes/js/modules/solid-gauge.src.js
+++ /dev/null
@@ -1,234 +0,0 @@
-/**
- * @license Highcharts JS v4.0.4 (2014-09-02)
- * Solid angular gauge module
- *
- * (c) 2010-2014 Torstein Honsi
- *
- * License: www.highcharts.com/license
- */
-
-/*global Highcharts*/
-(function (H) {
- "use strict";
-
- var defaultPlotOptions = H.getOptions().plotOptions,
- pInt = H.pInt,
- pick = H.pick,
- each = H.each,
- colorAxisMethods,
- UNDEFINED;
-
- // The default options
- defaultPlotOptions.solidgauge = H.merge(defaultPlotOptions.gauge, {
- colorByPoint: true
- });
-
-
- // These methods are defined in the ColorAxis object, and copied here.
- // If we implement an AMD system we should make ColorAxis a dependency.
- colorAxisMethods = {
-
-
- initDataClasses: function (userOptions) {
- var axis = this,
- chart = this.chart,
- dataClasses,
- colorCounter = 0,
- options = this.options;
- this.dataClasses = dataClasses = [];
-
- each(userOptions.dataClasses, function (dataClass, i) {
- var colors;
-
- dataClass = H.merge(dataClass);
- dataClasses.push(dataClass);
- if (!dataClass.color) {
- if (options.dataClassColor === 'category') {
- colors = chart.options.colors;
- dataClass.color = colors[colorCounter++];
- // loop back to zero
- if (colorCounter === colors.length) {
- colorCounter = 0;
- }
- } else {
- dataClass.color = axis.tweenColors(H.Color(options.minColor), H.Color(options.maxColor), i / (userOptions.dataClasses.length - 1));
- }
- }
- });
- },
-
- initStops: function (userOptions) {
- this.stops = userOptions.stops || [
- [0, this.options.minColor],
- [1, this.options.maxColor]
- ];
- each(this.stops, function (stop) {
- stop.color = H.Color(stop[1]);
- });
- },
- /**
- * Translate from a value to a color
- */
- toColor: function (value, point) {
- var pos,
- stops = this.stops,
- from,
- to,
- color,
- dataClasses = this.dataClasses,
- dataClass,
- i;
-
- if (dataClasses) {
- i = dataClasses.length;
- while (i--) {
- dataClass = dataClasses[i];
- from = dataClass.from;
- to = dataClass.to;
- if ((from === UNDEFINED || value >= from) && (to === UNDEFINED || value <= to)) {
- color = dataClass.color;
- if (point) {
- point.dataClass = i;
- }
- break;
- }
- }
-
- } else {
-
- if (this.isLog) {
- value = this.val2lin(value);
- }
- pos = 1 - ((this.max - value) / (this.max - this.min));
- i = stops.length;
- while (i--) {
- if (pos > stops[i][0]) {
- break;
- }
- }
- from = stops[i] || stops[i + 1];
- to = stops[i + 1] || from;
-
- // The position within the gradient
- pos = 1 - (to[0] - pos) / ((to[0] - from[0]) || 1);
-
- color = this.tweenColors(
- from.color,
- to.color,
- pos
- );
- }
- return color;
- },
- tweenColors: function (from, to, pos) {
- // Check for has alpha, because rgba colors perform worse due to lack of
- // support in WebKit.
- var hasAlpha = (to.rgba[3] !== 1 || from.rgba[3] !== 1);
-
- if (from.rgba.length === 0 || to.rgba.length === 0) {
- return 'none';
- }
- return (hasAlpha ? 'rgba(' : 'rgb(') +
- Math.round(to.rgba[0] + (from.rgba[0] - to.rgba[0]) * (1 - pos)) + ',' +
- Math.round(to.rgba[1] + (from.rgba[1] - to.rgba[1]) * (1 - pos)) + ',' +
- Math.round(to.rgba[2] + (from.rgba[2] - to.rgba[2]) * (1 - pos)) +
- (hasAlpha ? (',' + (to.rgba[3] + (from.rgba[3] - to.rgba[3]) * (1 - pos))) : '') + ')';
- }
- };
-
- // The series prototype
- H.seriesTypes.solidgauge = H.extendClass(H.seriesTypes.gauge, {
- type: 'solidgauge',
-
- bindAxes: function () {
- var axis;
- H.seriesTypes.gauge.prototype.bindAxes.call(this);
-
- axis = this.yAxis;
- H.extend(axis, colorAxisMethods);
-
- // Prepare data classes
- if (axis.options.dataClasses) {
- axis.initDataClasses(axis.options);
- }
- axis.initStops(axis.options);
- },
-
- /**
- * Draw the points where each point is one needle
- */
- drawPoints: function () {
- var series = this,
- yAxis = series.yAxis,
- center = yAxis.center,
- options = series.options,
- renderer = series.chart.renderer;
-
- H.each(series.points, function (point) {
- var graphic = point.graphic,
- rotation = yAxis.startAngleRad + yAxis.translate(point.y, null, null, null, true),
- radius = (pInt(pick(options.radius, 100)) * center[2]) / 200,
- innerRadius = (pInt(pick(options.innerRadius, 60)) * center[2]) / 200,
- shapeArgs,
- d,
- toColor = yAxis.toColor(point.y, point),
- fromColor;
-
- if (toColor !== 'none') {
- fromColor = point.color;
- point.color = toColor;
- }
-
- // Handle the wrap option
- if (options.wrap === false) {
- rotation = Math.max(yAxis.startAngleRad, Math.min(yAxis.endAngleRad, rotation));
- }
- rotation = rotation * 180 / Math.PI;
-
- var angle1 = rotation / (180 / Math.PI),
- angle2 = yAxis.startAngleRad,
- minAngle = Math.min(angle1, angle2),
- maxAngle = Math.max(angle1, angle2);
-
- if (maxAngle - minAngle > 2 * Math.PI) {
- maxAngle = minAngle + 2 * Math.PI;
- }
-
- shapeArgs = {
- x: center[0],
- y: center[1],
- r: radius,
- innerR: innerRadius,
- start: minAngle,
- end: maxAngle
- };
-
- if (graphic) {
- d = shapeArgs.d;
-
- /*jslint unparam: true*/
- graphic.attr({
- fill: point.color
- }).animate(shapeArgs, {
- step: function (value, fx) {
- graphic.attr('fill', colorAxisMethods.tweenColors(H.Color(fromColor), H.Color(toColor), fx.pos));
- }
- });
- /*jslint unparam: false*/
- shapeArgs.d = d; // animate alters it
- } else {
- point.graphic = renderer.arc(shapeArgs)
- .attr({
- stroke: options.borderColor || 'none',
- 'stroke-width': options.borderWidth || 0,
- fill: point.color,
- 'sweep-flag': 0
- })
- .add(series.group);
- }
- });
- },
- animate: null
- });
-
-}(Highcharts));