annotate src/DML/VendorAssetsBundle/Resources/assets/vega/2.2.6/vega.js @ 0:493bcb69166c

added public content
author Daniel Wolff
date Tue, 09 Feb 2016 20:54:02 +0100
parents
children
rev   line source
Daniel@0 1 (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.vg = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
Daniel@0 2 module.exports = {
Daniel@0 3 version: '2.2.6',
Daniel@0 4 dataflow: require('vega-dataflow'),
Daniel@0 5 parse: require('./src/parse/'),
Daniel@0 6 scene: {
Daniel@0 7 Bounder: require('./src/scene/Bounder'),
Daniel@0 8 Builder: require('./src/scene/Builder'),
Daniel@0 9 Encoder: require('./src/scene/Encoder'),
Daniel@0 10 GroupBuilder: require('./src/scene/GroupBuilder'),
Daniel@0 11 },
Daniel@0 12 transforms: require('./src/transforms'),
Daniel@0 13 schema: require('./src/core/schema'),
Daniel@0 14 config: require('./src/core/config'),
Daniel@0 15 util: require('datalib'),
Daniel@0 16 debug: require('vega-logging').debug
Daniel@0 17 };
Daniel@0 18 },{"./src/core/config":88,"./src/core/schema":89,"./src/parse/":95,"./src/scene/Bounder":107,"./src/scene/Builder":108,"./src/scene/Encoder":109,"./src/scene/GroupBuilder":110,"./src/transforms":139,"datalib":24,"vega-dataflow":39,"vega-logging":45}],2:[function(require,module,exports){
Daniel@0 19
Daniel@0 20 },{}],3:[function(require,module,exports){
Daniel@0 21 (function (global, factory) {
Daniel@0 22 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
Daniel@0 23 typeof define === 'function' && define.amd ? define(['exports'], factory) :
Daniel@0 24 factory((global.dsv = {}));
Daniel@0 25 }(this, function (exports) { 'use strict';
Daniel@0 26
Daniel@0 27 var dsv = function(delimiter) {
Daniel@0 28 var reFormat = new RegExp("[\"" + delimiter + "\n]"),
Daniel@0 29 delimiterCode = delimiter.charCodeAt(0);
Daniel@0 30
Daniel@0 31 function parse(text, f) {
Daniel@0 32 var o;
Daniel@0 33 return parseRows(text, function(row, i) {
Daniel@0 34 if (o) return o(row, i - 1);
Daniel@0 35 var a = new Function("d", "return {" + row.map(function(name, i) {
Daniel@0 36 return JSON.stringify(name) + ": d[" + i + "]";
Daniel@0 37 }).join(",") + "}");
Daniel@0 38 o = f ? function(row, i) { return f(a(row), i); } : a;
Daniel@0 39 });
Daniel@0 40 }
Daniel@0 41
Daniel@0 42 function parseRows(text, f) {
Daniel@0 43 var EOL = {}, // sentinel value for end-of-line
Daniel@0 44 EOF = {}, // sentinel value for end-of-file
Daniel@0 45 rows = [], // output rows
Daniel@0 46 N = text.length,
Daniel@0 47 I = 0, // current character index
Daniel@0 48 n = 0, // the current line number
Daniel@0 49 t, // the current token
Daniel@0 50 eol; // is the current token followed by EOL?
Daniel@0 51
Daniel@0 52 function token() {
Daniel@0 53 if (I >= N) return EOF; // special case: end of file
Daniel@0 54 if (eol) return eol = false, EOL; // special case: end of line
Daniel@0 55
Daniel@0 56 // special case: quotes
Daniel@0 57 var j = I;
Daniel@0 58 if (text.charCodeAt(j) === 34) {
Daniel@0 59 var i = j;
Daniel@0 60 while (i++ < N) {
Daniel@0 61 if (text.charCodeAt(i) === 34) {
Daniel@0 62 if (text.charCodeAt(i + 1) !== 34) break;
Daniel@0 63 ++i;
Daniel@0 64 }
Daniel@0 65 }
Daniel@0 66 I = i + 2;
Daniel@0 67 var c = text.charCodeAt(i + 1);
Daniel@0 68 if (c === 13) {
Daniel@0 69 eol = true;
Daniel@0 70 if (text.charCodeAt(i + 2) === 10) ++I;
Daniel@0 71 } else if (c === 10) {
Daniel@0 72 eol = true;
Daniel@0 73 }
Daniel@0 74 return text.slice(j + 1, i).replace(/""/g, "\"");
Daniel@0 75 }
Daniel@0 76
Daniel@0 77 // common case: find next delimiter or newline
Daniel@0 78 while (I < N) {
Daniel@0 79 var c = text.charCodeAt(I++), k = 1;
Daniel@0 80 if (c === 10) eol = true; // \n
Daniel@0 81 else if (c === 13) { eol = true; if (text.charCodeAt(I) === 10) ++I, ++k; } // \r|\r\n
Daniel@0 82 else if (c !== delimiterCode) continue;
Daniel@0 83 return text.slice(j, I - k);
Daniel@0 84 }
Daniel@0 85
Daniel@0 86 // special case: last token before EOF
Daniel@0 87 return text.slice(j);
Daniel@0 88 }
Daniel@0 89
Daniel@0 90 while ((t = token()) !== EOF) {
Daniel@0 91 var a = [];
Daniel@0 92 while (t !== EOL && t !== EOF) {
Daniel@0 93 a.push(t);
Daniel@0 94 t = token();
Daniel@0 95 }
Daniel@0 96 if (f && (a = f(a, n++)) == null) continue;
Daniel@0 97 rows.push(a);
Daniel@0 98 }
Daniel@0 99
Daniel@0 100 return rows;
Daniel@0 101 }
Daniel@0 102
Daniel@0 103 function format(rows) {
Daniel@0 104 if (Array.isArray(rows[0])) return formatRows(rows); // deprecated; use formatRows
Daniel@0 105 var fieldSet = Object.create(null), fields = [];
Daniel@0 106
Daniel@0 107 // Compute unique fields in order of discovery.
Daniel@0 108 rows.forEach(function(row) {
Daniel@0 109 for (var field in row) {
Daniel@0 110 if (!((field += "") in fieldSet)) {
Daniel@0 111 fields.push(fieldSet[field] = field);
Daniel@0 112 }
Daniel@0 113 }
Daniel@0 114 });
Daniel@0 115
Daniel@0 116 return [fields.map(formatValue).join(delimiter)].concat(rows.map(function(row) {
Daniel@0 117 return fields.map(function(field) {
Daniel@0 118 return formatValue(row[field]);
Daniel@0 119 }).join(delimiter);
Daniel@0 120 })).join("\n");
Daniel@0 121 }
Daniel@0 122
Daniel@0 123 function formatRows(rows) {
Daniel@0 124 return rows.map(formatRow).join("\n");
Daniel@0 125 }
Daniel@0 126
Daniel@0 127 function formatRow(row) {
Daniel@0 128 return row.map(formatValue).join(delimiter);
Daniel@0 129 }
Daniel@0 130
Daniel@0 131 function formatValue(text) {
Daniel@0 132 return reFormat.test(text) ? "\"" + text.replace(/\"/g, "\"\"") + "\"" : text;
Daniel@0 133 }
Daniel@0 134
Daniel@0 135 return {
Daniel@0 136 parse: parse,
Daniel@0 137 parseRows: parseRows,
Daniel@0 138 format: format,
Daniel@0 139 formatRows: formatRows
Daniel@0 140 };
Daniel@0 141 }
Daniel@0 142
Daniel@0 143 exports.csv = dsv(",");
Daniel@0 144 exports.tsv = dsv("\t");
Daniel@0 145
Daniel@0 146 exports.dsv = dsv;
Daniel@0 147
Daniel@0 148 }));
Daniel@0 149 },{}],4:[function(require,module,exports){
Daniel@0 150 if (typeof Map === "undefined") {
Daniel@0 151 Map = function() { this.clear(); };
Daniel@0 152 Map.prototype = {
Daniel@0 153 set: function(k, v) { this._[k] = v; return this; },
Daniel@0 154 get: function(k) { return this._[k]; },
Daniel@0 155 has: function(k) { return k in this._; },
Daniel@0 156 delete: function(k) { return k in this._ && delete this._[k]; },
Daniel@0 157 clear: function() { this._ = Object.create(null); },
Daniel@0 158 get size() { var n = 0; for (var k in this._) ++n; return n; },
Daniel@0 159 forEach: function(c) { for (var k in this._) c(this._[k], k, this); }
Daniel@0 160 };
Daniel@0 161 } else (function() {
Daniel@0 162 var m = new Map;
Daniel@0 163 if (m.set(0, 0) !== m) {
Daniel@0 164 m = m.set;
Daniel@0 165 Map.prototype.set = function() { m.apply(this, arguments); return this; };
Daniel@0 166 }
Daniel@0 167 })();
Daniel@0 168
Daniel@0 169 (function (global, factory) {
Daniel@0 170 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
Daniel@0 171 typeof define === 'function' && define.amd ? define(['exports'], factory) :
Daniel@0 172 factory((global.format = {}));
Daniel@0 173 }(this, function (exports) { 'use strict';
Daniel@0 174
Daniel@0 175 var zhCn = {
Daniel@0 176 decimal: ".",
Daniel@0 177 thousands: ",",
Daniel@0 178 grouping: [3],
Daniel@0 179 currency: ["¥", ""]
Daniel@0 180 };
Daniel@0 181
Daniel@0 182 var ruRu = {
Daniel@0 183 decimal: ",",
Daniel@0 184 thousands: "\xa0",
Daniel@0 185 grouping: [3],
Daniel@0 186 currency: ["", "\xa0руб."]
Daniel@0 187 };
Daniel@0 188
Daniel@0 189 var ptBr = {
Daniel@0 190 decimal: ",",
Daniel@0 191 thousands: ".",
Daniel@0 192 grouping: [3],
Daniel@0 193 currency: ["R$", ""]
Daniel@0 194 };
Daniel@0 195
Daniel@0 196 var plPl = {
Daniel@0 197 decimal: ",",
Daniel@0 198 thousands: ".",
Daniel@0 199 grouping: [3],
Daniel@0 200 currency: ["", "zł"]
Daniel@0 201 };
Daniel@0 202
Daniel@0 203 var nlNl = {
Daniel@0 204 decimal: ",",
Daniel@0 205 thousands: ".",
Daniel@0 206 grouping: [3],
Daniel@0 207 currency: ["€\xa0", ""]
Daniel@0 208 };
Daniel@0 209
Daniel@0 210 var mkMk = {
Daniel@0 211 decimal: ",",
Daniel@0 212 thousands: ".",
Daniel@0 213 grouping: [3],
Daniel@0 214 currency: ["", "\xa0ден."]
Daniel@0 215 };
Daniel@0 216
Daniel@0 217 var jaJp = {
Daniel@0 218 decimal: ".",
Daniel@0 219 thousands: ",",
Daniel@0 220 grouping: [3],
Daniel@0 221 currency: ["", "円"]
Daniel@0 222 };
Daniel@0 223
Daniel@0 224 var itIt = {
Daniel@0 225 decimal: ",",
Daniel@0 226 thousands: ".",
Daniel@0 227 grouping: [3],
Daniel@0 228 currency: ["€", ""]
Daniel@0 229 };
Daniel@0 230
Daniel@0 231 var heIl = {
Daniel@0 232 decimal: ".",
Daniel@0 233 thousands: ",",
Daniel@0 234 grouping: [3],
Daniel@0 235 currency: ["₪", ""]
Daniel@0 236 };
Daniel@0 237
Daniel@0 238 var frFr = {
Daniel@0 239 decimal: ",",
Daniel@0 240 thousands: ".",
Daniel@0 241 grouping: [3],
Daniel@0 242 currency: ["", "\xa0€"]
Daniel@0 243 };
Daniel@0 244
Daniel@0 245 var frCa = {
Daniel@0 246 decimal: ",",
Daniel@0 247 thousands: "\xa0",
Daniel@0 248 grouping: [3],
Daniel@0 249 currency: ["", "$"]
Daniel@0 250 };
Daniel@0 251
Daniel@0 252 var fiFi = {
Daniel@0 253 decimal: ",",
Daniel@0 254 thousands: "\xa0",
Daniel@0 255 grouping: [3],
Daniel@0 256 currency: ["", "\xa0€"]
Daniel@0 257 };
Daniel@0 258
Daniel@0 259 var esEs = {
Daniel@0 260 decimal: ",",
Daniel@0 261 thousands: ".",
Daniel@0 262 grouping: [3],
Daniel@0 263 currency: ["", "\xa0€"]
Daniel@0 264 };
Daniel@0 265
Daniel@0 266 var enUs = {
Daniel@0 267 decimal: ".",
Daniel@0 268 thousands: ",",
Daniel@0 269 grouping: [3],
Daniel@0 270 currency: ["$", ""]
Daniel@0 271 };
Daniel@0 272
Daniel@0 273 var enGb = {
Daniel@0 274 decimal: ".",
Daniel@0 275 thousands: ",",
Daniel@0 276 grouping: [3],
Daniel@0 277 currency: ["£", ""]
Daniel@0 278 };
Daniel@0 279
Daniel@0 280 var enCa = {
Daniel@0 281 decimal: ".",
Daniel@0 282 thousands: ",",
Daniel@0 283 grouping: [3],
Daniel@0 284 currency: ["$", ""]
Daniel@0 285 };
Daniel@0 286
Daniel@0 287 var deDe = {
Daniel@0 288 decimal: ",",
Daniel@0 289 thousands: ".",
Daniel@0 290 grouping: [3],
Daniel@0 291 currency: ["", "\xa0€"]
Daniel@0 292 };
Daniel@0 293
Daniel@0 294 var caEs = {
Daniel@0 295 decimal: ",",
Daniel@0 296 thousands: ".",
Daniel@0 297 grouping: [3],
Daniel@0 298 currency: ["", "\xa0€"]
Daniel@0 299 };
Daniel@0 300
Daniel@0 301
Daniel@0 302 // Computes the decimal coefficient and exponent of the specified number x with
Daniel@0 303 // significant digits p, where x is positive and p is in [1, 21] or undefined.
Daniel@0 304 // For example, formatDecimal(1.23) returns ["123", 0].
Daniel@0 305 function formatDecimal(x, p) {
Daniel@0 306 if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0) return null; // NaN, ±Infinity
Daniel@0 307 var i, coefficient = x.slice(0, i);
Daniel@0 308
Daniel@0 309 // The string returned by toExponential either has the form \d\.\d+e[-+]\d+
Daniel@0 310 // (e.g., 1.2e+3) or the form \de[-+]\d+ (e.g., 1e+3).
Daniel@0 311 return [
Daniel@0 312 coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient,
Daniel@0 313 +x.slice(i + 1)
Daniel@0 314 ];
Daniel@0 315 }
Daniel@0 316
Daniel@0 317 function exponent(x) {
Daniel@0 318 return x = formatDecimal(Math.abs(x)), x ? x[1] : NaN;
Daniel@0 319 }
Daniel@0 320
Daniel@0 321 var prefixExponent;
Daniel@0 322
Daniel@0 323 function formatPrefixAuto(x, p) {
Daniel@0 324 var d = formatDecimal(x, p);
Daniel@0 325 if (!d) return x + "";
Daniel@0 326 var coefficient = d[0],
Daniel@0 327 exponent = d[1],
Daniel@0 328 i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,
Daniel@0 329 n = coefficient.length;
Daniel@0 330 return i === n ? coefficient
Daniel@0 331 : i > n ? coefficient + new Array(i - n + 1).join("0")
Daniel@0 332 : i > 0 ? coefficient.slice(0, i) + "." + coefficient.slice(i)
Daniel@0 333 : "0." + new Array(1 - i).join("0") + formatDecimal(x, p + i - 1)[0]; // less than 1y!
Daniel@0 334 }
Daniel@0 335
Daniel@0 336 function formatRounded(x, p) {
Daniel@0 337 var d = formatDecimal(x, p);
Daniel@0 338 if (!d) return x + "";
Daniel@0 339 var coefficient = d[0],
Daniel@0 340 exponent = d[1];
Daniel@0 341 return exponent < 0 ? "0." + new Array(-exponent).join("0") + coefficient
Daniel@0 342 : coefficient.length > exponent + 1 ? coefficient.slice(0, exponent + 1) + "." + coefficient.slice(exponent + 1)
Daniel@0 343 : coefficient + new Array(exponent - coefficient.length + 2).join("0");
Daniel@0 344 }
Daniel@0 345
Daniel@0 346 function formatDefault(x, p) {
Daniel@0 347 x = x.toPrecision(p);
Daniel@0 348
Daniel@0 349 out: for (var n = x.length, i = 1, i0 = -1, i1; i < n; ++i) {
Daniel@0 350 switch (x[i]) {
Daniel@0 351 case ".": i0 = i1 = i; break;
Daniel@0 352 case "0": if (i0 === 0) i0 = i; i1 = i; break;
Daniel@0 353 case "e": break out;
Daniel@0 354 default: if (i0 > 0) i0 = 0; break;
Daniel@0 355 }
Daniel@0 356 }
Daniel@0 357
Daniel@0 358 return i0 > 0 ? x.slice(0, i0) + x.slice(i1 + 1) : x;
Daniel@0 359 }
Daniel@0 360
Daniel@0 361 var formatTypes = {
Daniel@0 362 "": formatDefault,
Daniel@0 363 "%": function(x, p) { return (x * 100).toFixed(p); },
Daniel@0 364 "b": function(x) { return Math.round(x).toString(2); },
Daniel@0 365 "c": function(x) { return x + ""; },
Daniel@0 366 "d": function(x) { return Math.round(x).toString(10); },
Daniel@0 367 "e": function(x, p) { return x.toExponential(p); },
Daniel@0 368 "f": function(x, p) { return x.toFixed(p); },
Daniel@0 369 "g": function(x, p) { return x.toPrecision(p); },
Daniel@0 370 "o": function(x) { return Math.round(x).toString(8); },
Daniel@0 371 "p": function(x, p) { return formatRounded(x * 100, p); },
Daniel@0 372 "r": formatRounded,
Daniel@0 373 "s": formatPrefixAuto,
Daniel@0 374 "X": function(x) { return Math.round(x).toString(16).toUpperCase(); },
Daniel@0 375 "x": function(x) { return Math.round(x).toString(16); }
Daniel@0 376 };
Daniel@0 377
Daniel@0 378
Daniel@0 379 // [[fill]align][sign][symbol][0][width][,][.precision][type]
Daniel@0 380 var re = /^(?:(.)?([<>=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i;
Daniel@0 381
Daniel@0 382 function formatSpecifier(specifier) {
Daniel@0 383 return new FormatSpecifier(specifier);
Daniel@0 384 }
Daniel@0 385
Daniel@0 386 function FormatSpecifier(specifier) {
Daniel@0 387 if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
Daniel@0 388
Daniel@0 389 var match,
Daniel@0 390 fill = match[1] || " ",
Daniel@0 391 align = match[2] || ">",
Daniel@0 392 sign = match[3] || "-",
Daniel@0 393 symbol = match[4] || "",
Daniel@0 394 zero = !!match[5],
Daniel@0 395 width = match[6] && +match[6],
Daniel@0 396 comma = !!match[7],
Daniel@0 397 precision = match[8] && +match[8].slice(1),
Daniel@0 398 type = match[9] || "";
Daniel@0 399
Daniel@0 400 // The "n" type is an alias for ",g".
Daniel@0 401 if (type === "n") comma = true, type = "g";
Daniel@0 402
Daniel@0 403 // Map invalid types to the default format.
Daniel@0 404 else if (!formatTypes[type]) type = "";
Daniel@0 405
Daniel@0 406 // If zero fill is specified, padding goes after sign and before digits.
Daniel@0 407 if (zero || (fill === "0" && align === "=")) zero = true, fill = "0", align = "=";
Daniel@0 408
Daniel@0 409 this.fill = fill;
Daniel@0 410 this.align = align;
Daniel@0 411 this.sign = sign;
Daniel@0 412 this.symbol = symbol;
Daniel@0 413 this.zero = zero;
Daniel@0 414 this.width = width;
Daniel@0 415 this.comma = comma;
Daniel@0 416 this.precision = precision;
Daniel@0 417 this.type = type;
Daniel@0 418 }
Daniel@0 419
Daniel@0 420 FormatSpecifier.prototype.toString = function() {
Daniel@0 421 return this.fill
Daniel@0 422 + this.align
Daniel@0 423 + this.sign
Daniel@0 424 + this.symbol
Daniel@0 425 + (this.zero ? "0" : "")
Daniel@0 426 + (this.width == null ? "" : Math.max(1, this.width | 0))
Daniel@0 427 + (this.comma ? "," : "")
Daniel@0 428 + (this.precision == null ? "" : "." + Math.max(0, this.precision | 0))
Daniel@0 429 + this.type;
Daniel@0 430 };
Daniel@0 431
Daniel@0 432 function formatGroup(grouping, thousands) {
Daniel@0 433 return function(value, width) {
Daniel@0 434 var i = value.length,
Daniel@0 435 t = [],
Daniel@0 436 j = 0,
Daniel@0 437 g = grouping[0],
Daniel@0 438 length = 0;
Daniel@0 439
Daniel@0 440 while (i > 0 && g > 0) {
Daniel@0 441 if (length + g + 1 > width) g = Math.max(1, width - length);
Daniel@0 442 t.push(value.substring(i -= g, i + g));
Daniel@0 443 if ((length += g + 1) > width) break;
Daniel@0 444 g = grouping[j = (j + 1) % grouping.length];
Daniel@0 445 }
Daniel@0 446
Daniel@0 447 return t.reverse().join(thousands);
Daniel@0 448 };
Daniel@0 449 }
Daniel@0 450
Daniel@0 451 var prefixes = ["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];
Daniel@0 452
Daniel@0 453 function identity(x) {
Daniel@0 454 return x;
Daniel@0 455 }
Daniel@0 456
Daniel@0 457 function locale(locale) {
Daniel@0 458 var group = locale.grouping && locale.thousands ? formatGroup(locale.grouping, locale.thousands) : identity,
Daniel@0 459 currency = locale.currency,
Daniel@0 460 decimal = locale.decimal;
Daniel@0 461
Daniel@0 462 function format(specifier) {
Daniel@0 463 specifier = formatSpecifier(specifier);
Daniel@0 464
Daniel@0 465 var fill = specifier.fill,
Daniel@0 466 align = specifier.align,
Daniel@0 467 sign = specifier.sign,
Daniel@0 468 symbol = specifier.symbol,
Daniel@0 469 zero = specifier.zero,
Daniel@0 470 width = specifier.width,
Daniel@0 471 comma = specifier.comma,
Daniel@0 472 precision = specifier.precision,
Daniel@0 473 type = specifier.type;
Daniel@0 474
Daniel@0 475 // Compute the prefix and suffix.
Daniel@0 476 // For SI-prefix, the suffix is lazily computed.
Daniel@0 477 var prefix = symbol === "$" ? currency[0] : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
Daniel@0 478 suffix = symbol === "$" ? currency[1] : /[%p]/.test(type) ? "%" : "";
Daniel@0 479
Daniel@0 480 // What format function should we use?
Daniel@0 481 // Is this an integer type?
Daniel@0 482 // Can this type generate exponential notation?
Daniel@0 483 var formatType = formatTypes[type],
Daniel@0 484 maybeSuffix = !type || /[defgprs%]/.test(type);
Daniel@0 485
Daniel@0 486 // Set the default precision if not specified,
Daniel@0 487 // or clamp the specified precision to the supported range.
Daniel@0 488 // For significant precision, it must be in [1, 21].
Daniel@0 489 // For fixed precision, it must be in [0, 20].
Daniel@0 490 precision = precision == null ? (type ? 6 : 12)
Daniel@0 491 : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision))
Daniel@0 492 : Math.max(0, Math.min(20, precision));
Daniel@0 493
Daniel@0 494 return function(value) {
Daniel@0 495 var valuePrefix = prefix,
Daniel@0 496 valueSuffix = suffix;
Daniel@0 497
Daniel@0 498 if (type === "c") {
Daniel@0 499 valueSuffix = formatType(value) + valueSuffix;
Daniel@0 500 value = "";
Daniel@0 501 } else {
Daniel@0 502 value = +value;
Daniel@0 503
Daniel@0 504 // Convert negative to positive, and compute the prefix.
Daniel@0 505 // Note that -0 is not less than 0, but 1 / -0 is!
Daniel@0 506 var valueNegative = (value < 0 || 1 / value < 0) && (value *= -1, true);
Daniel@0 507
Daniel@0 508 // Perform the initial formatting.
Daniel@0 509 value = formatType(value, precision);
Daniel@0 510
Daniel@0 511 // Compute the prefix and suffix.
Daniel@0 512 valuePrefix = (valueNegative ? (sign === "(" ? sign : "-") : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
Daniel@0 513 valueSuffix = valueSuffix + (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + (valueNegative && sign === "(" ? ")" : "");
Daniel@0 514
Daniel@0 515 // Break the formatted value into the integer “value” part that can be
Daniel@0 516 // grouped, and fractional or exponential “suffix” part that is not.
Daniel@0 517 if (maybeSuffix) {
Daniel@0 518 var i = -1, n = value.length, c;
Daniel@0 519 while (++i < n) {
Daniel@0 520 if (c = value.charCodeAt(i), 48 > c || c > 57) {
Daniel@0 521 valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
Daniel@0 522 value = value.slice(0, i);
Daniel@0 523 break;
Daniel@0 524 }
Daniel@0 525 }
Daniel@0 526 }
Daniel@0 527 }
Daniel@0 528
Daniel@0 529 // If the fill character is not "0", grouping is applied before padding.
Daniel@0 530 if (comma && !zero) value = group(value, Infinity);
Daniel@0 531
Daniel@0 532 // Compute the padding.
Daniel@0 533 var length = valuePrefix.length + value.length + valueSuffix.length,
Daniel@0 534 padding = length < width ? new Array(width - length + 1).join(fill) : "";
Daniel@0 535
Daniel@0 536 // If the fill character is "0", grouping is applied after padding.
Daniel@0 537 if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";
Daniel@0 538
Daniel@0 539 // Reconstruct the final output based on the desired alignment.
Daniel@0 540 switch (align) {
Daniel@0 541 case "<": return valuePrefix + value + valueSuffix + padding;
Daniel@0 542 case "=": return valuePrefix + padding + value + valueSuffix;
Daniel@0 543 case "^": return padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length);
Daniel@0 544 }
Daniel@0 545 return padding + valuePrefix + value + valueSuffix;
Daniel@0 546 };
Daniel@0 547 }
Daniel@0 548
Daniel@0 549 function formatPrefix(specifier, value) {
Daniel@0 550 var f = format((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
Daniel@0 551 e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3,
Daniel@0 552 k = Math.pow(10, -e),
Daniel@0 553 prefix = prefixes[8 + e / 3];
Daniel@0 554 return function(value) {
Daniel@0 555 return f(k * value) + prefix;
Daniel@0 556 };
Daniel@0 557 }
Daniel@0 558
Daniel@0 559 return {
Daniel@0 560 format: format,
Daniel@0 561 formatPrefix: formatPrefix
Daniel@0 562 };
Daniel@0 563 }
Daniel@0 564
Daniel@0 565 function precisionRound(step, max) {
Daniel@0 566 return Math.max(0, exponent(Math.abs(max)) - exponent(Math.abs(step))) + 1;
Daniel@0 567 }
Daniel@0 568
Daniel@0 569 function precisionPrefix(step, value) {
Daniel@0 570 return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3 - exponent(Math.abs(step)));
Daniel@0 571 }
Daniel@0 572
Daniel@0 573 function precisionFixed(step) {
Daniel@0 574 return Math.max(0, -exponent(Math.abs(step)));
Daniel@0 575 }
Daniel@0 576
Daniel@0 577 var localeDefinitions = (new Map)
Daniel@0 578 .set("ca-ES", caEs)
Daniel@0 579 .set("de-DE", deDe)
Daniel@0 580 .set("en-CA", enCa)
Daniel@0 581 .set("en-GB", enGb)
Daniel@0 582 .set("en-US", enUs)
Daniel@0 583 .set("es-ES", esEs)
Daniel@0 584 .set("fi-FI", fiFi)
Daniel@0 585 .set("fr-CA", frCa)
Daniel@0 586 .set("fr-FR", frFr)
Daniel@0 587 .set("he-IL", heIl)
Daniel@0 588 .set("it-IT", itIt)
Daniel@0 589 .set("ja-JP", jaJp)
Daniel@0 590 .set("mk-MK", mkMk)
Daniel@0 591 .set("nl-NL", nlNl)
Daniel@0 592 .set("pl-PL", plPl)
Daniel@0 593 .set("pt-BR", ptBr)
Daniel@0 594 .set("ru-RU", ruRu)
Daniel@0 595 .set("zh-CN", zhCn);
Daniel@0 596
Daniel@0 597 var defaultLocale = locale(enUs);
Daniel@0 598 exports.format = defaultLocale.format;
Daniel@0 599 exports.formatPrefix = defaultLocale.formatPrefix;
Daniel@0 600
Daniel@0 601 function localeFormat(definition) {
Daniel@0 602 if (typeof definition === "string") {
Daniel@0 603 definition = localeDefinitions.get(definition);
Daniel@0 604 if (!definition) return null;
Daniel@0 605 }
Daniel@0 606 return locale(definition);
Daniel@0 607 }
Daniel@0 608 ;
Daniel@0 609
Daniel@0 610 exports.localeFormat = localeFormat;
Daniel@0 611 exports.formatSpecifier = formatSpecifier;
Daniel@0 612 exports.precisionFixed = precisionFixed;
Daniel@0 613 exports.precisionPrefix = precisionPrefix;
Daniel@0 614 exports.precisionRound = precisionRound;
Daniel@0 615
Daniel@0 616 }));
Daniel@0 617 },{}],5:[function(require,module,exports){
Daniel@0 618 if (typeof Map === "undefined") {
Daniel@0 619 Map = function() { this.clear(); };
Daniel@0 620 Map.prototype = {
Daniel@0 621 set: function(k, v) { this._[k] = v; return this; },
Daniel@0 622 get: function(k) { return this._[k]; },
Daniel@0 623 has: function(k) { return k in this._; },
Daniel@0 624 delete: function(k) { return k in this._ && delete this._[k]; },
Daniel@0 625 clear: function() { this._ = Object.create(null); },
Daniel@0 626 get size() { var n = 0; for (var k in this._) ++n; return n; },
Daniel@0 627 forEach: function(c) { for (var k in this._) c(this._[k], k, this); }
Daniel@0 628 };
Daniel@0 629 } else (function() {
Daniel@0 630 var m = new Map;
Daniel@0 631 if (m.set(0, 0) !== m) {
Daniel@0 632 m = m.set;
Daniel@0 633 Map.prototype.set = function() { m.apply(this, arguments); return this; };
Daniel@0 634 }
Daniel@0 635 })();
Daniel@0 636
Daniel@0 637 (function (global, factory) {
Daniel@0 638 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
Daniel@0 639 typeof define === 'function' && define.amd ? define(['exports'], factory) :
Daniel@0 640 factory((global.timeFormat = {}));
Daniel@0 641 }(this, function (exports) { 'use strict';
Daniel@0 642
Daniel@0 643 var zhCn = {
Daniel@0 644 dateTime: "%a %b %e %X %Y",
Daniel@0 645 date: "%Y/%-m/%-d",
Daniel@0 646 time: "%H:%M:%S",
Daniel@0 647 periods: ["上午", "下午"],
Daniel@0 648 days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
Daniel@0 649 shortDays: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
Daniel@0 650 months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
Daniel@0 651 shortMonths: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"]
Daniel@0 652 };
Daniel@0 653
Daniel@0 654 var ruRu = {
Daniel@0 655 dateTime: "%A, %e %B %Y г. %X",
Daniel@0 656 date: "%d.%m.%Y",
Daniel@0 657 time: "%H:%M:%S",
Daniel@0 658 periods: ["AM", "PM"],
Daniel@0 659 days: ["воскресенье", "понедельник", "вторник", "среда", "четверг", "пятница", "суббота"],
Daniel@0 660 shortDays: ["вс", "пн", "вт", "ср", "чт", "пт", "сб"],
Daniel@0 661 months: ["января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря"],
Daniel@0 662 shortMonths: ["янв", "фев", "мар", "апр", "май", "июн", "июл", "авг", "сен", "окт", "ноя", "дек"]
Daniel@0 663 };
Daniel@0 664
Daniel@0 665 var ptBr = {
Daniel@0 666 dateTime: "%A, %e de %B de %Y. %X",
Daniel@0 667 date: "%d/%m/%Y",
Daniel@0 668 time: "%H:%M:%S",
Daniel@0 669 periods: ["AM", "PM"],
Daniel@0 670 days: ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado"],
Daniel@0 671 shortDays: ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb"],
Daniel@0 672 months: ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"],
Daniel@0 673 shortMonths: ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez"]
Daniel@0 674 };
Daniel@0 675
Daniel@0 676 var plPl = {
Daniel@0 677 dateTime: "%A, %e %B %Y, %X",
Daniel@0 678 date: "%d/%m/%Y",
Daniel@0 679 time: "%H:%M:%S",
Daniel@0 680 periods: ["AM", "PM"], // unused
Daniel@0 681 days: ["Niedziela", "Poniedziałek", "Wtorek", "Środa", "Czwartek", "Piątek", "Sobota"],
Daniel@0 682 shortDays: ["Niedz.", "Pon.", "Wt.", "Śr.", "Czw.", "Pt.", "Sob."],
Daniel@0 683 months: ["Styczeń", "Luty", "Marzec", "Kwiecień", "Maj", "Czerwiec", "Lipiec", "Sierpień", "Wrzesień", "Październik", "Listopad", "Grudzień"],
Daniel@0 684 shortMonths: ["Stycz.", "Luty", "Marz.", "Kwie.", "Maj", "Czerw.", "Lipc.", "Sierp.", "Wrz.", "Paźdz.", "Listop.", "Grudz."]/* In Polish language abbraviated months are not commonly used so there is a dispute about the proper abbraviations. */
Daniel@0 685 };
Daniel@0 686
Daniel@0 687 var nlNl = {
Daniel@0 688 dateTime: "%a %e %B %Y %T",
Daniel@0 689 date: "%d-%m-%Y",
Daniel@0 690 time: "%H:%M:%S",
Daniel@0 691 periods: ["AM", "PM"], // unused
Daniel@0 692 days: ["zondag", "maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag"],
Daniel@0 693 shortDays: ["zo", "ma", "di", "wo", "do", "vr", "za"],
Daniel@0 694 months: ["januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december"],
Daniel@0 695 shortMonths: ["jan", "feb", "mrt", "apr", "mei", "jun", "jul", "aug", "sep", "okt", "nov", "dec"]
Daniel@0 696 };
Daniel@0 697
Daniel@0 698 var mkMk = {
Daniel@0 699 dateTime: "%A, %e %B %Y г. %X",
Daniel@0 700 date: "%d.%m.%Y",
Daniel@0 701 time: "%H:%M:%S",
Daniel@0 702 periods: ["AM", "PM"],
Daniel@0 703 days: ["недела", "понеделник", "вторник", "среда", "четврток", "петок", "сабота"],
Daniel@0 704 shortDays: ["нед", "пон", "вто", "сре", "чет", "пет", "саб"],
Daniel@0 705 months: ["јануари", "февруари", "март", "април", "мај", "јуни", "јули", "август", "септември", "октомври", "ноември", "декември"],
Daniel@0 706 shortMonths: ["јан", "фев", "мар", "апр", "мај", "јун", "јул", "авг", "сеп", "окт", "ное", "дек"]
Daniel@0 707 };
Daniel@0 708
Daniel@0 709 var jaJp = {
Daniel@0 710 dateTime: "%Y %b %e %a %X",
Daniel@0 711 date: "%Y/%m/%d",
Daniel@0 712 time: "%H:%M:%S",
Daniel@0 713 periods: ["AM", "PM"],
Daniel@0 714 days: ["日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"],
Daniel@0 715 shortDays: ["日", "月", "火", "水", "木", "金", "土"],
Daniel@0 716 months: ["睦月", "如月", "弥生", "卯月", "皐月", "水無月", "文月", "葉月", "長月", "神無月", "霜月", "師走"],
Daniel@0 717 shortMonths: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"]
Daniel@0 718 };
Daniel@0 719
Daniel@0 720 var itIt = {
Daniel@0 721 dateTime: "%A %e %B %Y, %X",
Daniel@0 722 date: "%d/%m/%Y",
Daniel@0 723 time: "%H:%M:%S",
Daniel@0 724 periods: ["AM", "PM"], // unused
Daniel@0 725 days: ["Domenica", "Lunedì", "Martedì", "Mercoledì", "Giovedì", "Venerdì", "Sabato"],
Daniel@0 726 shortDays: ["Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab"],
Daniel@0 727 months: ["Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"],
Daniel@0 728 shortMonths: ["Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic"]
Daniel@0 729 };
Daniel@0 730
Daniel@0 731 var heIl = {
Daniel@0 732 dateTime: "%A, %e ב%B %Y %X",
Daniel@0 733 date: "%d.%m.%Y",
Daniel@0 734 time: "%H:%M:%S",
Daniel@0 735 periods: ["AM", "PM"],
Daniel@0 736 days: ["ראשון", "שני", "שלישי", "רביעי", "חמישי", "שישי", "שבת"],
Daniel@0 737 shortDays: ["א׳", "ב׳", "ג׳", "ד׳", "ה׳", "ו׳", "ש׳"],
Daniel@0 738 months: ["ינואר", "פברואר", "מרץ", "אפריל", "מאי", "יוני", "יולי", "אוגוסט", "ספטמבר", "אוקטובר", "נובמבר", "דצמבר"],
Daniel@0 739 shortMonths: ["ינו׳", "פבר׳", "מרץ", "אפר׳", "מאי", "יוני", "יולי", "אוג׳", "ספט׳", "אוק׳", "נוב׳", "דצמ׳"]
Daniel@0 740 };
Daniel@0 741
Daniel@0 742 var frFr = {
Daniel@0 743 dateTime: "%A, le %e %B %Y, %X",
Daniel@0 744 date: "%d/%m/%Y",
Daniel@0 745 time: "%H:%M:%S",
Daniel@0 746 periods: ["AM", "PM"], // unused
Daniel@0 747 days: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"],
Daniel@0 748 shortDays: ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."],
Daniel@0 749 months: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"],
Daniel@0 750 shortMonths: ["janv.", "févr.", "mars", "avr.", "mai", "juin", "juil.", "août", "sept.", "oct.", "nov.", "déc."]
Daniel@0 751 };
Daniel@0 752
Daniel@0 753 var frCa = {
Daniel@0 754 dateTime: "%a %e %b %Y %X",
Daniel@0 755 date: "%Y-%m-%d",
Daniel@0 756 time: "%H:%M:%S",
Daniel@0 757 periods: ["", ""],
Daniel@0 758 days: ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"],
Daniel@0 759 shortDays: ["dim", "lun", "mar", "mer", "jeu", "ven", "sam"],
Daniel@0 760 months: ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"],
Daniel@0 761 shortMonths: ["jan", "fév", "mar", "avr", "mai", "jui", "jul", "aoû", "sep", "oct", "nov", "déc"]
Daniel@0 762 };
Daniel@0 763
Daniel@0 764 var fiFi = {
Daniel@0 765 dateTime: "%A, %-d. %Bta %Y klo %X",
Daniel@0 766 date: "%-d.%-m.%Y",
Daniel@0 767 time: "%H:%M:%S",
Daniel@0 768 periods: ["a.m.", "p.m."],
Daniel@0 769 days: ["sunnuntai", "maanantai", "tiistai", "keskiviikko", "torstai", "perjantai", "lauantai"],
Daniel@0 770 shortDays: ["Su", "Ma", "Ti", "Ke", "To", "Pe", "La"],
Daniel@0 771 months: ["tammikuu", "helmikuu", "maaliskuu", "huhtikuu", "toukokuu", "kesäkuu", "heinäkuu", "elokuu", "syyskuu", "lokakuu", "marraskuu", "joulukuu"],
Daniel@0 772 shortMonths: ["Tammi", "Helmi", "Maalis", "Huhti", "Touko", "Kesä", "Heinä", "Elo", "Syys", "Loka", "Marras", "Joulu"]
Daniel@0 773 };
Daniel@0 774
Daniel@0 775 var esEs = {
Daniel@0 776 dateTime: "%A, %e de %B de %Y, %X",
Daniel@0 777 date: "%d/%m/%Y",
Daniel@0 778 time: "%H:%M:%S",
Daniel@0 779 periods: ["AM", "PM"],
Daniel@0 780 days: ["domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"],
Daniel@0 781 shortDays: ["dom", "lun", "mar", "mié", "jue", "vie", "sáb"],
Daniel@0 782 months: ["enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"],
Daniel@0 783 shortMonths: ["ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"]
Daniel@0 784 };
Daniel@0 785
Daniel@0 786 var enUs = {
Daniel@0 787 dateTime: "%a %b %e %X %Y",
Daniel@0 788 date: "%m/%d/%Y",
Daniel@0 789 time: "%H:%M:%S",
Daniel@0 790 periods: ["AM", "PM"],
Daniel@0 791 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
Daniel@0 792 shortDays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
Daniel@0 793 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
Daniel@0 794 shortMonths: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
Daniel@0 795 };
Daniel@0 796
Daniel@0 797 var enGb = {
Daniel@0 798 dateTime: "%a %e %b %X %Y",
Daniel@0 799 date: "%d/%m/%Y",
Daniel@0 800 time: "%H:%M:%S",
Daniel@0 801 periods: ["AM", "PM"],
Daniel@0 802 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
Daniel@0 803 shortDays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
Daniel@0 804 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
Daniel@0 805 shortMonths: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
Daniel@0 806 };
Daniel@0 807
Daniel@0 808 var enCa = {
Daniel@0 809 dateTime: "%a %b %e %X %Y",
Daniel@0 810 date: "%Y-%m-%d",
Daniel@0 811 time: "%H:%M:%S",
Daniel@0 812 periods: ["AM", "PM"],
Daniel@0 813 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
Daniel@0 814 shortDays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
Daniel@0 815 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
Daniel@0 816 shortMonths: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
Daniel@0 817 };
Daniel@0 818
Daniel@0 819 var deDe = {
Daniel@0 820 dateTime: "%A, der %e. %B %Y, %X",
Daniel@0 821 date: "%d.%m.%Y",
Daniel@0 822 time: "%H:%M:%S",
Daniel@0 823 periods: ["AM", "PM"], // unused
Daniel@0 824 days: ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"],
Daniel@0 825 shortDays: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"],
Daniel@0 826 months: ["Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"],
Daniel@0 827 shortMonths: ["Jan", "Feb", "Mrz", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"]
Daniel@0 828 };
Daniel@0 829
Daniel@0 830 var caEs = {
Daniel@0 831 dateTime: "%A, %e de %B de %Y, %X",
Daniel@0 832 date: "%d/%m/%Y",
Daniel@0 833 time: "%H:%M:%S",
Daniel@0 834 periods: ["AM", "PM"],
Daniel@0 835 days: ["diumenge", "dilluns", "dimarts", "dimecres", "dijous", "divendres", "dissabte"],
Daniel@0 836 shortDays: ["dg.", "dl.", "dt.", "dc.", "dj.", "dv.", "ds."],
Daniel@0 837 months: ["gener", "febrer", "març", "abril", "maig", "juny", "juliol", "agost", "setembre", "octubre", "novembre", "desembre"],
Daniel@0 838 shortMonths: ["gen.", "febr.", "març", "abr.", "maig", "juny", "jul.", "ag.", "set.", "oct.", "nov.", "des."]
Daniel@0 839 };
Daniel@0 840
Daniel@0 841 var t0 = new Date;
Daniel@0 842 var t1 = new Date;
Daniel@0 843
Daniel@0 844 function newInterval(floori, offseti, count) {
Daniel@0 845
Daniel@0 846 function interval(date) {
Daniel@0 847 return floori(date = new Date(+date)), date;
Daniel@0 848 }
Daniel@0 849
Daniel@0 850 interval.floor = interval;
Daniel@0 851
Daniel@0 852 interval.round = function(date) {
Daniel@0 853 var d0 = new Date(+date),
Daniel@0 854 d1 = new Date(date - 1);
Daniel@0 855 floori(d0), floori(d1), offseti(d1, 1);
Daniel@0 856 return date - d0 < d1 - date ? d0 : d1;
Daniel@0 857 };
Daniel@0 858
Daniel@0 859 interval.ceil = function(date) {
Daniel@0 860 return floori(date = new Date(date - 1)), offseti(date, 1), date;
Daniel@0 861 };
Daniel@0 862
Daniel@0 863 interval.offset = function(date, step) {
Daniel@0 864 return offseti(date = new Date(+date), step == null ? 1 : Math.floor(step)), date;
Daniel@0 865 };
Daniel@0 866
Daniel@0 867 interval.range = function(start, stop, step) {
Daniel@0 868 var range = [];
Daniel@0 869 start = new Date(start - 1);
Daniel@0 870 stop = new Date(+stop);
Daniel@0 871 step = step == null ? 1 : Math.floor(step);
Daniel@0 872 if (!(start < stop) || !(step > 0)) return range; // also handles Invalid Date
Daniel@0 873 offseti(start, 1), floori(start);
Daniel@0 874 if (start < stop) range.push(new Date(+start));
Daniel@0 875 while (offseti(start, step), floori(start), start < stop) range.push(new Date(+start));
Daniel@0 876 return range;
Daniel@0 877 };
Daniel@0 878
Daniel@0 879 interval.filter = function(test) {
Daniel@0 880 return newInterval(function(date) {
Daniel@0 881 while (floori(date), !test(date)) date.setTime(date - 1);
Daniel@0 882 }, function(date, step) {
Daniel@0 883 while (--step >= 0) while (offseti(date, 1), !test(date));
Daniel@0 884 });
Daniel@0 885 };
Daniel@0 886
Daniel@0 887 if (count) interval.count = function(start, end) {
Daniel@0 888 t0.setTime(+start), t1.setTime(+end);
Daniel@0 889 floori(t0), floori(t1);
Daniel@0 890 return Math.floor(count(t0, t1));
Daniel@0 891 };
Daniel@0 892
Daniel@0 893 return interval;
Daniel@0 894 }
Daniel@0 895
Daniel@0 896 var day = newInterval(function(date) {
Daniel@0 897 date.setHours(0, 0, 0, 0);
Daniel@0 898 }, function(date, step) {
Daniel@0 899 date.setDate(date.getDate() + step);
Daniel@0 900 }, function(start, end) {
Daniel@0 901 return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * 6e4) / 864e5;
Daniel@0 902 });
Daniel@0 903
Daniel@0 904 function weekday(i) {
Daniel@0 905 return newInterval(function(date) {
Daniel@0 906 date.setHours(0, 0, 0, 0);
Daniel@0 907 date.setDate(date.getDate() - (date.getDay() + 7 - i) % 7);
Daniel@0 908 }, function(date, step) {
Daniel@0 909 date.setDate(date.getDate() + step * 7);
Daniel@0 910 }, function(start, end) {
Daniel@0 911 return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * 6e4) / 6048e5;
Daniel@0 912 });
Daniel@0 913 }
Daniel@0 914
Daniel@0 915 var sunday = weekday(0);
Daniel@0 916 var monday = weekday(1);
Daniel@0 917
Daniel@0 918 var year = newInterval(function(date) {
Daniel@0 919 date.setHours(0, 0, 0, 0);
Daniel@0 920 date.setMonth(0, 1);
Daniel@0 921 }, function(date, step) {
Daniel@0 922 date.setFullYear(date.getFullYear() + step);
Daniel@0 923 }, function(start, end) {
Daniel@0 924 return end.getFullYear() - start.getFullYear();
Daniel@0 925 });
Daniel@0 926
Daniel@0 927 var utcDay = newInterval(function(date) {
Daniel@0 928 date.setUTCHours(0, 0, 0, 0);
Daniel@0 929 }, function(date, step) {
Daniel@0 930 date.setUTCDate(date.getUTCDate() + step);
Daniel@0 931 }, function(start, end) {
Daniel@0 932 return (end - start) / 864e5;
Daniel@0 933 });
Daniel@0 934
Daniel@0 935 function utcWeekday(i) {
Daniel@0 936 return newInterval(function(date) {
Daniel@0 937 date.setUTCHours(0, 0, 0, 0);
Daniel@0 938 date.setUTCDate(date.getUTCDate() - (date.getUTCDay() + 7 - i) % 7);
Daniel@0 939 }, function(date, step) {
Daniel@0 940 date.setUTCDate(date.getUTCDate() + step * 7);
Daniel@0 941 }, function(start, end) {
Daniel@0 942 return (end - start) / 6048e5;
Daniel@0 943 });
Daniel@0 944 }
Daniel@0 945
Daniel@0 946 var utcSunday = utcWeekday(0);
Daniel@0 947 var utcMonday = utcWeekday(1);
Daniel@0 948
Daniel@0 949 var utcYear = newInterval(function(date) {
Daniel@0 950 date.setUTCHours(0, 0, 0, 0);
Daniel@0 951 date.setUTCMonth(0, 1);
Daniel@0 952 }, function(date, step) {
Daniel@0 953 date.setUTCFullYear(date.getUTCFullYear() + step);
Daniel@0 954 }, function(start, end) {
Daniel@0 955 return end.getUTCFullYear() - start.getUTCFullYear();
Daniel@0 956 });
Daniel@0 957
Daniel@0 958 function localDate(d) {
Daniel@0 959 if (0 <= d.y && d.y < 100) {
Daniel@0 960 var date = new Date(-1, d.m, d.d, d.H, d.M, d.S, d.L);
Daniel@0 961 date.setFullYear(d.y);
Daniel@0 962 return date;
Daniel@0 963 }
Daniel@0 964 return new Date(d.y, d.m, d.d, d.H, d.M, d.S, d.L);
Daniel@0 965 }
Daniel@0 966
Daniel@0 967 function utcDate(d) {
Daniel@0 968 if (0 <= d.y && d.y < 100) {
Daniel@0 969 var date = new Date(Date.UTC(-1, d.m, d.d, d.H, d.M, d.S, d.L));
Daniel@0 970 date.setUTCFullYear(d.y);
Daniel@0 971 return date;
Daniel@0 972 }
Daniel@0 973 return new Date(Date.UTC(d.y, d.m, d.d, d.H, d.M, d.S, d.L));
Daniel@0 974 }
Daniel@0 975
Daniel@0 976 function newYear(y) {
Daniel@0 977 return {y: y, m: 0, d: 1, H: 0, M: 0, S: 0, L: 0};
Daniel@0 978 }
Daniel@0 979
Daniel@0 980 function locale(locale) {
Daniel@0 981 var locale_dateTime = locale.dateTime,
Daniel@0 982 locale_date = locale.date,
Daniel@0 983 locale_time = locale.time,
Daniel@0 984 locale_periods = locale.periods,
Daniel@0 985 locale_weekdays = locale.days,
Daniel@0 986 locale_shortWeekdays = locale.shortDays,
Daniel@0 987 locale_months = locale.months,
Daniel@0 988 locale_shortMonths = locale.shortMonths;
Daniel@0 989
Daniel@0 990 var periodLookup = formatLookup(locale_periods),
Daniel@0 991 weekdayRe = formatRe(locale_weekdays),
Daniel@0 992 weekdayLookup = formatLookup(locale_weekdays),
Daniel@0 993 shortWeekdayRe = formatRe(locale_shortWeekdays),
Daniel@0 994 shortWeekdayLookup = formatLookup(locale_shortWeekdays),
Daniel@0 995 monthRe = formatRe(locale_months),
Daniel@0 996 monthLookup = formatLookup(locale_months),
Daniel@0 997 shortMonthRe = formatRe(locale_shortMonths),
Daniel@0 998 shortMonthLookup = formatLookup(locale_shortMonths);
Daniel@0 999
Daniel@0 1000 var formats = {
Daniel@0 1001 "a": formatShortWeekday,
Daniel@0 1002 "A": formatWeekday,
Daniel@0 1003 "b": formatShortMonth,
Daniel@0 1004 "B": formatMonth,
Daniel@0 1005 "c": null,
Daniel@0 1006 "d": formatDayOfMonth,
Daniel@0 1007 "e": formatDayOfMonth,
Daniel@0 1008 "H": formatHour24,
Daniel@0 1009 "I": formatHour12,
Daniel@0 1010 "j": formatDayOfYear,
Daniel@0 1011 "L": formatMilliseconds,
Daniel@0 1012 "m": formatMonthNumber,
Daniel@0 1013 "M": formatMinutes,
Daniel@0 1014 "p": formatPeriod,
Daniel@0 1015 "S": formatSeconds,
Daniel@0 1016 "U": formatWeekNumberSunday,
Daniel@0 1017 "w": formatWeekdayNumber,
Daniel@0 1018 "W": formatWeekNumberMonday,
Daniel@0 1019 "x": null,
Daniel@0 1020 "X": null,
Daniel@0 1021 "y": formatYear,
Daniel@0 1022 "Y": formatFullYear,
Daniel@0 1023 "Z": formatZone,
Daniel@0 1024 "%": formatLiteralPercent
Daniel@0 1025 };
Daniel@0 1026
Daniel@0 1027 var utcFormats = {
Daniel@0 1028 "a": formatUTCShortWeekday,
Daniel@0 1029 "A": formatUTCWeekday,
Daniel@0 1030 "b": formatUTCShortMonth,
Daniel@0 1031 "B": formatUTCMonth,
Daniel@0 1032 "c": null,
Daniel@0 1033 "d": formatUTCDayOfMonth,
Daniel@0 1034 "e": formatUTCDayOfMonth,
Daniel@0 1035 "H": formatUTCHour24,
Daniel@0 1036 "I": formatUTCHour12,
Daniel@0 1037 "j": formatUTCDayOfYear,
Daniel@0 1038 "L": formatUTCMilliseconds,
Daniel@0 1039 "m": formatUTCMonthNumber,
Daniel@0 1040 "M": formatUTCMinutes,
Daniel@0 1041 "p": formatUTCPeriod,
Daniel@0 1042 "S": formatUTCSeconds,
Daniel@0 1043 "U": formatUTCWeekNumberSunday,
Daniel@0 1044 "w": formatUTCWeekdayNumber,
Daniel@0 1045 "W": formatUTCWeekNumberMonday,
Daniel@0 1046 "x": null,
Daniel@0 1047 "X": null,
Daniel@0 1048 "y": formatUTCYear,
Daniel@0 1049 "Y": formatUTCFullYear,
Daniel@0 1050 "Z": formatUTCZone,
Daniel@0 1051 "%": formatLiteralPercent
Daniel@0 1052 };
Daniel@0 1053
Daniel@0 1054 var parses = {
Daniel@0 1055 "a": parseShortWeekday,
Daniel@0 1056 "A": parseWeekday,
Daniel@0 1057 "b": parseShortMonth,
Daniel@0 1058 "B": parseMonth,
Daniel@0 1059 "c": parseLocaleDateTime,
Daniel@0 1060 "d": parseDayOfMonth,
Daniel@0 1061 "e": parseDayOfMonth,
Daniel@0 1062 "H": parseHour24,
Daniel@0 1063 "I": parseHour24,
Daniel@0 1064 "j": parseDayOfYear,
Daniel@0 1065 "L": parseMilliseconds,
Daniel@0 1066 "m": parseMonthNumber,
Daniel@0 1067 "M": parseMinutes,
Daniel@0 1068 "p": parsePeriod,
Daniel@0 1069 "S": parseSeconds,
Daniel@0 1070 "U": parseWeekNumberSunday,
Daniel@0 1071 "w": parseWeekdayNumber,
Daniel@0 1072 "W": parseWeekNumberMonday,
Daniel@0 1073 "x": parseLocaleDate,
Daniel@0 1074 "X": parseLocaleTime,
Daniel@0 1075 "y": parseYear,
Daniel@0 1076 "Y": parseFullYear,
Daniel@0 1077 "Z": parseZone,
Daniel@0 1078 "%": parseLiteralPercent
Daniel@0 1079 };
Daniel@0 1080
Daniel@0 1081 // These recursive directive definitions must be deferred.
Daniel@0 1082 formats.x = newFormat(locale_date, formats);
Daniel@0 1083 formats.X = newFormat(locale_time, formats);
Daniel@0 1084 formats.c = newFormat(locale_dateTime, formats);
Daniel@0 1085 utcFormats.x = newFormat(locale_date, utcFormats);
Daniel@0 1086 utcFormats.X = newFormat(locale_time, utcFormats);
Daniel@0 1087 utcFormats.c = newFormat(locale_dateTime, utcFormats);
Daniel@0 1088
Daniel@0 1089 function newFormat(specifier, formats) {
Daniel@0 1090 return function(date) {
Daniel@0 1091 var string = [],
Daniel@0 1092 i = -1,
Daniel@0 1093 j = 0,
Daniel@0 1094 n = specifier.length,
Daniel@0 1095 c,
Daniel@0 1096 pad,
Daniel@0 1097 format;
Daniel@0 1098
Daniel@0 1099 while (++i < n) {
Daniel@0 1100 if (specifier.charCodeAt(i) === 37) {
Daniel@0 1101 string.push(specifier.slice(j, i));
Daniel@0 1102 if ((pad = pads[c = specifier.charAt(++i)]) != null) c = specifier.charAt(++i);
Daniel@0 1103 if (format = formats[c]) c = format(date, pad == null ? (c === "e" ? " " : "0") : pad);
Daniel@0 1104 string.push(c);
Daniel@0 1105 j = i + 1;
Daniel@0 1106 }
Daniel@0 1107 }
Daniel@0 1108
Daniel@0 1109 string.push(specifier.slice(j, i));
Daniel@0 1110 return string.join("");
Daniel@0 1111 };
Daniel@0 1112 }
Daniel@0 1113
Daniel@0 1114 function newParse(specifier, newDate) {
Daniel@0 1115 return function(string) {
Daniel@0 1116 var d = newYear(1900),
Daniel@0 1117 i = parseSpecifier(d, specifier, string, 0);
Daniel@0 1118 if (i != string.length) return null;
Daniel@0 1119
Daniel@0 1120 // The am-pm flag is 0 for AM, and 1 for PM.
Daniel@0 1121 if ("p" in d) d.H = d.H % 12 + d.p * 12;
Daniel@0 1122
Daniel@0 1123 // If a time zone is specified, all fields are interpreted as UTC and then
Daniel@0 1124 // offset according to the specified time zone.
Daniel@0 1125 if ("Z" in d) {
Daniel@0 1126 if ("w" in d && ("W" in d || "U" in d)) {
Daniel@0 1127 var day = utcDate(newYear(d.y)).getUTCDay();
Daniel@0 1128 if ("W" in d) d.U = d.W, d.w = (d.w + 6) % 7, --day;
Daniel@0 1129 d.m = 0;
Daniel@0 1130 d.d = d.w + d.U * 7 - (day + 6) % 7;
Daniel@0 1131 }
Daniel@0 1132 d.H += d.Z / 100 | 0;
Daniel@0 1133 d.M += d.Z % 100;
Daniel@0 1134 return utcDate(d);
Daniel@0 1135 }
Daniel@0 1136
Daniel@0 1137 // Otherwise, all fields are in local time.
Daniel@0 1138 if ("w" in d && ("W" in d || "U" in d)) {
Daniel@0 1139 var day = newDate(newYear(d.y)).getDay();
Daniel@0 1140 if ("W" in d) d.U = d.W, d.w = (d.w + 6) % 7, --day;
Daniel@0 1141 d.m = 0;
Daniel@0 1142 d.d = d.w + d.U * 7 - (day + 6) % 7;
Daniel@0 1143 }
Daniel@0 1144 return newDate(d);
Daniel@0 1145 };
Daniel@0 1146 }
Daniel@0 1147
Daniel@0 1148 function parseSpecifier(d, specifier, string, j) {
Daniel@0 1149 var i = 0,
Daniel@0 1150 n = specifier.length,
Daniel@0 1151 m = string.length,
Daniel@0 1152 c,
Daniel@0 1153 parse;
Daniel@0 1154
Daniel@0 1155 while (i < n) {
Daniel@0 1156 if (j >= m) return -1;
Daniel@0 1157 c = specifier.charCodeAt(i++);
Daniel@0 1158 if (c === 37) {
Daniel@0 1159 c = specifier.charAt(i++);
Daniel@0 1160 parse = parses[c in pads ? specifier.charAt(i++) : c];
Daniel@0 1161 if (!parse || ((j = parse(d, string, j)) < 0)) return -1;
Daniel@0 1162 } else if (c != string.charCodeAt(j++)) {
Daniel@0 1163 return -1;
Daniel@0 1164 }
Daniel@0 1165 }
Daniel@0 1166
Daniel@0 1167 return j;
Daniel@0 1168 }
Daniel@0 1169
Daniel@0 1170 function parseShortWeekday(d, string, i) {
Daniel@0 1171 var n = shortWeekdayRe.exec(string.slice(i));
Daniel@0 1172 return n ? (d.w = shortWeekdayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
Daniel@0 1173 }
Daniel@0 1174
Daniel@0 1175 function parseWeekday(d, string, i) {
Daniel@0 1176 var n = weekdayRe.exec(string.slice(i));
Daniel@0 1177 return n ? (d.w = weekdayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
Daniel@0 1178 }
Daniel@0 1179
Daniel@0 1180 function parseShortMonth(d, string, i) {
Daniel@0 1181 var n = shortMonthRe.exec(string.slice(i));
Daniel@0 1182 return n ? (d.m = shortMonthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
Daniel@0 1183 }
Daniel@0 1184
Daniel@0 1185 function parseMonth(d, string, i) {
Daniel@0 1186 var n = monthRe.exec(string.slice(i));
Daniel@0 1187 return n ? (d.m = monthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
Daniel@0 1188 }
Daniel@0 1189
Daniel@0 1190 function parseLocaleDateTime(d, string, i) {
Daniel@0 1191 return parseSpecifier(d, locale_dateTime, string, i);
Daniel@0 1192 }
Daniel@0 1193
Daniel@0 1194 function parseLocaleDate(d, string, i) {
Daniel@0 1195 return parseSpecifier(d, locale_date, string, i);
Daniel@0 1196 }
Daniel@0 1197
Daniel@0 1198 function parseLocaleTime(d, string, i) {
Daniel@0 1199 return parseSpecifier(d, locale_time, string, i);
Daniel@0 1200 }
Daniel@0 1201
Daniel@0 1202 function parsePeriod(d, string, i) {
Daniel@0 1203 var n = periodLookup.get(string.slice(i, i += 2).toLowerCase());
Daniel@0 1204 return n == null ? -1 : (d.p = n, i);
Daniel@0 1205 }
Daniel@0 1206
Daniel@0 1207 function formatShortWeekday(d) {
Daniel@0 1208 return locale_shortWeekdays[d.getDay()];
Daniel@0 1209 }
Daniel@0 1210
Daniel@0 1211 function formatWeekday(d) {
Daniel@0 1212 return locale_weekdays[d.getDay()];
Daniel@0 1213 }
Daniel@0 1214
Daniel@0 1215 function formatShortMonth(d) {
Daniel@0 1216 return locale_shortMonths[d.getMonth()];
Daniel@0 1217 }
Daniel@0 1218
Daniel@0 1219 function formatMonth(d) {
Daniel@0 1220 return locale_months[d.getMonth()];
Daniel@0 1221 }
Daniel@0 1222
Daniel@0 1223 function formatPeriod(d) {
Daniel@0 1224 return locale_periods[+(d.getHours() >= 12)];
Daniel@0 1225 }
Daniel@0 1226
Daniel@0 1227 function formatUTCShortWeekday(d) {
Daniel@0 1228 return locale_shortWeekdays[d.getUTCDay()];
Daniel@0 1229 }
Daniel@0 1230
Daniel@0 1231 function formatUTCWeekday(d) {
Daniel@0 1232 return locale_weekdays[d.getUTCDay()];
Daniel@0 1233 }
Daniel@0 1234
Daniel@0 1235 function formatUTCShortMonth(d) {
Daniel@0 1236 return locale_shortMonths[d.getUTCMonth()];
Daniel@0 1237 }
Daniel@0 1238
Daniel@0 1239 function formatUTCMonth(d) {
Daniel@0 1240 return locale_months[d.getUTCMonth()];
Daniel@0 1241 }
Daniel@0 1242
Daniel@0 1243 function formatUTCPeriod(d) {
Daniel@0 1244 return locale_periods[+(d.getUTCHours() >= 12)];
Daniel@0 1245 }
Daniel@0 1246
Daniel@0 1247 return {
Daniel@0 1248 format: function(specifier) {
Daniel@0 1249 var f = newFormat(specifier += "", formats);
Daniel@0 1250 f.parse = newParse(specifier, localDate);
Daniel@0 1251 f.toString = function() { return specifier; };
Daniel@0 1252 return f;
Daniel@0 1253 },
Daniel@0 1254 utcFormat: function(specifier) {
Daniel@0 1255 var f = newFormat(specifier += "", utcFormats);
Daniel@0 1256 f.parse = newParse(specifier, utcDate);
Daniel@0 1257 f.toString = function() { return specifier; };
Daniel@0 1258 return f;
Daniel@0 1259 }
Daniel@0 1260 };
Daniel@0 1261 }
Daniel@0 1262
Daniel@0 1263 var pads = {"-": "", "_": " ", "0": "0"};
Daniel@0 1264 var numberRe = /^\s*\d+/;
Daniel@0 1265 var percentRe = /^%/;
Daniel@0 1266 var requoteRe = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
Daniel@0 1267
Daniel@0 1268 function pad(value, fill, width) {
Daniel@0 1269 var sign = value < 0 ? "-" : "",
Daniel@0 1270 string = (sign ? -value : value) + "",
Daniel@0 1271 length = string.length;
Daniel@0 1272 return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string);
Daniel@0 1273 }
Daniel@0 1274
Daniel@0 1275 function requote(s) {
Daniel@0 1276 return s.replace(requoteRe, "\\$&");
Daniel@0 1277 }
Daniel@0 1278
Daniel@0 1279 function formatRe(names) {
Daniel@0 1280 return new RegExp("^(?:" + names.map(requote).join("|") + ")", "i");
Daniel@0 1281 }
Daniel@0 1282
Daniel@0 1283 function formatLookup(names) {
Daniel@0 1284 var map = new Map, i = -1, n = names.length;
Daniel@0 1285 while (++i < n) map.set(names[i].toLowerCase(), i);
Daniel@0 1286 return map;
Daniel@0 1287 }
Daniel@0 1288
Daniel@0 1289 function parseWeekdayNumber(d, string, i) {
Daniel@0 1290 var n = numberRe.exec(string.slice(i, i + 1));
Daniel@0 1291 return n ? (d.w = +n[0], i + n[0].length) : -1;
Daniel@0 1292 }
Daniel@0 1293
Daniel@0 1294 function parseWeekNumberSunday(d, string, i) {
Daniel@0 1295 var n = numberRe.exec(string.slice(i));
Daniel@0 1296 return n ? (d.U = +n[0], i + n[0].length) : -1;
Daniel@0 1297 }
Daniel@0 1298
Daniel@0 1299 function parseWeekNumberMonday(d, string, i) {
Daniel@0 1300 var n = numberRe.exec(string.slice(i));
Daniel@0 1301 return n ? (d.W = +n[0], i + n[0].length) : -1;
Daniel@0 1302 }
Daniel@0 1303
Daniel@0 1304 function parseFullYear(d, string, i) {
Daniel@0 1305 var n = numberRe.exec(string.slice(i, i + 4));
Daniel@0 1306 return n ? (d.y = +n[0], i + n[0].length) : -1;
Daniel@0 1307 }
Daniel@0 1308
Daniel@0 1309 function parseYear(d, string, i) {
Daniel@0 1310 var n = numberRe.exec(string.slice(i, i + 2));
Daniel@0 1311 return n ? (d.y = +n[0] + (+n[0] > 68 ? 1900 : 2000), i + n[0].length) : -1;
Daniel@0 1312 }
Daniel@0 1313
Daniel@0 1314 function parseZone(d, string, i) {
Daniel@0 1315 return /^[+-]\d{4}$/.test(string = string.slice(i, i + 5))
Daniel@0 1316 ? (d.Z = -string, i + 5) // sign differs from getTimezoneOffset!
Daniel@0 1317 : -1;
Daniel@0 1318 }
Daniel@0 1319
Daniel@0 1320 function parseMonthNumber(d, string, i) {
Daniel@0 1321 var n = numberRe.exec(string.slice(i, i + 2));
Daniel@0 1322 return n ? (d.m = n[0] - 1, i + n[0].length) : -1;
Daniel@0 1323 }
Daniel@0 1324
Daniel@0 1325 function parseDayOfMonth(d, string, i) {
Daniel@0 1326 var n = numberRe.exec(string.slice(i, i + 2));
Daniel@0 1327 return n ? (d.d = +n[0], i + n[0].length) : -1;
Daniel@0 1328 }
Daniel@0 1329
Daniel@0 1330 function parseDayOfYear(d, string, i) {
Daniel@0 1331 var n = numberRe.exec(string.slice(i, i + 3));
Daniel@0 1332 return n ? (d.m = 0, d.d = +n[0], i + n[0].length) : -1;
Daniel@0 1333 }
Daniel@0 1334
Daniel@0 1335 function parseHour24(d, string, i) {
Daniel@0 1336 var n = numberRe.exec(string.slice(i, i + 2));
Daniel@0 1337 return n ? (d.H = +n[0], i + n[0].length) : -1;
Daniel@0 1338 }
Daniel@0 1339
Daniel@0 1340 function parseMinutes(d, string, i) {
Daniel@0 1341 var n = numberRe.exec(string.slice(i, i + 2));
Daniel@0 1342 return n ? (d.M = +n[0], i + n[0].length) : -1;
Daniel@0 1343 }
Daniel@0 1344
Daniel@0 1345 function parseSeconds(d, string, i) {
Daniel@0 1346 var n = numberRe.exec(string.slice(i, i + 2));
Daniel@0 1347 return n ? (d.S = +n[0], i + n[0].length) : -1;
Daniel@0 1348 }
Daniel@0 1349
Daniel@0 1350 function parseMilliseconds(d, string, i) {
Daniel@0 1351 var n = numberRe.exec(string.slice(i, i + 3));
Daniel@0 1352 return n ? (d.L = +n[0], i + n[0].length) : -1;
Daniel@0 1353 }
Daniel@0 1354
Daniel@0 1355 function parseLiteralPercent(d, string, i) {
Daniel@0 1356 var n = percentRe.exec(string.slice(i, i + 1));
Daniel@0 1357 return n ? i + n[0].length : -1;
Daniel@0 1358 }
Daniel@0 1359
Daniel@0 1360 function formatDayOfMonth(d, p) {
Daniel@0 1361 return pad(d.getDate(), p, 2);
Daniel@0 1362 }
Daniel@0 1363
Daniel@0 1364 function formatHour24(d, p) {
Daniel@0 1365 return pad(d.getHours(), p, 2);
Daniel@0 1366 }
Daniel@0 1367
Daniel@0 1368 function formatHour12(d, p) {
Daniel@0 1369 return pad(d.getHours() % 12 || 12, p, 2);
Daniel@0 1370 }
Daniel@0 1371
Daniel@0 1372 function formatDayOfYear(d, p) {
Daniel@0 1373 return pad(1 + day.count(year(d), d), p, 3);
Daniel@0 1374 }
Daniel@0 1375
Daniel@0 1376 function formatMilliseconds(d, p) {
Daniel@0 1377 return pad(d.getMilliseconds(), p, 3);
Daniel@0 1378 }
Daniel@0 1379
Daniel@0 1380 function formatMonthNumber(d, p) {
Daniel@0 1381 return pad(d.getMonth() + 1, p, 2);
Daniel@0 1382 }
Daniel@0 1383
Daniel@0 1384 function formatMinutes(d, p) {
Daniel@0 1385 return pad(d.getMinutes(), p, 2);
Daniel@0 1386 }
Daniel@0 1387
Daniel@0 1388 function formatSeconds(d, p) {
Daniel@0 1389 return pad(d.getSeconds(), p, 2);
Daniel@0 1390 }
Daniel@0 1391
Daniel@0 1392 function formatWeekNumberSunday(d, p) {
Daniel@0 1393 return pad(sunday.count(year(d), d), p, 2);
Daniel@0 1394 }
Daniel@0 1395
Daniel@0 1396 function formatWeekdayNumber(d) {
Daniel@0 1397 return d.getDay();
Daniel@0 1398 }
Daniel@0 1399
Daniel@0 1400 function formatWeekNumberMonday(d, p) {
Daniel@0 1401 return pad(monday.count(year(d), d), p, 2);
Daniel@0 1402 }
Daniel@0 1403
Daniel@0 1404 function formatYear(d, p) {
Daniel@0 1405 return pad(d.getFullYear() % 100, p, 2);
Daniel@0 1406 }
Daniel@0 1407
Daniel@0 1408 function formatFullYear(d, p) {
Daniel@0 1409 return pad(d.getFullYear() % 10000, p, 4);
Daniel@0 1410 }
Daniel@0 1411
Daniel@0 1412 function formatZone(d) {
Daniel@0 1413 var z = d.getTimezoneOffset();
Daniel@0 1414 return (z > 0 ? "-" : (z *= -1, "+"))
Daniel@0 1415 + pad(z / 60 | 0, "0", 2)
Daniel@0 1416 + pad(z % 60, "0", 2);
Daniel@0 1417 }
Daniel@0 1418
Daniel@0 1419 function formatUTCDayOfMonth(d, p) {
Daniel@0 1420 return pad(d.getUTCDate(), p, 2);
Daniel@0 1421 }
Daniel@0 1422
Daniel@0 1423 function formatUTCHour24(d, p) {
Daniel@0 1424 return pad(d.getUTCHours(), p, 2);
Daniel@0 1425 }
Daniel@0 1426
Daniel@0 1427 function formatUTCHour12(d, p) {
Daniel@0 1428 return pad(d.getUTCHours() % 12 || 12, p, 2);
Daniel@0 1429 }
Daniel@0 1430
Daniel@0 1431 function formatUTCDayOfYear(d, p) {
Daniel@0 1432 return pad(1 + utcDay.count(utcYear(d), d), p, 3);
Daniel@0 1433 }
Daniel@0 1434
Daniel@0 1435 function formatUTCMilliseconds(d, p) {
Daniel@0 1436 return pad(d.getUTCMilliseconds(), p, 3);
Daniel@0 1437 }
Daniel@0 1438
Daniel@0 1439 function formatUTCMonthNumber(d, p) {
Daniel@0 1440 return pad(d.getUTCMonth() + 1, p, 2);
Daniel@0 1441 }
Daniel@0 1442
Daniel@0 1443 function formatUTCMinutes(d, p) {
Daniel@0 1444 return pad(d.getUTCMinutes(), p, 2);
Daniel@0 1445 }
Daniel@0 1446
Daniel@0 1447 function formatUTCSeconds(d, p) {
Daniel@0 1448 return pad(d.getUTCSeconds(), p, 2);
Daniel@0 1449 }
Daniel@0 1450
Daniel@0 1451 function formatUTCWeekNumberSunday(d, p) {
Daniel@0 1452 return pad(utcSunday.count(utcYear(d), d), p, 2);
Daniel@0 1453 }
Daniel@0 1454
Daniel@0 1455 function formatUTCWeekdayNumber(d) {
Daniel@0 1456 return d.getUTCDay();
Daniel@0 1457 }
Daniel@0 1458
Daniel@0 1459 function formatUTCWeekNumberMonday(d, p) {
Daniel@0 1460 return pad(utcMonday.count(utcYear(d), d), p, 2);
Daniel@0 1461 }
Daniel@0 1462
Daniel@0 1463 function formatUTCYear(d, p) {
Daniel@0 1464 return pad(d.getUTCFullYear() % 100, p, 2);
Daniel@0 1465 }
Daniel@0 1466
Daniel@0 1467 function formatUTCFullYear(d, p) {
Daniel@0 1468 return pad(d.getUTCFullYear() % 10000, p, 4);
Daniel@0 1469 }
Daniel@0 1470
Daniel@0 1471 function formatUTCZone() {
Daniel@0 1472 return "+0000";
Daniel@0 1473 }
Daniel@0 1474
Daniel@0 1475 function formatLiteralPercent() {
Daniel@0 1476 return "%";
Daniel@0 1477 }
Daniel@0 1478
Daniel@0 1479 var isoSpecifier = "%Y-%m-%dT%H:%M:%S.%LZ";
Daniel@0 1480
Daniel@0 1481 function formatIsoNative(date) {
Daniel@0 1482 return date.toISOString();
Daniel@0 1483 }
Daniel@0 1484
Daniel@0 1485 formatIsoNative.parse = function(string) {
Daniel@0 1486 var date = new Date(string);
Daniel@0 1487 return isNaN(date) ? null : date;
Daniel@0 1488 };
Daniel@0 1489
Daniel@0 1490 formatIsoNative.toString = function() {
Daniel@0 1491 return isoSpecifier;
Daniel@0 1492 };
Daniel@0 1493
Daniel@0 1494 var formatIso = Date.prototype.toISOString && +new Date("2000-01-01T00:00:00.000Z")
Daniel@0 1495 ? formatIsoNative
Daniel@0 1496 : enUs.utcFormat(isoSpecifier);
Daniel@0 1497
Daniel@0 1498 var isoFormat = formatIso;
Daniel@0 1499
Daniel@0 1500 var localeDefinitions = (new Map)
Daniel@0 1501 .set("ca-ES", caEs)
Daniel@0 1502 .set("de-DE", deDe)
Daniel@0 1503 .set("en-CA", enCa)
Daniel@0 1504 .set("en-GB", enGb)
Daniel@0 1505 .set("en-US", enUs)
Daniel@0 1506 .set("es-ES", esEs)
Daniel@0 1507 .set("fi-FI", fiFi)
Daniel@0 1508 .set("fr-CA", frCa)
Daniel@0 1509 .set("fr-FR", frFr)
Daniel@0 1510 .set("he-IL", heIl)
Daniel@0 1511 .set("it-IT", itIt)
Daniel@0 1512 .set("ja-JP", jaJp)
Daniel@0 1513 .set("mk-MK", mkMk)
Daniel@0 1514 .set("nl-NL", nlNl)
Daniel@0 1515 .set("pl-PL", plPl)
Daniel@0 1516 .set("pt-BR", ptBr)
Daniel@0 1517 .set("ru-RU", ruRu)
Daniel@0 1518 .set("zh-CN", zhCn);
Daniel@0 1519
Daniel@0 1520 var defaultLocale = locale(enUs);
Daniel@0 1521 exports.format = defaultLocale.format;
Daniel@0 1522 exports.utcFormat = defaultLocale.utcFormat;
Daniel@0 1523
Daniel@0 1524 function localeFormat(definition) {
Daniel@0 1525 if (typeof definition === "string") {
Daniel@0 1526 definition = localeDefinitions.get(definition);
Daniel@0 1527 if (!definition) return null;
Daniel@0 1528 }
Daniel@0 1529 return locale(definition);
Daniel@0 1530 }
Daniel@0 1531 ;
Daniel@0 1532
Daniel@0 1533 exports.localeFormat = localeFormat;
Daniel@0 1534 exports.isoFormat = isoFormat;
Daniel@0 1535
Daniel@0 1536 }));
Daniel@0 1537 },{}],6:[function(require,module,exports){
Daniel@0 1538 (function (global, factory) {
Daniel@0 1539 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
Daniel@0 1540 typeof define === 'function' && define.amd ? define(['exports'], factory) :
Daniel@0 1541 factory((global.time = {}));
Daniel@0 1542 }(this, function (exports) { 'use strict';
Daniel@0 1543
Daniel@0 1544 var t1 = new Date;
Daniel@0 1545
Daniel@0 1546 var t0 = new Date;
Daniel@0 1547
Daniel@0 1548 function newInterval(floori, offseti, count) {
Daniel@0 1549
Daniel@0 1550 function interval(date) {
Daniel@0 1551 return floori(date = new Date(+date)), date;
Daniel@0 1552 }
Daniel@0 1553
Daniel@0 1554 interval.floor = interval;
Daniel@0 1555
Daniel@0 1556 interval.round = function(date) {
Daniel@0 1557 var d0 = new Date(+date),
Daniel@0 1558 d1 = new Date(date - 1);
Daniel@0 1559 floori(d0), floori(d1), offseti(d1, 1);
Daniel@0 1560 return date - d0 < d1 - date ? d0 : d1;
Daniel@0 1561 };
Daniel@0 1562
Daniel@0 1563 interval.ceil = function(date) {
Daniel@0 1564 return floori(date = new Date(date - 1)), offseti(date, 1), date;
Daniel@0 1565 };
Daniel@0 1566
Daniel@0 1567 interval.offset = function(date, step) {
Daniel@0 1568 return offseti(date = new Date(+date), step == null ? 1 : Math.floor(step)), date;
Daniel@0 1569 };
Daniel@0 1570
Daniel@0 1571 interval.range = function(start, stop, step) {
Daniel@0 1572 var range = [];
Daniel@0 1573 start = new Date(start - 1);
Daniel@0 1574 stop = new Date(+stop);
Daniel@0 1575 step = step == null ? 1 : Math.floor(step);
Daniel@0 1576 if (!(start < stop) || !(step > 0)) return range; // also handles Invalid Date
Daniel@0 1577 offseti(start, 1), floori(start);
Daniel@0 1578 if (start < stop) range.push(new Date(+start));
Daniel@0 1579 while (offseti(start, step), floori(start), start < stop) range.push(new Date(+start));
Daniel@0 1580 return range;
Daniel@0 1581 };
Daniel@0 1582
Daniel@0 1583 interval.filter = function(test) {
Daniel@0 1584 return newInterval(function(date) {
Daniel@0 1585 while (floori(date), !test(date)) date.setTime(date - 1);
Daniel@0 1586 }, function(date, step) {
Daniel@0 1587 while (--step >= 0) while (offseti(date, 1), !test(date));
Daniel@0 1588 });
Daniel@0 1589 };
Daniel@0 1590
Daniel@0 1591 if (count) interval.count = function(start, end) {
Daniel@0 1592 t0.setTime(+start), t1.setTime(+end);
Daniel@0 1593 floori(t0), floori(t1);
Daniel@0 1594 return Math.floor(count(t0, t1));
Daniel@0 1595 };
Daniel@0 1596
Daniel@0 1597 return interval;
Daniel@0 1598 }
Daniel@0 1599
Daniel@0 1600 var second = newInterval(function(date) {
Daniel@0 1601 date.setMilliseconds(0);
Daniel@0 1602 }, function(date, step) {
Daniel@0 1603 date.setTime(+date + step * 1e3);
Daniel@0 1604 }, function(start, end) {
Daniel@0 1605 return (end - start) / 1e3;
Daniel@0 1606 });
Daniel@0 1607
Daniel@0 1608 exports.seconds = second.range;
Daniel@0 1609
Daniel@0 1610 var minute = newInterval(function(date) {
Daniel@0 1611 date.setSeconds(0, 0);
Daniel@0 1612 }, function(date, step) {
Daniel@0 1613 date.setTime(+date + step * 6e4);
Daniel@0 1614 }, function(start, end) {
Daniel@0 1615 return (end - start) / 6e4;
Daniel@0 1616 });
Daniel@0 1617
Daniel@0 1618 exports.minutes = minute.range;
Daniel@0 1619
Daniel@0 1620 var hour = newInterval(function(date) {
Daniel@0 1621 date.setMinutes(0, 0, 0);
Daniel@0 1622 }, function(date, step) {
Daniel@0 1623 date.setTime(+date + step * 36e5);
Daniel@0 1624 }, function(start, end) {
Daniel@0 1625 return (end - start) / 36e5;
Daniel@0 1626 });
Daniel@0 1627
Daniel@0 1628 exports.hours = hour.range;
Daniel@0 1629
Daniel@0 1630 var day = newInterval(function(date) {
Daniel@0 1631 date.setHours(0, 0, 0, 0);
Daniel@0 1632 }, function(date, step) {
Daniel@0 1633 date.setDate(date.getDate() + step);
Daniel@0 1634 }, function(start, end) {
Daniel@0 1635 return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * 6e4) / 864e5;
Daniel@0 1636 });
Daniel@0 1637
Daniel@0 1638 exports.days = day.range;
Daniel@0 1639
Daniel@0 1640 function weekday(i) {
Daniel@0 1641 return newInterval(function(date) {
Daniel@0 1642 date.setHours(0, 0, 0, 0);
Daniel@0 1643 date.setDate(date.getDate() - (date.getDay() + 7 - i) % 7);
Daniel@0 1644 }, function(date, step) {
Daniel@0 1645 date.setDate(date.getDate() + step * 7);
Daniel@0 1646 }, function(start, end) {
Daniel@0 1647 return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * 6e4) / 6048e5;
Daniel@0 1648 });
Daniel@0 1649 }
Daniel@0 1650
Daniel@0 1651 exports.sunday = weekday(0);
Daniel@0 1652
Daniel@0 1653 exports.sundays = exports.sunday.range;
Daniel@0 1654
Daniel@0 1655 exports.monday = weekday(1);
Daniel@0 1656
Daniel@0 1657 exports.mondays = exports.monday.range;
Daniel@0 1658
Daniel@0 1659 exports.tuesday = weekday(2);
Daniel@0 1660
Daniel@0 1661 exports.tuesdays = exports.tuesday.range;
Daniel@0 1662
Daniel@0 1663 exports.wednesday = weekday(3);
Daniel@0 1664
Daniel@0 1665 exports.wednesdays = exports.wednesday.range;
Daniel@0 1666
Daniel@0 1667 exports.thursday = weekday(4);
Daniel@0 1668
Daniel@0 1669 exports.thursdays = exports.thursday.range;
Daniel@0 1670
Daniel@0 1671 exports.friday = weekday(5);
Daniel@0 1672
Daniel@0 1673 exports.fridays = exports.friday.range;
Daniel@0 1674
Daniel@0 1675 exports.saturday = weekday(6);
Daniel@0 1676
Daniel@0 1677 exports.saturdays = exports.saturday.range;
Daniel@0 1678
Daniel@0 1679 var week = exports.sunday;
Daniel@0 1680
Daniel@0 1681 exports.weeks = week.range;
Daniel@0 1682
Daniel@0 1683 var month = newInterval(function(date) {
Daniel@0 1684 date.setHours(0, 0, 0, 0);
Daniel@0 1685 date.setDate(1);
Daniel@0 1686 }, function(date, step) {
Daniel@0 1687 date.setMonth(date.getMonth() + step);
Daniel@0 1688 }, function(start, end) {
Daniel@0 1689 return end.getMonth() - start.getMonth() + (end.getFullYear() - start.getFullYear()) * 12;
Daniel@0 1690 });
Daniel@0 1691
Daniel@0 1692 exports.months = month.range;
Daniel@0 1693
Daniel@0 1694 var year = newInterval(function(date) {
Daniel@0 1695 date.setHours(0, 0, 0, 0);
Daniel@0 1696 date.setMonth(0, 1);
Daniel@0 1697 }, function(date, step) {
Daniel@0 1698 date.setFullYear(date.getFullYear() + step);
Daniel@0 1699 }, function(start, end) {
Daniel@0 1700 return end.getFullYear() - start.getFullYear();
Daniel@0 1701 });
Daniel@0 1702
Daniel@0 1703 exports.years = year.range;
Daniel@0 1704
Daniel@0 1705 var utcSecond = newInterval(function(date) {
Daniel@0 1706 date.setUTCMilliseconds(0);
Daniel@0 1707 }, function(date, step) {
Daniel@0 1708 date.setTime(+date + step * 1e3);
Daniel@0 1709 }, function(start, end) {
Daniel@0 1710 return (end - start) / 1e3;
Daniel@0 1711 });
Daniel@0 1712
Daniel@0 1713 exports.utcSeconds = utcSecond.range;
Daniel@0 1714
Daniel@0 1715 var utcMinute = newInterval(function(date) {
Daniel@0 1716 date.setUTCSeconds(0, 0);
Daniel@0 1717 }, function(date, step) {
Daniel@0 1718 date.setTime(+date + step * 6e4);
Daniel@0 1719 }, function(start, end) {
Daniel@0 1720 return (end - start) / 6e4;
Daniel@0 1721 });
Daniel@0 1722
Daniel@0 1723 exports.utcMinutes = utcMinute.range;
Daniel@0 1724
Daniel@0 1725 var utcHour = newInterval(function(date) {
Daniel@0 1726 date.setUTCMinutes(0, 0, 0);
Daniel@0 1727 }, function(date, step) {
Daniel@0 1728 date.setTime(+date + step * 36e5);
Daniel@0 1729 }, function(start, end) {
Daniel@0 1730 return (end - start) / 36e5;
Daniel@0 1731 });
Daniel@0 1732
Daniel@0 1733 exports.utcHours = utcHour.range;
Daniel@0 1734
Daniel@0 1735 var utcDay = newInterval(function(date) {
Daniel@0 1736 date.setUTCHours(0, 0, 0, 0);
Daniel@0 1737 }, function(date, step) {
Daniel@0 1738 date.setUTCDate(date.getUTCDate() + step);
Daniel@0 1739 }, function(start, end) {
Daniel@0 1740 return (end - start) / 864e5;
Daniel@0 1741 });
Daniel@0 1742
Daniel@0 1743 exports.utcDays = utcDay.range;
Daniel@0 1744
Daniel@0 1745 function utcWeekday(i) {
Daniel@0 1746 return newInterval(function(date) {
Daniel@0 1747 date.setUTCHours(0, 0, 0, 0);
Daniel@0 1748 date.setUTCDate(date.getUTCDate() - (date.getUTCDay() + 7 - i) % 7);
Daniel@0 1749 }, function(date, step) {
Daniel@0 1750 date.setUTCDate(date.getUTCDate() + step * 7);
Daniel@0 1751 }, function(start, end) {
Daniel@0 1752 return (end - start) / 6048e5;
Daniel@0 1753 });
Daniel@0 1754 }
Daniel@0 1755
Daniel@0 1756 exports.utcSunday = utcWeekday(0);
Daniel@0 1757
Daniel@0 1758 exports.utcSundays = exports.utcSunday.range;
Daniel@0 1759
Daniel@0 1760 exports.utcMonday = utcWeekday(1);
Daniel@0 1761
Daniel@0 1762 exports.utcMondays = exports.utcMonday.range;
Daniel@0 1763
Daniel@0 1764 exports.utcTuesday = utcWeekday(2);
Daniel@0 1765
Daniel@0 1766 exports.utcTuesdays = exports.utcTuesday.range;
Daniel@0 1767
Daniel@0 1768 exports.utcWednesday = utcWeekday(3);
Daniel@0 1769
Daniel@0 1770 exports.utcWednesdays = exports.utcWednesday.range;
Daniel@0 1771
Daniel@0 1772 exports.utcThursday = utcWeekday(4);
Daniel@0 1773
Daniel@0 1774 exports.utcThursdays = exports.utcThursday.range;
Daniel@0 1775
Daniel@0 1776 exports.utcFriday = utcWeekday(5);
Daniel@0 1777
Daniel@0 1778 exports.utcFridays = exports.utcFriday.range;
Daniel@0 1779
Daniel@0 1780 exports.utcSaturday = utcWeekday(6);
Daniel@0 1781
Daniel@0 1782 exports.utcSaturdays = exports.utcSaturday.range;
Daniel@0 1783
Daniel@0 1784 var utcWeek = exports.utcSunday;
Daniel@0 1785
Daniel@0 1786 exports.utcWeeks = utcWeek.range;
Daniel@0 1787
Daniel@0 1788 var utcMonth = newInterval(function(date) {
Daniel@0 1789 date.setUTCHours(0, 0, 0, 0);
Daniel@0 1790 date.setUTCDate(1);
Daniel@0 1791 }, function(date, step) {
Daniel@0 1792 date.setUTCMonth(date.getUTCMonth() + step);
Daniel@0 1793 }, function(start, end) {
Daniel@0 1794 return end.getUTCMonth() - start.getUTCMonth() + (end.getUTCFullYear() - start.getUTCFullYear()) * 12;
Daniel@0 1795 });
Daniel@0 1796
Daniel@0 1797 exports.utcMonths = utcMonth.range;
Daniel@0 1798
Daniel@0 1799 var utcYear = newInterval(function(date) {
Daniel@0 1800 date.setUTCHours(0, 0, 0, 0);
Daniel@0 1801 date.setUTCMonth(0, 1);
Daniel@0 1802 }, function(date, step) {
Daniel@0 1803 date.setUTCFullYear(date.getUTCFullYear() + step);
Daniel@0 1804 }, function(start, end) {
Daniel@0 1805 return end.getUTCFullYear() - start.getUTCFullYear();
Daniel@0 1806 });
Daniel@0 1807
Daniel@0 1808 exports.utcYears = utcYear.range;
Daniel@0 1809
Daniel@0 1810 exports.interval = newInterval;
Daniel@0 1811 exports.second = second;
Daniel@0 1812 exports.minute = minute;
Daniel@0 1813 exports.hour = hour;
Daniel@0 1814 exports.day = day;
Daniel@0 1815 exports.week = week;
Daniel@0 1816 exports.month = month;
Daniel@0 1817 exports.year = year;
Daniel@0 1818 exports.utcSecond = utcSecond;
Daniel@0 1819 exports.utcMinute = utcMinute;
Daniel@0 1820 exports.utcHour = utcHour;
Daniel@0 1821 exports.utcDay = utcDay;
Daniel@0 1822 exports.utcWeek = utcWeek;
Daniel@0 1823 exports.utcMonth = utcMonth;
Daniel@0 1824 exports.utcYear = utcYear;
Daniel@0 1825
Daniel@0 1826 }));
Daniel@0 1827 },{}],7:[function(require,module,exports){
Daniel@0 1828 var util = require('../util'),
Daniel@0 1829 Measures = require('./measures'),
Daniel@0 1830 Collector = require('./collector');
Daniel@0 1831
Daniel@0 1832 function Aggregator() {
Daniel@0 1833 this._cells = {};
Daniel@0 1834 this._aggr = [];
Daniel@0 1835 this._stream = false;
Daniel@0 1836 }
Daniel@0 1837
Daniel@0 1838 var Flags = Aggregator.Flags = {
Daniel@0 1839 ADD_CELL: 1,
Daniel@0 1840 MOD_CELL: 2
Daniel@0 1841 };
Daniel@0 1842
Daniel@0 1843 var proto = Aggregator.prototype;
Daniel@0 1844
Daniel@0 1845 // Parameters
Daniel@0 1846
Daniel@0 1847 proto.stream = function(v) {
Daniel@0 1848 if (v == null) return this._stream;
Daniel@0 1849 this._stream = !!v;
Daniel@0 1850 this._aggr = [];
Daniel@0 1851 return this;
Daniel@0 1852 };
Daniel@0 1853
Daniel@0 1854 // key accessor to use for streaming removes
Daniel@0 1855 proto.key = function(key) {
Daniel@0 1856 if (key == null) return this._key;
Daniel@0 1857 this._key = util.$(key);
Daniel@0 1858 return this;
Daniel@0 1859 };
Daniel@0 1860
Daniel@0 1861 // Input: array of objects of the form
Daniel@0 1862 // {name: string, get: function}
Daniel@0 1863 proto.groupby = function(dims) {
Daniel@0 1864 this._dims = util.array(dims).map(function(d, i) {
Daniel@0 1865 d = util.isString(d) ? {name: d, get: util.$(d)}
Daniel@0 1866 : util.isFunction(d) ? {name: util.name(d) || d.name || ('_' + i), get: d}
Daniel@0 1867 : (d.name && util.isFunction(d.get)) ? d : null;
Daniel@0 1868 if (d == null) throw 'Invalid groupby argument: ' + d;
Daniel@0 1869 return d;
Daniel@0 1870 });
Daniel@0 1871 return this.clear();
Daniel@0 1872 };
Daniel@0 1873
Daniel@0 1874 // Input: array of objects of the form
Daniel@0 1875 // {name: string, ops: [string, ...]}
Daniel@0 1876 proto.summarize = function(fields) {
Daniel@0 1877 fields = summarize_args(fields);
Daniel@0 1878 this._count = true;
Daniel@0 1879 var aggr = (this._aggr = []),
Daniel@0 1880 m, f, i, j, op, as, get;
Daniel@0 1881
Daniel@0 1882 for (i=0; i<fields.length; ++i) {
Daniel@0 1883 for (j=0, m=[], f=fields[i]; j<f.ops.length; ++j) {
Daniel@0 1884 op = f.ops[j];
Daniel@0 1885 if (op !== 'count') this._count = false;
Daniel@0 1886 as = (f.as && f.as[j]) || (op + (f.name==='*' ? '' : '_'+f.name));
Daniel@0 1887 m.push(Measures[op](as));
Daniel@0 1888 }
Daniel@0 1889 get = f.get && util.$(f.get) ||
Daniel@0 1890 (f.name === '*' ? util.identity : util.$(f.name));
Daniel@0 1891 aggr.push({
Daniel@0 1892 name: f.name,
Daniel@0 1893 measures: Measures.create(
Daniel@0 1894 m,
Daniel@0 1895 this._stream, // streaming remove flag
Daniel@0 1896 get, // input tuple getter
Daniel@0 1897 this._assign) // output tuple setter
Daniel@0 1898 });
Daniel@0 1899 }
Daniel@0 1900 return this.clear();
Daniel@0 1901 };
Daniel@0 1902
Daniel@0 1903 // Convenience method to summarize by count
Daniel@0 1904 proto.count = function() {
Daniel@0 1905 return this.summarize({'*':'count'});
Daniel@0 1906 };
Daniel@0 1907
Daniel@0 1908 // Override to perform custom tuple value assignment
Daniel@0 1909 proto._assign = function(object, name, value) {
Daniel@0 1910 object[name] = value;
Daniel@0 1911 };
Daniel@0 1912
Daniel@0 1913 function summarize_args(fields) {
Daniel@0 1914 if (util.isArray(fields)) { return fields; }
Daniel@0 1915 if (fields == null) { return []; }
Daniel@0 1916 var a = [], name, ops;
Daniel@0 1917 for (name in fields) {
Daniel@0 1918 ops = util.array(fields[name]);
Daniel@0 1919 a.push({name: name, ops: ops});
Daniel@0 1920 }
Daniel@0 1921 return a;
Daniel@0 1922 }
Daniel@0 1923
Daniel@0 1924 // Cell Management
Daniel@0 1925
Daniel@0 1926 proto.clear = function() {
Daniel@0 1927 return (this._cells = {}, this);
Daniel@0 1928 };
Daniel@0 1929
Daniel@0 1930 proto._cellkey = function(x) {
Daniel@0 1931 var d = this._dims,
Daniel@0 1932 n = d.length, i,
Daniel@0 1933 k = String(d[0].get(x));
Daniel@0 1934 for (i=1; i<n; ++i) {
Daniel@0 1935 k += '|' + d[i].get(x);
Daniel@0 1936 }
Daniel@0 1937 return k;
Daniel@0 1938 };
Daniel@0 1939
Daniel@0 1940 proto._cell = function(x) {
Daniel@0 1941 var key = this._dims.length ? this._cellkey(x) : '';
Daniel@0 1942 return this._cells[key] || (this._cells[key] = this._newcell(x, key));
Daniel@0 1943 };
Daniel@0 1944
Daniel@0 1945 proto._newcell = function(x, key) {
Daniel@0 1946 var cell = {
Daniel@0 1947 num: 0,
Daniel@0 1948 tuple: this._newtuple(x, key),
Daniel@0 1949 flag: Flags.ADD_CELL,
Daniel@0 1950 aggs: {}
Daniel@0 1951 };
Daniel@0 1952
Daniel@0 1953 var aggr = this._aggr, i;
Daniel@0 1954 for (i=0; i<aggr.length; ++i) {
Daniel@0 1955 cell.aggs[aggr[i].name] = new aggr[i].measures(cell, cell.tuple);
Daniel@0 1956 }
Daniel@0 1957 if (cell.collect) {
Daniel@0 1958 cell.data = new Collector(this._key);
Daniel@0 1959 }
Daniel@0 1960 return cell;
Daniel@0 1961 };
Daniel@0 1962
Daniel@0 1963 proto._newtuple = function(x) {
Daniel@0 1964 var dims = this._dims,
Daniel@0 1965 t = {}, i, n;
Daniel@0 1966 for (i=0, n=dims.length; i<n; ++i) {
Daniel@0 1967 t[dims[i].name] = dims[i].get(x);
Daniel@0 1968 }
Daniel@0 1969 return this._ingest(t);
Daniel@0 1970 };
Daniel@0 1971
Daniel@0 1972 // Override to perform custom tuple ingestion
Daniel@0 1973 proto._ingest = util.identity;
Daniel@0 1974
Daniel@0 1975 // Process Tuples
Daniel@0 1976
Daniel@0 1977 proto._add = function(x) {
Daniel@0 1978 var cell = this._cell(x),
Daniel@0 1979 aggr = this._aggr, i;
Daniel@0 1980
Daniel@0 1981 cell.num += 1;
Daniel@0 1982 if (!this._count) { // skip if count-only
Daniel@0 1983 if (cell.collect) cell.data.add(x);
Daniel@0 1984 for (i=0; i<aggr.length; ++i) {
Daniel@0 1985 cell.aggs[aggr[i].name].add(x);
Daniel@0 1986 }
Daniel@0 1987 }
Daniel@0 1988 cell.flag |= Flags.MOD_CELL;
Daniel@0 1989 if (this._on_add) this._on_add(x, cell);
Daniel@0 1990 };
Daniel@0 1991
Daniel@0 1992 proto._rem = function(x) {
Daniel@0 1993 var cell = this._cell(x),
Daniel@0 1994 aggr = this._aggr, i;
Daniel@0 1995
Daniel@0 1996 cell.num -= 1;
Daniel@0 1997 if (!this._count) { // skip if count-only
Daniel@0 1998 if (cell.collect) cell.data.rem(x);
Daniel@0 1999 for (i=0; i<aggr.length; ++i) {
Daniel@0 2000 cell.aggs[aggr[i].name].rem(x);
Daniel@0 2001 }
Daniel@0 2002 }
Daniel@0 2003 cell.flag |= Flags.MOD_CELL;
Daniel@0 2004 if (this._on_rem) this._on_rem(x, cell);
Daniel@0 2005 };
Daniel@0 2006
Daniel@0 2007 proto._mod = function(curr, prev) {
Daniel@0 2008 var cell0 = this._cell(prev),
Daniel@0 2009 cell1 = this._cell(curr),
Daniel@0 2010 aggr = this._aggr, i;
Daniel@0 2011
Daniel@0 2012 if (cell0 !== cell1) {
Daniel@0 2013 cell0.num -= 1;
Daniel@0 2014 cell1.num += 1;
Daniel@0 2015 if (cell0.collect) cell0.data.rem(prev);
Daniel@0 2016 if (cell1.collect) cell1.data.add(curr);
Daniel@0 2017 } else if (cell0.collect && !util.isObject(curr)) {
Daniel@0 2018 cell0.data.rem(prev);
Daniel@0 2019 cell0.data.add(curr);
Daniel@0 2020 }
Daniel@0 2021
Daniel@0 2022 for (i=0; i<aggr.length; ++i) {
Daniel@0 2023 cell0.aggs[aggr[i].name].rem(prev);
Daniel@0 2024 cell1.aggs[aggr[i].name].add(curr);
Daniel@0 2025 }
Daniel@0 2026 cell0.flag |= Flags.MOD_CELL;
Daniel@0 2027 cell1.flag |= Flags.MOD_CELL;
Daniel@0 2028 if (this._on_mod) this._on_mod(curr, prev, cell0, cell1);
Daniel@0 2029 };
Daniel@0 2030
Daniel@0 2031 proto.result = function() {
Daniel@0 2032 var result = [],
Daniel@0 2033 aggr = this._aggr,
Daniel@0 2034 cell, i, k;
Daniel@0 2035
Daniel@0 2036 for (k in this._cells) {
Daniel@0 2037 cell = this._cells[k];
Daniel@0 2038 if (cell.num > 0) {
Daniel@0 2039 // consolidate collector values
Daniel@0 2040 if (cell.collect) {
Daniel@0 2041 cell.data.values();
Daniel@0 2042 }
Daniel@0 2043 // update tuple properties
Daniel@0 2044 for (i=0; i<aggr.length; ++i) {
Daniel@0 2045 cell.aggs[aggr[i].name].set();
Daniel@0 2046 }
Daniel@0 2047 // add output tuple
Daniel@0 2048 result.push(cell.tuple);
Daniel@0 2049 } else {
Daniel@0 2050 delete this._cells[k];
Daniel@0 2051 }
Daniel@0 2052 cell.flag = 0;
Daniel@0 2053 }
Daniel@0 2054
Daniel@0 2055 this._rems = false;
Daniel@0 2056 return result;
Daniel@0 2057 };
Daniel@0 2058
Daniel@0 2059 proto.changes = function(output) {
Daniel@0 2060 var changes = output || {add:[], rem:[], mod:[]},
Daniel@0 2061 aggr = this._aggr,
Daniel@0 2062 cell, flag, i, k;
Daniel@0 2063
Daniel@0 2064 for (k in this._cells) {
Daniel@0 2065 cell = this._cells[k];
Daniel@0 2066 flag = cell.flag;
Daniel@0 2067
Daniel@0 2068 // consolidate collector values
Daniel@0 2069 if (cell.collect) {
Daniel@0 2070 cell.data.values();
Daniel@0 2071 }
Daniel@0 2072
Daniel@0 2073 // update tuple properties
Daniel@0 2074 for (i=0; i<aggr.length; ++i) {
Daniel@0 2075 cell.aggs[aggr[i].name].set();
Daniel@0 2076 }
Daniel@0 2077
Daniel@0 2078 // organize output tuples
Daniel@0 2079 if (cell.num <= 0) {
Daniel@0 2080 changes.rem.push(cell.tuple); // if (flag === Flags.MOD_CELL) { ??
Daniel@0 2081 delete this._cells[k];
Daniel@0 2082 if (this._on_drop) this._on_drop(cell);
Daniel@0 2083 } else {
Daniel@0 2084 if (this._on_keep) this._on_keep(cell);
Daniel@0 2085 if (flag & Flags.ADD_CELL) {
Daniel@0 2086 changes.add.push(cell.tuple);
Daniel@0 2087 } else if (flag & Flags.MOD_CELL) {
Daniel@0 2088 changes.mod.push(cell.tuple);
Daniel@0 2089 }
Daniel@0 2090 }
Daniel@0 2091
Daniel@0 2092 cell.flag = 0;
Daniel@0 2093 }
Daniel@0 2094
Daniel@0 2095 this._rems = false;
Daniel@0 2096 return changes;
Daniel@0 2097 };
Daniel@0 2098
Daniel@0 2099 proto.execute = function(input) {
Daniel@0 2100 return this.clear().insert(input).result();
Daniel@0 2101 };
Daniel@0 2102
Daniel@0 2103 proto.insert = function(input) {
Daniel@0 2104 this._consolidate();
Daniel@0 2105 for (var i=0; i<input.length; ++i) {
Daniel@0 2106 this._add(input[i]);
Daniel@0 2107 }
Daniel@0 2108 return this;
Daniel@0 2109 };
Daniel@0 2110
Daniel@0 2111 proto.remove = function(input) {
Daniel@0 2112 if (!this._stream) {
Daniel@0 2113 throw 'Aggregator not configured for streaming removes.' +
Daniel@0 2114 ' Call stream(true) prior to calling summarize.';
Daniel@0 2115 }
Daniel@0 2116 for (var i=0; i<input.length; ++i) {
Daniel@0 2117 this._rem(input[i]);
Daniel@0 2118 }
Daniel@0 2119 this._rems = true;
Daniel@0 2120 return this;
Daniel@0 2121 };
Daniel@0 2122
Daniel@0 2123 // consolidate removals
Daniel@0 2124 proto._consolidate = function() {
Daniel@0 2125 if (!this._rems) return;
Daniel@0 2126 for (var k in this._cells) {
Daniel@0 2127 if (this._cells[k].collect) {
Daniel@0 2128 this._cells[k].data.values();
Daniel@0 2129 }
Daniel@0 2130 }
Daniel@0 2131 this._rems = false;
Daniel@0 2132 };
Daniel@0 2133
Daniel@0 2134 module.exports = Aggregator;
Daniel@0 2135 },{"../util":29,"./collector":8,"./measures":10}],8:[function(require,module,exports){
Daniel@0 2136 var util = require('../util');
Daniel@0 2137 var stats = require('../stats');
Daniel@0 2138
Daniel@0 2139 var REM = '__dl_rem__';
Daniel@0 2140
Daniel@0 2141 function Collector(key) {
Daniel@0 2142 this._add = [];
Daniel@0 2143 this._rem = [];
Daniel@0 2144 this._key = key || null;
Daniel@0 2145 this._last = null;
Daniel@0 2146 }
Daniel@0 2147
Daniel@0 2148 var proto = Collector.prototype;
Daniel@0 2149
Daniel@0 2150 proto.add = function(v) {
Daniel@0 2151 this._add.push(v);
Daniel@0 2152 };
Daniel@0 2153
Daniel@0 2154 proto.rem = function(v) {
Daniel@0 2155 this._rem.push(v);
Daniel@0 2156 };
Daniel@0 2157
Daniel@0 2158 proto.values = function() {
Daniel@0 2159 this._get = null;
Daniel@0 2160 if (this._rem.length === 0) return this._add;
Daniel@0 2161
Daniel@0 2162 var a = this._add,
Daniel@0 2163 r = this._rem,
Daniel@0 2164 k = this._key,
Daniel@0 2165 x = Array(a.length - r.length),
Daniel@0 2166 i, j, n, m;
Daniel@0 2167
Daniel@0 2168 if (!util.isObject(r[0])) {
Daniel@0 2169 // processing raw values
Daniel@0 2170 m = stats.count.map(r);
Daniel@0 2171 for (i=0, j=0, n=a.length; i<n; ++i) {
Daniel@0 2172 if (m[a[i]] > 0) {
Daniel@0 2173 m[a[i]] -= 1;
Daniel@0 2174 } else {
Daniel@0 2175 x[j++] = a[i];
Daniel@0 2176 }
Daniel@0 2177 }
Daniel@0 2178 } else if (k) {
Daniel@0 2179 // has unique key field, so use that
Daniel@0 2180 m = util.toMap(r, k);
Daniel@0 2181 for (i=0, j=0, n=a.length; i<n; ++i) {
Daniel@0 2182 if (!m.hasOwnProperty(k(a[i]))) { x[j++] = a[i]; }
Daniel@0 2183 }
Daniel@0 2184 } else {
Daniel@0 2185 // no unique key, mark tuples directly
Daniel@0 2186 for (i=0, n=r.length; i<n; ++i) {
Daniel@0 2187 r[i][REM] = 1;
Daniel@0 2188 }
Daniel@0 2189 for (i=0, j=0, n=a.length; i<n; ++i) {
Daniel@0 2190 if (!a[i][REM]) { x[j++] = a[i]; }
Daniel@0 2191 }
Daniel@0 2192 for (i=0, n=r.length; i<n; ++i) {
Daniel@0 2193 delete r[i][REM];
Daniel@0 2194 }
Daniel@0 2195 }
Daniel@0 2196
Daniel@0 2197 this._rem = [];
Daniel@0 2198 return (this._add = x);
Daniel@0 2199 };
Daniel@0 2200
Daniel@0 2201 // memoizing statistics methods
Daniel@0 2202
Daniel@0 2203 proto.extent = function(get) {
Daniel@0 2204 if (this._get !== get || !this._ext) {
Daniel@0 2205 var v = this.values(),
Daniel@0 2206 i = stats.extent.index(v, get);
Daniel@0 2207 this._ext = [v[i[0]], v[i[1]]];
Daniel@0 2208 this._get = get;
Daniel@0 2209 }
Daniel@0 2210 return this._ext;
Daniel@0 2211 };
Daniel@0 2212
Daniel@0 2213 proto.argmin = function(get) {
Daniel@0 2214 return this.extent(get)[0];
Daniel@0 2215 };
Daniel@0 2216
Daniel@0 2217 proto.argmax = function(get) {
Daniel@0 2218 return this.extent(get)[1];
Daniel@0 2219 };
Daniel@0 2220
Daniel@0 2221 proto.min = function(get) {
Daniel@0 2222 var m = this.extent(get)[0];
Daniel@0 2223 return m ? get(m) : +Infinity;
Daniel@0 2224 };
Daniel@0 2225
Daniel@0 2226 proto.max = function(get) {
Daniel@0 2227 var m = this.extent(get)[1];
Daniel@0 2228 return m ? get(m) : -Infinity;
Daniel@0 2229 };
Daniel@0 2230
Daniel@0 2231 proto.quartile = function(get) {
Daniel@0 2232 if (this._get !== get || !this._q) {
Daniel@0 2233 this._q = stats.quartile(this.values(), get);
Daniel@0 2234 this._get = get;
Daniel@0 2235 }
Daniel@0 2236 return this._q;
Daniel@0 2237 };
Daniel@0 2238
Daniel@0 2239 proto.q1 = function(get) {
Daniel@0 2240 return this.quartile(get)[0];
Daniel@0 2241 };
Daniel@0 2242
Daniel@0 2243 proto.q2 = function(get) {
Daniel@0 2244 return this.quartile(get)[1];
Daniel@0 2245 };
Daniel@0 2246
Daniel@0 2247 proto.q3 = function(get) {
Daniel@0 2248 return this.quartile(get)[2];
Daniel@0 2249 };
Daniel@0 2250
Daniel@0 2251 module.exports = Collector;
Daniel@0 2252
Daniel@0 2253 },{"../stats":26,"../util":29}],9:[function(require,module,exports){
Daniel@0 2254 var util = require('../util');
Daniel@0 2255 var Aggregator = require('./aggregator');
Daniel@0 2256
Daniel@0 2257 module.exports = function() {
Daniel@0 2258 // flatten arguments into a single array
Daniel@0 2259 var args = [].reduce.call(arguments, function(a, x) {
Daniel@0 2260 return a.concat(util.array(x));
Daniel@0 2261 }, []);
Daniel@0 2262 // create and return an aggregator
Daniel@0 2263 return new Aggregator()
Daniel@0 2264 .groupby(args)
Daniel@0 2265 .summarize({'*':'values'});
Daniel@0 2266 };
Daniel@0 2267
Daniel@0 2268 },{"../util":29,"./aggregator":7}],10:[function(require,module,exports){
Daniel@0 2269 var util = require('../util');
Daniel@0 2270
Daniel@0 2271 var types = {
Daniel@0 2272 'values': measure({
Daniel@0 2273 name: 'values',
Daniel@0 2274 init: 'cell.collect = true;',
Daniel@0 2275 set: 'cell.data.values()', idx: -1
Daniel@0 2276 }),
Daniel@0 2277 'count': measure({
Daniel@0 2278 name: 'count',
Daniel@0 2279 set: 'cell.num'
Daniel@0 2280 }),
Daniel@0 2281 'missing': measure({
Daniel@0 2282 name: 'missing',
Daniel@0 2283 set: 'this.missing'
Daniel@0 2284 }),
Daniel@0 2285 'valid': measure({
Daniel@0 2286 name: 'valid',
Daniel@0 2287 set: 'this.valid'
Daniel@0 2288 }),
Daniel@0 2289 'sum': measure({
Daniel@0 2290 name: 'sum',
Daniel@0 2291 init: 'this.sum = 0;',
Daniel@0 2292 add: 'this.sum += v;',
Daniel@0 2293 rem: 'this.sum -= v;',
Daniel@0 2294 set: 'this.sum'
Daniel@0 2295 }),
Daniel@0 2296 'mean': measure({
Daniel@0 2297 name: 'mean',
Daniel@0 2298 init: 'this.mean = 0;',
Daniel@0 2299 add: 'var d = v - this.mean; this.mean += d / this.valid;',
Daniel@0 2300 rem: 'var d = v - this.mean; this.mean -= this.valid ? d / this.valid : this.mean;',
Daniel@0 2301 set: 'this.mean'
Daniel@0 2302 }),
Daniel@0 2303 'average': measure({
Daniel@0 2304 name: 'average',
Daniel@0 2305 set: 'this.mean',
Daniel@0 2306 req: ['mean'], idx: 1
Daniel@0 2307 }),
Daniel@0 2308 'variance': measure({
Daniel@0 2309 name: 'variance',
Daniel@0 2310 init: 'this.dev = 0;',
Daniel@0 2311 add: 'this.dev += d * (v - this.mean);',
Daniel@0 2312 rem: 'this.dev -= d * (v - this.mean);',
Daniel@0 2313 set: 'this.valid > 1 ? this.dev / (this.valid-1) : 0',
Daniel@0 2314 req: ['mean'], idx: 1
Daniel@0 2315 }),
Daniel@0 2316 'variancep': measure({
Daniel@0 2317 name: 'variancep',
Daniel@0 2318 set: 'this.valid > 1 ? this.dev / this.valid : 0',
Daniel@0 2319 req: ['variance'], idx: 2
Daniel@0 2320 }),
Daniel@0 2321 'stdev': measure({
Daniel@0 2322 name: 'stdev',
Daniel@0 2323 set: 'this.valid > 1 ? Math.sqrt(this.dev / (this.valid-1)) : 0',
Daniel@0 2324 req: ['variance'], idx: 2
Daniel@0 2325 }),
Daniel@0 2326 'stdevp': measure({
Daniel@0 2327 name: 'stdevp',
Daniel@0 2328 set: 'this.valid > 1 ? Math.sqrt(this.dev / this.valid) : 0',
Daniel@0 2329 req: ['variance'], idx: 2
Daniel@0 2330 }),
Daniel@0 2331 'median': measure({
Daniel@0 2332 name: 'median',
Daniel@0 2333 set: 'cell.data.q2(this.get)',
Daniel@0 2334 req: ['values'], idx: 3
Daniel@0 2335 }),
Daniel@0 2336 'q1': measure({
Daniel@0 2337 name: 'q1',
Daniel@0 2338 set: 'cell.data.q1(this.get)',
Daniel@0 2339 req: ['values'], idx: 3
Daniel@0 2340 }),
Daniel@0 2341 'q3': measure({
Daniel@0 2342 name: 'q3',
Daniel@0 2343 set: 'cell.data.q3(this.get)',
Daniel@0 2344 req: ['values'], idx: 3
Daniel@0 2345 }),
Daniel@0 2346 'distinct': measure({
Daniel@0 2347 name: 'distinct',
Daniel@0 2348 set: 'this.distinct(cell.data.values(), this.get)',
Daniel@0 2349 req: ['values'], idx: 3
Daniel@0 2350 }),
Daniel@0 2351 'argmin': measure({
Daniel@0 2352 name: 'argmin',
Daniel@0 2353 add: 'if (v < this.min) this.argmin = t;',
Daniel@0 2354 rem: 'if (v <= this.min) this.argmin = null;',
Daniel@0 2355 set: 'this.argmin = this.argmin || cell.data.argmin(this.get)',
Daniel@0 2356 req: ['min'], str: ['values'], idx: 3
Daniel@0 2357 }),
Daniel@0 2358 'argmax': measure({
Daniel@0 2359 name: 'argmax',
Daniel@0 2360 add: 'if (v > this.max) this.argmax = t;',
Daniel@0 2361 rem: 'if (v >= this.max) this.argmax = null;',
Daniel@0 2362 set: 'this.argmax = this.argmax || cell.data.argmax(this.get)',
Daniel@0 2363 req: ['max'], str: ['values'], idx: 3
Daniel@0 2364 }),
Daniel@0 2365 'min': measure({
Daniel@0 2366 name: 'min',
Daniel@0 2367 init: 'this.min = +Infinity;',
Daniel@0 2368 add: 'if (v < this.min) this.min = v;',
Daniel@0 2369 rem: 'if (v <= this.min) this.min = NaN;',
Daniel@0 2370 set: 'this.min = (isNaN(this.min) ? cell.data.min(this.get) : this.min)',
Daniel@0 2371 str: ['values'], idx: 4
Daniel@0 2372 }),
Daniel@0 2373 'max': measure({
Daniel@0 2374 name: 'max',
Daniel@0 2375 init: 'this.max = -Infinity;',
Daniel@0 2376 add: 'if (v > this.max) this.max = v;',
Daniel@0 2377 rem: 'if (v >= this.max) this.max = NaN;',
Daniel@0 2378 set: 'this.max = (isNaN(this.max) ? cell.data.max(this.get) : this.max)',
Daniel@0 2379 str: ['values'], idx: 4
Daniel@0 2380 }),
Daniel@0 2381 'modeskew': measure({
Daniel@0 2382 name: 'modeskew',
Daniel@0 2383 set: 'this.dev===0 ? 0 : (this.mean - cell.data.q2(this.get)) / Math.sqrt(this.dev/(this.valid-1))',
Daniel@0 2384 req: ['mean', 'stdev', 'median'], idx: 5
Daniel@0 2385 })
Daniel@0 2386 };
Daniel@0 2387
Daniel@0 2388 function measure(base) {
Daniel@0 2389 return function(out) {
Daniel@0 2390 var m = util.extend({init:'', add:'', rem:'', idx:0}, base);
Daniel@0 2391 m.out = out || base.name;
Daniel@0 2392 return m;
Daniel@0 2393 };
Daniel@0 2394 }
Daniel@0 2395
Daniel@0 2396 function resolve(agg, stream) {
Daniel@0 2397 function collect(m, a) {
Daniel@0 2398 function helper(r) { if (!m[r]) collect(m, m[r] = types[r]()); }
Daniel@0 2399 if (a.req) a.req.forEach(helper);
Daniel@0 2400 if (stream && a.str) a.str.forEach(helper);
Daniel@0 2401 return m;
Daniel@0 2402 }
Daniel@0 2403 var map = agg.reduce(
Daniel@0 2404 collect,
Daniel@0 2405 agg.reduce(function(m, a) { return (m[a.name] = a, m); }, {})
Daniel@0 2406 );
Daniel@0 2407 return util.vals(map).sort(function(a, b) { return a.idx - b.idx; });
Daniel@0 2408 }
Daniel@0 2409
Daniel@0 2410 function create(agg, stream, accessor, mutator) {
Daniel@0 2411 var all = resolve(agg, stream),
Daniel@0 2412 ctr = 'this.cell = cell; this.tuple = t; this.valid = 0; this.missing = 0;',
Daniel@0 2413 add = 'if (v==null) this.missing++; if (!this.isValid(v)) return; ++this.valid;',
Daniel@0 2414 rem = 'if (v==null) this.missing--; if (!this.isValid(v)) return; --this.valid;',
Daniel@0 2415 set = 'var t = this.tuple; var cell = this.cell;';
Daniel@0 2416
Daniel@0 2417 all.forEach(function(a) {
Daniel@0 2418 if (a.idx < 0) {
Daniel@0 2419 ctr = a.init + ctr;
Daniel@0 2420 add = a.add + add;
Daniel@0 2421 rem = a.rem + rem;
Daniel@0 2422 } else {
Daniel@0 2423 ctr += a.init;
Daniel@0 2424 add += a.add;
Daniel@0 2425 rem += a.rem;
Daniel@0 2426 }
Daniel@0 2427 });
Daniel@0 2428 agg.slice()
Daniel@0 2429 .sort(function(a, b) { return a.idx - b.idx; })
Daniel@0 2430 .forEach(function(a) {
Daniel@0 2431 set += 'this.assign(t,\''+a.out+'\','+a.set+');';
Daniel@0 2432 });
Daniel@0 2433 set += 'return t;';
Daniel@0 2434
Daniel@0 2435 /* jshint evil: true */
Daniel@0 2436 ctr = Function('cell', 't', ctr);
Daniel@0 2437 ctr.prototype.assign = mutator;
Daniel@0 2438 ctr.prototype.add = Function('t', 'var v = this.get(t);' + add);
Daniel@0 2439 ctr.prototype.rem = Function('t', 'var v = this.get(t);' + rem);
Daniel@0 2440 ctr.prototype.set = Function(set);
Daniel@0 2441 ctr.prototype.get = accessor;
Daniel@0 2442 ctr.prototype.distinct = require('../stats').count.distinct;
Daniel@0 2443 ctr.prototype.isValid = util.isValid;
Daniel@0 2444 ctr.fields = agg.map(util.$('out'));
Daniel@0 2445 return ctr;
Daniel@0 2446 }
Daniel@0 2447
Daniel@0 2448 types.create = create;
Daniel@0 2449 module.exports = types;
Daniel@0 2450 },{"../stats":26,"../util":29}],11:[function(require,module,exports){
Daniel@0 2451 var util = require('../util'),
Daniel@0 2452 time = require('../time'),
Daniel@0 2453 EPSILON = 1e-15;
Daniel@0 2454
Daniel@0 2455 function bins(opt) {
Daniel@0 2456 if (!opt) { throw Error("Missing binning options."); }
Daniel@0 2457
Daniel@0 2458 // determine range
Daniel@0 2459 var maxb = opt.maxbins || 15,
Daniel@0 2460 base = opt.base || 10,
Daniel@0 2461 logb = Math.log(base),
Daniel@0 2462 div = opt.div || [5, 2],
Daniel@0 2463 min = opt.min,
Daniel@0 2464 max = opt.max,
Daniel@0 2465 span = max - min,
Daniel@0 2466 step, level, minstep, precision, v, i, eps;
Daniel@0 2467
Daniel@0 2468 if (opt.step) {
Daniel@0 2469 // if step size is explicitly given, use that
Daniel@0 2470 step = opt.step;
Daniel@0 2471 } else if (opt.steps) {
Daniel@0 2472 // if provided, limit choice to acceptable step sizes
Daniel@0 2473 step = opt.steps[Math.min(
Daniel@0 2474 opt.steps.length - 1,
Daniel@0 2475 bisect(opt.steps, span/maxb, 0, opt.steps.length)
Daniel@0 2476 )];
Daniel@0 2477 } else {
Daniel@0 2478 // else use span to determine step size
Daniel@0 2479 level = Math.ceil(Math.log(maxb) / logb);
Daniel@0 2480 minstep = opt.minstep || 0;
Daniel@0 2481 step = Math.max(
Daniel@0 2482 minstep,
Daniel@0 2483 Math.pow(base, Math.round(Math.log(span) / logb) - level)
Daniel@0 2484 );
Daniel@0 2485
Daniel@0 2486 // increase step size if too many bins
Daniel@0 2487 do { step *= base; } while (Math.ceil(span/step) > maxb);
Daniel@0 2488
Daniel@0 2489 // decrease step size if allowed
Daniel@0 2490 for (i=0; i<div.length; ++i) {
Daniel@0 2491 v = step / div[i];
Daniel@0 2492 if (v >= minstep && span / v <= maxb) step = v;
Daniel@0 2493 }
Daniel@0 2494 }
Daniel@0 2495
Daniel@0 2496 // update precision, min and max
Daniel@0 2497 v = Math.log(step);
Daniel@0 2498 precision = v >= 0 ? 0 : ~~(-v / logb) + 1;
Daniel@0 2499 eps = Math.pow(base, -precision - 1);
Daniel@0 2500 min = Math.min(min, Math.floor(min / step + eps) * step);
Daniel@0 2501 max = Math.ceil(max / step) * step;
Daniel@0 2502
Daniel@0 2503 return {
Daniel@0 2504 start: min,
Daniel@0 2505 stop: max,
Daniel@0 2506 step: step,
Daniel@0 2507 unit: {precision: precision},
Daniel@0 2508 value: value,
Daniel@0 2509 index: index
Daniel@0 2510 };
Daniel@0 2511 }
Daniel@0 2512
Daniel@0 2513 function bisect(a, x, lo, hi) {
Daniel@0 2514 while (lo < hi) {
Daniel@0 2515 var mid = lo + hi >>> 1;
Daniel@0 2516 if (util.cmp(a[mid], x) < 0) { lo = mid + 1; }
Daniel@0 2517 else { hi = mid; }
Daniel@0 2518 }
Daniel@0 2519 return lo;
Daniel@0 2520 }
Daniel@0 2521
Daniel@0 2522 function value(v) {
Daniel@0 2523 return this.step * Math.floor(v / this.step + EPSILON);
Daniel@0 2524 }
Daniel@0 2525
Daniel@0 2526 function index(v) {
Daniel@0 2527 return Math.floor((v - this.start) / this.step + EPSILON);
Daniel@0 2528 }
Daniel@0 2529
Daniel@0 2530 function date_value(v) {
Daniel@0 2531 return this.unit.date(value.call(this, v));
Daniel@0 2532 }
Daniel@0 2533
Daniel@0 2534 function date_index(v) {
Daniel@0 2535 return index.call(this, this.unit.unit(v));
Daniel@0 2536 }
Daniel@0 2537
Daniel@0 2538 bins.date = function(opt) {
Daniel@0 2539 if (!opt) { throw Error("Missing date binning options."); }
Daniel@0 2540
Daniel@0 2541 // find time step, then bin
Daniel@0 2542 var units = opt.utc ? time.utc : time,
Daniel@0 2543 dmin = opt.min,
Daniel@0 2544 dmax = opt.max,
Daniel@0 2545 maxb = opt.maxbins || 20,
Daniel@0 2546 minb = opt.minbins || 4,
Daniel@0 2547 span = (+dmax) - (+dmin),
Daniel@0 2548 unit = opt.unit ? units[opt.unit] : units.find(span, minb, maxb),
Daniel@0 2549 spec = bins({
Daniel@0 2550 min: unit.min != null ? unit.min : unit.unit(dmin),
Daniel@0 2551 max: unit.max != null ? unit.max : unit.unit(dmax),
Daniel@0 2552 maxbins: maxb,
Daniel@0 2553 minstep: unit.minstep,
Daniel@0 2554 steps: unit.step
Daniel@0 2555 });
Daniel@0 2556
Daniel@0 2557 spec.unit = unit;
Daniel@0 2558 spec.index = date_index;
Daniel@0 2559 if (!opt.raw) spec.value = date_value;
Daniel@0 2560 return spec;
Daniel@0 2561 };
Daniel@0 2562
Daniel@0 2563 module.exports = bins;
Daniel@0 2564
Daniel@0 2565 },{"../time":28,"../util":29}],12:[function(require,module,exports){
Daniel@0 2566 var bins = require('./bins'),
Daniel@0 2567 gen = require('../generate'),
Daniel@0 2568 type = require('../import/type'),
Daniel@0 2569 util = require('../util'),
Daniel@0 2570 stats = require('../stats');
Daniel@0 2571
Daniel@0 2572 var qtype = {
Daniel@0 2573 'integer': 1,
Daniel@0 2574 'number': 1,
Daniel@0 2575 'date': 1
Daniel@0 2576 };
Daniel@0 2577
Daniel@0 2578 function $bin(values, f, opt) {
Daniel@0 2579 opt = options(values, f, opt);
Daniel@0 2580 var b = spec(opt);
Daniel@0 2581 return !b ? (opt.accessor || util.identity) :
Daniel@0 2582 util.$func('bin', b.unit.unit ?
Daniel@0 2583 function(x) { return b.value(b.unit.unit(x)); } :
Daniel@0 2584 function(x) { return b.value(x); }
Daniel@0 2585 )(opt.accessor);
Daniel@0 2586 }
Daniel@0 2587
Daniel@0 2588 function histogram(values, f, opt) {
Daniel@0 2589 opt = options(values, f, opt);
Daniel@0 2590 var b = spec(opt);
Daniel@0 2591 return b ?
Daniel@0 2592 numerical(values, opt.accessor, b) :
Daniel@0 2593 categorical(values, opt.accessor, opt && opt.sort);
Daniel@0 2594 }
Daniel@0 2595
Daniel@0 2596 function spec(opt) {
Daniel@0 2597 var t = opt.type, b = null;
Daniel@0 2598 if (t == null || qtype[t]) {
Daniel@0 2599 if (t === 'integer' && opt.minstep == null) opt.minstep = 1;
Daniel@0 2600 b = (t === 'date') ? bins.date(opt) : bins(opt);
Daniel@0 2601 }
Daniel@0 2602 return b;
Daniel@0 2603 }
Daniel@0 2604
Daniel@0 2605 function options() {
Daniel@0 2606 var a = arguments,
Daniel@0 2607 i = 0,
Daniel@0 2608 values = util.isArray(a[i]) ? a[i++] : null,
Daniel@0 2609 f = util.isFunction(a[i]) || util.isString(a[i]) ? util.$(a[i++]) : null,
Daniel@0 2610 opt = util.extend({}, a[i]);
Daniel@0 2611
Daniel@0 2612 if (values) {
Daniel@0 2613 opt.type = opt.type || type(values, f);
Daniel@0 2614 if (qtype[opt.type]) {
Daniel@0 2615 var ext = stats.extent(values, f);
Daniel@0 2616 opt = util.extend({min: ext[0], max: ext[1]}, opt);
Daniel@0 2617 }
Daniel@0 2618 }
Daniel@0 2619 if (f) { opt.accessor = f; }
Daniel@0 2620 return opt;
Daniel@0 2621 }
Daniel@0 2622
Daniel@0 2623 function numerical(values, f, b) {
Daniel@0 2624 var h = gen.range(b.start, b.stop + b.step/2, b.step)
Daniel@0 2625 .map(function(v) { return {value: b.value(v), count: 0}; });
Daniel@0 2626
Daniel@0 2627 for (var i=0, v, j; i<values.length; ++i) {
Daniel@0 2628 v = f ? f(values[i]) : values[i];
Daniel@0 2629 if (util.isValid(v)) {
Daniel@0 2630 j = b.index(v);
Daniel@0 2631 if (j < 0 || j >= h.length || !isFinite(j)) continue;
Daniel@0 2632 h[j].count += 1;
Daniel@0 2633 }
Daniel@0 2634 }
Daniel@0 2635 h.bins = b;
Daniel@0 2636 return h;
Daniel@0 2637 }
Daniel@0 2638
Daniel@0 2639 function categorical(values, f, sort) {
Daniel@0 2640 var u = stats.unique(values, f),
Daniel@0 2641 c = stats.count.map(values, f);
Daniel@0 2642 return u.map(function(k) { return {value: k, count: c[k]}; })
Daniel@0 2643 .sort(util.comparator(sort ? '-count' : '+value'));
Daniel@0 2644 }
Daniel@0 2645
Daniel@0 2646 module.exports = {
Daniel@0 2647 $bin: $bin,
Daniel@0 2648 histogram: histogram
Daniel@0 2649 };
Daniel@0 2650 },{"../generate":14,"../import/type":23,"../stats":26,"../util":29,"./bins":11}],13:[function(require,module,exports){
Daniel@0 2651 var d3_time = require('d3-time'),
Daniel@0 2652 d3_timeF = require('d3-time-format'),
Daniel@0 2653 d3_numberF = require('d3-format'),
Daniel@0 2654 numberF = d3_numberF, // defaults to EN-US
Daniel@0 2655 timeF = d3_timeF; // defaults to EN-US
Daniel@0 2656
Daniel@0 2657 function numberLocale(l) {
Daniel@0 2658 var f = d3_numberF.localeFormat(l);
Daniel@0 2659 if (f == null) throw Error('Unrecognized locale: ' + l);
Daniel@0 2660 numberF = f;
Daniel@0 2661 }
Daniel@0 2662
Daniel@0 2663 function timeLocale(l) {
Daniel@0 2664 var f = d3_timeF.localeFormat(l);
Daniel@0 2665 if (f == null) throw Error('Unrecognized locale: ' + l);
Daniel@0 2666 timeF = f;
Daniel@0 2667 }
Daniel@0 2668
Daniel@0 2669 module.exports = {
Daniel@0 2670 // Update number formatter to use provided locale configuration.
Daniel@0 2671 // For more see https://github.com/d3/d3-format
Daniel@0 2672 numberLocale: numberLocale,
Daniel@0 2673 number: function(f) { return numberF.format(f); },
Daniel@0 2674 numberPrefix: function(f, v) { return numberF.formatPrefix(f, v); },
Daniel@0 2675
Daniel@0 2676 // Update time formatter to use provided locale configuration.
Daniel@0 2677 // For more see https://github.com/d3/d3-time-format
Daniel@0 2678 timeLocale: timeLocale,
Daniel@0 2679 time: function(f) { return timeF.format(f); },
Daniel@0 2680 utc: function(f) { return timeF.utcFormat(f); },
Daniel@0 2681
Daniel@0 2682 // Set number and time locale simultaneously.
Daniel@0 2683 locale: function(l) { numberLocale(l); timeLocale(l); },
Daniel@0 2684
Daniel@0 2685 // automatic formatting functions
Daniel@0 2686 auto: {
Daniel@0 2687 number: numberAutoFormat,
Daniel@0 2688 time: function() { return timeAutoFormat(); },
Daniel@0 2689 utc: function() { return utcAutoFormat(); }
Daniel@0 2690 }
Daniel@0 2691 };
Daniel@0 2692
Daniel@0 2693 var e10 = Math.sqrt(50),
Daniel@0 2694 e5 = Math.sqrt(10),
Daniel@0 2695 e2 = Math.sqrt(2);
Daniel@0 2696
Daniel@0 2697 function intervals(domain, count) {
Daniel@0 2698 if (!domain.length) domain = [0];
Daniel@0 2699 if (count == null) count = 10;
Daniel@0 2700
Daniel@0 2701 var start = domain[0],
Daniel@0 2702 stop = domain[domain.length - 1];
Daniel@0 2703
Daniel@0 2704 if (stop < start) { error = stop; stop = start; start = error; }
Daniel@0 2705
Daniel@0 2706 var span = (stop - start) || (count = 1, start || stop || 1),
Daniel@0 2707 step = Math.pow(10, Math.floor(Math.log(span / count) / Math.LN10)),
Daniel@0 2708 error = span / count / step;
Daniel@0 2709
Daniel@0 2710 // Filter ticks to get closer to the desired count.
Daniel@0 2711 if (error >= e10) step *= 10;
Daniel@0 2712 else if (error >= e5) step *= 5;
Daniel@0 2713 else if (error >= e2) step *= 2;
Daniel@0 2714
Daniel@0 2715 // Round start and stop values to step interval.
Daniel@0 2716 return [
Daniel@0 2717 Math.ceil(start / step) * step,
Daniel@0 2718 Math.floor(stop / step) * step + step / 2, // inclusive
Daniel@0 2719 step
Daniel@0 2720 ];
Daniel@0 2721 }
Daniel@0 2722
Daniel@0 2723 function numberAutoFormat(domain, count, f) {
Daniel@0 2724 var range = intervals(domain, count);
Daniel@0 2725 if (f == null) {
Daniel@0 2726 f = ',.' + d3_numberF.precisionFixed(range[2]) + 'f';
Daniel@0 2727 } else {
Daniel@0 2728 switch (f = d3_numberF.formatSpecifier(f), f.type) {
Daniel@0 2729 case 's': {
Daniel@0 2730 var value = Math.max(Math.abs(range[0]), Math.abs(range[1]));
Daniel@0 2731 if (f.precision == null) f.precision = d3_numberF.precisionPrefix(range[2], value);
Daniel@0 2732 return numberF.formatPrefix(f, value);
Daniel@0 2733 }
Daniel@0 2734 case '':
Daniel@0 2735 case 'e':
Daniel@0 2736 case 'g':
Daniel@0 2737 case 'p':
Daniel@0 2738 case 'r': {
Daniel@0 2739 if (f.precision == null) f.precision = d3_numberF.precisionRound(range[2], Math.max(Math.abs(range[0]), Math.abs(range[1]))) - (f.type === 'e');
Daniel@0 2740 break;
Daniel@0 2741 }
Daniel@0 2742 case 'f':
Daniel@0 2743 case '%': {
Daniel@0 2744 if (f.precision == null) f.precision = d3_numberF.precisionFixed(range[2]) - (f.type === '%') * 2;
Daniel@0 2745 break;
Daniel@0 2746 }
Daniel@0 2747 }
Daniel@0 2748 }
Daniel@0 2749 return numberF.format(f);
Daniel@0 2750 }
Daniel@0 2751
Daniel@0 2752 function timeAutoFormat() {
Daniel@0 2753 var f = timeF.format,
Daniel@0 2754 formatMillisecond = f('.%L'),
Daniel@0 2755 formatSecond = f(':%S'),
Daniel@0 2756 formatMinute = f('%I:%M'),
Daniel@0 2757 formatHour = f('%I %p'),
Daniel@0 2758 formatDay = f('%a %d'),
Daniel@0 2759 formatWeek = f('%b %d'),
Daniel@0 2760 formatMonth = f('%B'),
Daniel@0 2761 formatYear = f('%Y');
Daniel@0 2762
Daniel@0 2763 return function(date) {
Daniel@0 2764 var d = +date;
Daniel@0 2765 return (d3_time.second(date) < d ? formatMillisecond
Daniel@0 2766 : d3_time.minute(date) < d ? formatSecond
Daniel@0 2767 : d3_time.hour(date) < d ? formatMinute
Daniel@0 2768 : d3_time.day(date) < d ? formatHour
Daniel@0 2769 : d3_time.month(date) < d ?
Daniel@0 2770 (d3_time.week(date) < d ? formatDay : formatWeek)
Daniel@0 2771 : d3_time.year(date) < d ? formatMonth
Daniel@0 2772 : formatYear)(date);
Daniel@0 2773 };
Daniel@0 2774 }
Daniel@0 2775
Daniel@0 2776 function utcAutoFormat() {
Daniel@0 2777 var f = timeF.utcFormat,
Daniel@0 2778 formatMillisecond = f('.%L'),
Daniel@0 2779 formatSecond = f(':%S'),
Daniel@0 2780 formatMinute = f('%I:%M'),
Daniel@0 2781 formatHour = f('%I %p'),
Daniel@0 2782 formatDay = f('%a %d'),
Daniel@0 2783 formatWeek = f('%b %d'),
Daniel@0 2784 formatMonth = f('%B'),
Daniel@0 2785 formatYear = f('%Y');
Daniel@0 2786
Daniel@0 2787 return function(date) {
Daniel@0 2788 var d = +date;
Daniel@0 2789 return (d3_time.utcSecond(date) < d ? formatMillisecond
Daniel@0 2790 : d3_time.utcMinute(date) < d ? formatSecond
Daniel@0 2791 : d3_time.utcHour(date) < d ? formatMinute
Daniel@0 2792 : d3_time.utcDay(date) < d ? formatHour
Daniel@0 2793 : d3_time.utcMonth(date) < d ?
Daniel@0 2794 (d3_time.utcWeek(date) < d ? formatDay : formatWeek)
Daniel@0 2795 : d3_time.utcYear(date) < d ? formatMonth
Daniel@0 2796 : formatYear)(date);
Daniel@0 2797 };
Daniel@0 2798 }
Daniel@0 2799
Daniel@0 2800 },{"d3-format":4,"d3-time":6,"d3-time-format":5}],14:[function(require,module,exports){
Daniel@0 2801 var gen = module.exports = {};
Daniel@0 2802
Daniel@0 2803 gen.repeat = function(val, n) {
Daniel@0 2804 var a = Array(n), i;
Daniel@0 2805 for (i=0; i<n; ++i) a[i] = val;
Daniel@0 2806 return a;
Daniel@0 2807 };
Daniel@0 2808
Daniel@0 2809 gen.zeros = function(n) {
Daniel@0 2810 return gen.repeat(0, n);
Daniel@0 2811 };
Daniel@0 2812
Daniel@0 2813 gen.range = function(start, stop, step) {
Daniel@0 2814 if (arguments.length < 3) {
Daniel@0 2815 step = 1;
Daniel@0 2816 if (arguments.length < 2) {
Daniel@0 2817 stop = start;
Daniel@0 2818 start = 0;
Daniel@0 2819 }
Daniel@0 2820 }
Daniel@0 2821 if ((stop - start) / step == Infinity) throw new Error('Infinite range');
Daniel@0 2822 var range = [], i = -1, j;
Daniel@0 2823 if (step < 0) while ((j = start + step * ++i) > stop) range.push(j);
Daniel@0 2824 else while ((j = start + step * ++i) < stop) range.push(j);
Daniel@0 2825 return range;
Daniel@0 2826 };
Daniel@0 2827
Daniel@0 2828 gen.random = {};
Daniel@0 2829
Daniel@0 2830 gen.random.uniform = function(min, max) {
Daniel@0 2831 if (max === undefined) {
Daniel@0 2832 max = min === undefined ? 1 : min;
Daniel@0 2833 min = 0;
Daniel@0 2834 }
Daniel@0 2835 var d = max - min;
Daniel@0 2836 var f = function() {
Daniel@0 2837 return min + d * Math.random();
Daniel@0 2838 };
Daniel@0 2839 f.samples = function(n) { return gen.zeros(n).map(f); };
Daniel@0 2840 return f;
Daniel@0 2841 };
Daniel@0 2842
Daniel@0 2843 gen.random.integer = function(a, b) {
Daniel@0 2844 if (b === undefined) {
Daniel@0 2845 b = a;
Daniel@0 2846 a = 0;
Daniel@0 2847 }
Daniel@0 2848 var d = b - a;
Daniel@0 2849 var f = function() {
Daniel@0 2850 return a + Math.floor(d * Math.random());
Daniel@0 2851 };
Daniel@0 2852 f.samples = function(n) { return gen.zeros(n).map(f); };
Daniel@0 2853 return f;
Daniel@0 2854 };
Daniel@0 2855
Daniel@0 2856 gen.random.normal = function(mean, stdev) {
Daniel@0 2857 mean = mean || 0;
Daniel@0 2858 stdev = stdev || 1;
Daniel@0 2859 var next;
Daniel@0 2860 var f = function() {
Daniel@0 2861 var x = 0, y = 0, rds, c;
Daniel@0 2862 if (next !== undefined) {
Daniel@0 2863 x = next;
Daniel@0 2864 next = undefined;
Daniel@0 2865 return x;
Daniel@0 2866 }
Daniel@0 2867 do {
Daniel@0 2868 x = Math.random()*2-1;
Daniel@0 2869 y = Math.random()*2-1;
Daniel@0 2870 rds = x*x + y*y;
Daniel@0 2871 } while (rds === 0 || rds > 1);
Daniel@0 2872 c = Math.sqrt(-2*Math.log(rds)/rds); // Box-Muller transform
Daniel@0 2873 next = mean + y*c*stdev;
Daniel@0 2874 return mean + x*c*stdev;
Daniel@0 2875 };
Daniel@0 2876 f.samples = function(n) { return gen.zeros(n).map(f); };
Daniel@0 2877 return f;
Daniel@0 2878 };
Daniel@0 2879 },{}],15:[function(require,module,exports){
Daniel@0 2880 var util = require('../../util');
Daniel@0 2881 var d3_dsv = require('d3-dsv');
Daniel@0 2882
Daniel@0 2883 function dsv(data, format) {
Daniel@0 2884 if (data) {
Daniel@0 2885 var h = format.header;
Daniel@0 2886 data = (h ? h.join(format.delimiter) + '\n' : '') + data;
Daniel@0 2887 }
Daniel@0 2888 return d3_dsv.dsv(format.delimiter).parse(data);
Daniel@0 2889 }
Daniel@0 2890
Daniel@0 2891 dsv.delimiter = function(delim) {
Daniel@0 2892 var fmt = {delimiter: delim};
Daniel@0 2893 return function(data, format) {
Daniel@0 2894 return dsv(data, format ? util.extend(format, fmt) : fmt);
Daniel@0 2895 };
Daniel@0 2896 };
Daniel@0 2897
Daniel@0 2898 module.exports = dsv;
Daniel@0 2899 },{"../../util":29,"d3-dsv":3}],16:[function(require,module,exports){
Daniel@0 2900 var dsv = require('./dsv');
Daniel@0 2901
Daniel@0 2902 module.exports = {
Daniel@0 2903 json: require('./json'),
Daniel@0 2904 topojson: require('./topojson'),
Daniel@0 2905 treejson: require('./treejson'),
Daniel@0 2906 dsv: dsv,
Daniel@0 2907 csv: dsv.delimiter(','),
Daniel@0 2908 tsv: dsv.delimiter('\t')
Daniel@0 2909 };
Daniel@0 2910 },{"./dsv":15,"./json":17,"./topojson":18,"./treejson":19}],17:[function(require,module,exports){
Daniel@0 2911 var util = require('../../util');
Daniel@0 2912
Daniel@0 2913 module.exports = function(data, format) {
Daniel@0 2914 var d = util.isObject(data) && !util.isBuffer(data) ?
Daniel@0 2915 data : JSON.parse(data);
Daniel@0 2916 if (format && format.property) {
Daniel@0 2917 d = util.accessor(format.property)(d);
Daniel@0 2918 }
Daniel@0 2919 return d;
Daniel@0 2920 };
Daniel@0 2921
Daniel@0 2922 },{"../../util":29}],18:[function(require,module,exports){
Daniel@0 2923 (function (global){
Daniel@0 2924 var json = require('./json');
Daniel@0 2925
Daniel@0 2926 var reader = function(data, format) {
Daniel@0 2927 var topojson = reader.topojson;
Daniel@0 2928 if (topojson == null) { throw Error('TopoJSON library not loaded.'); }
Daniel@0 2929
Daniel@0 2930 var t = json(data, format), obj;
Daniel@0 2931
Daniel@0 2932 if (format && format.feature) {
Daniel@0 2933 if ((obj = t.objects[format.feature])) {
Daniel@0 2934 return topojson.feature(t, obj).features;
Daniel@0 2935 } else {
Daniel@0 2936 throw Error('Invalid TopoJSON object: ' + format.feature);
Daniel@0 2937 }
Daniel@0 2938 } else if (format && format.mesh) {
Daniel@0 2939 if ((obj = t.objects[format.mesh])) {
Daniel@0 2940 return [topojson.mesh(t, t.objects[format.mesh])];
Daniel@0 2941 } else {
Daniel@0 2942 throw Error('Invalid TopoJSON object: ' + format.mesh);
Daniel@0 2943 }
Daniel@0 2944 } else {
Daniel@0 2945 throw Error('Missing TopoJSON feature or mesh parameter.');
Daniel@0 2946 }
Daniel@0 2947 };
Daniel@0 2948
Daniel@0 2949 reader.topojson = (typeof window !== "undefined" ? window['topojson'] : typeof global !== "undefined" ? global['topojson'] : null);
Daniel@0 2950 module.exports = reader;
Daniel@0 2951 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
Daniel@0 2952
Daniel@0 2953 },{"./json":17}],19:[function(require,module,exports){
Daniel@0 2954 var json = require('./json');
Daniel@0 2955
Daniel@0 2956 module.exports = function(data, format) {
Daniel@0 2957 data = json(data, format);
Daniel@0 2958 return toTable(data, (format && format.children));
Daniel@0 2959 };
Daniel@0 2960
Daniel@0 2961 function toTable(root, childrenField) {
Daniel@0 2962 childrenField = childrenField || 'children';
Daniel@0 2963 var table = [];
Daniel@0 2964
Daniel@0 2965 function visit(node) {
Daniel@0 2966 table.push(node);
Daniel@0 2967 var children = node[childrenField];
Daniel@0 2968 if (children) {
Daniel@0 2969 for (var i=0; i<children.length; ++i) {
Daniel@0 2970 visit(children[i], node);
Daniel@0 2971 }
Daniel@0 2972 }
Daniel@0 2973 }
Daniel@0 2974
Daniel@0 2975 visit(root, null);
Daniel@0 2976 return (table.root = root, table);
Daniel@0 2977 }
Daniel@0 2978 },{"./json":17}],20:[function(require,module,exports){
Daniel@0 2979 // Matches absolute URLs with optional protocol
Daniel@0 2980 // https://... file://... //...
Daniel@0 2981 var protocol_re = /^([A-Za-z]+:)?\/\//;
Daniel@0 2982
Daniel@0 2983 // Special treatment in node.js for the file: protocol
Daniel@0 2984 var fileProtocol = 'file://';
Daniel@0 2985
Daniel@0 2986 // Validate and cleanup URL to ensure that it is allowed to be accessed
Daniel@0 2987 // Returns cleaned up URL, or false if access is not allowed
Daniel@0 2988 function sanitizeUrl(opt) {
Daniel@0 2989 var url = opt.url;
Daniel@0 2990 if (!url && opt.file) { return fileProtocol + opt.file; }
Daniel@0 2991
Daniel@0 2992 // In case this is a relative url (has no host), prepend opt.baseURL
Daniel@0 2993 if (opt.baseURL && !protocol_re.test(url)) {
Daniel@0 2994 if (!startsWith(url, '/') && opt.baseURL[opt.baseURL.length-1] !== '/') {
Daniel@0 2995 url = '/' + url; // Ensure that there is a slash between the baseURL (e.g. hostname) and url
Daniel@0 2996 }
Daniel@0 2997 url = opt.baseURL + url;
Daniel@0 2998 }
Daniel@0 2999 // relative protocol, starts with '//'
Daniel@0 3000 if (!load.useXHR && startsWith(url, '//')) {
Daniel@0 3001 url = (opt.defaultProtocol || 'http') + ':' + url;
Daniel@0 3002 }
Daniel@0 3003 // If opt.domainWhiteList is set, only allows url, whose hostname
Daniel@0 3004 // * Is the same as the origin (window.location.hostname)
Daniel@0 3005 // * Equals one of the values in the whitelist
Daniel@0 3006 // * Is a proper subdomain of one of the values in the whitelist
Daniel@0 3007 if (opt.domainWhiteList) {
Daniel@0 3008 var domain, origin;
Daniel@0 3009 if (load.useXHR) {
Daniel@0 3010 var a = document.createElement('a');
Daniel@0 3011 a.href = url;
Daniel@0 3012 // From http://stackoverflow.com/questions/736513/how-do-i-parse-a-url-into-hostname-and-path-in-javascript
Daniel@0 3013 // IE doesn't populate all link properties when setting .href with a relative URL,
Daniel@0 3014 // however .href will return an absolute URL which then can be used on itself
Daniel@0 3015 // to populate these additional fields.
Daniel@0 3016 if (a.host === '') {
Daniel@0 3017 a.href = a.href;
Daniel@0 3018 }
Daniel@0 3019 domain = a.hostname.toLowerCase();
Daniel@0 3020 origin = window.location.hostname;
Daniel@0 3021 } else {
Daniel@0 3022 // relative protocol is broken: https://github.com/defunctzombie/node-url/issues/5
Daniel@0 3023 var parts = require('url').parse(url);
Daniel@0 3024 domain = parts.hostname;
Daniel@0 3025 origin = null;
Daniel@0 3026 }
Daniel@0 3027
Daniel@0 3028 if (origin !== domain) {
Daniel@0 3029 var whiteListed = opt.domainWhiteList.some(function(d) {
Daniel@0 3030 var idx = domain.length - d.length;
Daniel@0 3031 return d === domain ||
Daniel@0 3032 (idx > 1 && domain[idx-1] === '.' && domain.lastIndexOf(d) === idx);
Daniel@0 3033 });
Daniel@0 3034 if (!whiteListed) {
Daniel@0 3035 throw 'URL is not whitelisted: ' + url;
Daniel@0 3036 }
Daniel@0 3037 }
Daniel@0 3038 }
Daniel@0 3039 return url;
Daniel@0 3040 }
Daniel@0 3041
Daniel@0 3042 function load(opt, callback) {
Daniel@0 3043 var error = callback || function(e) { throw e; }, url;
Daniel@0 3044
Daniel@0 3045 try {
Daniel@0 3046 url = load.sanitizeUrl(opt); // enable override
Daniel@0 3047 } catch (err) {
Daniel@0 3048 error(err);
Daniel@0 3049 return;
Daniel@0 3050 }
Daniel@0 3051
Daniel@0 3052 if (!url) {
Daniel@0 3053 error('Invalid URL: ' + opt.url);
Daniel@0 3054 } else if (load.useXHR) {
Daniel@0 3055 // on client, use xhr
Daniel@0 3056 return xhr(url, callback);
Daniel@0 3057 } else if (startsWith(url, fileProtocol)) {
Daniel@0 3058 // on server, if url starts with 'file://', strip it and load from file
Daniel@0 3059 return file(url.slice(fileProtocol.length), callback);
Daniel@0 3060 } else if (url.indexOf('://') < 0) { // TODO better protocol check?
Daniel@0 3061 // on server, if no protocol assume file
Daniel@0 3062 return file(url, callback);
Daniel@0 3063 } else {
Daniel@0 3064 // for regular URLs on server
Daniel@0 3065 return http(url, callback);
Daniel@0 3066 }
Daniel@0 3067 }
Daniel@0 3068
Daniel@0 3069 function xhrHasResponse(request) {
Daniel@0 3070 var type = request.responseType;
Daniel@0 3071 return type && type !== 'text' ?
Daniel@0 3072 request.response : // null on error
Daniel@0 3073 request.responseText; // '' on error
Daniel@0 3074 }
Daniel@0 3075
Daniel@0 3076 function xhr(url, callback) {
Daniel@0 3077 var async = !!callback;
Daniel@0 3078 var request = new XMLHttpRequest();
Daniel@0 3079 // If IE does not support CORS, use XDomainRequest (copied from d3.xhr)
Daniel@0 3080 if (this.XDomainRequest &&
Daniel@0 3081 !('withCredentials' in request) &&
Daniel@0 3082 /^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest();
Daniel@0 3083
Daniel@0 3084 function respond() {
Daniel@0 3085 var status = request.status;
Daniel@0 3086 if (!status && xhrHasResponse(request) || status >= 200 && status < 300 || status === 304) {
Daniel@0 3087 callback(null, request.responseText);
Daniel@0 3088 } else {
Daniel@0 3089 callback(request, null);
Daniel@0 3090 }
Daniel@0 3091 }
Daniel@0 3092
Daniel@0 3093 if (async) {
Daniel@0 3094 if ('onload' in request) {
Daniel@0 3095 request.onload = request.onerror = respond;
Daniel@0 3096 } else {
Daniel@0 3097 request.onreadystatechange = function() {
Daniel@0 3098 if (request.readyState > 3) respond();
Daniel@0 3099 };
Daniel@0 3100 }
Daniel@0 3101 }
Daniel@0 3102
Daniel@0 3103 request.open('GET', url, async);
Daniel@0 3104 request.send();
Daniel@0 3105
Daniel@0 3106 if (!async && xhrHasResponse(request)) {
Daniel@0 3107 return request.responseText;
Daniel@0 3108 }
Daniel@0 3109 }
Daniel@0 3110
Daniel@0 3111 function file(filename, callback) {
Daniel@0 3112 var fs = require('fs');
Daniel@0 3113 if (!callback) {
Daniel@0 3114 return fs.readFileSync(filename, 'utf8');
Daniel@0 3115 }
Daniel@0 3116 fs.readFile(filename, callback);
Daniel@0 3117 }
Daniel@0 3118
Daniel@0 3119 function http(url, callback) {
Daniel@0 3120 if (!callback) {
Daniel@0 3121 return require('sync-request')('GET', url).getBody();
Daniel@0 3122 }
Daniel@0 3123
Daniel@0 3124 var options = {url: url, encoding: null, gzip: true};
Daniel@0 3125 require('request')(options, function(error, response, body) {
Daniel@0 3126 if (!error && response.statusCode === 200) {
Daniel@0 3127 callback(null, body);
Daniel@0 3128 } else {
Daniel@0 3129 error = error ||
Daniel@0 3130 'Load failed with response code ' + response.statusCode + '.';
Daniel@0 3131 callback(error, null);
Daniel@0 3132 }
Daniel@0 3133 });
Daniel@0 3134 }
Daniel@0 3135
Daniel@0 3136 function startsWith(string, searchString) {
Daniel@0 3137 return string == null ? false : string.lastIndexOf(searchString, 0) === 0;
Daniel@0 3138 }
Daniel@0 3139
Daniel@0 3140 load.sanitizeUrl = sanitizeUrl;
Daniel@0 3141
Daniel@0 3142 load.useXHR = (typeof XMLHttpRequest !== 'undefined');
Daniel@0 3143
Daniel@0 3144 module.exports = load;
Daniel@0 3145
Daniel@0 3146 },{"fs":2,"request":2,"sync-request":2,"url":2}],21:[function(require,module,exports){
Daniel@0 3147 var util = require('../util');
Daniel@0 3148 var type = require('./type');
Daniel@0 3149 var formats = require('./formats');
Daniel@0 3150
Daniel@0 3151 function read(data, format) {
Daniel@0 3152 var type = (format && format.type) || 'json';
Daniel@0 3153 data = formats[type](data, format);
Daniel@0 3154 if (format && format.parse) parse(data, format.parse);
Daniel@0 3155 return data;
Daniel@0 3156 }
Daniel@0 3157
Daniel@0 3158 function parse(data, types) {
Daniel@0 3159 var cols, parsers, d, i, j, clen, len = data.length;
Daniel@0 3160
Daniel@0 3161 types = (types==='auto') ? type.inferAll(data) : util.duplicate(types);
Daniel@0 3162 cols = util.keys(types);
Daniel@0 3163 parsers = cols.map(function(c) { return type.parsers[types[c]]; });
Daniel@0 3164
Daniel@0 3165 for (i=0, clen=cols.length; i<len; ++i) {
Daniel@0 3166 d = data[i];
Daniel@0 3167 for (j=0; j<clen; ++j) {
Daniel@0 3168 d[cols[j]] = parsers[j](d[cols[j]]);
Daniel@0 3169 }
Daniel@0 3170 }
Daniel@0 3171 type.annotation(data, types);
Daniel@0 3172 }
Daniel@0 3173
Daniel@0 3174 read.formats = formats;
Daniel@0 3175 module.exports = read;
Daniel@0 3176
Daniel@0 3177 },{"../util":29,"./formats":16,"./type":23}],22:[function(require,module,exports){
Daniel@0 3178 var util = require('../util');
Daniel@0 3179 var load = require('./load');
Daniel@0 3180 var read = require('./read');
Daniel@0 3181
Daniel@0 3182 module.exports = util
Daniel@0 3183 .keys(read.formats)
Daniel@0 3184 .reduce(function(out, type) {
Daniel@0 3185 out[type] = function(opt, format, callback) {
Daniel@0 3186 // process arguments
Daniel@0 3187 if (util.isString(opt)) { opt = {url: opt}; }
Daniel@0 3188 if (arguments.length === 2 && util.isFunction(format)) {
Daniel@0 3189 callback = format;
Daniel@0 3190 format = undefined;
Daniel@0 3191 }
Daniel@0 3192
Daniel@0 3193 // set up read format
Daniel@0 3194 format = util.extend({parse: 'auto'}, format);
Daniel@0 3195 format.type = type;
Daniel@0 3196
Daniel@0 3197 // load data
Daniel@0 3198 var data = load(opt, callback ? function(error, data) {
Daniel@0 3199 if (error) { callback(error, null); return; }
Daniel@0 3200 try {
Daniel@0 3201 // data loaded, now parse it (async)
Daniel@0 3202 data = read(data, format);
Daniel@0 3203 callback(null, data);
Daniel@0 3204 } catch (e) {
Daniel@0 3205 callback(e, null);
Daniel@0 3206 }
Daniel@0 3207 } : undefined);
Daniel@0 3208
Daniel@0 3209 // data loaded, now parse it (sync)
Daniel@0 3210 if (!callback) return read(data, format);
Daniel@0 3211 };
Daniel@0 3212 return out;
Daniel@0 3213 }, {});
Daniel@0 3214
Daniel@0 3215 },{"../util":29,"./load":20,"./read":21}],23:[function(require,module,exports){
Daniel@0 3216 var util = require('../util');
Daniel@0 3217
Daniel@0 3218 var TYPES = '__types__';
Daniel@0 3219
Daniel@0 3220 var PARSERS = {
Daniel@0 3221 boolean: util.boolean,
Daniel@0 3222 integer: util.number,
Daniel@0 3223 number: util.number,
Daniel@0 3224 date: util.date,
Daniel@0 3225 string: function(x) { return x==='' ? null : x; }
Daniel@0 3226 };
Daniel@0 3227
Daniel@0 3228 var TESTS = {
Daniel@0 3229 boolean: function(x) { return x==='true' || x==='false' || util.isBoolean(x); },
Daniel@0 3230 integer: function(x) { return TESTS.number(x) && (x=+x) === ~~x; },
Daniel@0 3231 number: function(x) { return !isNaN(+x) && !util.isDate(x); },
Daniel@0 3232 date: function(x) { return !isNaN(Date.parse(x)); }
Daniel@0 3233 };
Daniel@0 3234
Daniel@0 3235 function annotation(data, types) {
Daniel@0 3236 if (!types) return data && data[TYPES] || null;
Daniel@0 3237 data[TYPES] = types;
Daniel@0 3238 }
Daniel@0 3239
Daniel@0 3240 function type(values, f) {
Daniel@0 3241 f = util.$(f);
Daniel@0 3242 var v, i, n;
Daniel@0 3243
Daniel@0 3244 // if data array has type annotations, use them
Daniel@0 3245 if (values[TYPES]) {
Daniel@0 3246 v = f(values[TYPES]);
Daniel@0 3247 if (util.isString(v)) return v;
Daniel@0 3248 }
Daniel@0 3249
Daniel@0 3250 for (i=0, n=values.length; !util.isValid(v) && i<n; ++i) {
Daniel@0 3251 v = f ? f(values[i]) : values[i];
Daniel@0 3252 }
Daniel@0 3253
Daniel@0 3254 return util.isDate(v) ? 'date' :
Daniel@0 3255 util.isNumber(v) ? 'number' :
Daniel@0 3256 util.isBoolean(v) ? 'boolean' :
Daniel@0 3257 util.isString(v) ? 'string' : null;
Daniel@0 3258 }
Daniel@0 3259
Daniel@0 3260 function typeAll(data, fields) {
Daniel@0 3261 if (!data.length) return;
Daniel@0 3262 fields = fields || util.keys(data[0]);
Daniel@0 3263 return fields.reduce(function(types, f) {
Daniel@0 3264 return (types[f] = type(data, f), types);
Daniel@0 3265 }, {});
Daniel@0 3266 }
Daniel@0 3267
Daniel@0 3268 function infer(values, f) {
Daniel@0 3269 f = util.$(f);
Daniel@0 3270 var i, j, v;
Daniel@0 3271
Daniel@0 3272 // types to test for, in precedence order
Daniel@0 3273 var types = ['boolean', 'integer', 'number', 'date'];
Daniel@0 3274
Daniel@0 3275 for (i=0; i<values.length; ++i) {
Daniel@0 3276 // get next value to test
Daniel@0 3277 v = f ? f(values[i]) : values[i];
Daniel@0 3278 // test value against remaining types
Daniel@0 3279 for (j=0; j<types.length; ++j) {
Daniel@0 3280 if (util.isValid(v) && !TESTS[types[j]](v)) {
Daniel@0 3281 types.splice(j, 1);
Daniel@0 3282 j -= 1;
Daniel@0 3283 }
Daniel@0 3284 }
Daniel@0 3285 // if no types left, return 'string'
Daniel@0 3286 if (types.length === 0) return 'string';
Daniel@0 3287 }
Daniel@0 3288
Daniel@0 3289 return types[0];
Daniel@0 3290 }
Daniel@0 3291
Daniel@0 3292 function inferAll(data, fields) {
Daniel@0 3293 fields = fields || util.keys(data[0]);
Daniel@0 3294 return fields.reduce(function(types, f) {
Daniel@0 3295 types[f] = infer(data, f);
Daniel@0 3296 return types;
Daniel@0 3297 }, {});
Daniel@0 3298 }
Daniel@0 3299
Daniel@0 3300 type.annotation = annotation;
Daniel@0 3301 type.all = typeAll;
Daniel@0 3302 type.infer = infer;
Daniel@0 3303 type.inferAll = inferAll;
Daniel@0 3304 type.parsers = PARSERS;
Daniel@0 3305 module.exports = type;
Daniel@0 3306 },{"../util":29}],24:[function(require,module,exports){
Daniel@0 3307 var util = require('./util');
Daniel@0 3308
Daniel@0 3309 var dl = {
Daniel@0 3310 version: '1.4.6',
Daniel@0 3311 load: require('./import/load'),
Daniel@0 3312 read: require('./import/read'),
Daniel@0 3313 type: require('./import/type'),
Daniel@0 3314 Aggregator: require('./aggregate/aggregator'),
Daniel@0 3315 groupby: require('./aggregate/groupby'),
Daniel@0 3316 bins: require('./bins/bins'),
Daniel@0 3317 $bin: require('./bins/histogram').$bin,
Daniel@0 3318 histogram: require('./bins/histogram').histogram,
Daniel@0 3319 format: require('./format'),
Daniel@0 3320 print: require('./print'),
Daniel@0 3321 template: require('./template'),
Daniel@0 3322 time: require('./time')
Daniel@0 3323 };
Daniel@0 3324
Daniel@0 3325 util.extend(dl, util);
Daniel@0 3326 util.extend(dl, require('./generate'));
Daniel@0 3327 util.extend(dl, require('./stats'));
Daniel@0 3328 util.extend(dl, require('./import/readers'));
Daniel@0 3329
Daniel@0 3330 module.exports = dl;
Daniel@0 3331 },{"./aggregate/aggregator":7,"./aggregate/groupby":9,"./bins/bins":11,"./bins/histogram":12,"./format":13,"./generate":14,"./import/load":20,"./import/read":21,"./import/readers":22,"./import/type":23,"./print":25,"./stats":26,"./template":27,"./time":28,"./util":29}],25:[function(require,module,exports){
Daniel@0 3332 var util = require('./util');
Daniel@0 3333 var type = require('./import/type');
Daniel@0 3334 var stats = require('./stats');
Daniel@0 3335 var template = require('./template');
Daniel@0 3336
Daniel@0 3337 var FMT = {
Daniel@0 3338 'date': '|time:"%m/%d/%Y %H:%M:%S"',
Daniel@0 3339 'number': '|number:".4f"',
Daniel@0 3340 'integer': '|number:"d"'
Daniel@0 3341 };
Daniel@0 3342
Daniel@0 3343 var POS = {
Daniel@0 3344 'number': 'left',
Daniel@0 3345 'integer': 'left'
Daniel@0 3346 };
Daniel@0 3347
Daniel@0 3348 module.exports.table = function(data, opt) {
Daniel@0 3349 opt = util.extend({separator:' ', minwidth: 8, maxwidth: 15}, opt);
Daniel@0 3350 var fields = opt.fields || util.keys(data[0]),
Daniel@0 3351 types = type.all(data);
Daniel@0 3352
Daniel@0 3353 if (opt.start || opt.limit) {
Daniel@0 3354 var a = opt.start || 0,
Daniel@0 3355 b = opt.limit ? a + opt.limit : data.length;
Daniel@0 3356 data = data.slice(a, b);
Daniel@0 3357 }
Daniel@0 3358
Daniel@0 3359 // determine char width of fields
Daniel@0 3360 var lens = fields.map(function(name) {
Daniel@0 3361 var format = FMT[types[name]] || '',
Daniel@0 3362 t = template('{{' + name + format + '}}'),
Daniel@0 3363 l = stats.max(data, function(x) { return t(x).length; });
Daniel@0 3364 l = Math.max(Math.min(name.length, opt.minwidth), l);
Daniel@0 3365 return opt.maxwidth > 0 ? Math.min(l, opt.maxwidth) : l;
Daniel@0 3366 });
Daniel@0 3367
Daniel@0 3368 // print header row
Daniel@0 3369 var head = fields.map(function(name, i) {
Daniel@0 3370 return util.truncate(util.pad(name, lens[i], 'center'), lens[i]);
Daniel@0 3371 }).join(opt.separator);
Daniel@0 3372
Daniel@0 3373 // build template function for each row
Daniel@0 3374 var tmpl = template(fields.map(function(name, i) {
Daniel@0 3375 return '{{' +
Daniel@0 3376 name +
Daniel@0 3377 (FMT[types[name]] || '') +
Daniel@0 3378 ('|pad:' + lens[i] + ',' + (POS[types[name]] || 'right')) +
Daniel@0 3379 ('|truncate:' + lens[i]) +
Daniel@0 3380 '}}';
Daniel@0 3381 }).join(opt.separator));
Daniel@0 3382
Daniel@0 3383 // print table
Daniel@0 3384 return head + "\n" + data.map(tmpl).join('\n');
Daniel@0 3385 };
Daniel@0 3386
Daniel@0 3387 module.exports.summary = function(s) {
Daniel@0 3388 s = s ? s.__summary__ ? s : stats.summary(s) : this;
Daniel@0 3389 var str = [], i, n;
Daniel@0 3390 for (i=0, n=s.length; i<n; ++i) {
Daniel@0 3391 str.push('-- ' + s[i].field + ' --');
Daniel@0 3392 if (s[i].type === 'string' || s[i].distinct < 10) {
Daniel@0 3393 str.push(printCategoricalProfile(s[i]));
Daniel@0 3394 } else {
Daniel@0 3395 str.push(printQuantitativeProfile(s[i]));
Daniel@0 3396 }
Daniel@0 3397 str.push('');
Daniel@0 3398 }
Daniel@0 3399 return str.join('\n');
Daniel@0 3400 };
Daniel@0 3401
Daniel@0 3402 function printQuantitativeProfile(p) {
Daniel@0 3403 return [
Daniel@0 3404 'valid: ' + p.valid,
Daniel@0 3405 'missing: ' + p.missing,
Daniel@0 3406 'distinct: ' + p.distinct,
Daniel@0 3407 'min: ' + p.min,
Daniel@0 3408 'max: ' + p.max,
Daniel@0 3409 'median: ' + p.median,
Daniel@0 3410 'mean: ' + p.mean,
Daniel@0 3411 'stdev: ' + p.stdev,
Daniel@0 3412 'modeskew: ' + p.modeskew
Daniel@0 3413 ].join('\n');
Daniel@0 3414 }
Daniel@0 3415
Daniel@0 3416 function printCategoricalProfile(p) {
Daniel@0 3417 var list = [
Daniel@0 3418 'valid: ' + p.valid,
Daniel@0 3419 'missing: ' + p.missing,
Daniel@0 3420 'distinct: ' + p.distinct,
Daniel@0 3421 'top values: '
Daniel@0 3422 ];
Daniel@0 3423 var u = p.unique;
Daniel@0 3424 var top = util.keys(u)
Daniel@0 3425 .sort(function(a,b) { return u[b] - u[a]; })
Daniel@0 3426 .slice(0, 6)
Daniel@0 3427 .map(function(v) { return ' \'' + v + '\' (' + u[v] + ')'; });
Daniel@0 3428 return list.concat(top).join('\n');
Daniel@0 3429 }
Daniel@0 3430 },{"./import/type":23,"./stats":26,"./template":27,"./util":29}],26:[function(require,module,exports){
Daniel@0 3431 var util = require('./util');
Daniel@0 3432 var type = require('./import/type');
Daniel@0 3433 var gen = require('./generate');
Daniel@0 3434 var stats = {};
Daniel@0 3435
Daniel@0 3436 // Collect unique values.
Daniel@0 3437 // Output: an array of unique values, in first-observed order
Daniel@0 3438 stats.unique = function(values, f, results) {
Daniel@0 3439 f = util.$(f);
Daniel@0 3440 results = results || [];
Daniel@0 3441 var u = {}, v, i, n;
Daniel@0 3442 for (i=0, n=values.length; i<n; ++i) {
Daniel@0 3443 v = f ? f(values[i]) : values[i];
Daniel@0 3444 if (v in u) continue;
Daniel@0 3445 u[v] = 1;
Daniel@0 3446 results.push(v);
Daniel@0 3447 }
Daniel@0 3448 return results;
Daniel@0 3449 };
Daniel@0 3450
Daniel@0 3451 // Return the length of the input array.
Daniel@0 3452 stats.count = function(values) {
Daniel@0 3453 return values && values.length || 0;
Daniel@0 3454 };
Daniel@0 3455
Daniel@0 3456 // Count the number of non-null, non-undefined, non-NaN values.
Daniel@0 3457 stats.count.valid = function(values, f) {
Daniel@0 3458 f = util.$(f);
Daniel@0 3459 var v, i, n, valid = 0;
Daniel@0 3460 for (i=0, n=values.length; i<n; ++i) {
Daniel@0 3461 v = f ? f(values[i]) : values[i];
Daniel@0 3462 if (util.isValid(v)) valid += 1;
Daniel@0 3463 }
Daniel@0 3464 return valid;
Daniel@0 3465 };
Daniel@0 3466
Daniel@0 3467 // Count the number of null or undefined values.
Daniel@0 3468 stats.count.missing = function(values, f) {
Daniel@0 3469 f = util.$(f);
Daniel@0 3470 var v, i, n, count = 0;
Daniel@0 3471 for (i=0, n=values.length; i<n; ++i) {
Daniel@0 3472 v = f ? f(values[i]) : values[i];
Daniel@0 3473 if (v == null) count += 1;
Daniel@0 3474 }
Daniel@0 3475 return count;
Daniel@0 3476 };
Daniel@0 3477
Daniel@0 3478 // Count the number of distinct values.
Daniel@0 3479 // Null, undefined and NaN are each considered distinct values.
Daniel@0 3480 stats.count.distinct = function(values, f) {
Daniel@0 3481 f = util.$(f);
Daniel@0 3482 var u = {}, v, i, n, count = 0;
Daniel@0 3483 for (i=0, n=values.length; i<n; ++i) {
Daniel@0 3484 v = f ? f(values[i]) : values[i];
Daniel@0 3485 if (v in u) continue;
Daniel@0 3486 u[v] = 1;
Daniel@0 3487 count += 1;
Daniel@0 3488 }
Daniel@0 3489 return count;
Daniel@0 3490 };
Daniel@0 3491
Daniel@0 3492 // Construct a map from distinct values to occurrence counts.
Daniel@0 3493 stats.count.map = function(values, f) {
Daniel@0 3494 f = util.$(f);
Daniel@0 3495 var map = {}, v, i, n;
Daniel@0 3496 for (i=0, n=values.length; i<n; ++i) {
Daniel@0 3497 v = f ? f(values[i]) : values[i];
Daniel@0 3498 map[v] = (v in map) ? map[v] + 1 : 1;
Daniel@0 3499 }
Daniel@0 3500 return map;
Daniel@0 3501 };
Daniel@0 3502
Daniel@0 3503 // Compute the median of an array of numbers.
Daniel@0 3504 stats.median = function(values, f) {
Daniel@0 3505 if (f) values = values.map(util.$(f));
Daniel@0 3506 values = values.filter(util.isValid).sort(util.cmp);
Daniel@0 3507 return stats.quantile(values, 0.5);
Daniel@0 3508 };
Daniel@0 3509
Daniel@0 3510 // Computes the quartile boundaries of an array of numbers.
Daniel@0 3511 stats.quartile = function(values, f) {
Daniel@0 3512 if (f) values = values.map(util.$(f));
Daniel@0 3513 values = values.filter(util.isValid).sort(util.cmp);
Daniel@0 3514 var q = stats.quantile;
Daniel@0 3515 return [q(values, 0.25), q(values, 0.50), q(values, 0.75)];
Daniel@0 3516 };
Daniel@0 3517
Daniel@0 3518 // Compute the quantile of a sorted array of numbers.
Daniel@0 3519 // Adapted from the D3.js implementation.
Daniel@0 3520 stats.quantile = function(values, f, p) {
Daniel@0 3521 if (p === undefined) { p = f; f = util.identity; }
Daniel@0 3522 f = util.$(f);
Daniel@0 3523 var H = (values.length - 1) * p + 1,
Daniel@0 3524 h = Math.floor(H),
Daniel@0 3525 v = +f(values[h - 1]),
Daniel@0 3526 e = H - h;
Daniel@0 3527 return e ? v + e * (f(values[h]) - v) : v;
Daniel@0 3528 };
Daniel@0 3529
Daniel@0 3530 // Compute the sum of an array of numbers.
Daniel@0 3531 stats.sum = function(values, f) {
Daniel@0 3532 f = util.$(f);
Daniel@0 3533 for (var sum=0, i=0, n=values.length, v; i<n; ++i) {
Daniel@0 3534 v = f ? f(values[i]) : values[i];
Daniel@0 3535 if (util.isValid(v)) sum += v;
Daniel@0 3536 }
Daniel@0 3537 return sum;
Daniel@0 3538 };
Daniel@0 3539
Daniel@0 3540 // Compute the mean (average) of an array of numbers.
Daniel@0 3541 stats.mean = function(values, f) {
Daniel@0 3542 f = util.$(f);
Daniel@0 3543 var mean = 0, delta, i, n, c, v;
Daniel@0 3544 for (i=0, c=0, n=values.length; i<n; ++i) {
Daniel@0 3545 v = f ? f(values[i]) : values[i];
Daniel@0 3546 if (util.isValid(v)) {
Daniel@0 3547 delta = v - mean;
Daniel@0 3548 mean = mean + delta / (++c);
Daniel@0 3549 }
Daniel@0 3550 }
Daniel@0 3551 return mean;
Daniel@0 3552 };
Daniel@0 3553
Daniel@0 3554 // Compute the sample variance of an array of numbers.
Daniel@0 3555 stats.variance = function(values, f) {
Daniel@0 3556 f = util.$(f);
Daniel@0 3557 if (!util.isArray(values) || values.length < 2) return 0;
Daniel@0 3558 var mean = 0, M2 = 0, delta, i, c, v;
Daniel@0 3559 for (i=0, c=0; i<values.length; ++i) {
Daniel@0 3560 v = f ? f(values[i]) : values[i];
Daniel@0 3561 if (util.isValid(v)) {
Daniel@0 3562 delta = v - mean;
Daniel@0 3563 mean = mean + delta / (++c);
Daniel@0 3564 M2 = M2 + delta * (v - mean);
Daniel@0 3565 }
Daniel@0 3566 }
Daniel@0 3567 M2 = M2 / (c - 1);
Daniel@0 3568 return M2;
Daniel@0 3569 };
Daniel@0 3570
Daniel@0 3571 // Compute the sample standard deviation of an array of numbers.
Daniel@0 3572 stats.stdev = function(values, f) {
Daniel@0 3573 return Math.sqrt(stats.variance(values, f));
Daniel@0 3574 };
Daniel@0 3575
Daniel@0 3576 // Compute the Pearson mode skewness ((median-mean)/stdev) of an array of numbers.
Daniel@0 3577 stats.modeskew = function(values, f) {
Daniel@0 3578 var avg = stats.mean(values, f),
Daniel@0 3579 med = stats.median(values, f),
Daniel@0 3580 std = stats.stdev(values, f);
Daniel@0 3581 return std === 0 ? 0 : (avg - med) / std;
Daniel@0 3582 };
Daniel@0 3583
Daniel@0 3584 // Find the minimum value in an array.
Daniel@0 3585 stats.min = function(values, f) {
Daniel@0 3586 return stats.extent(values, f)[0];
Daniel@0 3587 };
Daniel@0 3588
Daniel@0 3589 // Find the maximum value in an array.
Daniel@0 3590 stats.max = function(values, f) {
Daniel@0 3591 return stats.extent(values, f)[1];
Daniel@0 3592 };
Daniel@0 3593
Daniel@0 3594 // Find the minimum and maximum of an array of values.
Daniel@0 3595 stats.extent = function(values, f) {
Daniel@0 3596 f = util.$(f);
Daniel@0 3597 var a, b, v, i, n = values.length;
Daniel@0 3598 for (i=0; i<n; ++i) {
Daniel@0 3599 v = f ? f(values[i]) : values[i];
Daniel@0 3600 if (util.isValid(v)) { a = b = v; break; }
Daniel@0 3601 }
Daniel@0 3602 for (; i<n; ++i) {
Daniel@0 3603 v = f ? f(values[i]) : values[i];
Daniel@0 3604 if (util.isValid(v)) {
Daniel@0 3605 if (v < a) a = v;
Daniel@0 3606 if (v > b) b = v;
Daniel@0 3607 }
Daniel@0 3608 }
Daniel@0 3609 return [a, b];
Daniel@0 3610 };
Daniel@0 3611
Daniel@0 3612 // Find the integer indices of the minimum and maximum values.
Daniel@0 3613 stats.extent.index = function(values, f) {
Daniel@0 3614 f = util.$(f);
Daniel@0 3615 var x = -1, y = -1, a, b, v, i, n = values.length;
Daniel@0 3616 for (i=0; i<n; ++i) {
Daniel@0 3617 v = f ? f(values[i]) : values[i];
Daniel@0 3618 if (util.isValid(v)) { a = b = v; x = y = i; break; }
Daniel@0 3619 }
Daniel@0 3620 for (; i<n; ++i) {
Daniel@0 3621 v = f ? f(values[i]) : values[i];
Daniel@0 3622 if (util.isValid(v)) {
Daniel@0 3623 if (v < a) { a = v; x = i; }
Daniel@0 3624 if (v > b) { b = v; y = i; }
Daniel@0 3625 }
Daniel@0 3626 }
Daniel@0 3627 return [x, y];
Daniel@0 3628 };
Daniel@0 3629
Daniel@0 3630 // Compute the dot product of two arrays of numbers.
Daniel@0 3631 stats.dot = function(values, a, b) {
Daniel@0 3632 var sum = 0, i, v;
Daniel@0 3633 if (!b) {
Daniel@0 3634 if (values.length !== a.length) {
Daniel@0 3635 throw Error('Array lengths must match.');
Daniel@0 3636 }
Daniel@0 3637 for (i=0; i<values.length; ++i) {
Daniel@0 3638 v = values[i] * a[i];
Daniel@0 3639 if (v === v) sum += v;
Daniel@0 3640 }
Daniel@0 3641 } else {
Daniel@0 3642 a = util.$(a);
Daniel@0 3643 b = util.$(b);
Daniel@0 3644 for (i=0; i<values.length; ++i) {
Daniel@0 3645 v = a(values[i]) * b(values[i]);
Daniel@0 3646 if (v === v) sum += v;
Daniel@0 3647 }
Daniel@0 3648 }
Daniel@0 3649 return sum;
Daniel@0 3650 };
Daniel@0 3651
Daniel@0 3652 // Compute ascending rank scores for an array of values.
Daniel@0 3653 // Ties are assigned their collective mean rank.
Daniel@0 3654 stats.rank = function(values, f) {
Daniel@0 3655 f = util.$(f) || util.identity;
Daniel@0 3656 var a = values.map(function(v, i) {
Daniel@0 3657 return {idx: i, val: f(v)};
Daniel@0 3658 })
Daniel@0 3659 .sort(util.comparator('val'));
Daniel@0 3660
Daniel@0 3661 var n = values.length,
Daniel@0 3662 r = Array(n),
Daniel@0 3663 tie = -1, p = {}, i, v, mu;
Daniel@0 3664
Daniel@0 3665 for (i=0; i<n; ++i) {
Daniel@0 3666 v = a[i].val;
Daniel@0 3667 if (tie < 0 && p === v) {
Daniel@0 3668 tie = i - 1;
Daniel@0 3669 } else if (tie > -1 && p !== v) {
Daniel@0 3670 mu = 1 + (i-1 + tie) / 2;
Daniel@0 3671 for (; tie<i; ++tie) r[a[tie].idx] = mu;
Daniel@0 3672 tie = -1;
Daniel@0 3673 }
Daniel@0 3674 r[a[i].idx] = i + 1;
Daniel@0 3675 p = v;
Daniel@0 3676 }
Daniel@0 3677
Daniel@0 3678 if (tie > -1) {
Daniel@0 3679 mu = 1 + (n-1 + tie) / 2;
Daniel@0 3680 for (; tie<n; ++tie) r[a[tie].idx] = mu;
Daniel@0 3681 }
Daniel@0 3682
Daniel@0 3683 return r;
Daniel@0 3684 };
Daniel@0 3685
Daniel@0 3686 // Compute the sample Pearson product-moment correlation of two arrays of numbers.
Daniel@0 3687 stats.cor = function(values, a, b) {
Daniel@0 3688 var fn = b;
Daniel@0 3689 b = fn ? values.map(util.$(b)) : a;
Daniel@0 3690 a = fn ? values.map(util.$(a)) : values;
Daniel@0 3691
Daniel@0 3692 var dot = stats.dot(a, b),
Daniel@0 3693 mua = stats.mean(a),
Daniel@0 3694 mub = stats.mean(b),
Daniel@0 3695 sda = stats.stdev(a),
Daniel@0 3696 sdb = stats.stdev(b),
Daniel@0 3697 n = values.length;
Daniel@0 3698
Daniel@0 3699 return (dot - n*mua*mub) / ((n-1) * sda * sdb);
Daniel@0 3700 };
Daniel@0 3701
Daniel@0 3702 // Compute the Spearman rank correlation of two arrays of values.
Daniel@0 3703 stats.cor.rank = function(values, a, b) {
Daniel@0 3704 var ra = b ? stats.rank(values, util.$(a)) : stats.rank(values),
Daniel@0 3705 rb = b ? stats.rank(values, util.$(b)) : stats.rank(a),
Daniel@0 3706 n = values.length, i, s, d;
Daniel@0 3707
Daniel@0 3708 for (i=0, s=0; i<n; ++i) {
Daniel@0 3709 d = ra[i] - rb[i];
Daniel@0 3710 s += d * d;
Daniel@0 3711 }
Daniel@0 3712
Daniel@0 3713 return 1 - 6*s / (n * (n*n-1));
Daniel@0 3714 };
Daniel@0 3715
Daniel@0 3716 // Compute the distance correlation of two arrays of numbers.
Daniel@0 3717 // http://en.wikipedia.org/wiki/Distance_correlation
Daniel@0 3718 stats.cor.dist = function(values, a, b) {
Daniel@0 3719 var X = b ? values.map(util.$(a)) : values,
Daniel@0 3720 Y = b ? values.map(util.$(b)) : a;
Daniel@0 3721
Daniel@0 3722 var A = stats.dist.mat(X),
Daniel@0 3723 B = stats.dist.mat(Y),
Daniel@0 3724 n = A.length,
Daniel@0 3725 i, aa, bb, ab;
Daniel@0 3726
Daniel@0 3727 for (i=0, aa=0, bb=0, ab=0; i<n; ++i) {
Daniel@0 3728 aa += A[i]*A[i];
Daniel@0 3729 bb += B[i]*B[i];
Daniel@0 3730 ab += A[i]*B[i];
Daniel@0 3731 }
Daniel@0 3732
Daniel@0 3733 return Math.sqrt(ab / Math.sqrt(aa*bb));
Daniel@0 3734 };
Daniel@0 3735
Daniel@0 3736 // Compute the vector distance between two arrays of numbers.
Daniel@0 3737 // Default is Euclidean (exp=2) distance, configurable via exp argument.
Daniel@0 3738 stats.dist = function(values, a, b, exp) {
Daniel@0 3739 var f = util.isFunction(b) || util.isString(b),
Daniel@0 3740 X = values,
Daniel@0 3741 Y = f ? values : a,
Daniel@0 3742 e = f ? exp : b,
Daniel@0 3743 L2 = e === 2 || e == null,
Daniel@0 3744 n = values.length, s = 0, d, i;
Daniel@0 3745 if (f) {
Daniel@0 3746 a = util.$(a);
Daniel@0 3747 b = util.$(b);
Daniel@0 3748 }
Daniel@0 3749 for (i=0; i<n; ++i) {
Daniel@0 3750 d = f ? (a(X[i])-b(Y[i])) : (X[i]-Y[i]);
Daniel@0 3751 s += L2 ? d*d : Math.pow(Math.abs(d), e);
Daniel@0 3752 }
Daniel@0 3753 return L2 ? Math.sqrt(s) : Math.pow(s, 1/e);
Daniel@0 3754 };
Daniel@0 3755
Daniel@0 3756 // Construct a mean-centered distance matrix for an array of numbers.
Daniel@0 3757 stats.dist.mat = function(X) {
Daniel@0 3758 var n = X.length,
Daniel@0 3759 m = n*n,
Daniel@0 3760 A = Array(m),
Daniel@0 3761 R = gen.zeros(n),
Daniel@0 3762 M = 0, v, i, j;
Daniel@0 3763
Daniel@0 3764 for (i=0; i<n; ++i) {
Daniel@0 3765 A[i*n+i] = 0;
Daniel@0 3766 for (j=i+1; j<n; ++j) {
Daniel@0 3767 A[i*n+j] = (v = Math.abs(X[i] - X[j]));
Daniel@0 3768 A[j*n+i] = v;
Daniel@0 3769 R[i] += v;
Daniel@0 3770 R[j] += v;
Daniel@0 3771 }
Daniel@0 3772 }
Daniel@0 3773
Daniel@0 3774 for (i=0; i<n; ++i) {
Daniel@0 3775 M += R[i];
Daniel@0 3776 R[i] /= n;
Daniel@0 3777 }
Daniel@0 3778 M /= m;
Daniel@0 3779
Daniel@0 3780 for (i=0; i<n; ++i) {
Daniel@0 3781 for (j=i; j<n; ++j) {
Daniel@0 3782 A[i*n+j] += M - R[i] - R[j];
Daniel@0 3783 A[j*n+i] = A[i*n+j];
Daniel@0 3784 }
Daniel@0 3785 }
Daniel@0 3786
Daniel@0 3787 return A;
Daniel@0 3788 };
Daniel@0 3789
Daniel@0 3790 // Compute the Shannon entropy (log base 2) of an array of counts.
Daniel@0 3791 stats.entropy = function(counts, f) {
Daniel@0 3792 f = util.$(f);
Daniel@0 3793 var i, p, s = 0, H = 0, n = counts.length;
Daniel@0 3794 for (i=0; i<n; ++i) {
Daniel@0 3795 s += (f ? f(counts[i]) : counts[i]);
Daniel@0 3796 }
Daniel@0 3797 if (s === 0) return 0;
Daniel@0 3798 for (i=0; i<n; ++i) {
Daniel@0 3799 p = (f ? f(counts[i]) : counts[i]) / s;
Daniel@0 3800 if (p) H += p * Math.log(p);
Daniel@0 3801 }
Daniel@0 3802 return -H / Math.LN2;
Daniel@0 3803 };
Daniel@0 3804
Daniel@0 3805 // Compute the mutual information between two discrete variables.
Daniel@0 3806 // Returns an array of the form [MI, MI_distance]
Daniel@0 3807 // MI_distance is defined as 1 - I(a,b) / H(a,b).
Daniel@0 3808 // http://en.wikipedia.org/wiki/Mutual_information
Daniel@0 3809 stats.mutual = function(values, a, b, counts) {
Daniel@0 3810 var x = counts ? values.map(util.$(a)) : values,
Daniel@0 3811 y = counts ? values.map(util.$(b)) : a,
Daniel@0 3812 z = counts ? values.map(util.$(counts)) : b;
Daniel@0 3813
Daniel@0 3814 var px = {},
Daniel@0 3815 py = {},
Daniel@0 3816 n = z.length,
Daniel@0 3817 s = 0, I = 0, H = 0, p, t, i;
Daniel@0 3818
Daniel@0 3819 for (i=0; i<n; ++i) {
Daniel@0 3820 px[x[i]] = 0;
Daniel@0 3821 py[y[i]] = 0;
Daniel@0 3822 }
Daniel@0 3823
Daniel@0 3824 for (i=0; i<n; ++i) {
Daniel@0 3825 px[x[i]] += z[i];
Daniel@0 3826 py[y[i]] += z[i];
Daniel@0 3827 s += z[i];
Daniel@0 3828 }
Daniel@0 3829
Daniel@0 3830 t = 1 / (s * Math.LN2);
Daniel@0 3831 for (i=0; i<n; ++i) {
Daniel@0 3832 if (z[i] === 0) continue;
Daniel@0 3833 p = (s * z[i]) / (px[x[i]] * py[y[i]]);
Daniel@0 3834 I += z[i] * t * Math.log(p);
Daniel@0 3835 H += z[i] * t * Math.log(z[i]/s);
Daniel@0 3836 }
Daniel@0 3837
Daniel@0 3838 return [I, 1 + I/H];
Daniel@0 3839 };
Daniel@0 3840
Daniel@0 3841 // Compute the mutual information between two discrete variables.
Daniel@0 3842 stats.mutual.info = function(values, a, b, counts) {
Daniel@0 3843 return stats.mutual(values, a, b, counts)[0];
Daniel@0 3844 };
Daniel@0 3845
Daniel@0 3846 // Compute the mutual information distance between two discrete variables.
Daniel@0 3847 // MI_distance is defined as 1 - I(a,b) / H(a,b).
Daniel@0 3848 stats.mutual.dist = function(values, a, b, counts) {
Daniel@0 3849 return stats.mutual(values, a, b, counts)[1];
Daniel@0 3850 };
Daniel@0 3851
Daniel@0 3852 // Compute a profile of summary statistics for a variable.
Daniel@0 3853 stats.profile = function(values, f) {
Daniel@0 3854 var mean = 0,
Daniel@0 3855 valid = 0,
Daniel@0 3856 missing = 0,
Daniel@0 3857 distinct = 0,
Daniel@0 3858 min = null,
Daniel@0 3859 max = null,
Daniel@0 3860 M2 = 0,
Daniel@0 3861 vals = [],
Daniel@0 3862 u = {}, delta, sd, i, v, x;
Daniel@0 3863
Daniel@0 3864 // compute summary stats
Daniel@0 3865 for (i=0; i<values.length; ++i) {
Daniel@0 3866 v = f ? f(values[i]) : values[i];
Daniel@0 3867
Daniel@0 3868 // update unique values
Daniel@0 3869 u[v] = (v in u) ? u[v] + 1 : (distinct += 1, 1);
Daniel@0 3870
Daniel@0 3871 if (v == null) {
Daniel@0 3872 ++missing;
Daniel@0 3873 } else if (util.isValid(v)) {
Daniel@0 3874 // update stats
Daniel@0 3875 x = (typeof v === 'string') ? v.length : v;
Daniel@0 3876 if (min===null || x < min) min = x;
Daniel@0 3877 if (max===null || x > max) max = x;
Daniel@0 3878 delta = x - mean;
Daniel@0 3879 mean = mean + delta / (++valid);
Daniel@0 3880 M2 = M2 + delta * (x - mean);
Daniel@0 3881 vals.push(x);
Daniel@0 3882 }
Daniel@0 3883 }
Daniel@0 3884 M2 = M2 / (valid - 1);
Daniel@0 3885 sd = Math.sqrt(M2);
Daniel@0 3886
Daniel@0 3887 // sort values for median and iqr
Daniel@0 3888 vals.sort(util.cmp);
Daniel@0 3889
Daniel@0 3890 return {
Daniel@0 3891 type: type(values, f),
Daniel@0 3892 unique: u,
Daniel@0 3893 count: values.length,
Daniel@0 3894 valid: valid,
Daniel@0 3895 missing: missing,
Daniel@0 3896 distinct: distinct,
Daniel@0 3897 min: min,
Daniel@0 3898 max: max,
Daniel@0 3899 mean: mean,
Daniel@0 3900 stdev: sd,
Daniel@0 3901 median: (v = stats.quantile(vals, 0.5)),
Daniel@0 3902 q1: stats.quantile(vals, 0.25),
Daniel@0 3903 q3: stats.quantile(vals, 0.75),
Daniel@0 3904 modeskew: sd === 0 ? 0 : (mean - v) / sd
Daniel@0 3905 };
Daniel@0 3906 };
Daniel@0 3907
Daniel@0 3908 // Compute profiles for all variables in a data set.
Daniel@0 3909 stats.summary = function(data, fields) {
Daniel@0 3910 fields = fields || util.keys(data[0]);
Daniel@0 3911 var s = fields.map(function(f) {
Daniel@0 3912 var p = stats.profile(data, util.$(f));
Daniel@0 3913 return (p.field = f, p);
Daniel@0 3914 });
Daniel@0 3915 return (s.__summary__ = true, s);
Daniel@0 3916 };
Daniel@0 3917
Daniel@0 3918 module.exports = stats;
Daniel@0 3919 },{"./generate":14,"./import/type":23,"./util":29}],27:[function(require,module,exports){
Daniel@0 3920 var util = require('./util'),
Daniel@0 3921 format = require('./format');
Daniel@0 3922
Daniel@0 3923 var context = {
Daniel@0 3924 formats: [],
Daniel@0 3925 format_map: {},
Daniel@0 3926 truncate: util.truncate,
Daniel@0 3927 pad: util.pad
Daniel@0 3928 };
Daniel@0 3929
Daniel@0 3930 function template(text) {
Daniel@0 3931 var src = source(text, 'd');
Daniel@0 3932 src = 'var __t; return ' + src + ';';
Daniel@0 3933
Daniel@0 3934 /* jshint evil: true */
Daniel@0 3935 return (new Function('d', src)).bind(context);
Daniel@0 3936 }
Daniel@0 3937
Daniel@0 3938 template.source = source;
Daniel@0 3939 template.context = context;
Daniel@0 3940 module.exports = template;
Daniel@0 3941
Daniel@0 3942 // Clear cache of format objects.
Daniel@0 3943 // This can *break* prior template functions, so invoke with care!
Daniel@0 3944 template.clearFormatCache = function() {
Daniel@0 3945 context.formats = [];
Daniel@0 3946 context.format_map = {};
Daniel@0 3947 };
Daniel@0 3948
Daniel@0 3949 // Generate property access code for use within template source.
Daniel@0 3950 // object: the name of the object (variable) containing template data
Daniel@0 3951 // property: the property access string, verbatim from template tag
Daniel@0 3952 template.property = function(object, property) {
Daniel@0 3953 var src = util.field(property).map(util.str).join('][');
Daniel@0 3954 return object + '[' + src + ']';
Daniel@0 3955 };
Daniel@0 3956
Daniel@0 3957 // Generate source code for a template function.
Daniel@0 3958 // text: the template text
Daniel@0 3959 // variable: the name of the data object variable ('obj' by default)
Daniel@0 3960 // properties: optional hash for collecting all accessed properties
Daniel@0 3961 function source(text, variable, properties) {
Daniel@0 3962 variable = variable || 'obj';
Daniel@0 3963 var index = 0;
Daniel@0 3964 var src = '\'';
Daniel@0 3965 var regex = template_re;
Daniel@0 3966
Daniel@0 3967 // Compile the template source, escaping string literals appropriately.
Daniel@0 3968 text.replace(regex, function(match, interpolate, offset) {
Daniel@0 3969 src += text
Daniel@0 3970 .slice(index, offset)
Daniel@0 3971 .replace(template_escaper, template_escapeChar);
Daniel@0 3972 index = offset + match.length;
Daniel@0 3973
Daniel@0 3974 if (interpolate) {
Daniel@0 3975 src += '\'\n+((__t=(' +
Daniel@0 3976 template_var(interpolate, variable, properties) +
Daniel@0 3977 '))==null?\'\':__t)+\n\'';
Daniel@0 3978 }
Daniel@0 3979
Daniel@0 3980 // Adobe VMs need the match returned to produce the correct offest.
Daniel@0 3981 return match;
Daniel@0 3982 });
Daniel@0 3983 return src + '\'';
Daniel@0 3984 }
Daniel@0 3985
Daniel@0 3986 function template_var(text, variable, properties) {
Daniel@0 3987 var filters = text.match(filter_re);
Daniel@0 3988 var prop = filters.shift().trim();
Daniel@0 3989 var stringCast = true;
Daniel@0 3990
Daniel@0 3991 function strcall(fn) {
Daniel@0 3992 fn = fn || '';
Daniel@0 3993 if (stringCast) {
Daniel@0 3994 stringCast = false;
Daniel@0 3995 src = 'String(' + src + ')' + fn;
Daniel@0 3996 } else {
Daniel@0 3997 src += fn;
Daniel@0 3998 }
Daniel@0 3999 return src;
Daniel@0 4000 }
Daniel@0 4001
Daniel@0 4002 function date() {
Daniel@0 4003 return '(typeof ' + src + '==="number"?new Date('+src+'):'+src+')';
Daniel@0 4004 }
Daniel@0 4005
Daniel@0 4006 function number_format(fmt, key) {
Daniel@0 4007 a = template_format(args[0], key, fmt);
Daniel@0 4008 stringCast = false;
Daniel@0 4009 src = 'this.formats['+a+']('+src+')';
Daniel@0 4010 }
Daniel@0 4011
Daniel@0 4012 function time_format(fmt, key) {
Daniel@0 4013 a = template_format(args[0], key, fmt);
Daniel@0 4014 stringCast = false;
Daniel@0 4015 src = 'this.formats['+a+']('+date()+')';
Daniel@0 4016 }
Daniel@0 4017
Daniel@0 4018 if (properties) properties[prop] = 1;
Daniel@0 4019 var src = template.property(variable, prop);
Daniel@0 4020
Daniel@0 4021 for (var i=0; i<filters.length; ++i) {
Daniel@0 4022 var f = filters[i], args = null, pidx, a, b;
Daniel@0 4023
Daniel@0 4024 if ((pidx=f.indexOf(':')) > 0) {
Daniel@0 4025 f = f.slice(0, pidx);
Daniel@0 4026 args = filters[i].slice(pidx+1)
Daniel@0 4027 .match(args_re)
Daniel@0 4028 .map(function(s) { return s.trim(); });
Daniel@0 4029 }
Daniel@0 4030 f = f.trim();
Daniel@0 4031
Daniel@0 4032 switch (f) {
Daniel@0 4033 case 'length':
Daniel@0 4034 strcall('.length');
Daniel@0 4035 break;
Daniel@0 4036 case 'lower':
Daniel@0 4037 strcall('.toLowerCase()');
Daniel@0 4038 break;
Daniel@0 4039 case 'upper':
Daniel@0 4040 strcall('.toUpperCase()');
Daniel@0 4041 break;
Daniel@0 4042 case 'lower-locale':
Daniel@0 4043 strcall('.toLocaleLowerCase()');
Daniel@0 4044 break;
Daniel@0 4045 case 'upper-locale':
Daniel@0 4046 strcall('.toLocaleUpperCase()');
Daniel@0 4047 break;
Daniel@0 4048 case 'trim':
Daniel@0 4049 strcall('.trim()');
Daniel@0 4050 break;
Daniel@0 4051 case 'left':
Daniel@0 4052 a = util.number(args[0]);
Daniel@0 4053 strcall('.slice(0,' + a + ')');
Daniel@0 4054 break;
Daniel@0 4055 case 'right':
Daniel@0 4056 a = util.number(args[0]);
Daniel@0 4057 strcall('.slice(-' + a +')');
Daniel@0 4058 break;
Daniel@0 4059 case 'mid':
Daniel@0 4060 a = util.number(args[0]);
Daniel@0 4061 b = a + util.number(args[1]);
Daniel@0 4062 strcall('.slice(+'+a+','+b+')');
Daniel@0 4063 break;
Daniel@0 4064 case 'slice':
Daniel@0 4065 a = util.number(args[0]);
Daniel@0 4066 strcall('.slice('+ a +
Daniel@0 4067 (args.length > 1 ? ',' + util.number(args[1]) : '') +
Daniel@0 4068 ')');
Daniel@0 4069 break;
Daniel@0 4070 case 'truncate':
Daniel@0 4071 a = util.number(args[0]);
Daniel@0 4072 b = args[1];
Daniel@0 4073 b = (b!=='left' && b!=='middle' && b!=='center') ? 'right' : b;
Daniel@0 4074 src = 'this.truncate(' + strcall() + ',' + a + ',\'' + b + '\')';
Daniel@0 4075 break;
Daniel@0 4076 case 'pad':
Daniel@0 4077 a = util.number(args[0]);
Daniel@0 4078 b = args[1];
Daniel@0 4079 b = (b!=='left' && b!=='middle' && b!=='center') ? 'right' : b;
Daniel@0 4080 src = 'this.pad(' + strcall() + ',' + a + ',\'' + b + '\')';
Daniel@0 4081 break;
Daniel@0 4082 case 'number':
Daniel@0 4083 number_format(format.number, 'number');
Daniel@0 4084 break;
Daniel@0 4085 case 'time':
Daniel@0 4086 time_format(format.time, 'time');
Daniel@0 4087 break;
Daniel@0 4088 case 'time-utc':
Daniel@0 4089 time_format(format.utc, 'time-utc');
Daniel@0 4090 break;
Daniel@0 4091 default:
Daniel@0 4092 throw Error('Unrecognized template filter: ' + f);
Daniel@0 4093 }
Daniel@0 4094 }
Daniel@0 4095
Daniel@0 4096 return src;
Daniel@0 4097 }
Daniel@0 4098
Daniel@0 4099 var template_re = /\{\{(.+?)\}\}|$/g,
Daniel@0 4100 filter_re = /(?:"[^"]*"|\'[^\']*\'|[^\|"]+|[^\|\']+)+/g,
Daniel@0 4101 args_re = /(?:"[^"]*"|\'[^\']*\'|[^,"]+|[^,\']+)+/g;
Daniel@0 4102
Daniel@0 4103 // Certain characters need to be escaped so that they can be put into a
Daniel@0 4104 // string literal.
Daniel@0 4105 var template_escapes = {
Daniel@0 4106 '\'': '\'',
Daniel@0 4107 '\\': '\\',
Daniel@0 4108 '\r': 'r',
Daniel@0 4109 '\n': 'n',
Daniel@0 4110 '\u2028': 'u2028',
Daniel@0 4111 '\u2029': 'u2029'
Daniel@0 4112 };
Daniel@0 4113
Daniel@0 4114 var template_escaper = /\\|'|\r|\n|\u2028|\u2029/g;
Daniel@0 4115
Daniel@0 4116 function template_escapeChar(match) {
Daniel@0 4117 return '\\' + template_escapes[match];
Daniel@0 4118 }
Daniel@0 4119
Daniel@0 4120 function template_format(pattern, key, fmt) {
Daniel@0 4121 if ((pattern[0] === '\'' && pattern[pattern.length-1] === '\'') ||
Daniel@0 4122 (pattern[0] === '"' && pattern[pattern.length-1] === '"')) {
Daniel@0 4123 pattern = pattern.slice(1, -1);
Daniel@0 4124 } else {
Daniel@0 4125 throw Error('Format pattern must be quoted: ' + pattern);
Daniel@0 4126 }
Daniel@0 4127 key = key + ':' + pattern;
Daniel@0 4128 if (!context.format_map[key]) {
Daniel@0 4129 var f = fmt(pattern);
Daniel@0 4130 var i = context.formats.length;
Daniel@0 4131 context.formats.push(f);
Daniel@0 4132 context.format_map[key] = i;
Daniel@0 4133 }
Daniel@0 4134 return context.format_map[key];
Daniel@0 4135 }
Daniel@0 4136
Daniel@0 4137 },{"./format":13,"./util":29}],28:[function(require,module,exports){
Daniel@0 4138 var d3_time = require('d3-time');
Daniel@0 4139
Daniel@0 4140 var tempDate = new Date(),
Daniel@0 4141 baseDate = new Date(0, 0, 1).setFullYear(0), // Jan 1, 0 AD
Daniel@0 4142 utcBaseDate = new Date(Date.UTC(0, 0, 1)).setUTCFullYear(0);
Daniel@0 4143
Daniel@0 4144 function date(d) {
Daniel@0 4145 return (tempDate.setTime(+d), tempDate);
Daniel@0 4146 }
Daniel@0 4147
Daniel@0 4148 // create a time unit entry
Daniel@0 4149 function entry(type, date, unit, step, min, max) {
Daniel@0 4150 var e = {
Daniel@0 4151 type: type,
Daniel@0 4152 date: date,
Daniel@0 4153 unit: unit
Daniel@0 4154 };
Daniel@0 4155 if (step) {
Daniel@0 4156 e.step = step;
Daniel@0 4157 } else {
Daniel@0 4158 e.minstep = 1;
Daniel@0 4159 }
Daniel@0 4160 if (min != null) e.min = min;
Daniel@0 4161 if (max != null) e.max = max;
Daniel@0 4162 return e;
Daniel@0 4163 }
Daniel@0 4164
Daniel@0 4165 function create(type, unit, base, step, min, max) {
Daniel@0 4166 return entry(type,
Daniel@0 4167 function(d) { return unit.offset(base, d); },
Daniel@0 4168 function(d) { return unit.count(base, d); },
Daniel@0 4169 step, min, max);
Daniel@0 4170 }
Daniel@0 4171
Daniel@0 4172 var locale = [
Daniel@0 4173 create('second', d3_time.second, baseDate),
Daniel@0 4174 create('minute', d3_time.minute, baseDate),
Daniel@0 4175 create('hour', d3_time.hour, baseDate),
Daniel@0 4176 create('day', d3_time.day, baseDate, [1, 7]),
Daniel@0 4177 create('month', d3_time.month, baseDate, [1, 3, 6]),
Daniel@0 4178 create('year', d3_time.year, baseDate),
Daniel@0 4179
Daniel@0 4180 // periodic units
Daniel@0 4181 entry('seconds',
Daniel@0 4182 function(d) { return new Date(1970, 0, 1, 0, 0, d); },
Daniel@0 4183 function(d) { return date(d).getSeconds(); },
Daniel@0 4184 null, 0, 59
Daniel@0 4185 ),
Daniel@0 4186 entry('minutes',
Daniel@0 4187 function(d) { return new Date(1970, 0, 1, 0, d); },
Daniel@0 4188 function(d) { return date(d).getMinutes(); },
Daniel@0 4189 null, 0, 59
Daniel@0 4190 ),
Daniel@0 4191 entry('hours',
Daniel@0 4192 function(d) { return new Date(1970, 0, 1, d); },
Daniel@0 4193 function(d) { return date(d).getHours(); },
Daniel@0 4194 null, 0, 23
Daniel@0 4195 ),
Daniel@0 4196 entry('weekdays',
Daniel@0 4197 function(d) { return new Date(1970, 0, 4+d); },
Daniel@0 4198 function(d) { return date(d).getDay(); },
Daniel@0 4199 [1], 0, 6
Daniel@0 4200 ),
Daniel@0 4201 entry('dates',
Daniel@0 4202 function(d) { return new Date(1970, 0, d); },
Daniel@0 4203 function(d) { return date(d).getDate(); },
Daniel@0 4204 [1], 1, 31
Daniel@0 4205 ),
Daniel@0 4206 entry('months',
Daniel@0 4207 function(d) { return new Date(1970, d % 12, 1); },
Daniel@0 4208 function(d) { return date(d).getMonth(); },
Daniel@0 4209 [1], 0, 11
Daniel@0 4210 )
Daniel@0 4211 ];
Daniel@0 4212
Daniel@0 4213 var utc = [
Daniel@0 4214 create('second', d3_time.utcSecond, utcBaseDate),
Daniel@0 4215 create('minute', d3_time.utcMinute, utcBaseDate),
Daniel@0 4216 create('hour', d3_time.utcHour, utcBaseDate),
Daniel@0 4217 create('day', d3_time.utcDay, utcBaseDate, [1, 7]),
Daniel@0 4218 create('month', d3_time.utcMonth, utcBaseDate, [1, 3, 6]),
Daniel@0 4219 create('year', d3_time.utcYear, utcBaseDate),
Daniel@0 4220
Daniel@0 4221 // periodic units
Daniel@0 4222 entry('seconds',
Daniel@0 4223 function(d) { return new Date(Date.UTC(1970, 0, 1, 0, 0, d)); },
Daniel@0 4224 function(d) { return date(d).getUTCSeconds(); },
Daniel@0 4225 null, 0, 59
Daniel@0 4226 ),
Daniel@0 4227 entry('minutes',
Daniel@0 4228 function(d) { return new Date(Date.UTC(1970, 0, 1, 0, d)); },
Daniel@0 4229 function(d) { return date(d).getUTCMinutes(); },
Daniel@0 4230 null, 0, 59
Daniel@0 4231 ),
Daniel@0 4232 entry('hours',
Daniel@0 4233 function(d) { return new Date(Date.UTC(1970, 0, 1, d)); },
Daniel@0 4234 function(d) { return date(d).getUTCHours(); },
Daniel@0 4235 null, 0, 23
Daniel@0 4236 ),
Daniel@0 4237 entry('weekdays',
Daniel@0 4238 function(d) { return new Date(Date.UTC(1970, 0, 4+d)); },
Daniel@0 4239 function(d) { return date(d).getUTCDay(); },
Daniel@0 4240 [1], 0, 6
Daniel@0 4241 ),
Daniel@0 4242 entry('dates',
Daniel@0 4243 function(d) { return new Date(Date.UTC(1970, 0, d)); },
Daniel@0 4244 function(d) { return date(d).getUTCDate(); },
Daniel@0 4245 [1], 1, 31
Daniel@0 4246 ),
Daniel@0 4247 entry('months',
Daniel@0 4248 function(d) { return new Date(Date.UTC(1970, d % 12, 1)); },
Daniel@0 4249 function(d) { return date(d).getUTCMonth(); },
Daniel@0 4250 [1], 0, 11
Daniel@0 4251 )
Daniel@0 4252 ];
Daniel@0 4253
Daniel@0 4254 var STEPS = [
Daniel@0 4255 [31536e6, 5], // 1-year
Daniel@0 4256 [7776e6, 4], // 3-month
Daniel@0 4257 [2592e6, 4], // 1-month
Daniel@0 4258 [12096e5, 3], // 2-week
Daniel@0 4259 [6048e5, 3], // 1-week
Daniel@0 4260 [1728e5, 3], // 2-day
Daniel@0 4261 [864e5, 3], // 1-day
Daniel@0 4262 [432e5, 2], // 12-hour
Daniel@0 4263 [216e5, 2], // 6-hour
Daniel@0 4264 [108e5, 2], // 3-hour
Daniel@0 4265 [36e5, 2], // 1-hour
Daniel@0 4266 [18e5, 1], // 30-minute
Daniel@0 4267 [9e5, 1], // 15-minute
Daniel@0 4268 [3e5, 1], // 5-minute
Daniel@0 4269 [6e4, 1], // 1-minute
Daniel@0 4270 [3e4, 0], // 30-second
Daniel@0 4271 [15e3, 0], // 15-second
Daniel@0 4272 [5e3, 0], // 5-second
Daniel@0 4273 [1e3, 0] // 1-second
Daniel@0 4274 ];
Daniel@0 4275
Daniel@0 4276 function find(units, span, minb, maxb) {
Daniel@0 4277 var step = STEPS[0], i, n, bins;
Daniel@0 4278
Daniel@0 4279 for (i=1, n=STEPS.length; i<n; ++i) {
Daniel@0 4280 step = STEPS[i];
Daniel@0 4281 if (span > step[0]) {
Daniel@0 4282 bins = span / step[0];
Daniel@0 4283 if (bins > maxb) {
Daniel@0 4284 return units[STEPS[i-1][1]];
Daniel@0 4285 }
Daniel@0 4286 if (bins >= minb) {
Daniel@0 4287 return units[step[1]];
Daniel@0 4288 }
Daniel@0 4289 }
Daniel@0 4290 }
Daniel@0 4291 return units[STEPS[n-1][1]];
Daniel@0 4292 }
Daniel@0 4293
Daniel@0 4294 function toUnitMap(units) {
Daniel@0 4295 var map = {}, i, n;
Daniel@0 4296 for (i=0, n=units.length; i<n; ++i) {
Daniel@0 4297 map[units[i].type] = units[i];
Daniel@0 4298 }
Daniel@0 4299 map.find = function(span, minb, maxb) {
Daniel@0 4300 return find(units, span, minb, maxb);
Daniel@0 4301 };
Daniel@0 4302 return map;
Daniel@0 4303 }
Daniel@0 4304
Daniel@0 4305 module.exports = toUnitMap(locale);
Daniel@0 4306 module.exports.utc = toUnitMap(utc);
Daniel@0 4307
Daniel@0 4308 },{"d3-time":6}],29:[function(require,module,exports){
Daniel@0 4309 var buffer = require('buffer'),
Daniel@0 4310 time = require('./time'),
Daniel@0 4311 utc = time.utc;
Daniel@0 4312
Daniel@0 4313 var u = module.exports = {};
Daniel@0 4314
Daniel@0 4315 // utility functions
Daniel@0 4316
Daniel@0 4317 var FNAME = '__name__';
Daniel@0 4318
Daniel@0 4319 u.namedfunc = function(name, f) { return (f[FNAME] = name, f); };
Daniel@0 4320
Daniel@0 4321 u.name = function(f) { return f==null ? null : f[FNAME]; };
Daniel@0 4322
Daniel@0 4323 u.identity = function(x) { return x; };
Daniel@0 4324
Daniel@0 4325 u.true = u.namedfunc('true', function() { return true; });
Daniel@0 4326
Daniel@0 4327 u.false = u.namedfunc('false', function() { return false; });
Daniel@0 4328
Daniel@0 4329 u.duplicate = function(obj) {
Daniel@0 4330 return JSON.parse(JSON.stringify(obj));
Daniel@0 4331 };
Daniel@0 4332
Daniel@0 4333 u.equal = function(a, b) {
Daniel@0 4334 return JSON.stringify(a) === JSON.stringify(b);
Daniel@0 4335 };
Daniel@0 4336
Daniel@0 4337 u.extend = function(obj) {
Daniel@0 4338 for (var x, name, i=1, len=arguments.length; i<len; ++i) {
Daniel@0 4339 x = arguments[i];
Daniel@0 4340 for (name in x) { obj[name] = x[name]; }
Daniel@0 4341 }
Daniel@0 4342 return obj;
Daniel@0 4343 };
Daniel@0 4344
Daniel@0 4345 u.length = function(x) {
Daniel@0 4346 return x != null && x.length != null ? x.length : null;
Daniel@0 4347 };
Daniel@0 4348
Daniel@0 4349 u.keys = function(x) {
Daniel@0 4350 var keys = [], k;
Daniel@0 4351 for (k in x) keys.push(k);
Daniel@0 4352 return keys;
Daniel@0 4353 };
Daniel@0 4354
Daniel@0 4355 u.vals = function(x) {
Daniel@0 4356 var vals = [], k;
Daniel@0 4357 for (k in x) vals.push(x[k]);
Daniel@0 4358 return vals;
Daniel@0 4359 };
Daniel@0 4360
Daniel@0 4361 u.toMap = function(list, f) {
Daniel@0 4362 return (f = u.$(f)) ?
Daniel@0 4363 list.reduce(function(obj, x) { return (obj[f(x)] = 1, obj); }, {}) :
Daniel@0 4364 list.reduce(function(obj, x) { return (obj[x] = 1, obj); }, {});
Daniel@0 4365 };
Daniel@0 4366
Daniel@0 4367 u.keystr = function(values) {
Daniel@0 4368 // use to ensure consistent key generation across modules
Daniel@0 4369 var n = values.length;
Daniel@0 4370 if (!n) return '';
Daniel@0 4371 for (var s=String(values[0]), i=1; i<n; ++i) {
Daniel@0 4372 s += '|' + String(values[i]);
Daniel@0 4373 }
Daniel@0 4374 return s;
Daniel@0 4375 };
Daniel@0 4376
Daniel@0 4377 // type checking functions
Daniel@0 4378
Daniel@0 4379 var toString = Object.prototype.toString;
Daniel@0 4380
Daniel@0 4381 u.isObject = function(obj) {
Daniel@0 4382 return obj === Object(obj);
Daniel@0 4383 };
Daniel@0 4384
Daniel@0 4385 u.isFunction = function(obj) {
Daniel@0 4386 return toString.call(obj) === '[object Function]';
Daniel@0 4387 };
Daniel@0 4388
Daniel@0 4389 u.isString = function(obj) {
Daniel@0 4390 return typeof value === 'string' || toString.call(obj) === '[object String]';
Daniel@0 4391 };
Daniel@0 4392
Daniel@0 4393 u.isArray = Array.isArray || function(obj) {
Daniel@0 4394 return toString.call(obj) === '[object Array]';
Daniel@0 4395 };
Daniel@0 4396
Daniel@0 4397 u.isNumber = function(obj) {
Daniel@0 4398 return typeof obj === 'number' || toString.call(obj) === '[object Number]';
Daniel@0 4399 };
Daniel@0 4400
Daniel@0 4401 u.isBoolean = function(obj) {
Daniel@0 4402 return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
Daniel@0 4403 };
Daniel@0 4404
Daniel@0 4405 u.isDate = function(obj) {
Daniel@0 4406 return toString.call(obj) === '[object Date]';
Daniel@0 4407 };
Daniel@0 4408
Daniel@0 4409 u.isValid = function(obj) {
Daniel@0 4410 return obj != null && obj === obj;
Daniel@0 4411 };
Daniel@0 4412
Daniel@0 4413 u.isBuffer = (buffer.Buffer && buffer.Buffer.isBuffer) || u.false;
Daniel@0 4414
Daniel@0 4415 // type coercion functions
Daniel@0 4416
Daniel@0 4417 u.number = function(s) {
Daniel@0 4418 return s == null || s === '' ? null : +s;
Daniel@0 4419 };
Daniel@0 4420
Daniel@0 4421 u.boolean = function(s) {
Daniel@0 4422 return s == null || s === '' ? null : s==='false' ? false : !!s;
Daniel@0 4423 };
Daniel@0 4424
Daniel@0 4425 u.date = function(s) {
Daniel@0 4426 return s == null || s === '' ? null : Date.parse(s);
Daniel@0 4427 };
Daniel@0 4428
Daniel@0 4429 u.array = function(x) {
Daniel@0 4430 return x != null ? (u.isArray(x) ? x : [x]) : [];
Daniel@0 4431 };
Daniel@0 4432
Daniel@0 4433 u.str = function(x) {
Daniel@0 4434 return u.isArray(x) ? '[' + x.map(u.str) + ']'
Daniel@0 4435 : u.isObject(x) ? JSON.stringify(x)
Daniel@0 4436 : u.isString(x) ? ('\''+util_escape_str(x)+'\'') : x;
Daniel@0 4437 };
Daniel@0 4438
Daniel@0 4439 var escape_str_re = /(^|[^\\])'/g;
Daniel@0 4440
Daniel@0 4441 function util_escape_str(x) {
Daniel@0 4442 return x.replace(escape_str_re, '$1\\\'');
Daniel@0 4443 }
Daniel@0 4444
Daniel@0 4445 // data access functions
Daniel@0 4446
Daniel@0 4447 var field_re = /\[(.*?)\]|[^.\[]+/g;
Daniel@0 4448
Daniel@0 4449 u.field = function(f) {
Daniel@0 4450 return String(f).match(field_re).map(function(d) {
Daniel@0 4451 return d[0] !== '[' ? d :
Daniel@0 4452 d[1] !== "'" && d[1] !== '"' ? d.slice(1, -1) :
Daniel@0 4453 d.slice(2, -2).replace(/\\(["'])/g, '$1');
Daniel@0 4454 });
Daniel@0 4455 };
Daniel@0 4456
Daniel@0 4457 u.accessor = function(f) {
Daniel@0 4458 var s;
Daniel@0 4459 return f==null || u.isFunction(f) ? f :
Daniel@0 4460 u.namedfunc(f, (s = u.field(f)).length > 1 ?
Daniel@0 4461 function(x) { return s.reduce(function(x,f) { return x[f]; }, x); } :
Daniel@0 4462 function(x) { return x[f]; }
Daniel@0 4463 );
Daniel@0 4464 };
Daniel@0 4465
Daniel@0 4466 // short-cut for accessor
Daniel@0 4467 u.$ = u.accessor;
Daniel@0 4468
Daniel@0 4469 u.mutator = function(f) {
Daniel@0 4470 var s;
Daniel@0 4471 return u.isString(f) && (s=u.field(f)).length > 1 ?
Daniel@0 4472 function(x, v) {
Daniel@0 4473 for (var i=0; i<s.length-1; ++i) x = x[s[i]];
Daniel@0 4474 x[s[i]] = v;
Daniel@0 4475 } :
Daniel@0 4476 function(x, v) { x[f] = v; };
Daniel@0 4477 };
Daniel@0 4478
Daniel@0 4479
Daniel@0 4480 u.$func = function(name, op) {
Daniel@0 4481 return function(f) {
Daniel@0 4482 f = u.$(f) || u.identity;
Daniel@0 4483 var n = name + (u.name(f) ? '_'+u.name(f) : '');
Daniel@0 4484 return u.namedfunc(n, function(d) { return op(f(d)); });
Daniel@0 4485 };
Daniel@0 4486 };
Daniel@0 4487
Daniel@0 4488 u.$valid = u.$func('valid', u.isValid);
Daniel@0 4489 u.$length = u.$func('length', u.length);
Daniel@0 4490
Daniel@0 4491 u.$in = function(f, values) {
Daniel@0 4492 f = u.$(f);
Daniel@0 4493 var map = u.isArray(values) ? u.toMap(values) : values;
Daniel@0 4494 return function(d) { return !!map[f(d)]; };
Daniel@0 4495 };
Daniel@0 4496
Daniel@0 4497 u.$year = u.$func('year', time.year.unit);
Daniel@0 4498 u.$month = u.$func('month', time.months.unit);
Daniel@0 4499 u.$date = u.$func('date', time.dates.unit);
Daniel@0 4500 u.$day = u.$func('day', time.weekdays.unit);
Daniel@0 4501 u.$hour = u.$func('hour', time.hours.unit);
Daniel@0 4502 u.$minute = u.$func('minute', time.minutes.unit);
Daniel@0 4503 u.$second = u.$func('second', time.seconds.unit);
Daniel@0 4504
Daniel@0 4505 u.$utcYear = u.$func('utcYear', utc.year.unit);
Daniel@0 4506 u.$utcMonth = u.$func('utcMonth', utc.months.unit);
Daniel@0 4507 u.$utcDate = u.$func('utcDate', utc.dates.unit);
Daniel@0 4508 u.$utcDay = u.$func('utcDay', utc.weekdays.unit);
Daniel@0 4509 u.$utcHour = u.$func('utcHour', utc.hours.unit);
Daniel@0 4510 u.$utcMinute = u.$func('utcMinute', utc.minutes.unit);
Daniel@0 4511 u.$utcSecond = u.$func('utcSecond', utc.seconds.unit);
Daniel@0 4512
Daniel@0 4513 // comparison / sorting functions
Daniel@0 4514
Daniel@0 4515 u.comparator = function(sort) {
Daniel@0 4516 var sign = [];
Daniel@0 4517 if (sort === undefined) sort = [];
Daniel@0 4518 sort = u.array(sort).map(function(f) {
Daniel@0 4519 var s = 1;
Daniel@0 4520 if (f[0] === '-') { s = -1; f = f.slice(1); }
Daniel@0 4521 else if (f[0] === '+') { s = +1; f = f.slice(1); }
Daniel@0 4522 sign.push(s);
Daniel@0 4523 return u.accessor(f);
Daniel@0 4524 });
Daniel@0 4525 return function(a,b) {
Daniel@0 4526 var i, n, f, x, y;
Daniel@0 4527 for (i=0, n=sort.length; i<n; ++i) {
Daniel@0 4528 f = sort[i]; x = f(a); y = f(b);
Daniel@0 4529 if (x < y) return -1 * sign[i];
Daniel@0 4530 if (x > y) return sign[i];
Daniel@0 4531 }
Daniel@0 4532 return 0;
Daniel@0 4533 };
Daniel@0 4534 };
Daniel@0 4535
Daniel@0 4536 u.cmp = function(a, b) {
Daniel@0 4537 if (a < b) {
Daniel@0 4538 return -1;
Daniel@0 4539 } else if (a > b) {
Daniel@0 4540 return 1;
Daniel@0 4541 } else if (a >= b) {
Daniel@0 4542 return 0;
Daniel@0 4543 } else if (a === null) {
Daniel@0 4544 return -1;
Daniel@0 4545 } else if (b === null) {
Daniel@0 4546 return 1;
Daniel@0 4547 }
Daniel@0 4548 return NaN;
Daniel@0 4549 };
Daniel@0 4550
Daniel@0 4551 u.numcmp = function(a, b) { return a - b; };
Daniel@0 4552
Daniel@0 4553 u.stablesort = function(array, sortBy, keyFn) {
Daniel@0 4554 var indices = array.reduce(function(idx, v, i) {
Daniel@0 4555 return (idx[keyFn(v)] = i, idx);
Daniel@0 4556 }, {});
Daniel@0 4557
Daniel@0 4558 array.sort(function(a, b) {
Daniel@0 4559 var sa = sortBy(a),
Daniel@0 4560 sb = sortBy(b);
Daniel@0 4561 return sa < sb ? -1 : sa > sb ? 1
Daniel@0 4562 : (indices[keyFn(a)] - indices[keyFn(b)]);
Daniel@0 4563 });
Daniel@0 4564
Daniel@0 4565 return array;
Daniel@0 4566 };
Daniel@0 4567
Daniel@0 4568
Daniel@0 4569 // string functions
Daniel@0 4570
Daniel@0 4571 u.pad = function(s, length, pos, padchar) {
Daniel@0 4572 padchar = padchar || " ";
Daniel@0 4573 var d = length - s.length;
Daniel@0 4574 if (d <= 0) return s;
Daniel@0 4575 switch (pos) {
Daniel@0 4576 case 'left':
Daniel@0 4577 return strrep(d, padchar) + s;
Daniel@0 4578 case 'middle':
Daniel@0 4579 case 'center':
Daniel@0 4580 return strrep(Math.floor(d/2), padchar) +
Daniel@0 4581 s + strrep(Math.ceil(d/2), padchar);
Daniel@0 4582 default:
Daniel@0 4583 return s + strrep(d, padchar);
Daniel@0 4584 }
Daniel@0 4585 };
Daniel@0 4586
Daniel@0 4587 function strrep(n, str) {
Daniel@0 4588 var s = "", i;
Daniel@0 4589 for (i=0; i<n; ++i) s += str;
Daniel@0 4590 return s;
Daniel@0 4591 }
Daniel@0 4592
Daniel@0 4593 u.truncate = function(s, length, pos, word, ellipsis) {
Daniel@0 4594 var len = s.length;
Daniel@0 4595 if (len <= length) return s;
Daniel@0 4596 ellipsis = ellipsis !== undefined ? String(ellipsis) : '\u2026';
Daniel@0 4597 var l = Math.max(0, length - ellipsis.length);
Daniel@0 4598
Daniel@0 4599 switch (pos) {
Daniel@0 4600 case 'left':
Daniel@0 4601 return ellipsis + (word ? truncateOnWord(s,l,1) : s.slice(len-l));
Daniel@0 4602 case 'middle':
Daniel@0 4603 case 'center':
Daniel@0 4604 var l1 = Math.ceil(l/2), l2 = Math.floor(l/2);
Daniel@0 4605 return (word ? truncateOnWord(s,l1) : s.slice(0,l1)) +
Daniel@0 4606 ellipsis + (word ? truncateOnWord(s,l2,1) : s.slice(len-l2));
Daniel@0 4607 default:
Daniel@0 4608 return (word ? truncateOnWord(s,l) : s.slice(0,l)) + ellipsis;
Daniel@0 4609 }
Daniel@0 4610 };
Daniel@0 4611
Daniel@0 4612 function truncateOnWord(s, len, rev) {
Daniel@0 4613 var cnt = 0, tok = s.split(truncate_word_re);
Daniel@0 4614 if (rev) {
Daniel@0 4615 s = (tok = tok.reverse())
Daniel@0 4616 .filter(function(w) { cnt += w.length; return cnt <= len; })
Daniel@0 4617 .reverse();
Daniel@0 4618 } else {
Daniel@0 4619 s = tok.filter(function(w) { cnt += w.length; return cnt <= len; });
Daniel@0 4620 }
Daniel@0 4621 return s.length ? s.join('').trim() : tok[0].slice(0, len);
Daniel@0 4622 }
Daniel@0 4623
Daniel@0 4624 var truncate_word_re = /([\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u2028\u2029\u3000\uFEFF])/;
Daniel@0 4625
Daniel@0 4626 },{"./time":28,"buffer":2}],30:[function(require,module,exports){
Daniel@0 4627 var DEPS = require('./Dependencies').ALL;
Daniel@0 4628
Daniel@0 4629 function create(cs, reflow) {
Daniel@0 4630 var out = {};
Daniel@0 4631 copy(cs, out);
Daniel@0 4632
Daniel@0 4633 out.add = [];
Daniel@0 4634 out.mod = [];
Daniel@0 4635 out.rem = [];
Daniel@0 4636
Daniel@0 4637 out.reflow = reflow;
Daniel@0 4638
Daniel@0 4639 return out;
Daniel@0 4640 }
Daniel@0 4641
Daniel@0 4642 function copy(a, b) {
Daniel@0 4643 b.stamp = a ? a.stamp : 0;
Daniel@0 4644 b.sort = a ? a.sort : null;
Daniel@0 4645 b.facet = a ? a.facet : null;
Daniel@0 4646 b.trans = a ? a.trans : null;
Daniel@0 4647 b.dirty = a ? a.dirty : [];
Daniel@0 4648 b.request = a ? a.request : null;
Daniel@0 4649 for (var d, i=0, n=DEPS.length; i<n; ++i) {
Daniel@0 4650 b[d=DEPS[i]] = a ? a[d] : {};
Daniel@0 4651 }
Daniel@0 4652 }
Daniel@0 4653
Daniel@0 4654 module.exports = {
Daniel@0 4655 create: create,
Daniel@0 4656 copy: copy
Daniel@0 4657 };
Daniel@0 4658 },{"./Dependencies":33}],31:[function(require,module,exports){
Daniel@0 4659 var log = require('vega-logging'),
Daniel@0 4660 Tuple = require('./Tuple'),
Daniel@0 4661 Base = require('./Node').prototype;
Daniel@0 4662
Daniel@0 4663 function Collector(graph) {
Daniel@0 4664 Base.init.call(this, graph);
Daniel@0 4665 this._data = [];
Daniel@0 4666 this.router(true).collector(true);
Daniel@0 4667 }
Daniel@0 4668
Daniel@0 4669 var prototype = (Collector.prototype = Object.create(Base));
Daniel@0 4670 prototype.constructor = Collector;
Daniel@0 4671
Daniel@0 4672 prototype.data = function() {
Daniel@0 4673 return this._data;
Daniel@0 4674 };
Daniel@0 4675
Daniel@0 4676 prototype.evaluate = function(input) {
Daniel@0 4677 log.debug(input, ["collecting"]);
Daniel@0 4678
Daniel@0 4679 if (input.rem.length) {
Daniel@0 4680 this._data = Tuple.idFilter(this._data, input.rem);
Daniel@0 4681 }
Daniel@0 4682
Daniel@0 4683 if (input.add.length) {
Daniel@0 4684 this._data = this._data.length ? this._data.concat(input.add) : input.add;
Daniel@0 4685 }
Daniel@0 4686
Daniel@0 4687 if (input.sort) {
Daniel@0 4688 this._data.sort(input.sort);
Daniel@0 4689 }
Daniel@0 4690
Daniel@0 4691 if (input.reflow) {
Daniel@0 4692 input.mod = input.mod.concat(
Daniel@0 4693 Tuple.idFilter(this._data, input.add, input.mod, input.rem));
Daniel@0 4694 input.reflow = false;
Daniel@0 4695 }
Daniel@0 4696
Daniel@0 4697 return input;
Daniel@0 4698 };
Daniel@0 4699
Daniel@0 4700 module.exports = Collector;
Daniel@0 4701 },{"./Node":36,"./Tuple":38,"vega-logging":45}],32:[function(require,module,exports){
Daniel@0 4702 var log = require('vega-logging'),
Daniel@0 4703 ChangeSet = require('./ChangeSet'),
Daniel@0 4704 Collector = require('./Collector'),
Daniel@0 4705 Tuple = require('./Tuple'),
Daniel@0 4706 Node = require('./Node'); // jshint ignore:line
Daniel@0 4707
Daniel@0 4708 function DataSource(graph, name, facet) {
Daniel@0 4709 this._graph = graph;
Daniel@0 4710 this._name = name;
Daniel@0 4711 this._data = [];
Daniel@0 4712 this._source = null;
Daniel@0 4713 this._facet = facet;
Daniel@0 4714 this._input = ChangeSet.create();
Daniel@0 4715 this._output = null; // Output changeset
Daniel@0 4716
Daniel@0 4717 this._inputNode = null;
Daniel@0 4718 this._outputNode = null;
Daniel@0 4719 this._pipeline = null; // Pipeline of transformations.
Daniel@0 4720 this._collector = null; // Collector to materialize output of pipeline.
Daniel@0 4721 this._mutates = false; // Does any pipeline operator mutate tuples?
Daniel@0 4722 }
Daniel@0 4723
Daniel@0 4724 var prototype = DataSource.prototype;
Daniel@0 4725
Daniel@0 4726 prototype.name = function(name) {
Daniel@0 4727 if (!arguments.length) return this._name;
Daniel@0 4728 return (this._name = name, this);
Daniel@0 4729 };
Daniel@0 4730
Daniel@0 4731 prototype.source = function(src) {
Daniel@0 4732 if (!arguments.length) return this._source;
Daniel@0 4733 return (this._source = this._graph.data(src));
Daniel@0 4734 };
Daniel@0 4735
Daniel@0 4736 prototype.insert = function(tuples) {
Daniel@0 4737 this._input.add = this._input.add.concat(tuples.map(Tuple.ingest));
Daniel@0 4738 return this;
Daniel@0 4739 };
Daniel@0 4740
Daniel@0 4741 prototype.remove = function(where) {
Daniel@0 4742 var remove = this._data.filter(where);
Daniel@0 4743 this._input.rem = this._input.rem.concat(remove);
Daniel@0 4744 return this;
Daniel@0 4745 };
Daniel@0 4746
Daniel@0 4747 prototype.update = function(where, field, func) {
Daniel@0 4748 var mod = this._input.mod,
Daniel@0 4749 ids = Tuple.idMap(mod);
Daniel@0 4750
Daniel@0 4751 this._input.fields[field] = 1;
Daniel@0 4752
Daniel@0 4753 this._data.filter(where).forEach(function(x) {
Daniel@0 4754 var prev = x[field],
Daniel@0 4755 next = func(x);
Daniel@0 4756 if (prev !== next) {
Daniel@0 4757 Tuple.set(x, field, next);
Daniel@0 4758 if (ids[x._id] !== 1) {
Daniel@0 4759 mod.push(x);
Daniel@0 4760 ids[x._id] = 1;
Daniel@0 4761 }
Daniel@0 4762 }
Daniel@0 4763 });
Daniel@0 4764
Daniel@0 4765 return this;
Daniel@0 4766 };
Daniel@0 4767
Daniel@0 4768 prototype.values = function(data) {
Daniel@0 4769 if (!arguments.length) return this._collector.data();
Daniel@0 4770
Daniel@0 4771 // Replace backing data
Daniel@0 4772 this._input.rem = this._data.slice();
Daniel@0 4773 if (data) { this.insert(data); }
Daniel@0 4774 return this;
Daniel@0 4775 };
Daniel@0 4776
Daniel@0 4777 prototype.mutates = function(m) {
Daniel@0 4778 if (!arguments.length) return this._mutates;
Daniel@0 4779 this._mutates = this._mutates || m;
Daniel@0 4780 return this;
Daniel@0 4781 };
Daniel@0 4782
Daniel@0 4783 prototype.last = function() {
Daniel@0 4784 return this._output;
Daniel@0 4785 };
Daniel@0 4786
Daniel@0 4787 prototype.fire = function(input) {
Daniel@0 4788 if (input) this._input = input;
Daniel@0 4789 this._graph.propagate(this._input, this._pipeline[0]);
Daniel@0 4790 return this;
Daniel@0 4791 };
Daniel@0 4792
Daniel@0 4793 prototype.pipeline = function(pipeline) {
Daniel@0 4794 if (!arguments.length) return this._pipeline;
Daniel@0 4795
Daniel@0 4796 var graph = this._graph,
Daniel@0 4797 status;
Daniel@0 4798
Daniel@0 4799 pipeline.unshift(this._inputNode = DataSourceInput(this));
Daniel@0 4800 status = graph.preprocess(pipeline);
Daniel@0 4801
Daniel@0 4802 if (status.router) {
Daniel@0 4803 pipeline.push(status.collector = new Collector(graph));
Daniel@0 4804 }
Daniel@0 4805
Daniel@0 4806 pipeline.push(this._outputNode = DataSourceOutput(this));
Daniel@0 4807 this._collector = status.collector;
Daniel@0 4808 this._mutates = !!status.mutates;
Daniel@0 4809 graph.connect(this._pipeline = pipeline);
Daniel@0 4810
Daniel@0 4811 return this;
Daniel@0 4812 };
Daniel@0 4813
Daniel@0 4814 prototype.synchronize = function() {
Daniel@0 4815 this._graph.synchronize(this._pipeline);
Daniel@0 4816 return this;
Daniel@0 4817 };
Daniel@0 4818
Daniel@0 4819 prototype.listener = function() {
Daniel@0 4820 return DataSourceListener(this).addListener(this._inputNode);
Daniel@0 4821 };
Daniel@0 4822
Daniel@0 4823 prototype.addListener = function(l) {
Daniel@0 4824 if (l instanceof DataSource) {
Daniel@0 4825 this._collector.addListener(l.listener());
Daniel@0 4826 } else {
Daniel@0 4827 this._outputNode.addListener(l);
Daniel@0 4828 }
Daniel@0 4829 return this;
Daniel@0 4830 };
Daniel@0 4831
Daniel@0 4832 prototype.removeListener = function(l) {
Daniel@0 4833 this._outputNode.removeListener(l);
Daniel@0 4834 };
Daniel@0 4835
Daniel@0 4836 prototype.listeners = function(ds) {
Daniel@0 4837 return (ds ? this._collector : this._outputNode).listeners();
Daniel@0 4838 };
Daniel@0 4839
Daniel@0 4840 // Input node applies the datasource's delta, and propagates it to
Daniel@0 4841 // the rest of the pipeline. It receives touches to reflow data.
Daniel@0 4842 function DataSourceInput(ds) {
Daniel@0 4843 var input = new Node(ds._graph)
Daniel@0 4844 .router(true)
Daniel@0 4845 .collector(true);
Daniel@0 4846
Daniel@0 4847 input.data = function() {
Daniel@0 4848 return ds._data;
Daniel@0 4849 };
Daniel@0 4850
Daniel@0 4851 input.evaluate = function(input) {
Daniel@0 4852 log.debug(input, ['input', ds._name]);
Daniel@0 4853
Daniel@0 4854 var delta = ds._input,
Daniel@0 4855 out = ChangeSet.create(input), f;
Daniel@0 4856
Daniel@0 4857 // Delta might contain fields updated through API
Daniel@0 4858 for (f in delta.fields) {
Daniel@0 4859 out.fields[f] = 1;
Daniel@0 4860 }
Daniel@0 4861
Daniel@0 4862 // update data
Daniel@0 4863 if (delta.rem.length) {
Daniel@0 4864 ds._data = Tuple.idFilter(ds._data, delta.rem);
Daniel@0 4865 }
Daniel@0 4866
Daniel@0 4867 if (delta.add.length) {
Daniel@0 4868 ds._data = ds._data.concat(delta.add);
Daniel@0 4869 }
Daniel@0 4870
Daniel@0 4871 // if reflowing, add any other tuples not currently in changeset
Daniel@0 4872 if (input.reflow) {
Daniel@0 4873 delta.mod = delta.mod.concat(
Daniel@0 4874 Tuple.idFilter(ds._data, delta.add, delta.mod, delta.rem));
Daniel@0 4875 }
Daniel@0 4876
Daniel@0 4877 // reset change list
Daniel@0 4878 ds._input = ChangeSet.create();
Daniel@0 4879
Daniel@0 4880 out.add = delta.add;
Daniel@0 4881 out.mod = delta.mod;
Daniel@0 4882 out.rem = delta.rem;
Daniel@0 4883 out.facet = ds._facet;
Daniel@0 4884 return out;
Daniel@0 4885 };
Daniel@0 4886
Daniel@0 4887 return input;
Daniel@0 4888 }
Daniel@0 4889
Daniel@0 4890 // Output node captures the last changeset seen by this datasource
Daniel@0 4891 // (needed for joins and builds) and materializes any nested data.
Daniel@0 4892 // If this datasource is faceted, materializes the values in the facet.
Daniel@0 4893 function DataSourceOutput(ds) {
Daniel@0 4894 var output = new Node(ds._graph)
Daniel@0 4895 .router(true)
Daniel@0 4896 .reflows(true)
Daniel@0 4897 .collector(true);
Daniel@0 4898
Daniel@0 4899 output.data = function() {
Daniel@0 4900 return ds._collector ? ds._collector.data() : ds._data;
Daniel@0 4901 };
Daniel@0 4902
Daniel@0 4903 output.evaluate = function(input) {
Daniel@0 4904 log.debug(input, ['output', ds._name]);
Daniel@0 4905
Daniel@0 4906 var out = ChangeSet.create(input, true);
Daniel@0 4907
Daniel@0 4908 if (ds._facet) {
Daniel@0 4909 ds._facet.values = ds.values();
Daniel@0 4910 input.facet = null;
Daniel@0 4911 }
Daniel@0 4912
Daniel@0 4913 ds._output = input;
Daniel@0 4914 out.data[ds._name] = 1;
Daniel@0 4915 return out;
Daniel@0 4916 };
Daniel@0 4917
Daniel@0 4918 return output;
Daniel@0 4919 }
Daniel@0 4920
Daniel@0 4921 function DataSourceListener(ds) {
Daniel@0 4922 var l = new Node(ds._graph).router(true);
Daniel@0 4923
Daniel@0 4924 l.evaluate = function(input) {
Daniel@0 4925 // Tuple derivation carries a cost. So only derive if the pipeline has
Daniel@0 4926 // operators that mutate, and thus would override the source data.
Daniel@0 4927 if (ds.mutates()) {
Daniel@0 4928 var map = ds._srcMap || (ds._srcMap = {}), // to propagate tuples correctly
Daniel@0 4929 output = ChangeSet.create(input);
Daniel@0 4930
Daniel@0 4931 output.add = input.add.map(function(t) {
Daniel@0 4932 return (map[t._id] = Tuple.derive(t));
Daniel@0 4933 });
Daniel@0 4934
Daniel@0 4935 output.mod = input.mod.map(function(t) {
Daniel@0 4936 return Tuple.rederive(t, map[t._id]);
Daniel@0 4937 });
Daniel@0 4938
Daniel@0 4939 output.rem = input.rem.map(function(t) {
Daniel@0 4940 var o = map[t._id];
Daniel@0 4941 return (map[t._id] = null, o);
Daniel@0 4942 });
Daniel@0 4943
Daniel@0 4944 return (ds._input = output);
Daniel@0 4945 } else {
Daniel@0 4946 return (ds._input = input);
Daniel@0 4947 }
Daniel@0 4948 };
Daniel@0 4949
Daniel@0 4950 return l;
Daniel@0 4951 }
Daniel@0 4952
Daniel@0 4953 module.exports = DataSource;
Daniel@0 4954
Daniel@0 4955 },{"./ChangeSet":30,"./Collector":31,"./Node":36,"./Tuple":38,"vega-logging":45}],33:[function(require,module,exports){
Daniel@0 4956 var deps = module.exports = {
Daniel@0 4957 ALL: ['data', 'fields', 'scales', 'signals']
Daniel@0 4958 };
Daniel@0 4959 deps.ALL.forEach(function(k) { deps[k.toUpperCase()] = k; });
Daniel@0 4960
Daniel@0 4961 },{}],34:[function(require,module,exports){
Daniel@0 4962 var dl = require('datalib'),
Daniel@0 4963 Heap = require('./Heap'),
Daniel@0 4964 ChangeSet = require('./ChangeSet'),
Daniel@0 4965 DataSource = require('./DataSource'),
Daniel@0 4966 Collector = require('./Collector'),
Daniel@0 4967 Tuple = require('./Tuple'),
Daniel@0 4968 Signal = require('./Signal'),
Daniel@0 4969 Deps = require('./Dependencies');
Daniel@0 4970
Daniel@0 4971 function Graph() {
Daniel@0 4972 }
Daniel@0 4973
Daniel@0 4974 var prototype = Graph.prototype;
Daniel@0 4975
Daniel@0 4976 prototype.init = function() {
Daniel@0 4977 this._stamp = 0;
Daniel@0 4978 this._rank = 0;
Daniel@0 4979
Daniel@0 4980 this._data = {};
Daniel@0 4981 this._signals = {};
Daniel@0 4982
Daniel@0 4983 this.doNotPropagate = {};
Daniel@0 4984 };
Daniel@0 4985
Daniel@0 4986 prototype.rank = function() {
Daniel@0 4987 return ++this._rank;
Daniel@0 4988 };
Daniel@0 4989
Daniel@0 4990 prototype.values = function(type, names, hash) {
Daniel@0 4991 var data = (type === Deps.SIGNALS ? this._signals : this._data),
Daniel@0 4992 n = (names !== undefined ? names : dl.keys(data)),
Daniel@0 4993 vals, i;
Daniel@0 4994
Daniel@0 4995 if (Array.isArray(n)) {
Daniel@0 4996 vals = hash || {};
Daniel@0 4997 for (i=0; i<n.length; ++i) {
Daniel@0 4998 vals[n[i]] = data[n[i]].values();
Daniel@0 4999 }
Daniel@0 5000 return vals;
Daniel@0 5001 } else {
Daniel@0 5002 return data[n].values();
Daniel@0 5003 }
Daniel@0 5004 };
Daniel@0 5005
Daniel@0 5006 // Retain for backwards-compatibility
Daniel@0 5007 prototype.dataValues = function(names) {
Daniel@0 5008 return this.values(Deps.DATA, names);
Daniel@0 5009 };
Daniel@0 5010
Daniel@0 5011 // Retain for backwards-compatibility
Daniel@0 5012 prototype.signalValues = function(names) {
Daniel@0 5013 return this.values(Deps.SIGNALS, names);
Daniel@0 5014 };
Daniel@0 5015
Daniel@0 5016 prototype.data = function(name, pipeline, facet) {
Daniel@0 5017 var db = this._data;
Daniel@0 5018 if (!arguments.length) {
Daniel@0 5019 var all = [], key;
Daniel@0 5020 for (key in db) { all.push(db[key]); }
Daniel@0 5021 return all;
Daniel@0 5022 } else if (arguments.length === 1) {
Daniel@0 5023 return db[name];
Daniel@0 5024 } else {
Daniel@0 5025 return (db[name] = new DataSource(this, name, facet).pipeline(pipeline));
Daniel@0 5026 }
Daniel@0 5027 };
Daniel@0 5028
Daniel@0 5029 prototype.signal = function(name, init) {
Daniel@0 5030 if (arguments.length === 1) {
Daniel@0 5031 var m = this;
Daniel@0 5032 return Array.isArray(name) ?
Daniel@0 5033 name.map(function(n) { return m._signals[n]; }) :
Daniel@0 5034 this._signals[name];
Daniel@0 5035 } else {
Daniel@0 5036 return (this._signals[name] = new Signal(this, name, init));
Daniel@0 5037 }
Daniel@0 5038 };
Daniel@0 5039
Daniel@0 5040 prototype.signalRef = function(ref) {
Daniel@0 5041 if (!Array.isArray(ref)) {
Daniel@0 5042 ref = dl.field(ref);
Daniel@0 5043 }
Daniel@0 5044
Daniel@0 5045 var value = this.signal(ref[0]).value();
Daniel@0 5046 if (ref.length > 1) {
Daniel@0 5047 for (var i=1, n=ref.length; i<n; ++i) {
Daniel@0 5048 value = value[ref[i]];
Daniel@0 5049 }
Daniel@0 5050 }
Daniel@0 5051 return value;
Daniel@0 5052 };
Daniel@0 5053
Daniel@0 5054 // Stamp should be specified with caution. It is necessary for inline datasources,
Daniel@0 5055 // which need to be populated during the same cycle even though propagation has
Daniel@0 5056 // passed that part of the dataflow graph.
Daniel@0 5057 prototype.propagate = function(pulse, node, stamp) {
Daniel@0 5058 var pulses = {},
Daniel@0 5059 listeners, next, nplse, tpls, ntpls, i, len;
Daniel@0 5060
Daniel@0 5061 // new PQ with each propagation cycle so that we can pulse branches
Daniel@0 5062 // of the dataflow graph during a propagation (e.g., when creating
Daniel@0 5063 // a new inline datasource).
Daniel@0 5064 var pq = new Heap(function(a, b) {
Daniel@0 5065 // Sort on qrank (queue-rank).
Daniel@0 5066 // Rank can change during propagation due to rewiring.
Daniel@0 5067 return a._qrank - b._qrank;
Daniel@0 5068 });
Daniel@0 5069
Daniel@0 5070 if (pulse.stamp) throw Error('Pulse already has a non-zero stamp.');
Daniel@0 5071
Daniel@0 5072 pulse.stamp = stamp || ++this._stamp;
Daniel@0 5073 pulses[node._id] = pulse;
Daniel@0 5074 pq.push(node.qrank(true));
Daniel@0 5075
Daniel@0 5076 while (pq.size() > 0) {
Daniel@0 5077 node = pq.peek();
Daniel@0 5078 pulse = pulses[node._id];
Daniel@0 5079
Daniel@0 5080 if (node.rank() !== node.qrank()) {
Daniel@0 5081 // A node's rank might change during a propagation. Re-queue if so.
Daniel@0 5082 pq.replace(node.qrank(true));
Daniel@0 5083 } else {
Daniel@0 5084 // Evaluate node and propagate pulse.
Daniel@0 5085 pq.pop();
Daniel@0 5086 pulses[node._id] = null;
Daniel@0 5087 listeners = node._listeners;
Daniel@0 5088 pulse = this.evaluate(pulse, node);
Daniel@0 5089
Daniel@0 5090 // Propagate the pulse.
Daniel@0 5091 if (pulse !== this.doNotPropagate) {
Daniel@0 5092 // Ensure reflow pulses always send reflow pulses even if skipped.
Daniel@0 5093 if (!pulse.reflow && node.reflows()) {
Daniel@0 5094 pulse = ChangeSet.create(pulse, true);
Daniel@0 5095 }
Daniel@0 5096
Daniel@0 5097 for (i=0, len=listeners.length; i<len; ++i) {
Daniel@0 5098 next = listeners[i];
Daniel@0 5099
Daniel@0 5100 if ((nplse = pulses[next._id]) !== undefined) {
Daniel@0 5101 if (nplse === null) throw Error('Already propagated to node.');
Daniel@0 5102 if (nplse === pulse) continue; // Re-queueing the same pulse.
Daniel@0 5103
Daniel@0 5104 // We've already queued this node. Ensure there should be at most one
Daniel@0 5105 // pulse with tuples (add/mod/rem), and the remainder will be reflows.
Daniel@0 5106 tpls = pulse.add.length || pulse.mod.length || pulse.rem.length;
Daniel@0 5107 ntpls = nplse.add.length || nplse.mod.length || nplse.rem.length;
Daniel@0 5108
Daniel@0 5109 if (tpls && ntpls) throw Error('Multiple changeset pulses to same node');
Daniel@0 5110
Daniel@0 5111 // Combine reflow and tuples into a single pulse.
Daniel@0 5112 pulses[next._id] = tpls ? pulse : nplse;
Daniel@0 5113 pulses[next._id].reflow = pulse.reflow || nplse.reflow;
Daniel@0 5114 } else {
Daniel@0 5115 // First time we're seeing this node, queue it for propagation.
Daniel@0 5116 pq.push(next.qrank(true));
Daniel@0 5117 pulses[next._id] = pulse;
Daniel@0 5118 }
Daniel@0 5119 }
Daniel@0 5120 }
Daniel@0 5121 }
Daniel@0 5122 }
Daniel@0 5123 };
Daniel@0 5124
Daniel@0 5125 // Process a new branch of the dataflow graph prior to connection:
Daniel@0 5126 // (1) Insert new Collector nodes as needed.
Daniel@0 5127 // (2) Track + return mutation/routing status of the branch.
Daniel@0 5128 prototype.preprocess = function(branch) {
Daniel@0 5129 var graph = this,
Daniel@0 5130 mutates = 0,
Daniel@0 5131 node, router, collector, collects;
Daniel@0 5132
Daniel@0 5133 for (var i=0; i<branch.length; ++i) {
Daniel@0 5134 node = branch[i];
Daniel@0 5135
Daniel@0 5136 // Batch nodes need access to a materialized dataset.
Daniel@0 5137 if (node.batch() && !node._collector) {
Daniel@0 5138 if (router || !collector) {
Daniel@0 5139 node = new Collector(graph);
Daniel@0 5140 branch.splice(i, 0, node);
Daniel@0 5141 router = false;
Daniel@0 5142 } else {
Daniel@0 5143 node._collector = collector;
Daniel@0 5144 }
Daniel@0 5145 }
Daniel@0 5146
Daniel@0 5147 if ((collects = node.collector())) collector = node;
Daniel@0 5148 router = router || node.router() && !collects;
Daniel@0 5149 mutates = mutates || node.mutates();
Daniel@0 5150
Daniel@0 5151 // A collector needs to be inserted after tuple-producing
Daniel@0 5152 // nodes for correct previous value tracking.
Daniel@0 5153 if (node.produces()) {
Daniel@0 5154 branch.splice(i+1, 0, new Collector(graph));
Daniel@0 5155 router = false;
Daniel@0 5156 }
Daniel@0 5157 }
Daniel@0 5158
Daniel@0 5159 return {router: router, collector: collector, mutates: mutates};
Daniel@0 5160 };
Daniel@0 5161
Daniel@0 5162 prototype.connect = function(branch) {
Daniel@0 5163 var collector, node, data, signals, i, n, j, m;
Daniel@0 5164
Daniel@0 5165 // connect the pipeline
Daniel@0 5166 for (i=0, n=branch.length; i<n; ++i) {
Daniel@0 5167 node = branch[i];
Daniel@0 5168 if (node.collector()) collector = node;
Daniel@0 5169
Daniel@0 5170 data = node.dependency(Deps.DATA);
Daniel@0 5171 for (j=0, m=data.length; j<m; ++j) {
Daniel@0 5172 this.data(data[j]).addListener(collector);
Daniel@0 5173 }
Daniel@0 5174
Daniel@0 5175 signals = node.dependency(Deps.SIGNALS);
Daniel@0 5176 for (j=0, m=signals.length; j<m; ++j) {
Daniel@0 5177 this.signal(signals[j]).addListener(collector);
Daniel@0 5178 }
Daniel@0 5179
Daniel@0 5180 if (i > 0) branch[i-1].addListener(node);
Daniel@0 5181 }
Daniel@0 5182
Daniel@0 5183 return branch;
Daniel@0 5184 };
Daniel@0 5185
Daniel@0 5186 prototype.disconnect = function(branch) {
Daniel@0 5187 var collector, node, data, signals, i, n, j, m;
Daniel@0 5188
Daniel@0 5189 for (i=0, n=branch.length; i<n; ++i) {
Daniel@0 5190 node = branch[i];
Daniel@0 5191 if (node.collector()) collector = node;
Daniel@0 5192
Daniel@0 5193 data = node.dependency(Deps.DATA);
Daniel@0 5194 for (j=0, m=data.length; j<m; ++j) {
Daniel@0 5195 this.data(data[j]).removeListener(collector);
Daniel@0 5196 }
Daniel@0 5197
Daniel@0 5198 signals = node.dependency(Deps.SIGNALS);
Daniel@0 5199 for (j=0, m=signals.length; j<m; ++j) {
Daniel@0 5200 this.signal(signals[j]).removeListener(collector);
Daniel@0 5201 }
Daniel@0 5202
Daniel@0 5203 node.disconnect();
Daniel@0 5204 }
Daniel@0 5205
Daniel@0 5206 return branch;
Daniel@0 5207 };
Daniel@0 5208
Daniel@0 5209 prototype.synchronize = function(branch) {
Daniel@0 5210 var ids = {},
Daniel@0 5211 node, data, i, n, j, m, d, id;
Daniel@0 5212
Daniel@0 5213 for (i=0, n=branch.length; i<n; ++i) {
Daniel@0 5214 node = branch[i];
Daniel@0 5215 if (!node.collector()) continue;
Daniel@0 5216
Daniel@0 5217 for (j=0, data=node.data(), m=data.length; j<m; ++j) {
Daniel@0 5218 id = (d = data[j])._id;
Daniel@0 5219 if (ids[id]) continue;
Daniel@0 5220 Tuple.prev_update(d);
Daniel@0 5221 ids[id] = 1;
Daniel@0 5222 }
Daniel@0 5223 }
Daniel@0 5224
Daniel@0 5225 return this;
Daniel@0 5226 };
Daniel@0 5227
Daniel@0 5228 prototype.reevaluate = function(pulse, node) {
Daniel@0 5229 var reflowed = pulse.reflow && node.last() >= pulse.stamp,
Daniel@0 5230 run = node.router() || pulse.add.length || pulse.rem.length;
Daniel@0 5231
Daniel@0 5232 return run || !reflowed || node.reevaluate(pulse);
Daniel@0 5233 };
Daniel@0 5234
Daniel@0 5235 prototype.evaluate = function(pulse, node) {
Daniel@0 5236 if (!this.reevaluate(pulse, node)) return pulse;
Daniel@0 5237 pulse = node.evaluate(pulse);
Daniel@0 5238 node.last(pulse.stamp);
Daniel@0 5239 return pulse;
Daniel@0 5240 };
Daniel@0 5241
Daniel@0 5242 module.exports = Graph;
Daniel@0 5243
Daniel@0 5244 },{"./ChangeSet":30,"./Collector":31,"./DataSource":32,"./Dependencies":33,"./Heap":35,"./Signal":37,"./Tuple":38,"datalib":24}],35:[function(require,module,exports){
Daniel@0 5245 function Heap(comparator) {
Daniel@0 5246 this.cmp = comparator;
Daniel@0 5247 this.nodes = [];
Daniel@0 5248 }
Daniel@0 5249
Daniel@0 5250 var prototype = Heap.prototype;
Daniel@0 5251
Daniel@0 5252 prototype.size = function() {
Daniel@0 5253 return this.nodes.length;
Daniel@0 5254 };
Daniel@0 5255
Daniel@0 5256 prototype.clear = function() {
Daniel@0 5257 return (this.nodes = [], this);
Daniel@0 5258 };
Daniel@0 5259
Daniel@0 5260 prototype.peek = function() {
Daniel@0 5261 return this.nodes[0];
Daniel@0 5262 };
Daniel@0 5263
Daniel@0 5264 prototype.push = function(x) {
Daniel@0 5265 var array = this.nodes;
Daniel@0 5266 array.push(x);
Daniel@0 5267 return _siftdown(array, 0, array.length-1, this.cmp);
Daniel@0 5268 };
Daniel@0 5269
Daniel@0 5270 prototype.pop = function() {
Daniel@0 5271 var array = this.nodes,
Daniel@0 5272 last = array.pop(),
Daniel@0 5273 item;
Daniel@0 5274
Daniel@0 5275 if (array.length) {
Daniel@0 5276 item = array[0];
Daniel@0 5277 array[0] = last;
Daniel@0 5278 _siftup(array, 0, this.cmp);
Daniel@0 5279 } else {
Daniel@0 5280 item = last;
Daniel@0 5281 }
Daniel@0 5282 return item;
Daniel@0 5283 };
Daniel@0 5284
Daniel@0 5285 prototype.replace = function(item) {
Daniel@0 5286 var array = this.nodes,
Daniel@0 5287 retval = array[0];
Daniel@0 5288 array[0] = item;
Daniel@0 5289 _siftup(array, 0, this.cmp);
Daniel@0 5290 return retval;
Daniel@0 5291 };
Daniel@0 5292
Daniel@0 5293 prototype.pushpop = function(item) {
Daniel@0 5294 var array = this.nodes, ref = array[0];
Daniel@0 5295 if (array.length && this.cmp(ref, item) < 0) {
Daniel@0 5296 array[0] = item;
Daniel@0 5297 item = ref;
Daniel@0 5298 _siftup(array, 0, this.cmp);
Daniel@0 5299 }
Daniel@0 5300 return item;
Daniel@0 5301 };
Daniel@0 5302
Daniel@0 5303 function _siftdown(array, start, idx, cmp) {
Daniel@0 5304 var item, parent, pidx;
Daniel@0 5305
Daniel@0 5306 item = array[idx];
Daniel@0 5307 while (idx > start) {
Daniel@0 5308 pidx = (idx - 1) >> 1;
Daniel@0 5309 parent = array[pidx];
Daniel@0 5310 if (cmp(item, parent) < 0) {
Daniel@0 5311 array[idx] = parent;
Daniel@0 5312 idx = pidx;
Daniel@0 5313 continue;
Daniel@0 5314 }
Daniel@0 5315 break;
Daniel@0 5316 }
Daniel@0 5317 return (array[idx] = item);
Daniel@0 5318 }
Daniel@0 5319
Daniel@0 5320 function _siftup(array, idx, cmp) {
Daniel@0 5321 var start = idx,
Daniel@0 5322 end = array.length,
Daniel@0 5323 item = array[idx],
Daniel@0 5324 cidx = 2 * idx + 1, ridx;
Daniel@0 5325
Daniel@0 5326 while (cidx < end) {
Daniel@0 5327 ridx = cidx + 1;
Daniel@0 5328 if (ridx < end && cmp(array[cidx], array[ridx]) >= 0) {
Daniel@0 5329 cidx = ridx;
Daniel@0 5330 }
Daniel@0 5331 array[idx] = array[cidx];
Daniel@0 5332 idx = cidx;
Daniel@0 5333 cidx = 2 * idx + 1;
Daniel@0 5334 }
Daniel@0 5335 array[idx] = item;
Daniel@0 5336 return _siftdown(array, start, idx, cmp);
Daniel@0 5337 }
Daniel@0 5338
Daniel@0 5339 module.exports = Heap;
Daniel@0 5340
Daniel@0 5341 },{}],36:[function(require,module,exports){
Daniel@0 5342 var DEPS = require('./Dependencies').ALL,
Daniel@0 5343 nodeID = 0;
Daniel@0 5344
Daniel@0 5345 function Node(graph) {
Daniel@0 5346 if (graph) this.init(graph);
Daniel@0 5347 }
Daniel@0 5348
Daniel@0 5349 var Flags = Node.Flags = {
Daniel@0 5350 Router: 0x01, // Responsible for propagating tuples, cannot be skipped.
Daniel@0 5351 Collector: 0x02, // Holds a materialized dataset, pulse node to reflow.
Daniel@0 5352 Produces: 0x04, // Produces new tuples.
Daniel@0 5353 Mutates: 0x08, // Sets properties of incoming tuples.
Daniel@0 5354 Reflows: 0x10, // Forwards a reflow pulse.
Daniel@0 5355 Batch: 0x20 // Performs batch data processing, needs collector.
Daniel@0 5356 };
Daniel@0 5357
Daniel@0 5358 var prototype = Node.prototype;
Daniel@0 5359
Daniel@0 5360 prototype.init = function(graph) {
Daniel@0 5361 this._id = ++nodeID;
Daniel@0 5362 this._graph = graph;
Daniel@0 5363 this._rank = graph.rank(); // Topological sort by rank
Daniel@0 5364 this._qrank = null; // Rank when enqueued for propagation
Daniel@0 5365 this._stamp = 0; // Last stamp seen
Daniel@0 5366
Daniel@0 5367 this._listeners = [];
Daniel@0 5368 this._listeners._ids = {}; // To prevent duplicate listeners
Daniel@0 5369
Daniel@0 5370 // Initialize dependencies.
Daniel@0 5371 this._deps = {};
Daniel@0 5372 for (var i=0, n=DEPS.length; i<n; ++i) {
Daniel@0 5373 this._deps[DEPS[i]] = [];
Daniel@0 5374 }
Daniel@0 5375
Daniel@0 5376 // Initialize status flags.
Daniel@0 5377 this._flags = 0;
Daniel@0 5378
Daniel@0 5379 return this;
Daniel@0 5380 };
Daniel@0 5381
Daniel@0 5382 prototype.rank = function() {
Daniel@0 5383 return this._rank;
Daniel@0 5384 };
Daniel@0 5385
Daniel@0 5386 prototype.qrank = function(/* set */) {
Daniel@0 5387 if (!arguments.length) return this._qrank;
Daniel@0 5388 return (this._qrank = this._rank, this);
Daniel@0 5389 };
Daniel@0 5390
Daniel@0 5391 prototype.last = function(stamp) {
Daniel@0 5392 if (!arguments.length) return this._stamp;
Daniel@0 5393 return (this._stamp = stamp, this);
Daniel@0 5394 };
Daniel@0 5395
Daniel@0 5396 // -- status flags ---
Daniel@0 5397
Daniel@0 5398 prototype._setf = function(v, b) {
Daniel@0 5399 if (b) { this._flags |= v; } else { this._flags &= ~v; }
Daniel@0 5400 return this;
Daniel@0 5401 };
Daniel@0 5402
Daniel@0 5403 prototype.router = function(state) {
Daniel@0 5404 if (!arguments.length) return (this._flags & Flags.Router);
Daniel@0 5405 return this._setf(Flags.Router, state);
Daniel@0 5406 };
Daniel@0 5407
Daniel@0 5408 prototype.collector = function(state) {
Daniel@0 5409 if (!arguments.length) return (this._flags & Flags.Collector);
Daniel@0 5410 return this._setf(Flags.Collector, state);
Daniel@0 5411 };
Daniel@0 5412
Daniel@0 5413 prototype.produces = function(state) {
Daniel@0 5414 if (!arguments.length) return (this._flags & Flags.Produces);
Daniel@0 5415 return this._setf(Flags.Produces, state);
Daniel@0 5416 };
Daniel@0 5417
Daniel@0 5418 prototype.mutates = function(state) {
Daniel@0 5419 if (!arguments.length) return (this._flags & Flags.Mutates);
Daniel@0 5420 return this._setf(Flags.Mutates, state);
Daniel@0 5421 };
Daniel@0 5422
Daniel@0 5423 prototype.reflows = function(state) {
Daniel@0 5424 if (!arguments.length) return (this._flags & Flags.Reflows);
Daniel@0 5425 return this._setf(Flags.Reflows, state);
Daniel@0 5426 };
Daniel@0 5427
Daniel@0 5428 prototype.batch = function(state) {
Daniel@0 5429 if (!arguments.length) return (this._flags & Flags.Batch);
Daniel@0 5430 return this._setf(Flags.Batch, state);
Daniel@0 5431 };
Daniel@0 5432
Daniel@0 5433 prototype.dependency = function(type, deps) {
Daniel@0 5434 var d = this._deps[type],
Daniel@0 5435 n = d._names || (d._names = {}); // To prevent dupe deps
Daniel@0 5436
Daniel@0 5437 // Get dependencies of the given type
Daniel@0 5438 if (arguments.length === 1) {
Daniel@0 5439 return d;
Daniel@0 5440 }
Daniel@0 5441
Daniel@0 5442 if (deps === null) {
Daniel@0 5443 // Clear dependencies of the given type
Daniel@0 5444 d.splice(0, d.length);
Daniel@0 5445 d._names = {};
Daniel@0 5446 } else if (!Array.isArray(deps)) {
Daniel@0 5447 // Separate this case to avoid cost of array creation
Daniel@0 5448 if (n[deps]) return this;
Daniel@0 5449 d.push(deps);
Daniel@0 5450 n[deps] = 1;
Daniel@0 5451 } else {
Daniel@0 5452 for (var i=0, len=deps.length, dep; i<len; ++i) {
Daniel@0 5453 dep = deps[i];
Daniel@0 5454 if (n[dep]) continue;
Daniel@0 5455 d.push(dep);
Daniel@0 5456 n[dep] = 1;
Daniel@0 5457 }
Daniel@0 5458 }
Daniel@0 5459
Daniel@0 5460 return this;
Daniel@0 5461 };
Daniel@0 5462
Daniel@0 5463 prototype.listeners = function() {
Daniel@0 5464 return this._listeners;
Daniel@0 5465 };
Daniel@0 5466
Daniel@0 5467 prototype.addListener = function(l) {
Daniel@0 5468 if (!(l instanceof Node)) {
Daniel@0 5469 throw Error('Listener is not a Node');
Daniel@0 5470 }
Daniel@0 5471 if (this._listeners._ids[l._id]) return this;
Daniel@0 5472
Daniel@0 5473 this._listeners.push(l);
Daniel@0 5474 this._listeners._ids[l._id] = 1;
Daniel@0 5475 if (this._rank > l._rank) {
Daniel@0 5476 var q = [l],
Daniel@0 5477 g = this._graph, cur;
Daniel@0 5478 while (q.length) {
Daniel@0 5479 cur = q.shift();
Daniel@0 5480 cur._rank = g.rank();
Daniel@0 5481 q.unshift.apply(q, cur.listeners());
Daniel@0 5482 }
Daniel@0 5483 }
Daniel@0 5484
Daniel@0 5485 return this;
Daniel@0 5486 };
Daniel@0 5487
Daniel@0 5488 prototype.removeListener = function(l) {
Daniel@0 5489 if (!this._listeners._ids[l._id]) return false;
Daniel@0 5490
Daniel@0 5491 var idx = this._listeners.indexOf(l),
Daniel@0 5492 b = idx >= 0;
Daniel@0 5493
Daniel@0 5494 if (b) {
Daniel@0 5495 this._listeners.splice(idx, 1);
Daniel@0 5496 this._listeners._ids[l._id] = null;
Daniel@0 5497 }
Daniel@0 5498 return b;
Daniel@0 5499 };
Daniel@0 5500
Daniel@0 5501 prototype.disconnect = function() {
Daniel@0 5502 this._listeners = [];
Daniel@0 5503 this._listeners._ids = {};
Daniel@0 5504 };
Daniel@0 5505
Daniel@0 5506 // Evaluate this dataflow node for the current pulse.
Daniel@0 5507 // Subclasses should override to perform custom processing.
Daniel@0 5508 prototype.evaluate = function(pulse) {
Daniel@0 5509 return pulse;
Daniel@0 5510 };
Daniel@0 5511
Daniel@0 5512 // Should this node be re-evaluated for the current pulse?
Daniel@0 5513 // Searches pulse to see if any dependencies have updated.
Daniel@0 5514 prototype.reevaluate = function(pulse) {
Daniel@0 5515 var prop, dep, i, n, j, m;
Daniel@0 5516
Daniel@0 5517 for (i=0, n=DEPS.length; i<n; ++i) {
Daniel@0 5518 prop = DEPS[i];
Daniel@0 5519 dep = this._deps[prop];
Daniel@0 5520 for (j=0, m=dep.length; j<m; ++j) {
Daniel@0 5521 if (pulse[prop][dep[j]]) return true;
Daniel@0 5522 }
Daniel@0 5523 }
Daniel@0 5524
Daniel@0 5525 return false;
Daniel@0 5526 };
Daniel@0 5527
Daniel@0 5528 Node.reset = function() { nodeID = 0; };
Daniel@0 5529
Daniel@0 5530 module.exports = Node;
Daniel@0 5531
Daniel@0 5532 },{"./Dependencies":33}],37:[function(require,module,exports){
Daniel@0 5533 var ChangeSet = require('./ChangeSet'),
Daniel@0 5534 Node = require('./Node'), // jshint ignore:line
Daniel@0 5535 Base = Node.prototype;
Daniel@0 5536
Daniel@0 5537 function Signal(graph, name, initialValue) {
Daniel@0 5538 Base.init.call(this, graph);
Daniel@0 5539 this._name = name;
Daniel@0 5540 this._value = initialValue;
Daniel@0 5541 this._verbose = false; // Verbose signals re-pulse the graph even if prev === val.
Daniel@0 5542 this._handlers = [];
Daniel@0 5543 return this;
Daniel@0 5544 }
Daniel@0 5545
Daniel@0 5546 var prototype = (Signal.prototype = Object.create(Base));
Daniel@0 5547 prototype.constructor = Signal;
Daniel@0 5548
Daniel@0 5549 prototype.name = function() {
Daniel@0 5550 return this._name;
Daniel@0 5551 };
Daniel@0 5552
Daniel@0 5553 prototype.value = function(val) {
Daniel@0 5554 if (!arguments.length) return this._value;
Daniel@0 5555 return (this._value = val, this);
Daniel@0 5556 };
Daniel@0 5557
Daniel@0 5558 // Alias to value, for shared API with DataSource
Daniel@0 5559 prototype.values = prototype.value;
Daniel@0 5560
Daniel@0 5561 prototype.verbose = function(v) {
Daniel@0 5562 if (!arguments.length) return this._verbose;
Daniel@0 5563 return (this._verbose = !!v, this);
Daniel@0 5564 };
Daniel@0 5565
Daniel@0 5566 prototype.evaluate = function(input) {
Daniel@0 5567 return input.signals[this._name] ? input : this._graph.doNotPropagate;
Daniel@0 5568 };
Daniel@0 5569
Daniel@0 5570 prototype.fire = function(cs) {
Daniel@0 5571 if (!cs) cs = ChangeSet.create(null, true);
Daniel@0 5572 cs.signals[this._name] = 1;
Daniel@0 5573 this._graph.propagate(cs, this);
Daniel@0 5574 };
Daniel@0 5575
Daniel@0 5576 prototype.on = function(handler) {
Daniel@0 5577 var signal = this,
Daniel@0 5578 node = new Node(this._graph);
Daniel@0 5579
Daniel@0 5580 node.evaluate = function(input) {
Daniel@0 5581 handler(signal.name(), signal.value());
Daniel@0 5582 return input;
Daniel@0 5583 };
Daniel@0 5584
Daniel@0 5585 this._handlers.push({
Daniel@0 5586 handler: handler,
Daniel@0 5587 node: node
Daniel@0 5588 });
Daniel@0 5589
Daniel@0 5590 return this.addListener(node);
Daniel@0 5591 };
Daniel@0 5592
Daniel@0 5593 prototype.off = function(handler) {
Daniel@0 5594 var h = this._handlers, i, x;
Daniel@0 5595
Daniel@0 5596 for (i=h.length; --i>=0;) {
Daniel@0 5597 if (!handler || h[i].handler === handler) {
Daniel@0 5598 x = h.splice(i, 1)[0];
Daniel@0 5599 this.removeListener(x.node);
Daniel@0 5600 }
Daniel@0 5601 }
Daniel@0 5602
Daniel@0 5603 return this;
Daniel@0 5604 };
Daniel@0 5605
Daniel@0 5606 module.exports = Signal;
Daniel@0 5607
Daniel@0 5608 },{"./ChangeSet":30,"./Node":36}],38:[function(require,module,exports){
Daniel@0 5609 var tupleID = 0;
Daniel@0 5610
Daniel@0 5611 function ingest(datum) {
Daniel@0 5612 datum = (datum === Object(datum)) ? datum : {data: datum};
Daniel@0 5613 datum._id = ++tupleID;
Daniel@0 5614 if (datum._prev) datum._prev = null;
Daniel@0 5615 return datum;
Daniel@0 5616 }
Daniel@0 5617
Daniel@0 5618 function idMap(a, ids) {
Daniel@0 5619 ids = ids || {};
Daniel@0 5620 for (var i=0, n=a.length; i<n; ++i) {
Daniel@0 5621 ids[a[i]._id] = 1;
Daniel@0 5622 }
Daniel@0 5623 return ids;
Daniel@0 5624 }
Daniel@0 5625
Daniel@0 5626 function copy(t, c) {
Daniel@0 5627 c = c || {};
Daniel@0 5628 for (var k in t) {
Daniel@0 5629 if (k !== '_prev' && k !== '_id') c[k] = t[k];
Daniel@0 5630 }
Daniel@0 5631 return c;
Daniel@0 5632 }
Daniel@0 5633
Daniel@0 5634 module.exports = {
Daniel@0 5635 ingest: ingest,
Daniel@0 5636 idMap: idMap,
Daniel@0 5637
Daniel@0 5638 derive: function(d) {
Daniel@0 5639 return ingest(copy(d));
Daniel@0 5640 },
Daniel@0 5641
Daniel@0 5642 rederive: function(d, t) {
Daniel@0 5643 return copy(d, t);
Daniel@0 5644 },
Daniel@0 5645
Daniel@0 5646 set: function(t, k, v) {
Daniel@0 5647 return t[k] === v ? 0 : (t[k] = v, 1);
Daniel@0 5648 },
Daniel@0 5649
Daniel@0 5650 prev: function(t) {
Daniel@0 5651 return t._prev || t;
Daniel@0 5652 },
Daniel@0 5653
Daniel@0 5654 prev_init: function(t) {
Daniel@0 5655 if (!t._prev) { t._prev = {_id: t._id}; }
Daniel@0 5656 },
Daniel@0 5657
Daniel@0 5658 prev_update: function(t) {
Daniel@0 5659 var p = t._prev, k, v;
Daniel@0 5660 if (p) for (k in t) {
Daniel@0 5661 if (k !== '_prev' && k !== '_id') {
Daniel@0 5662 p[k] = ((v=t[k]) instanceof Object && v._prev) ? v._prev : v;
Daniel@0 5663 }
Daniel@0 5664 }
Daniel@0 5665 },
Daniel@0 5666
Daniel@0 5667 reset: function() { tupleID = 0; },
Daniel@0 5668
Daniel@0 5669 idFilter: function(data) {
Daniel@0 5670 var ids = {};
Daniel@0 5671 for (var i=arguments.length; --i>0;) {
Daniel@0 5672 idMap(arguments[i], ids);
Daniel@0 5673 }
Daniel@0 5674 return data.filter(function(x) { return !ids[x._id]; });
Daniel@0 5675 }
Daniel@0 5676 };
Daniel@0 5677
Daniel@0 5678 },{}],39:[function(require,module,exports){
Daniel@0 5679 module.exports = {
Daniel@0 5680 ChangeSet: require('./ChangeSet'),
Daniel@0 5681 Collector: require('./Collector'),
Daniel@0 5682 DataSource: require('./DataSource'),
Daniel@0 5683 Dependencies: require('./Dependencies'),
Daniel@0 5684 Graph: require('./Graph'),
Daniel@0 5685 Node: require('./Node'),
Daniel@0 5686 Signal: require('./Signal'),
Daniel@0 5687 Tuple: require('./Tuple'),
Daniel@0 5688 debug: require('vega-logging').debug
Daniel@0 5689 };
Daniel@0 5690
Daniel@0 5691 },{"./ChangeSet":30,"./Collector":31,"./DataSource":32,"./Dependencies":33,"./Graph":34,"./Node":36,"./Signal":37,"./Tuple":38,"vega-logging":45}],40:[function(require,module,exports){
Daniel@0 5692 function toMap(list) {
Daniel@0 5693 var map = {}, i, n;
Daniel@0 5694 for (i=0, n=list.length; i<n; ++i) map[list[i]] = 1;
Daniel@0 5695 return map;
Daniel@0 5696 }
Daniel@0 5697
Daniel@0 5698 function keys(object) {
Daniel@0 5699 var list = [], k;
Daniel@0 5700 for (k in object) list.push(k);
Daniel@0 5701 return list;
Daniel@0 5702 }
Daniel@0 5703
Daniel@0 5704 module.exports = function(opt) {
Daniel@0 5705 opt = opt || {};
Daniel@0 5706 var constants = opt.constants || require('./constants'),
Daniel@0 5707 functions = (opt.functions || require('./functions'))(codegen),
Daniel@0 5708 idWhiteList = opt.idWhiteList ? toMap(opt.idWhiteList) : null,
Daniel@0 5709 idBlackList = opt.idBlackList ? toMap(opt.idBlackList) : null,
Daniel@0 5710 memberDepth = 0,
Daniel@0 5711 FIELD_VAR = opt.fieldVar || 'datum',
Daniel@0 5712 GLOBAL_VAR = opt.globalVar || 'signals',
Daniel@0 5713 globals = {},
Daniel@0 5714 fields = {};
Daniel@0 5715
Daniel@0 5716 function codegen_wrap(ast) {
Daniel@0 5717 var retval = {
Daniel@0 5718 code: codegen(ast),
Daniel@0 5719 globals: keys(globals),
Daniel@0 5720 fields: keys(fields)
Daniel@0 5721 };
Daniel@0 5722 globals = {};
Daniel@0 5723 fields = {};
Daniel@0 5724 return retval;
Daniel@0 5725 }
Daniel@0 5726
Daniel@0 5727 function lookupGlobal(id) {
Daniel@0 5728 return GLOBAL_VAR + '["' + id + '"]';
Daniel@0 5729 }
Daniel@0 5730
Daniel@0 5731 function codegen(ast) {
Daniel@0 5732 if (typeof ast === 'string') return ast;
Daniel@0 5733 var generator = CODEGEN_TYPES[ast.type];
Daniel@0 5734 if (generator == null) {
Daniel@0 5735 throw new Error('Unsupported type: ' + ast.type);
Daniel@0 5736 }
Daniel@0 5737 return generator(ast);
Daniel@0 5738 }
Daniel@0 5739
Daniel@0 5740 var CODEGEN_TYPES = {
Daniel@0 5741 'Literal': function(n) {
Daniel@0 5742 return n.raw;
Daniel@0 5743 },
Daniel@0 5744 'Identifier': function(n) {
Daniel@0 5745 var id = n.name;
Daniel@0 5746 if (memberDepth > 0) {
Daniel@0 5747 return id;
Daniel@0 5748 }
Daniel@0 5749 if (constants.hasOwnProperty(id)) {
Daniel@0 5750 return constants[id];
Daniel@0 5751 }
Daniel@0 5752 if (idWhiteList) {
Daniel@0 5753 if (idWhiteList.hasOwnProperty(id)) {
Daniel@0 5754 return id;
Daniel@0 5755 } else {
Daniel@0 5756 globals[id] = 1;
Daniel@0 5757 return lookupGlobal(id);
Daniel@0 5758 }
Daniel@0 5759 }
Daniel@0 5760 if (idBlackList && idBlackList.hasOwnProperty(id)) {
Daniel@0 5761 throw new Error('Illegal identifier: ' + id);
Daniel@0 5762 }
Daniel@0 5763 return id;
Daniel@0 5764 },
Daniel@0 5765 'Program': function(n) {
Daniel@0 5766 return n.body.map(codegen).join('\n');
Daniel@0 5767 },
Daniel@0 5768 'MemberExpression': function(n) {
Daniel@0 5769 var d = !n.computed;
Daniel@0 5770 var o = codegen(n.object);
Daniel@0 5771 if (d) memberDepth += 1;
Daniel@0 5772 var p = codegen(n.property);
Daniel@0 5773 if (o === FIELD_VAR) { fields[p] = 1; } // HACKish...
Daniel@0 5774 if (d) memberDepth -= 1;
Daniel@0 5775 return o + (d ? '.'+p : '['+p+']');
Daniel@0 5776 },
Daniel@0 5777 'CallExpression': function(n) {
Daniel@0 5778 if (n.callee.type !== 'Identifier') {
Daniel@0 5779 throw new Error('Illegal callee type: ' + n.callee.type);
Daniel@0 5780 }
Daniel@0 5781 var callee = n.callee.name;
Daniel@0 5782 var args = n.arguments;
Daniel@0 5783 var fn = functions.hasOwnProperty(callee) && functions[callee];
Daniel@0 5784 if (!fn) throw new Error('Unrecognized function: ' + callee);
Daniel@0 5785 return fn instanceof Function ?
Daniel@0 5786 fn(args) :
Daniel@0 5787 fn + '(' + args.map(codegen).join(',') + ')';
Daniel@0 5788 },
Daniel@0 5789 'ArrayExpression': function(n) {
Daniel@0 5790 return '[' + n.elements.map(codegen).join(',') + ']';
Daniel@0 5791 },
Daniel@0 5792 'BinaryExpression': function(n) {
Daniel@0 5793 return '(' + codegen(n.left) + n.operator + codegen(n.right) + ')';
Daniel@0 5794 },
Daniel@0 5795 'UnaryExpression': function(n) {
Daniel@0 5796 return '(' + n.operator + codegen(n.argument) + ')';
Daniel@0 5797 },
Daniel@0 5798 'ConditionalExpression': function(n) {
Daniel@0 5799 return '(' + codegen(n.test) +
Daniel@0 5800 '?' + codegen(n.consequent) +
Daniel@0 5801 ':' + codegen(n.alternate) +
Daniel@0 5802 ')';
Daniel@0 5803 },
Daniel@0 5804 'LogicalExpression': function(n) {
Daniel@0 5805 return '(' + codegen(n.left) + n.operator + codegen(n.right) + ')';
Daniel@0 5806 },
Daniel@0 5807 'ObjectExpression': function(n) {
Daniel@0 5808 return '{' + n.properties.map(codegen).join(',') + '}';
Daniel@0 5809 },
Daniel@0 5810 'Property': function(n) {
Daniel@0 5811 memberDepth += 1;
Daniel@0 5812 var k = codegen(n.key);
Daniel@0 5813 memberDepth -= 1;
Daniel@0 5814 return k + ':' + codegen(n.value);
Daniel@0 5815 },
Daniel@0 5816 'ExpressionStatement': function(n) {
Daniel@0 5817 return codegen(n.expression);
Daniel@0 5818 }
Daniel@0 5819 };
Daniel@0 5820
Daniel@0 5821 codegen_wrap.functions = functions;
Daniel@0 5822 codegen_wrap.constants = constants;
Daniel@0 5823 return codegen_wrap;
Daniel@0 5824 };
Daniel@0 5825
Daniel@0 5826 },{"./constants":41,"./functions":42}],41:[function(require,module,exports){
Daniel@0 5827 module.exports = {
Daniel@0 5828 'NaN': 'NaN',
Daniel@0 5829 'E': 'Math.E',
Daniel@0 5830 'LN2': 'Math.LN2',
Daniel@0 5831 'LN10': 'Math.LN10',
Daniel@0 5832 'LOG2E': 'Math.LOG2E',
Daniel@0 5833 'LOG10E': 'Math.LOG10E',
Daniel@0 5834 'PI': 'Math.PI',
Daniel@0 5835 'SQRT1_2': 'Math.SQRT1_2',
Daniel@0 5836 'SQRT2': 'Math.SQRT2'
Daniel@0 5837 };
Daniel@0 5838 },{}],42:[function(require,module,exports){
Daniel@0 5839 module.exports = function(codegen) {
Daniel@0 5840
Daniel@0 5841 function fncall(name, args, cast, type) {
Daniel@0 5842 var obj = codegen(args[0]);
Daniel@0 5843 if (cast) {
Daniel@0 5844 obj = cast + '(' + obj + ')';
Daniel@0 5845 if (cast.lastIndexOf('new ', 0) === 0) obj = '(' + obj + ')';
Daniel@0 5846 }
Daniel@0 5847 return obj + '.' + name + (type < 0 ? '' : type === 0 ?
Daniel@0 5848 '()' :
Daniel@0 5849 '(' + args.slice(1).map(codegen).join(',') + ')');
Daniel@0 5850 }
Daniel@0 5851
Daniel@0 5852 function fn(name, cast, type) {
Daniel@0 5853 return function(args) {
Daniel@0 5854 return fncall(name, args, cast, type);
Daniel@0 5855 };
Daniel@0 5856 }
Daniel@0 5857
Daniel@0 5858 var DATE = 'new Date',
Daniel@0 5859 STRING = 'String',
Daniel@0 5860 REGEXP = 'RegExp';
Daniel@0 5861
Daniel@0 5862 return {
Daniel@0 5863 // MATH functions
Daniel@0 5864 'isNaN': 'isNaN',
Daniel@0 5865 'isFinite': 'isFinite',
Daniel@0 5866 'abs': 'Math.abs',
Daniel@0 5867 'acos': 'Math.acos',
Daniel@0 5868 'asin': 'Math.asin',
Daniel@0 5869 'atan': 'Math.atan',
Daniel@0 5870 'atan2': 'Math.atan2',
Daniel@0 5871 'ceil': 'Math.ceil',
Daniel@0 5872 'cos': 'Math.cos',
Daniel@0 5873 'exp': 'Math.exp',
Daniel@0 5874 'floor': 'Math.floor',
Daniel@0 5875 'log': 'Math.log',
Daniel@0 5876 'max': 'Math.max',
Daniel@0 5877 'min': 'Math.min',
Daniel@0 5878 'pow': 'Math.pow',
Daniel@0 5879 'random': 'Math.random',
Daniel@0 5880 'round': 'Math.round',
Daniel@0 5881 'sin': 'Math.sin',
Daniel@0 5882 'sqrt': 'Math.sqrt',
Daniel@0 5883 'tan': 'Math.tan',
Daniel@0 5884
Daniel@0 5885 'clamp': function(args) {
Daniel@0 5886 if (args.length < 3)
Daniel@0 5887 throw new Error('Missing arguments to clamp function.');
Daniel@0 5888 if (args.length > 3)
Daniel@0 5889 throw new Error('Too many arguments to clamp function.');
Daniel@0 5890 var a = args.map(codegen);
Daniel@0 5891 return 'Math.max('+a[1]+', Math.min('+a[2]+','+a[0]+'))';
Daniel@0 5892 },
Daniel@0 5893
Daniel@0 5894 // DATE functions
Daniel@0 5895 'now': 'Date.now',
Daniel@0 5896 'datetime': DATE,
Daniel@0 5897 'date': fn('getDate', DATE, 0),
Daniel@0 5898 'day': fn('getDay', DATE, 0),
Daniel@0 5899 'year': fn('getFullYear', DATE, 0),
Daniel@0 5900 'month': fn('getMonth', DATE, 0),
Daniel@0 5901 'hours': fn('getHours', DATE, 0),
Daniel@0 5902 'minutes': fn('getMinutes', DATE, 0),
Daniel@0 5903 'seconds': fn('getSeconds', DATE, 0),
Daniel@0 5904 'milliseconds': fn('getMilliseconds', DATE, 0),
Daniel@0 5905 'time': fn('getTime', DATE, 0),
Daniel@0 5906 'timezoneoffset': fn('getTimezoneOffset', DATE, 0),
Daniel@0 5907 'utcdate': fn('getUTCDate', DATE, 0),
Daniel@0 5908 'utcday': fn('getUTCDay', DATE, 0),
Daniel@0 5909 'utcyear': fn('getUTCFullYear', DATE, 0),
Daniel@0 5910 'utcmonth': fn('getUTCMonth', DATE, 0),
Daniel@0 5911 'utchours': fn('getUTCHours', DATE, 0),
Daniel@0 5912 'utcminutes': fn('getUTCMinutes', DATE, 0),
Daniel@0 5913 'utcseconds': fn('getUTCSeconds', DATE, 0),
Daniel@0 5914 'utcmilliseconds': fn('getUTCMilliseconds', DATE, 0),
Daniel@0 5915
Daniel@0 5916 // shared sequence functions
Daniel@0 5917 'length': fn('length', null, -1),
Daniel@0 5918 'indexof': fn('indexOf', null),
Daniel@0 5919 'lastindexof': fn('lastIndexOf', null),
Daniel@0 5920
Daniel@0 5921 // STRING functions
Daniel@0 5922 'parseFloat': 'parseFloat',
Daniel@0 5923 'parseInt': 'parseInt',
Daniel@0 5924 'upper': fn('toUpperCase', STRING, 0),
Daniel@0 5925 'lower': fn('toLowerCase', STRING, 0),
Daniel@0 5926 'slice': fn('slice', STRING),
Daniel@0 5927 'substring': fn('substring', STRING),
Daniel@0 5928
Daniel@0 5929 // REGEXP functions
Daniel@0 5930 'regexp': REGEXP,
Daniel@0 5931 'test': fn('test', REGEXP),
Daniel@0 5932
Daniel@0 5933 // Control Flow functions
Daniel@0 5934 'if': function(args) {
Daniel@0 5935 if (args.length < 3)
Daniel@0 5936 throw new Error('Missing arguments to if function.');
Daniel@0 5937 if (args.length > 3)
Daniel@0 5938 throw new Error('Too many arguments to if function.');
Daniel@0 5939 var a = args.map(codegen);
Daniel@0 5940 return a[0]+'?'+a[1]+':'+a[2];
Daniel@0 5941 }
Daniel@0 5942 };
Daniel@0 5943 };
Daniel@0 5944 },{}],43:[function(require,module,exports){
Daniel@0 5945 var parser = require('./parser'),
Daniel@0 5946 codegen = require('./codegen');
Daniel@0 5947
Daniel@0 5948 var expr = module.exports = {
Daniel@0 5949 parse: function(input, opt) {
Daniel@0 5950 return parser.parse('('+input+')', opt);
Daniel@0 5951 },
Daniel@0 5952 code: function(opt) {
Daniel@0 5953 return codegen(opt);
Daniel@0 5954 },
Daniel@0 5955 compiler: function(args, opt) {
Daniel@0 5956 args = args.slice();
Daniel@0 5957 var generator = codegen(opt),
Daniel@0 5958 len = args.length,
Daniel@0 5959 compile = function(str) {
Daniel@0 5960 var value = generator(expr.parse(str));
Daniel@0 5961 args[len] = '"use strict"; return (' + value.code + ');';
Daniel@0 5962 value.fn = Function.apply(null, args);
Daniel@0 5963 return value;
Daniel@0 5964 };
Daniel@0 5965 compile.codegen = generator;
Daniel@0 5966 return compile;
Daniel@0 5967 },
Daniel@0 5968 functions: require('./functions'),
Daniel@0 5969 constants: require('./constants')
Daniel@0 5970 };
Daniel@0 5971
Daniel@0 5972 },{"./codegen":40,"./constants":41,"./functions":42,"./parser":44}],44:[function(require,module,exports){
Daniel@0 5973 /*
Daniel@0 5974 The following expression parser is based on Esprima (http://esprima.org/).
Daniel@0 5975 Original header comment and license for Esprima is included here:
Daniel@0 5976
Daniel@0 5977 Copyright (C) 2013 Ariya Hidayat <ariya.hidayat@gmail.com>
Daniel@0 5978 Copyright (C) 2013 Thaddee Tyl <thaddee.tyl@gmail.com>
Daniel@0 5979 Copyright (C) 2013 Mathias Bynens <mathias@qiwi.be>
Daniel@0 5980 Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
Daniel@0 5981 Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be>
Daniel@0 5982 Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
Daniel@0 5983 Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
Daniel@0 5984 Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
Daniel@0 5985 Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
Daniel@0 5986 Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
Daniel@0 5987
Daniel@0 5988 Redistribution and use in source and binary forms, with or without
Daniel@0 5989 modification, are permitted provided that the following conditions are met:
Daniel@0 5990
Daniel@0 5991 * Redistributions of source code must retain the above copyright
Daniel@0 5992 notice, this list of conditions and the following disclaimer.
Daniel@0 5993 * Redistributions in binary form must reproduce the above copyright
Daniel@0 5994 notice, this list of conditions and the following disclaimer in the
Daniel@0 5995 documentation and/or other materials provided with the distribution.
Daniel@0 5996
Daniel@0 5997 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
Daniel@0 5998 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Daniel@0 5999 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Daniel@0 6000 ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
Daniel@0 6001 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
Daniel@0 6002 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
Daniel@0 6003 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
Daniel@0 6004 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Daniel@0 6005 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
Daniel@0 6006 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Daniel@0 6007 */
Daniel@0 6008 /* istanbul ignore next */
Daniel@0 6009 module.exports = (function() {
Daniel@0 6010 'use strict';
Daniel@0 6011
Daniel@0 6012 var Token,
Daniel@0 6013 TokenName,
Daniel@0 6014 Syntax,
Daniel@0 6015 PropertyKind,
Daniel@0 6016 Messages,
Daniel@0 6017 Regex,
Daniel@0 6018 source,
Daniel@0 6019 strict,
Daniel@0 6020 index,
Daniel@0 6021 lineNumber,
Daniel@0 6022 lineStart,
Daniel@0 6023 length,
Daniel@0 6024 lookahead,
Daniel@0 6025 state,
Daniel@0 6026 extra;
Daniel@0 6027
Daniel@0 6028 Token = {
Daniel@0 6029 BooleanLiteral: 1,
Daniel@0 6030 EOF: 2,
Daniel@0 6031 Identifier: 3,
Daniel@0 6032 Keyword: 4,
Daniel@0 6033 NullLiteral: 5,
Daniel@0 6034 NumericLiteral: 6,
Daniel@0 6035 Punctuator: 7,
Daniel@0 6036 StringLiteral: 8,
Daniel@0 6037 RegularExpression: 9
Daniel@0 6038 };
Daniel@0 6039
Daniel@0 6040 TokenName = {};
Daniel@0 6041 TokenName[Token.BooleanLiteral] = 'Boolean';
Daniel@0 6042 TokenName[Token.EOF] = '<end>';
Daniel@0 6043 TokenName[Token.Identifier] = 'Identifier';
Daniel@0 6044 TokenName[Token.Keyword] = 'Keyword';
Daniel@0 6045 TokenName[Token.NullLiteral] = 'Null';
Daniel@0 6046 TokenName[Token.NumericLiteral] = 'Numeric';
Daniel@0 6047 TokenName[Token.Punctuator] = 'Punctuator';
Daniel@0 6048 TokenName[Token.StringLiteral] = 'String';
Daniel@0 6049 TokenName[Token.RegularExpression] = 'RegularExpression';
Daniel@0 6050
Daniel@0 6051 Syntax = {
Daniel@0 6052 AssignmentExpression: 'AssignmentExpression',
Daniel@0 6053 ArrayExpression: 'ArrayExpression',
Daniel@0 6054 BinaryExpression: 'BinaryExpression',
Daniel@0 6055 CallExpression: 'CallExpression',
Daniel@0 6056 ConditionalExpression: 'ConditionalExpression',
Daniel@0 6057 ExpressionStatement: 'ExpressionStatement',
Daniel@0 6058 Identifier: 'Identifier',
Daniel@0 6059 Literal: 'Literal',
Daniel@0 6060 LogicalExpression: 'LogicalExpression',
Daniel@0 6061 MemberExpression: 'MemberExpression',
Daniel@0 6062 ObjectExpression: 'ObjectExpression',
Daniel@0 6063 Program: 'Program',
Daniel@0 6064 Property: 'Property',
Daniel@0 6065 UnaryExpression: 'UnaryExpression'
Daniel@0 6066 };
Daniel@0 6067
Daniel@0 6068 PropertyKind = {
Daniel@0 6069 Data: 1,
Daniel@0 6070 Get: 2,
Daniel@0 6071 Set: 4
Daniel@0 6072 };
Daniel@0 6073
Daniel@0 6074 // Error messages should be identical to V8.
Daniel@0 6075 Messages = {
Daniel@0 6076 UnexpectedToken: 'Unexpected token %0',
Daniel@0 6077 UnexpectedNumber: 'Unexpected number',
Daniel@0 6078 UnexpectedString: 'Unexpected string',
Daniel@0 6079 UnexpectedIdentifier: 'Unexpected identifier',
Daniel@0 6080 UnexpectedReserved: 'Unexpected reserved word',
Daniel@0 6081 UnexpectedEOS: 'Unexpected end of input',
Daniel@0 6082 NewlineAfterThrow: 'Illegal newline after throw',
Daniel@0 6083 InvalidRegExp: 'Invalid regular expression',
Daniel@0 6084 UnterminatedRegExp: 'Invalid regular expression: missing /',
Daniel@0 6085 InvalidLHSInAssignment: 'Invalid left-hand side in assignment',
Daniel@0 6086 InvalidLHSInForIn: 'Invalid left-hand side in for-in',
Daniel@0 6087 MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
Daniel@0 6088 NoCatchOrFinally: 'Missing catch or finally after try',
Daniel@0 6089 UnknownLabel: 'Undefined label \'%0\'',
Daniel@0 6090 Redeclaration: '%0 \'%1\' has already been declared',
Daniel@0 6091 IllegalContinue: 'Illegal continue statement',
Daniel@0 6092 IllegalBreak: 'Illegal break statement',
Daniel@0 6093 IllegalReturn: 'Illegal return statement',
Daniel@0 6094 StrictModeWith: 'Strict mode code may not include a with statement',
Daniel@0 6095 StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
Daniel@0 6096 StrictVarName: 'Variable name may not be eval or arguments in strict mode',
Daniel@0 6097 StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode',
Daniel@0 6098 StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
Daniel@0 6099 StrictFunctionName: 'Function name may not be eval or arguments in strict mode',
Daniel@0 6100 StrictOctalLiteral: 'Octal literals are not allowed in strict mode.',
Daniel@0 6101 StrictDelete: 'Delete of an unqualified identifier in strict mode.',
Daniel@0 6102 StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode',
Daniel@0 6103 AccessorDataProperty: 'Object literal may not have data and accessor property with the same name',
Daniel@0 6104 AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name',
Daniel@0 6105 StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
Daniel@0 6106 StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
Daniel@0 6107 StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
Daniel@0 6108 StrictReservedWord: 'Use of future reserved word in strict mode'
Daniel@0 6109 };
Daniel@0 6110
Daniel@0 6111 // See also tools/generate-unicode-regex.py.
Daniel@0 6112 Regex = {
Daniel@0 6113 NonAsciiIdentifierStart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B2\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]'),
Daniel@0 6114 NonAsciiIdentifierPart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B2\u08E4-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA69D\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2D\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]')
Daniel@0 6115 };
Daniel@0 6116
Daniel@0 6117 // Ensure the condition is true, otherwise throw an error.
Daniel@0 6118 // This is only to have a better contract semantic, i.e. another safety net
Daniel@0 6119 // to catch a logic error. The condition shall be fulfilled in normal case.
Daniel@0 6120 // Do NOT use this to enforce a certain condition on any user input.
Daniel@0 6121
Daniel@0 6122 function assert(condition, message) {
Daniel@0 6123 if (!condition) {
Daniel@0 6124 throw new Error('ASSERT: ' + message);
Daniel@0 6125 }
Daniel@0 6126 }
Daniel@0 6127
Daniel@0 6128 function isDecimalDigit(ch) {
Daniel@0 6129 return (ch >= 0x30 && ch <= 0x39); // 0..9
Daniel@0 6130 }
Daniel@0 6131
Daniel@0 6132 function isHexDigit(ch) {
Daniel@0 6133 return '0123456789abcdefABCDEF'.indexOf(ch) >= 0;
Daniel@0 6134 }
Daniel@0 6135
Daniel@0 6136 function isOctalDigit(ch) {
Daniel@0 6137 return '01234567'.indexOf(ch) >= 0;
Daniel@0 6138 }
Daniel@0 6139
Daniel@0 6140 // 7.2 White Space
Daniel@0 6141
Daniel@0 6142 function isWhiteSpace(ch) {
Daniel@0 6143 return (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) ||
Daniel@0 6144 (ch >= 0x1680 && [0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(ch) >= 0);
Daniel@0 6145 }
Daniel@0 6146
Daniel@0 6147 // 7.3 Line Terminators
Daniel@0 6148
Daniel@0 6149 function isLineTerminator(ch) {
Daniel@0 6150 return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029);
Daniel@0 6151 }
Daniel@0 6152
Daniel@0 6153 // 7.6 Identifier Names and Identifiers
Daniel@0 6154
Daniel@0 6155 function isIdentifierStart(ch) {
Daniel@0 6156 return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore)
Daniel@0 6157 (ch >= 0x41 && ch <= 0x5A) || // A..Z
Daniel@0 6158 (ch >= 0x61 && ch <= 0x7A) || // a..z
Daniel@0 6159 (ch === 0x5C) || // \ (backslash)
Daniel@0 6160 ((ch >= 0x80) && Regex.NonAsciiIdentifierStart.test(String.fromCharCode(ch)));
Daniel@0 6161 }
Daniel@0 6162
Daniel@0 6163 function isIdentifierPart(ch) {
Daniel@0 6164 return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore)
Daniel@0 6165 (ch >= 0x41 && ch <= 0x5A) || // A..Z
Daniel@0 6166 (ch >= 0x61 && ch <= 0x7A) || // a..z
Daniel@0 6167 (ch >= 0x30 && ch <= 0x39) || // 0..9
Daniel@0 6168 (ch === 0x5C) || // \ (backslash)
Daniel@0 6169 ((ch >= 0x80) && Regex.NonAsciiIdentifierPart.test(String.fromCharCode(ch)));
Daniel@0 6170 }
Daniel@0 6171
Daniel@0 6172 // 7.6.1.2 Future Reserved Words
Daniel@0 6173
Daniel@0 6174 function isFutureReservedWord(id) {
Daniel@0 6175 switch (id) {
Daniel@0 6176 case 'class':
Daniel@0 6177 case 'enum':
Daniel@0 6178 case 'export':
Daniel@0 6179 case 'extends':
Daniel@0 6180 case 'import':
Daniel@0 6181 case 'super':
Daniel@0 6182 return true;
Daniel@0 6183 default:
Daniel@0 6184 return false;
Daniel@0 6185 }
Daniel@0 6186 }
Daniel@0 6187
Daniel@0 6188 function isStrictModeReservedWord(id) {
Daniel@0 6189 switch (id) {
Daniel@0 6190 case 'implements':
Daniel@0 6191 case 'interface':
Daniel@0 6192 case 'package':
Daniel@0 6193 case 'private':
Daniel@0 6194 case 'protected':
Daniel@0 6195 case 'public':
Daniel@0 6196 case 'static':
Daniel@0 6197 case 'yield':
Daniel@0 6198 case 'let':
Daniel@0 6199 return true;
Daniel@0 6200 default:
Daniel@0 6201 return false;
Daniel@0 6202 }
Daniel@0 6203 }
Daniel@0 6204
Daniel@0 6205 // 7.6.1.1 Keywords
Daniel@0 6206
Daniel@0 6207 function isKeyword(id) {
Daniel@0 6208 if (strict && isStrictModeReservedWord(id)) {
Daniel@0 6209 return true;
Daniel@0 6210 }
Daniel@0 6211
Daniel@0 6212 // 'const' is specialized as Keyword in V8.
Daniel@0 6213 // 'yield' and 'let' are for compatiblity with SpiderMonkey and ES.next.
Daniel@0 6214 // Some others are from future reserved words.
Daniel@0 6215
Daniel@0 6216 switch (id.length) {
Daniel@0 6217 case 2:
Daniel@0 6218 return (id === 'if') || (id === 'in') || (id === 'do');
Daniel@0 6219 case 3:
Daniel@0 6220 return (id === 'var') || (id === 'for') || (id === 'new') ||
Daniel@0 6221 (id === 'try') || (id === 'let');
Daniel@0 6222 case 4:
Daniel@0 6223 return (id === 'this') || (id === 'else') || (id === 'case') ||
Daniel@0 6224 (id === 'void') || (id === 'with') || (id === 'enum');
Daniel@0 6225 case 5:
Daniel@0 6226 return (id === 'while') || (id === 'break') || (id === 'catch') ||
Daniel@0 6227 (id === 'throw') || (id === 'const') || (id === 'yield') ||
Daniel@0 6228 (id === 'class') || (id === 'super');
Daniel@0 6229 case 6:
Daniel@0 6230 return (id === 'return') || (id === 'typeof') || (id === 'delete') ||
Daniel@0 6231 (id === 'switch') || (id === 'export') || (id === 'import');
Daniel@0 6232 case 7:
Daniel@0 6233 return (id === 'default') || (id === 'finally') || (id === 'extends');
Daniel@0 6234 case 8:
Daniel@0 6235 return (id === 'function') || (id === 'continue') || (id === 'debugger');
Daniel@0 6236 case 10:
Daniel@0 6237 return (id === 'instanceof');
Daniel@0 6238 default:
Daniel@0 6239 return false;
Daniel@0 6240 }
Daniel@0 6241 }
Daniel@0 6242
Daniel@0 6243 function skipComment() {
Daniel@0 6244 var ch, start;
Daniel@0 6245
Daniel@0 6246 start = (index === 0);
Daniel@0 6247 while (index < length) {
Daniel@0 6248 ch = source.charCodeAt(index);
Daniel@0 6249
Daniel@0 6250 if (isWhiteSpace(ch)) {
Daniel@0 6251 ++index;
Daniel@0 6252 } else if (isLineTerminator(ch)) {
Daniel@0 6253 ++index;
Daniel@0 6254 if (ch === 0x0D && source.charCodeAt(index) === 0x0A) {
Daniel@0 6255 ++index;
Daniel@0 6256 }
Daniel@0 6257 ++lineNumber;
Daniel@0 6258 lineStart = index;
Daniel@0 6259 start = true;
Daniel@0 6260 } else {
Daniel@0 6261 break;
Daniel@0 6262 }
Daniel@0 6263 }
Daniel@0 6264 }
Daniel@0 6265
Daniel@0 6266 function scanHexEscape(prefix) {
Daniel@0 6267 var i, len, ch, code = 0;
Daniel@0 6268
Daniel@0 6269 len = (prefix === 'u') ? 4 : 2;
Daniel@0 6270 for (i = 0; i < len; ++i) {
Daniel@0 6271 if (index < length && isHexDigit(source[index])) {
Daniel@0 6272 ch = source[index++];
Daniel@0 6273 code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
Daniel@0 6274 } else {
Daniel@0 6275 return '';
Daniel@0 6276 }
Daniel@0 6277 }
Daniel@0 6278 return String.fromCharCode(code);
Daniel@0 6279 }
Daniel@0 6280
Daniel@0 6281 function scanUnicodeCodePointEscape() {
Daniel@0 6282 var ch, code, cu1, cu2;
Daniel@0 6283
Daniel@0 6284 ch = source[index];
Daniel@0 6285 code = 0;
Daniel@0 6286
Daniel@0 6287 // At least, one hex digit is required.
Daniel@0 6288 if (ch === '}') {
Daniel@0 6289 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
Daniel@0 6290 }
Daniel@0 6291
Daniel@0 6292 while (index < length) {
Daniel@0 6293 ch = source[index++];
Daniel@0 6294 if (!isHexDigit(ch)) {
Daniel@0 6295 break;
Daniel@0 6296 }
Daniel@0 6297 code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
Daniel@0 6298 }
Daniel@0 6299
Daniel@0 6300 if (code > 0x10FFFF || ch !== '}') {
Daniel@0 6301 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
Daniel@0 6302 }
Daniel@0 6303
Daniel@0 6304 // UTF-16 Encoding
Daniel@0 6305 if (code <= 0xFFFF) {
Daniel@0 6306 return String.fromCharCode(code);
Daniel@0 6307 }
Daniel@0 6308 cu1 = ((code - 0x10000) >> 10) + 0xD800;
Daniel@0 6309 cu2 = ((code - 0x10000) & 1023) + 0xDC00;
Daniel@0 6310 return String.fromCharCode(cu1, cu2);
Daniel@0 6311 }
Daniel@0 6312
Daniel@0 6313 function getEscapedIdentifier() {
Daniel@0 6314 var ch, id;
Daniel@0 6315
Daniel@0 6316 ch = source.charCodeAt(index++);
Daniel@0 6317 id = String.fromCharCode(ch);
Daniel@0 6318
Daniel@0 6319 // '\u' (U+005C, U+0075) denotes an escaped character.
Daniel@0 6320 if (ch === 0x5C) {
Daniel@0 6321 if (source.charCodeAt(index) !== 0x75) {
Daniel@0 6322 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
Daniel@0 6323 }
Daniel@0 6324 ++index;
Daniel@0 6325 ch = scanHexEscape('u');
Daniel@0 6326 if (!ch || ch === '\\' || !isIdentifierStart(ch.charCodeAt(0))) {
Daniel@0 6327 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
Daniel@0 6328 }
Daniel@0 6329 id = ch;
Daniel@0 6330 }
Daniel@0 6331
Daniel@0 6332 while (index < length) {
Daniel@0 6333 ch = source.charCodeAt(index);
Daniel@0 6334 if (!isIdentifierPart(ch)) {
Daniel@0 6335 break;
Daniel@0 6336 }
Daniel@0 6337 ++index;
Daniel@0 6338 id += String.fromCharCode(ch);
Daniel@0 6339
Daniel@0 6340 // '\u' (U+005C, U+0075) denotes an escaped character.
Daniel@0 6341 if (ch === 0x5C) {
Daniel@0 6342 id = id.substr(0, id.length - 1);
Daniel@0 6343 if (source.charCodeAt(index) !== 0x75) {
Daniel@0 6344 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
Daniel@0 6345 }
Daniel@0 6346 ++index;
Daniel@0 6347 ch = scanHexEscape('u');
Daniel@0 6348 if (!ch || ch === '\\' || !isIdentifierPart(ch.charCodeAt(0))) {
Daniel@0 6349 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
Daniel@0 6350 }
Daniel@0 6351 id += ch;
Daniel@0 6352 }
Daniel@0 6353 }
Daniel@0 6354
Daniel@0 6355 return id;
Daniel@0 6356 }
Daniel@0 6357
Daniel@0 6358 function getIdentifier() {
Daniel@0 6359 var start, ch;
Daniel@0 6360
Daniel@0 6361 start = index++;
Daniel@0 6362 while (index < length) {
Daniel@0 6363 ch = source.charCodeAt(index);
Daniel@0 6364 if (ch === 0x5C) {
Daniel@0 6365 // Blackslash (U+005C) marks Unicode escape sequence.
Daniel@0 6366 index = start;
Daniel@0 6367 return getEscapedIdentifier();
Daniel@0 6368 }
Daniel@0 6369 if (isIdentifierPart(ch)) {
Daniel@0 6370 ++index;
Daniel@0 6371 } else {
Daniel@0 6372 break;
Daniel@0 6373 }
Daniel@0 6374 }
Daniel@0 6375
Daniel@0 6376 return source.slice(start, index);
Daniel@0 6377 }
Daniel@0 6378
Daniel@0 6379 function scanIdentifier() {
Daniel@0 6380 var start, id, type;
Daniel@0 6381
Daniel@0 6382 start = index;
Daniel@0 6383
Daniel@0 6384 // Backslash (U+005C) starts an escaped character.
Daniel@0 6385 id = (source.charCodeAt(index) === 0x5C) ? getEscapedIdentifier() : getIdentifier();
Daniel@0 6386
Daniel@0 6387 // There is no keyword or literal with only one character.
Daniel@0 6388 // Thus, it must be an identifier.
Daniel@0 6389 if (id.length === 1) {
Daniel@0 6390 type = Token.Identifier;
Daniel@0 6391 } else if (isKeyword(id)) {
Daniel@0 6392 type = Token.Keyword;
Daniel@0 6393 } else if (id === 'null') {
Daniel@0 6394 type = Token.NullLiteral;
Daniel@0 6395 } else if (id === 'true' || id === 'false') {
Daniel@0 6396 type = Token.BooleanLiteral;
Daniel@0 6397 } else {
Daniel@0 6398 type = Token.Identifier;
Daniel@0 6399 }
Daniel@0 6400
Daniel@0 6401 return {
Daniel@0 6402 type: type,
Daniel@0 6403 value: id,
Daniel@0 6404 lineNumber: lineNumber,
Daniel@0 6405 lineStart: lineStart,
Daniel@0 6406 start: start,
Daniel@0 6407 end: index
Daniel@0 6408 };
Daniel@0 6409 }
Daniel@0 6410
Daniel@0 6411 // 7.7 Punctuators
Daniel@0 6412
Daniel@0 6413 function scanPunctuator() {
Daniel@0 6414 var start = index,
Daniel@0 6415 code = source.charCodeAt(index),
Daniel@0 6416 code2,
Daniel@0 6417 ch1 = source[index],
Daniel@0 6418 ch2,
Daniel@0 6419 ch3,
Daniel@0 6420 ch4;
Daniel@0 6421
Daniel@0 6422 switch (code) {
Daniel@0 6423
Daniel@0 6424 // Check for most common single-character punctuators.
Daniel@0 6425 case 0x2E: // . dot
Daniel@0 6426 case 0x28: // ( open bracket
Daniel@0 6427 case 0x29: // ) close bracket
Daniel@0 6428 case 0x3B: // ; semicolon
Daniel@0 6429 case 0x2C: // , comma
Daniel@0 6430 case 0x7B: // { open curly brace
Daniel@0 6431 case 0x7D: // } close curly brace
Daniel@0 6432 case 0x5B: // [
Daniel@0 6433 case 0x5D: // ]
Daniel@0 6434 case 0x3A: // :
Daniel@0 6435 case 0x3F: // ?
Daniel@0 6436 case 0x7E: // ~
Daniel@0 6437 ++index;
Daniel@0 6438 if (extra.tokenize) {
Daniel@0 6439 if (code === 0x28) {
Daniel@0 6440 extra.openParenToken = extra.tokens.length;
Daniel@0 6441 } else if (code === 0x7B) {
Daniel@0 6442 extra.openCurlyToken = extra.tokens.length;
Daniel@0 6443 }
Daniel@0 6444 }
Daniel@0 6445 return {
Daniel@0 6446 type: Token.Punctuator,
Daniel@0 6447 value: String.fromCharCode(code),
Daniel@0 6448 lineNumber: lineNumber,
Daniel@0 6449 lineStart: lineStart,
Daniel@0 6450 start: start,
Daniel@0 6451 end: index
Daniel@0 6452 };
Daniel@0 6453
Daniel@0 6454 default:
Daniel@0 6455 code2 = source.charCodeAt(index + 1);
Daniel@0 6456
Daniel@0 6457 // '=' (U+003D) marks an assignment or comparison operator.
Daniel@0 6458 if (code2 === 0x3D) {
Daniel@0 6459 switch (code) {
Daniel@0 6460 case 0x2B: // +
Daniel@0 6461 case 0x2D: // -
Daniel@0 6462 case 0x2F: // /
Daniel@0 6463 case 0x3C: // <
Daniel@0 6464 case 0x3E: // >
Daniel@0 6465 case 0x5E: // ^
Daniel@0 6466 case 0x7C: // |
Daniel@0 6467 case 0x25: // %
Daniel@0 6468 case 0x26: // &
Daniel@0 6469 case 0x2A: // *
Daniel@0 6470 index += 2;
Daniel@0 6471 return {
Daniel@0 6472 type: Token.Punctuator,
Daniel@0 6473 value: String.fromCharCode(code) + String.fromCharCode(code2),
Daniel@0 6474 lineNumber: lineNumber,
Daniel@0 6475 lineStart: lineStart,
Daniel@0 6476 start: start,
Daniel@0 6477 end: index
Daniel@0 6478 };
Daniel@0 6479
Daniel@0 6480 case 0x21: // !
Daniel@0 6481 case 0x3D: // =
Daniel@0 6482 index += 2;
Daniel@0 6483
Daniel@0 6484 // !== and ===
Daniel@0 6485 if (source.charCodeAt(index) === 0x3D) {
Daniel@0 6486 ++index;
Daniel@0 6487 }
Daniel@0 6488 return {
Daniel@0 6489 type: Token.Punctuator,
Daniel@0 6490 value: source.slice(start, index),
Daniel@0 6491 lineNumber: lineNumber,
Daniel@0 6492 lineStart: lineStart,
Daniel@0 6493 start: start,
Daniel@0 6494 end: index
Daniel@0 6495 };
Daniel@0 6496 }
Daniel@0 6497 }
Daniel@0 6498 }
Daniel@0 6499
Daniel@0 6500 // 4-character punctuator: >>>=
Daniel@0 6501
Daniel@0 6502 ch4 = source.substr(index, 4);
Daniel@0 6503
Daniel@0 6504 if (ch4 === '>>>=') {
Daniel@0 6505 index += 4;
Daniel@0 6506 return {
Daniel@0 6507 type: Token.Punctuator,
Daniel@0 6508 value: ch4,
Daniel@0 6509 lineNumber: lineNumber,
Daniel@0 6510 lineStart: lineStart,
Daniel@0 6511 start: start,
Daniel@0 6512 end: index
Daniel@0 6513 };
Daniel@0 6514 }
Daniel@0 6515
Daniel@0 6516 // 3-character punctuators: === !== >>> <<= >>=
Daniel@0 6517
Daniel@0 6518 ch3 = ch4.substr(0, 3);
Daniel@0 6519
Daniel@0 6520 if (ch3 === '>>>' || ch3 === '<<=' || ch3 === '>>=') {
Daniel@0 6521 index += 3;
Daniel@0 6522 return {
Daniel@0 6523 type: Token.Punctuator,
Daniel@0 6524 value: ch3,
Daniel@0 6525 lineNumber: lineNumber,
Daniel@0 6526 lineStart: lineStart,
Daniel@0 6527 start: start,
Daniel@0 6528 end: index
Daniel@0 6529 };
Daniel@0 6530 }
Daniel@0 6531
Daniel@0 6532 // Other 2-character punctuators: ++ -- << >> && ||
Daniel@0 6533 ch2 = ch3.substr(0, 2);
Daniel@0 6534
Daniel@0 6535 if ((ch1 === ch2[1] && ('+-<>&|'.indexOf(ch1) >= 0)) || ch2 === '=>') {
Daniel@0 6536 index += 2;
Daniel@0 6537 return {
Daniel@0 6538 type: Token.Punctuator,
Daniel@0 6539 value: ch2,
Daniel@0 6540 lineNumber: lineNumber,
Daniel@0 6541 lineStart: lineStart,
Daniel@0 6542 start: start,
Daniel@0 6543 end: index
Daniel@0 6544 };
Daniel@0 6545 }
Daniel@0 6546
Daniel@0 6547 // 1-character punctuators: < > = ! + - * % & | ^ /
Daniel@0 6548
Daniel@0 6549 if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) {
Daniel@0 6550 ++index;
Daniel@0 6551 return {
Daniel@0 6552 type: Token.Punctuator,
Daniel@0 6553 value: ch1,
Daniel@0 6554 lineNumber: lineNumber,
Daniel@0 6555 lineStart: lineStart,
Daniel@0 6556 start: start,
Daniel@0 6557 end: index
Daniel@0 6558 };
Daniel@0 6559 }
Daniel@0 6560
Daniel@0 6561 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
Daniel@0 6562 }
Daniel@0 6563
Daniel@0 6564 // 7.8.3 Numeric Literals
Daniel@0 6565
Daniel@0 6566 function scanHexLiteral(start) {
Daniel@0 6567 var number = '';
Daniel@0 6568
Daniel@0 6569 while (index < length) {
Daniel@0 6570 if (!isHexDigit(source[index])) {
Daniel@0 6571 break;
Daniel@0 6572 }
Daniel@0 6573 number += source[index++];
Daniel@0 6574 }
Daniel@0 6575
Daniel@0 6576 if (number.length === 0) {
Daniel@0 6577 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
Daniel@0 6578 }
Daniel@0 6579
Daniel@0 6580 if (isIdentifierStart(source.charCodeAt(index))) {
Daniel@0 6581 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
Daniel@0 6582 }
Daniel@0 6583
Daniel@0 6584 return {
Daniel@0 6585 type: Token.NumericLiteral,
Daniel@0 6586 value: parseInt('0x' + number, 16),
Daniel@0 6587 lineNumber: lineNumber,
Daniel@0 6588 lineStart: lineStart,
Daniel@0 6589 start: start,
Daniel@0 6590 end: index
Daniel@0 6591 };
Daniel@0 6592 }
Daniel@0 6593
Daniel@0 6594 function scanOctalLiteral(start) {
Daniel@0 6595 var number = '0' + source[index++];
Daniel@0 6596 while (index < length) {
Daniel@0 6597 if (!isOctalDigit(source[index])) {
Daniel@0 6598 break;
Daniel@0 6599 }
Daniel@0 6600 number += source[index++];
Daniel@0 6601 }
Daniel@0 6602
Daniel@0 6603 if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) {
Daniel@0 6604 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
Daniel@0 6605 }
Daniel@0 6606
Daniel@0 6607 return {
Daniel@0 6608 type: Token.NumericLiteral,
Daniel@0 6609 value: parseInt(number, 8),
Daniel@0 6610 octal: true,
Daniel@0 6611 lineNumber: lineNumber,
Daniel@0 6612 lineStart: lineStart,
Daniel@0 6613 start: start,
Daniel@0 6614 end: index
Daniel@0 6615 };
Daniel@0 6616 }
Daniel@0 6617
Daniel@0 6618 function scanNumericLiteral() {
Daniel@0 6619 var number, start, ch;
Daniel@0 6620
Daniel@0 6621 ch = source[index];
Daniel@0 6622 assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'),
Daniel@0 6623 'Numeric literal must start with a decimal digit or a decimal point');
Daniel@0 6624
Daniel@0 6625 start = index;
Daniel@0 6626 number = '';
Daniel@0 6627 if (ch !== '.') {
Daniel@0 6628 number = source[index++];
Daniel@0 6629 ch = source[index];
Daniel@0 6630
Daniel@0 6631 // Hex number starts with '0x'.
Daniel@0 6632 // Octal number starts with '0'.
Daniel@0 6633 if (number === '0') {
Daniel@0 6634 if (ch === 'x' || ch === 'X') {
Daniel@0 6635 ++index;
Daniel@0 6636 return scanHexLiteral(start);
Daniel@0 6637 }
Daniel@0 6638 if (isOctalDigit(ch)) {
Daniel@0 6639 return scanOctalLiteral(start);
Daniel@0 6640 }
Daniel@0 6641
Daniel@0 6642 // decimal number starts with '0' such as '09' is illegal.
Daniel@0 6643 if (ch && isDecimalDigit(ch.charCodeAt(0))) {
Daniel@0 6644 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
Daniel@0 6645 }
Daniel@0 6646 }
Daniel@0 6647
Daniel@0 6648 while (isDecimalDigit(source.charCodeAt(index))) {
Daniel@0 6649 number += source[index++];
Daniel@0 6650 }
Daniel@0 6651 ch = source[index];
Daniel@0 6652 }
Daniel@0 6653
Daniel@0 6654 if (ch === '.') {
Daniel@0 6655 number += source[index++];
Daniel@0 6656 while (isDecimalDigit(source.charCodeAt(index))) {
Daniel@0 6657 number += source[index++];
Daniel@0 6658 }
Daniel@0 6659 ch = source[index];
Daniel@0 6660 }
Daniel@0 6661
Daniel@0 6662 if (ch === 'e' || ch === 'E') {
Daniel@0 6663 number += source[index++];
Daniel@0 6664
Daniel@0 6665 ch = source[index];
Daniel@0 6666 if (ch === '+' || ch === '-') {
Daniel@0 6667 number += source[index++];
Daniel@0 6668 }
Daniel@0 6669 if (isDecimalDigit(source.charCodeAt(index))) {
Daniel@0 6670 while (isDecimalDigit(source.charCodeAt(index))) {
Daniel@0 6671 number += source[index++];
Daniel@0 6672 }
Daniel@0 6673 } else {
Daniel@0 6674 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
Daniel@0 6675 }
Daniel@0 6676 }
Daniel@0 6677
Daniel@0 6678 if (isIdentifierStart(source.charCodeAt(index))) {
Daniel@0 6679 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
Daniel@0 6680 }
Daniel@0 6681
Daniel@0 6682 return {
Daniel@0 6683 type: Token.NumericLiteral,
Daniel@0 6684 value: parseFloat(number),
Daniel@0 6685 lineNumber: lineNumber,
Daniel@0 6686 lineStart: lineStart,
Daniel@0 6687 start: start,
Daniel@0 6688 end: index
Daniel@0 6689 };
Daniel@0 6690 }
Daniel@0 6691
Daniel@0 6692 // 7.8.4 String Literals
Daniel@0 6693
Daniel@0 6694 function scanStringLiteral() {
Daniel@0 6695 var str = '', quote, start, ch, code, unescaped, restore, octal = false, startLineNumber, startLineStart;
Daniel@0 6696 startLineNumber = lineNumber;
Daniel@0 6697 startLineStart = lineStart;
Daniel@0 6698
Daniel@0 6699 quote = source[index];
Daniel@0 6700 assert((quote === '\'' || quote === '"'),
Daniel@0 6701 'String literal must starts with a quote');
Daniel@0 6702
Daniel@0 6703 start = index;
Daniel@0 6704 ++index;
Daniel@0 6705
Daniel@0 6706 while (index < length) {
Daniel@0 6707 ch = source[index++];
Daniel@0 6708
Daniel@0 6709 if (ch === quote) {
Daniel@0 6710 quote = '';
Daniel@0 6711 break;
Daniel@0 6712 } else if (ch === '\\') {
Daniel@0 6713 ch = source[index++];
Daniel@0 6714 if (!ch || !isLineTerminator(ch.charCodeAt(0))) {
Daniel@0 6715 switch (ch) {
Daniel@0 6716 case 'u':
Daniel@0 6717 case 'x':
Daniel@0 6718 if (source[index] === '{') {
Daniel@0 6719 ++index;
Daniel@0 6720 str += scanUnicodeCodePointEscape();
Daniel@0 6721 } else {
Daniel@0 6722 restore = index;
Daniel@0 6723 unescaped = scanHexEscape(ch);
Daniel@0 6724 if (unescaped) {
Daniel@0 6725 str += unescaped;
Daniel@0 6726 } else {
Daniel@0 6727 index = restore;
Daniel@0 6728 str += ch;
Daniel@0 6729 }
Daniel@0 6730 }
Daniel@0 6731 break;
Daniel@0 6732 case 'n':
Daniel@0 6733 str += '\n';
Daniel@0 6734 break;
Daniel@0 6735 case 'r':
Daniel@0 6736 str += '\r';
Daniel@0 6737 break;
Daniel@0 6738 case 't':
Daniel@0 6739 str += '\t';
Daniel@0 6740 break;
Daniel@0 6741 case 'b':
Daniel@0 6742 str += '\b';
Daniel@0 6743 break;
Daniel@0 6744 case 'f':
Daniel@0 6745 str += '\f';
Daniel@0 6746 break;
Daniel@0 6747 case 'v':
Daniel@0 6748 str += '\x0B';
Daniel@0 6749 break;
Daniel@0 6750
Daniel@0 6751 default:
Daniel@0 6752 if (isOctalDigit(ch)) {
Daniel@0 6753 code = '01234567'.indexOf(ch);
Daniel@0 6754
Daniel@0 6755 // \0 is not octal escape sequence
Daniel@0 6756 if (code !== 0) {
Daniel@0 6757 octal = true;
Daniel@0 6758 }
Daniel@0 6759
Daniel@0 6760 if (index < length && isOctalDigit(source[index])) {
Daniel@0 6761 octal = true;
Daniel@0 6762 code = code * 8 + '01234567'.indexOf(source[index++]);
Daniel@0 6763
Daniel@0 6764 // 3 digits are only allowed when string starts
Daniel@0 6765 // with 0, 1, 2, 3
Daniel@0 6766 if ('0123'.indexOf(ch) >= 0 &&
Daniel@0 6767 index < length &&
Daniel@0 6768 isOctalDigit(source[index])) {
Daniel@0 6769 code = code * 8 + '01234567'.indexOf(source[index++]);
Daniel@0 6770 }
Daniel@0 6771 }
Daniel@0 6772 str += String.fromCharCode(code);
Daniel@0 6773 } else {
Daniel@0 6774 str += ch;
Daniel@0 6775 }
Daniel@0 6776 break;
Daniel@0 6777 }
Daniel@0 6778 } else {
Daniel@0 6779 ++lineNumber;
Daniel@0 6780 if (ch === '\r' && source[index] === '\n') {
Daniel@0 6781 ++index;
Daniel@0 6782 }
Daniel@0 6783 lineStart = index;
Daniel@0 6784 }
Daniel@0 6785 } else if (isLineTerminator(ch.charCodeAt(0))) {
Daniel@0 6786 break;
Daniel@0 6787 } else {
Daniel@0 6788 str += ch;
Daniel@0 6789 }
Daniel@0 6790 }
Daniel@0 6791
Daniel@0 6792 if (quote !== '') {
Daniel@0 6793 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
Daniel@0 6794 }
Daniel@0 6795
Daniel@0 6796 return {
Daniel@0 6797 type: Token.StringLiteral,
Daniel@0 6798 value: str,
Daniel@0 6799 octal: octal,
Daniel@0 6800 startLineNumber: startLineNumber,
Daniel@0 6801 startLineStart: startLineStart,
Daniel@0 6802 lineNumber: lineNumber,
Daniel@0 6803 lineStart: lineStart,
Daniel@0 6804 start: start,
Daniel@0 6805 end: index
Daniel@0 6806 };
Daniel@0 6807 }
Daniel@0 6808
Daniel@0 6809 function testRegExp(pattern, flags) {
Daniel@0 6810 var tmp = pattern,
Daniel@0 6811 value;
Daniel@0 6812
Daniel@0 6813 if (flags.indexOf('u') >= 0) {
Daniel@0 6814 // Replace each astral symbol and every Unicode code point
Daniel@0 6815 // escape sequence with a single ASCII symbol to avoid throwing on
Daniel@0 6816 // regular expressions that are only valid in combination with the
Daniel@0 6817 // `/u` flag.
Daniel@0 6818 // Note: replacing with the ASCII symbol `x` might cause false
Daniel@0 6819 // negatives in unlikely scenarios. For example, `[\u{61}-b]` is a
Daniel@0 6820 // perfectly valid pattern that is equivalent to `[a-b]`, but it
Daniel@0 6821 // would be replaced by `[x-b]` which throws an error.
Daniel@0 6822 tmp = tmp
Daniel@0 6823 .replace(/\\u\{([0-9a-fA-F]+)\}/g, function ($0, $1) {
Daniel@0 6824 if (parseInt($1, 16) <= 0x10FFFF) {
Daniel@0 6825 return 'x';
Daniel@0 6826 }
Daniel@0 6827 throwError({}, Messages.InvalidRegExp);
Daniel@0 6828 })
Daniel@0 6829 .replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, 'x');
Daniel@0 6830 }
Daniel@0 6831
Daniel@0 6832 // First, detect invalid regular expressions.
Daniel@0 6833 try {
Daniel@0 6834 value = new RegExp(tmp);
Daniel@0 6835 } catch (e) {
Daniel@0 6836 throwError({}, Messages.InvalidRegExp);
Daniel@0 6837 }
Daniel@0 6838
Daniel@0 6839 // Return a regular expression object for this pattern-flag pair, or
Daniel@0 6840 // `null` in case the current environment doesn't support the flags it
Daniel@0 6841 // uses.
Daniel@0 6842 try {
Daniel@0 6843 return new RegExp(pattern, flags);
Daniel@0 6844 } catch (exception) {
Daniel@0 6845 return null;
Daniel@0 6846 }
Daniel@0 6847 }
Daniel@0 6848
Daniel@0 6849 function scanRegExpBody() {
Daniel@0 6850 var ch, str, classMarker, terminated, body;
Daniel@0 6851
Daniel@0 6852 ch = source[index];
Daniel@0 6853 assert(ch === '/', 'Regular expression literal must start with a slash');
Daniel@0 6854 str = source[index++];
Daniel@0 6855
Daniel@0 6856 classMarker = false;
Daniel@0 6857 terminated = false;
Daniel@0 6858 while (index < length) {
Daniel@0 6859 ch = source[index++];
Daniel@0 6860 str += ch;
Daniel@0 6861 if (ch === '\\') {
Daniel@0 6862 ch = source[index++];
Daniel@0 6863 // ECMA-262 7.8.5
Daniel@0 6864 if (isLineTerminator(ch.charCodeAt(0))) {
Daniel@0 6865 throwError({}, Messages.UnterminatedRegExp);
Daniel@0 6866 }
Daniel@0 6867 str += ch;
Daniel@0 6868 } else if (isLineTerminator(ch.charCodeAt(0))) {
Daniel@0 6869 throwError({}, Messages.UnterminatedRegExp);
Daniel@0 6870 } else if (classMarker) {
Daniel@0 6871 if (ch === ']') {
Daniel@0 6872 classMarker = false;
Daniel@0 6873 }
Daniel@0 6874 } else {
Daniel@0 6875 if (ch === '/') {
Daniel@0 6876 terminated = true;
Daniel@0 6877 break;
Daniel@0 6878 } else if (ch === '[') {
Daniel@0 6879 classMarker = true;
Daniel@0 6880 }
Daniel@0 6881 }
Daniel@0 6882 }
Daniel@0 6883
Daniel@0 6884 if (!terminated) {
Daniel@0 6885 throwError({}, Messages.UnterminatedRegExp);
Daniel@0 6886 }
Daniel@0 6887
Daniel@0 6888 // Exclude leading and trailing slash.
Daniel@0 6889 body = str.substr(1, str.length - 2);
Daniel@0 6890 return {
Daniel@0 6891 value: body,
Daniel@0 6892 literal: str
Daniel@0 6893 };
Daniel@0 6894 }
Daniel@0 6895
Daniel@0 6896 function scanRegExpFlags() {
Daniel@0 6897 var ch, str, flags, restore;
Daniel@0 6898
Daniel@0 6899 str = '';
Daniel@0 6900 flags = '';
Daniel@0 6901 while (index < length) {
Daniel@0 6902 ch = source[index];
Daniel@0 6903 if (!isIdentifierPart(ch.charCodeAt(0))) {
Daniel@0 6904 break;
Daniel@0 6905 }
Daniel@0 6906
Daniel@0 6907 ++index;
Daniel@0 6908 if (ch === '\\' && index < length) {
Daniel@0 6909 ch = source[index];
Daniel@0 6910 if (ch === 'u') {
Daniel@0 6911 ++index;
Daniel@0 6912 restore = index;
Daniel@0 6913 ch = scanHexEscape('u');
Daniel@0 6914 if (ch) {
Daniel@0 6915 flags += ch;
Daniel@0 6916 for (str += '\\u'; restore < index; ++restore) {
Daniel@0 6917 str += source[restore];
Daniel@0 6918 }
Daniel@0 6919 } else {
Daniel@0 6920 index = restore;
Daniel@0 6921 flags += 'u';
Daniel@0 6922 str += '\\u';
Daniel@0 6923 }
Daniel@0 6924 throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL');
Daniel@0 6925 } else {
Daniel@0 6926 str += '\\';
Daniel@0 6927 throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL');
Daniel@0 6928 }
Daniel@0 6929 } else {
Daniel@0 6930 flags += ch;
Daniel@0 6931 str += ch;
Daniel@0 6932 }
Daniel@0 6933 }
Daniel@0 6934
Daniel@0 6935 return {
Daniel@0 6936 value: flags,
Daniel@0 6937 literal: str
Daniel@0 6938 };
Daniel@0 6939 }
Daniel@0 6940
Daniel@0 6941 function scanRegExp() {
Daniel@0 6942 var start, body, flags, value;
Daniel@0 6943
Daniel@0 6944 lookahead = null;
Daniel@0 6945 skipComment();
Daniel@0 6946 start = index;
Daniel@0 6947
Daniel@0 6948 body = scanRegExpBody();
Daniel@0 6949 flags = scanRegExpFlags();
Daniel@0 6950 value = testRegExp(body.value, flags.value);
Daniel@0 6951
Daniel@0 6952 if (extra.tokenize) {
Daniel@0 6953 return {
Daniel@0 6954 type: Token.RegularExpression,
Daniel@0 6955 value: value,
Daniel@0 6956 regex: {
Daniel@0 6957 pattern: body.value,
Daniel@0 6958 flags: flags.value
Daniel@0 6959 },
Daniel@0 6960 lineNumber: lineNumber,
Daniel@0 6961 lineStart: lineStart,
Daniel@0 6962 start: start,
Daniel@0 6963 end: index
Daniel@0 6964 };
Daniel@0 6965 }
Daniel@0 6966
Daniel@0 6967 return {
Daniel@0 6968 literal: body.literal + flags.literal,
Daniel@0 6969 value: value,
Daniel@0 6970 regex: {
Daniel@0 6971 pattern: body.value,
Daniel@0 6972 flags: flags.value
Daniel@0 6973 },
Daniel@0 6974 start: start,
Daniel@0 6975 end: index
Daniel@0 6976 };
Daniel@0 6977 }
Daniel@0 6978
Daniel@0 6979 function collectRegex() {
Daniel@0 6980 var pos, loc, regex, token;
Daniel@0 6981
Daniel@0 6982 skipComment();
Daniel@0 6983
Daniel@0 6984 pos = index;
Daniel@0 6985 loc = {
Daniel@0 6986 start: {
Daniel@0 6987 line: lineNumber,
Daniel@0 6988 column: index - lineStart
Daniel@0 6989 }
Daniel@0 6990 };
Daniel@0 6991
Daniel@0 6992 regex = scanRegExp();
Daniel@0 6993
Daniel@0 6994 loc.end = {
Daniel@0 6995 line: lineNumber,
Daniel@0 6996 column: index - lineStart
Daniel@0 6997 };
Daniel@0 6998
Daniel@0 6999 if (!extra.tokenize) {
Daniel@0 7000 // Pop the previous token, which is likely '/' or '/='
Daniel@0 7001 if (extra.tokens.length > 0) {
Daniel@0 7002 token = extra.tokens[extra.tokens.length - 1];
Daniel@0 7003 if (token.range[0] === pos && token.type === 'Punctuator') {
Daniel@0 7004 if (token.value === '/' || token.value === '/=') {
Daniel@0 7005 extra.tokens.pop();
Daniel@0 7006 }
Daniel@0 7007 }
Daniel@0 7008 }
Daniel@0 7009
Daniel@0 7010 extra.tokens.push({
Daniel@0 7011 type: 'RegularExpression',
Daniel@0 7012 value: regex.literal,
Daniel@0 7013 regex: regex.regex,
Daniel@0 7014 range: [pos, index],
Daniel@0 7015 loc: loc
Daniel@0 7016 });
Daniel@0 7017 }
Daniel@0 7018
Daniel@0 7019 return regex;
Daniel@0 7020 }
Daniel@0 7021
Daniel@0 7022 function isIdentifierName(token) {
Daniel@0 7023 return token.type === Token.Identifier ||
Daniel@0 7024 token.type === Token.Keyword ||
Daniel@0 7025 token.type === Token.BooleanLiteral ||
Daniel@0 7026 token.type === Token.NullLiteral;
Daniel@0 7027 }
Daniel@0 7028
Daniel@0 7029 function advanceSlash() {
Daniel@0 7030 var prevToken,
Daniel@0 7031 checkToken;
Daniel@0 7032 // Using the following algorithm:
Daniel@0 7033 // https://github.com/mozilla/sweet.js/wiki/design
Daniel@0 7034 prevToken = extra.tokens[extra.tokens.length - 1];
Daniel@0 7035 if (!prevToken) {
Daniel@0 7036 // Nothing before that: it cannot be a division.
Daniel@0 7037 return collectRegex();
Daniel@0 7038 }
Daniel@0 7039 if (prevToken.type === 'Punctuator') {
Daniel@0 7040 if (prevToken.value === ']') {
Daniel@0 7041 return scanPunctuator();
Daniel@0 7042 }
Daniel@0 7043 if (prevToken.value === ')') {
Daniel@0 7044 checkToken = extra.tokens[extra.openParenToken - 1];
Daniel@0 7045 if (checkToken &&
Daniel@0 7046 checkToken.type === 'Keyword' &&
Daniel@0 7047 (checkToken.value === 'if' ||
Daniel@0 7048 checkToken.value === 'while' ||
Daniel@0 7049 checkToken.value === 'for' ||
Daniel@0 7050 checkToken.value === 'with')) {
Daniel@0 7051 return collectRegex();
Daniel@0 7052 }
Daniel@0 7053 return scanPunctuator();
Daniel@0 7054 }
Daniel@0 7055 if (prevToken.value === '}') {
Daniel@0 7056 // Dividing a function by anything makes little sense,
Daniel@0 7057 // but we have to check for that.
Daniel@0 7058 if (extra.tokens[extra.openCurlyToken - 3] &&
Daniel@0 7059 extra.tokens[extra.openCurlyToken - 3].type === 'Keyword') {
Daniel@0 7060 // Anonymous function.
Daniel@0 7061 checkToken = extra.tokens[extra.openCurlyToken - 4];
Daniel@0 7062 if (!checkToken) {
Daniel@0 7063 return scanPunctuator();
Daniel@0 7064 }
Daniel@0 7065 } else if (extra.tokens[extra.openCurlyToken - 4] &&
Daniel@0 7066 extra.tokens[extra.openCurlyToken - 4].type === 'Keyword') {
Daniel@0 7067 // Named function.
Daniel@0 7068 checkToken = extra.tokens[extra.openCurlyToken - 5];
Daniel@0 7069 if (!checkToken) {
Daniel@0 7070 return collectRegex();
Daniel@0 7071 }
Daniel@0 7072 } else {
Daniel@0 7073 return scanPunctuator();
Daniel@0 7074 }
Daniel@0 7075 return scanPunctuator();
Daniel@0 7076 }
Daniel@0 7077 return collectRegex();
Daniel@0 7078 }
Daniel@0 7079 if (prevToken.type === 'Keyword' && prevToken.value !== 'this') {
Daniel@0 7080 return collectRegex();
Daniel@0 7081 }
Daniel@0 7082 return scanPunctuator();
Daniel@0 7083 }
Daniel@0 7084
Daniel@0 7085 function advance() {
Daniel@0 7086 var ch;
Daniel@0 7087
Daniel@0 7088 skipComment();
Daniel@0 7089
Daniel@0 7090 if (index >= length) {
Daniel@0 7091 return {
Daniel@0 7092 type: Token.EOF,
Daniel@0 7093 lineNumber: lineNumber,
Daniel@0 7094 lineStart: lineStart,
Daniel@0 7095 start: index,
Daniel@0 7096 end: index
Daniel@0 7097 };
Daniel@0 7098 }
Daniel@0 7099
Daniel@0 7100 ch = source.charCodeAt(index);
Daniel@0 7101
Daniel@0 7102 if (isIdentifierStart(ch)) {
Daniel@0 7103 return scanIdentifier();
Daniel@0 7104 }
Daniel@0 7105
Daniel@0 7106 // Very common: ( and ) and ;
Daniel@0 7107 if (ch === 0x28 || ch === 0x29 || ch === 0x3B) {
Daniel@0 7108 return scanPunctuator();
Daniel@0 7109 }
Daniel@0 7110
Daniel@0 7111 // String literal starts with single quote (U+0027) or double quote (U+0022).
Daniel@0 7112 if (ch === 0x27 || ch === 0x22) {
Daniel@0 7113 return scanStringLiteral();
Daniel@0 7114 }
Daniel@0 7115
Daniel@0 7116
Daniel@0 7117 // Dot (.) U+002E can also start a floating-point number, hence the need
Daniel@0 7118 // to check the next character.
Daniel@0 7119 if (ch === 0x2E) {
Daniel@0 7120 if (isDecimalDigit(source.charCodeAt(index + 1))) {
Daniel@0 7121 return scanNumericLiteral();
Daniel@0 7122 }
Daniel@0 7123 return scanPunctuator();
Daniel@0 7124 }
Daniel@0 7125
Daniel@0 7126 if (isDecimalDigit(ch)) {
Daniel@0 7127 return scanNumericLiteral();
Daniel@0 7128 }
Daniel@0 7129
Daniel@0 7130 // Slash (/) U+002F can also start a regex.
Daniel@0 7131 if (extra.tokenize && ch === 0x2F) {
Daniel@0 7132 return advanceSlash();
Daniel@0 7133 }
Daniel@0 7134
Daniel@0 7135 return scanPunctuator();
Daniel@0 7136 }
Daniel@0 7137
Daniel@0 7138 function collectToken() {
Daniel@0 7139 var loc, token, value, entry;
Daniel@0 7140
Daniel@0 7141 skipComment();
Daniel@0 7142 loc = {
Daniel@0 7143 start: {
Daniel@0 7144 line: lineNumber,
Daniel@0 7145 column: index - lineStart
Daniel@0 7146 }
Daniel@0 7147 };
Daniel@0 7148
Daniel@0 7149 token = advance();
Daniel@0 7150 loc.end = {
Daniel@0 7151 line: lineNumber,
Daniel@0 7152 column: index - lineStart
Daniel@0 7153 };
Daniel@0 7154
Daniel@0 7155 if (token.type !== Token.EOF) {
Daniel@0 7156 value = source.slice(token.start, token.end);
Daniel@0 7157 entry = {
Daniel@0 7158 type: TokenName[token.type],
Daniel@0 7159 value: value,
Daniel@0 7160 range: [token.start, token.end],
Daniel@0 7161 loc: loc
Daniel@0 7162 };
Daniel@0 7163 if (token.regex) {
Daniel@0 7164 entry.regex = {
Daniel@0 7165 pattern: token.regex.pattern,
Daniel@0 7166 flags: token.regex.flags
Daniel@0 7167 };
Daniel@0 7168 }
Daniel@0 7169 extra.tokens.push(entry);
Daniel@0 7170 }
Daniel@0 7171
Daniel@0 7172 return token;
Daniel@0 7173 }
Daniel@0 7174
Daniel@0 7175 function lex() {
Daniel@0 7176 var token;
Daniel@0 7177
Daniel@0 7178 token = lookahead;
Daniel@0 7179 index = token.end;
Daniel@0 7180 lineNumber = token.lineNumber;
Daniel@0 7181 lineStart = token.lineStart;
Daniel@0 7182
Daniel@0 7183 lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
Daniel@0 7184
Daniel@0 7185 index = token.end;
Daniel@0 7186 lineNumber = token.lineNumber;
Daniel@0 7187 lineStart = token.lineStart;
Daniel@0 7188
Daniel@0 7189 return token;
Daniel@0 7190 }
Daniel@0 7191
Daniel@0 7192 function peek() {
Daniel@0 7193 var pos, line, start;
Daniel@0 7194
Daniel@0 7195 pos = index;
Daniel@0 7196 line = lineNumber;
Daniel@0 7197 start = lineStart;
Daniel@0 7198 lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
Daniel@0 7199 index = pos;
Daniel@0 7200 lineNumber = line;
Daniel@0 7201 lineStart = start;
Daniel@0 7202 }
Daniel@0 7203
Daniel@0 7204 function Position() {
Daniel@0 7205 this.line = lineNumber;
Daniel@0 7206 this.column = index - lineStart;
Daniel@0 7207 }
Daniel@0 7208
Daniel@0 7209 function SourceLocation() {
Daniel@0 7210 this.start = new Position();
Daniel@0 7211 this.end = null;
Daniel@0 7212 }
Daniel@0 7213
Daniel@0 7214 function WrappingSourceLocation(startToken) {
Daniel@0 7215 if (startToken.type === Token.StringLiteral) {
Daniel@0 7216 this.start = {
Daniel@0 7217 line: startToken.startLineNumber,
Daniel@0 7218 column: startToken.start - startToken.startLineStart
Daniel@0 7219 };
Daniel@0 7220 } else {
Daniel@0 7221 this.start = {
Daniel@0 7222 line: startToken.lineNumber,
Daniel@0 7223 column: startToken.start - startToken.lineStart
Daniel@0 7224 };
Daniel@0 7225 }
Daniel@0 7226 this.end = null;
Daniel@0 7227 }
Daniel@0 7228
Daniel@0 7229 function Node() {
Daniel@0 7230 // Skip comment.
Daniel@0 7231 index = lookahead.start;
Daniel@0 7232 if (lookahead.type === Token.StringLiteral) {
Daniel@0 7233 lineNumber = lookahead.startLineNumber;
Daniel@0 7234 lineStart = lookahead.startLineStart;
Daniel@0 7235 } else {
Daniel@0 7236 lineNumber = lookahead.lineNumber;
Daniel@0 7237 lineStart = lookahead.lineStart;
Daniel@0 7238 }
Daniel@0 7239 if (extra.range) {
Daniel@0 7240 this.range = [index, 0];
Daniel@0 7241 }
Daniel@0 7242 if (extra.loc) {
Daniel@0 7243 this.loc = new SourceLocation();
Daniel@0 7244 }
Daniel@0 7245 }
Daniel@0 7246
Daniel@0 7247 function WrappingNode(startToken) {
Daniel@0 7248 if (extra.range) {
Daniel@0 7249 this.range = [startToken.start, 0];
Daniel@0 7250 }
Daniel@0 7251 if (extra.loc) {
Daniel@0 7252 this.loc = new WrappingSourceLocation(startToken);
Daniel@0 7253 }
Daniel@0 7254 }
Daniel@0 7255
Daniel@0 7256 WrappingNode.prototype = Node.prototype = {
Daniel@0 7257
Daniel@0 7258 finish: function () {
Daniel@0 7259 if (extra.range) {
Daniel@0 7260 this.range[1] = index;
Daniel@0 7261 }
Daniel@0 7262 if (extra.loc) {
Daniel@0 7263 this.loc.end = new Position();
Daniel@0 7264 if (extra.source) {
Daniel@0 7265 this.loc.source = extra.source;
Daniel@0 7266 }
Daniel@0 7267 }
Daniel@0 7268 },
Daniel@0 7269
Daniel@0 7270 finishArrayExpression: function (elements) {
Daniel@0 7271 this.type = Syntax.ArrayExpression;
Daniel@0 7272 this.elements = elements;
Daniel@0 7273 this.finish();
Daniel@0 7274 return this;
Daniel@0 7275 },
Daniel@0 7276
Daniel@0 7277 finishAssignmentExpression: function (operator, left, right) {
Daniel@0 7278 this.type = Syntax.AssignmentExpression;
Daniel@0 7279 this.operator = operator;
Daniel@0 7280 this.left = left;
Daniel@0 7281 this.right = right;
Daniel@0 7282 this.finish();
Daniel@0 7283 return this;
Daniel@0 7284 },
Daniel@0 7285
Daniel@0 7286 finishBinaryExpression: function (operator, left, right) {
Daniel@0 7287 this.type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression : Syntax.BinaryExpression;
Daniel@0 7288 this.operator = operator;
Daniel@0 7289 this.left = left;
Daniel@0 7290 this.right = right;
Daniel@0 7291 this.finish();
Daniel@0 7292 return this;
Daniel@0 7293 },
Daniel@0 7294
Daniel@0 7295 finishCallExpression: function (callee, args) {
Daniel@0 7296 this.type = Syntax.CallExpression;
Daniel@0 7297 this.callee = callee;
Daniel@0 7298 this.arguments = args;
Daniel@0 7299 this.finish();
Daniel@0 7300 return this;
Daniel@0 7301 },
Daniel@0 7302
Daniel@0 7303 finishConditionalExpression: function (test, consequent, alternate) {
Daniel@0 7304 this.type = Syntax.ConditionalExpression;
Daniel@0 7305 this.test = test;
Daniel@0 7306 this.consequent = consequent;
Daniel@0 7307 this.alternate = alternate;
Daniel@0 7308 this.finish();
Daniel@0 7309 return this;
Daniel@0 7310 },
Daniel@0 7311
Daniel@0 7312 finishExpressionStatement: function (expression) {
Daniel@0 7313 this.type = Syntax.ExpressionStatement;
Daniel@0 7314 this.expression = expression;
Daniel@0 7315 this.finish();
Daniel@0 7316 return this;
Daniel@0 7317 },
Daniel@0 7318
Daniel@0 7319 finishIdentifier: function (name) {
Daniel@0 7320 this.type = Syntax.Identifier;
Daniel@0 7321 this.name = name;
Daniel@0 7322 this.finish();
Daniel@0 7323 return this;
Daniel@0 7324 },
Daniel@0 7325
Daniel@0 7326 finishLiteral: function (token) {
Daniel@0 7327 this.type = Syntax.Literal;
Daniel@0 7328 this.value = token.value;
Daniel@0 7329 this.raw = source.slice(token.start, token.end);
Daniel@0 7330 if (token.regex) {
Daniel@0 7331 if (this.raw == '//') {
Daniel@0 7332 this.raw = '/(?:)/';
Daniel@0 7333 }
Daniel@0 7334 this.regex = token.regex;
Daniel@0 7335 }
Daniel@0 7336 this.finish();
Daniel@0 7337 return this;
Daniel@0 7338 },
Daniel@0 7339
Daniel@0 7340 finishMemberExpression: function (accessor, object, property) {
Daniel@0 7341 this.type = Syntax.MemberExpression;
Daniel@0 7342 this.computed = accessor === '[';
Daniel@0 7343 this.object = object;
Daniel@0 7344 this.property = property;
Daniel@0 7345 this.finish();
Daniel@0 7346 return this;
Daniel@0 7347 },
Daniel@0 7348
Daniel@0 7349 finishObjectExpression: function (properties) {
Daniel@0 7350 this.type = Syntax.ObjectExpression;
Daniel@0 7351 this.properties = properties;
Daniel@0 7352 this.finish();
Daniel@0 7353 return this;
Daniel@0 7354 },
Daniel@0 7355
Daniel@0 7356 finishProgram: function (body) {
Daniel@0 7357 this.type = Syntax.Program;
Daniel@0 7358 this.body = body;
Daniel@0 7359 this.finish();
Daniel@0 7360 return this;
Daniel@0 7361 },
Daniel@0 7362
Daniel@0 7363 finishProperty: function (kind, key, value) {
Daniel@0 7364 this.type = Syntax.Property;
Daniel@0 7365 this.key = key;
Daniel@0 7366 this.value = value;
Daniel@0 7367 this.kind = kind;
Daniel@0 7368 this.finish();
Daniel@0 7369 return this;
Daniel@0 7370 },
Daniel@0 7371
Daniel@0 7372 finishUnaryExpression: function (operator, argument) {
Daniel@0 7373 this.type = Syntax.UnaryExpression;
Daniel@0 7374 this.operator = operator;
Daniel@0 7375 this.argument = argument;
Daniel@0 7376 this.prefix = true;
Daniel@0 7377 this.finish();
Daniel@0 7378 return this;
Daniel@0 7379 }
Daniel@0 7380 };
Daniel@0 7381
Daniel@0 7382 // Return true if there is a line terminator before the next token.
Daniel@0 7383
Daniel@0 7384 function peekLineTerminator() {
Daniel@0 7385 var pos, line, start, found;
Daniel@0 7386
Daniel@0 7387 pos = index;
Daniel@0 7388 line = lineNumber;
Daniel@0 7389 start = lineStart;
Daniel@0 7390 skipComment();
Daniel@0 7391 found = lineNumber !== line;
Daniel@0 7392 index = pos;
Daniel@0 7393 lineNumber = line;
Daniel@0 7394 lineStart = start;
Daniel@0 7395
Daniel@0 7396 return found;
Daniel@0 7397 }
Daniel@0 7398
Daniel@0 7399 // Throw an exception
Daniel@0 7400
Daniel@0 7401 function throwError(token, messageFormat) {
Daniel@0 7402 var error,
Daniel@0 7403 args = Array.prototype.slice.call(arguments, 2),
Daniel@0 7404 msg = messageFormat.replace(
Daniel@0 7405 /%(\d)/g,
Daniel@0 7406 function (whole, index) {
Daniel@0 7407 assert(index < args.length, 'Message reference must be in range');
Daniel@0 7408 return args[index];
Daniel@0 7409 }
Daniel@0 7410 );
Daniel@0 7411
Daniel@0 7412 if (typeof token.lineNumber === 'number') {
Daniel@0 7413 error = new Error('Line ' + token.lineNumber + ': ' + msg);
Daniel@0 7414 error.index = token.start;
Daniel@0 7415 error.lineNumber = token.lineNumber;
Daniel@0 7416 error.column = token.start - lineStart + 1;
Daniel@0 7417 } else {
Daniel@0 7418 error = new Error('Line ' + lineNumber + ': ' + msg);
Daniel@0 7419 error.index = index;
Daniel@0 7420 error.lineNumber = lineNumber;
Daniel@0 7421 error.column = index - lineStart + 1;
Daniel@0 7422 }
Daniel@0 7423
Daniel@0 7424 error.description = msg;
Daniel@0 7425 throw error;
Daniel@0 7426 }
Daniel@0 7427
Daniel@0 7428 function throwErrorTolerant() {
Daniel@0 7429 try {
Daniel@0 7430 throwError.apply(null, arguments);
Daniel@0 7431 } catch (e) {
Daniel@0 7432 if (extra.errors) {
Daniel@0 7433 extra.errors.push(e);
Daniel@0 7434 } else {
Daniel@0 7435 throw e;
Daniel@0 7436 }
Daniel@0 7437 }
Daniel@0 7438 }
Daniel@0 7439
Daniel@0 7440
Daniel@0 7441 // Throw an exception because of the token.
Daniel@0 7442
Daniel@0 7443 function throwUnexpected(token) {
Daniel@0 7444 if (token.type === Token.EOF) {
Daniel@0 7445 throwError(token, Messages.UnexpectedEOS);
Daniel@0 7446 }
Daniel@0 7447
Daniel@0 7448 if (token.type === Token.NumericLiteral) {
Daniel@0 7449 throwError(token, Messages.UnexpectedNumber);
Daniel@0 7450 }
Daniel@0 7451
Daniel@0 7452 if (token.type === Token.StringLiteral) {
Daniel@0 7453 throwError(token, Messages.UnexpectedString);
Daniel@0 7454 }
Daniel@0 7455
Daniel@0 7456 if (token.type === Token.Identifier) {
Daniel@0 7457 throwError(token, Messages.UnexpectedIdentifier);
Daniel@0 7458 }
Daniel@0 7459
Daniel@0 7460 if (token.type === Token.Keyword) {
Daniel@0 7461 if (isFutureReservedWord(token.value)) {
Daniel@0 7462 throwError(token, Messages.UnexpectedReserved);
Daniel@0 7463 } else if (strict && isStrictModeReservedWord(token.value)) {
Daniel@0 7464 throwErrorTolerant(token, Messages.StrictReservedWord);
Daniel@0 7465 return;
Daniel@0 7466 }
Daniel@0 7467 throwError(token, Messages.UnexpectedToken, token.value);
Daniel@0 7468 }
Daniel@0 7469
Daniel@0 7470 // BooleanLiteral, NullLiteral, or Punctuator.
Daniel@0 7471 throwError(token, Messages.UnexpectedToken, token.value);
Daniel@0 7472 }
Daniel@0 7473
Daniel@0 7474 // Expect the next token to match the specified punctuator.
Daniel@0 7475 // If not, an exception will be thrown.
Daniel@0 7476
Daniel@0 7477 function expect(value) {
Daniel@0 7478 var token = lex();
Daniel@0 7479 if (token.type !== Token.Punctuator || token.value !== value) {
Daniel@0 7480 throwUnexpected(token);
Daniel@0 7481 }
Daniel@0 7482 }
Daniel@0 7483
Daniel@0 7484 /**
Daniel@0 7485 * @name expectTolerant
Daniel@0 7486 * @description Quietly expect the given token value when in tolerant mode, otherwise delegates
Daniel@0 7487 * to <code>expect(value)</code>
Daniel@0 7488 * @param {String} value The value we are expecting the lookahead token to have
Daniel@0 7489 * @since 2.0
Daniel@0 7490 */
Daniel@0 7491 function expectTolerant(value) {
Daniel@0 7492 if (extra.errors) {
Daniel@0 7493 var token = lookahead;
Daniel@0 7494 if (token.type !== Token.Punctuator && token.value !== value) {
Daniel@0 7495 throwErrorTolerant(token, Messages.UnexpectedToken, token.value);
Daniel@0 7496 } else {
Daniel@0 7497 lex();
Daniel@0 7498 }
Daniel@0 7499 } else {
Daniel@0 7500 expect(value);
Daniel@0 7501 }
Daniel@0 7502 }
Daniel@0 7503
Daniel@0 7504 // Return true if the next token matches the specified punctuator.
Daniel@0 7505
Daniel@0 7506 function match(value) {
Daniel@0 7507 return lookahead.type === Token.Punctuator && lookahead.value === value;
Daniel@0 7508 }
Daniel@0 7509
Daniel@0 7510 // Return true if the next token matches the specified keyword
Daniel@0 7511
Daniel@0 7512 function matchKeyword(keyword) {
Daniel@0 7513 return lookahead.type === Token.Keyword && lookahead.value === keyword;
Daniel@0 7514 }
Daniel@0 7515
Daniel@0 7516 function consumeSemicolon() {
Daniel@0 7517 var line;
Daniel@0 7518
Daniel@0 7519 // Catch the very common case first: immediately a semicolon (U+003B).
Daniel@0 7520 if (source.charCodeAt(index) === 0x3B || match(';')) {
Daniel@0 7521 lex();
Daniel@0 7522 return;
Daniel@0 7523 }
Daniel@0 7524
Daniel@0 7525 line = lineNumber;
Daniel@0 7526 skipComment();
Daniel@0 7527 if (lineNumber !== line) {
Daniel@0 7528 return;
Daniel@0 7529 }
Daniel@0 7530
Daniel@0 7531 if (lookahead.type !== Token.EOF && !match('}')) {
Daniel@0 7532 throwUnexpected(lookahead);
Daniel@0 7533 }
Daniel@0 7534 }
Daniel@0 7535
Daniel@0 7536 // 11.1.4 Array Initialiser
Daniel@0 7537
Daniel@0 7538 function parseArrayInitialiser() {
Daniel@0 7539 var elements = [], node = new Node();
Daniel@0 7540
Daniel@0 7541 expect('[');
Daniel@0 7542
Daniel@0 7543 while (!match(']')) {
Daniel@0 7544 if (match(',')) {
Daniel@0 7545 lex();
Daniel@0 7546 elements.push(null);
Daniel@0 7547 } else {
Daniel@0 7548 elements.push(parseAssignmentExpression());
Daniel@0 7549
Daniel@0 7550 if (!match(']')) {
Daniel@0 7551 expect(',');
Daniel@0 7552 }
Daniel@0 7553 }
Daniel@0 7554 }
Daniel@0 7555
Daniel@0 7556 lex();
Daniel@0 7557
Daniel@0 7558 return node.finishArrayExpression(elements);
Daniel@0 7559 }
Daniel@0 7560
Daniel@0 7561 // 11.1.5 Object Initialiser
Daniel@0 7562
Daniel@0 7563 function parseObjectPropertyKey() {
Daniel@0 7564 var token, node = new Node();
Daniel@0 7565
Daniel@0 7566 token = lex();
Daniel@0 7567
Daniel@0 7568 // Note: This function is called only from parseObjectProperty(), where
Daniel@0 7569 // EOF and Punctuator tokens are already filtered out.
Daniel@0 7570
Daniel@0 7571 if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) {
Daniel@0 7572 if (strict && token.octal) {
Daniel@0 7573 throwErrorTolerant(token, Messages.StrictOctalLiteral);
Daniel@0 7574 }
Daniel@0 7575 return node.finishLiteral(token);
Daniel@0 7576 }
Daniel@0 7577
Daniel@0 7578 return node.finishIdentifier(token.value);
Daniel@0 7579 }
Daniel@0 7580
Daniel@0 7581 function parseObjectProperty() {
Daniel@0 7582 var token, key, id, value, node = new Node();
Daniel@0 7583
Daniel@0 7584 token = lookahead;
Daniel@0 7585
Daniel@0 7586 if (token.type === Token.Identifier) {
Daniel@0 7587 id = parseObjectPropertyKey();
Daniel@0 7588 expect(':');
Daniel@0 7589 value = parseAssignmentExpression();
Daniel@0 7590 return node.finishProperty('init', id, value);
Daniel@0 7591 }
Daniel@0 7592 if (token.type === Token.EOF || token.type === Token.Punctuator) {
Daniel@0 7593 throwUnexpected(token);
Daniel@0 7594 } else {
Daniel@0 7595 key = parseObjectPropertyKey();
Daniel@0 7596 expect(':');
Daniel@0 7597 value = parseAssignmentExpression();
Daniel@0 7598 return node.finishProperty('init', key, value);
Daniel@0 7599 }
Daniel@0 7600 }
Daniel@0 7601
Daniel@0 7602 function parseObjectInitialiser() {
Daniel@0 7603 var properties = [], property, name, key, kind, map = {}, toString = String, node = new Node();
Daniel@0 7604
Daniel@0 7605 expect('{');
Daniel@0 7606
Daniel@0 7607 while (!match('}')) {
Daniel@0 7608 property = parseObjectProperty();
Daniel@0 7609
Daniel@0 7610 if (property.key.type === Syntax.Identifier) {
Daniel@0 7611 name = property.key.name;
Daniel@0 7612 } else {
Daniel@0 7613 name = toString(property.key.value);
Daniel@0 7614 }
Daniel@0 7615 kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set;
Daniel@0 7616
Daniel@0 7617 key = '$' + name;
Daniel@0 7618 if (Object.prototype.hasOwnProperty.call(map, key)) {
Daniel@0 7619 if (map[key] === PropertyKind.Data) {
Daniel@0 7620 if (strict && kind === PropertyKind.Data) {
Daniel@0 7621 throwErrorTolerant({}, Messages.StrictDuplicateProperty);
Daniel@0 7622 } else if (kind !== PropertyKind.Data) {
Daniel@0 7623 throwErrorTolerant({}, Messages.AccessorDataProperty);
Daniel@0 7624 }
Daniel@0 7625 } else {
Daniel@0 7626 if (kind === PropertyKind.Data) {
Daniel@0 7627 throwErrorTolerant({}, Messages.AccessorDataProperty);
Daniel@0 7628 } else if (map[key] & kind) {
Daniel@0 7629 throwErrorTolerant({}, Messages.AccessorGetSet);
Daniel@0 7630 }
Daniel@0 7631 }
Daniel@0 7632 map[key] |= kind;
Daniel@0 7633 } else {
Daniel@0 7634 map[key] = kind;
Daniel@0 7635 }
Daniel@0 7636
Daniel@0 7637 properties.push(property);
Daniel@0 7638
Daniel@0 7639 if (!match('}')) {
Daniel@0 7640 expectTolerant(',');
Daniel@0 7641 }
Daniel@0 7642 }
Daniel@0 7643
Daniel@0 7644 expect('}');
Daniel@0 7645
Daniel@0 7646 return node.finishObjectExpression(properties);
Daniel@0 7647 }
Daniel@0 7648
Daniel@0 7649 // 11.1.6 The Grouping Operator
Daniel@0 7650
Daniel@0 7651 function parseGroupExpression() {
Daniel@0 7652 var expr;
Daniel@0 7653
Daniel@0 7654 expect('(');
Daniel@0 7655
Daniel@0 7656 ++state.parenthesisCount;
Daniel@0 7657
Daniel@0 7658 expr = parseExpression();
Daniel@0 7659
Daniel@0 7660 expect(')');
Daniel@0 7661
Daniel@0 7662 return expr;
Daniel@0 7663 }
Daniel@0 7664
Daniel@0 7665
Daniel@0 7666 // 11.1 Primary Expressions
Daniel@0 7667
Daniel@0 7668 var legalKeywords = {"if":1, "this":1};
Daniel@0 7669
Daniel@0 7670 function parsePrimaryExpression() {
Daniel@0 7671 var type, token, expr, node;
Daniel@0 7672
Daniel@0 7673 if (match('(')) {
Daniel@0 7674 return parseGroupExpression();
Daniel@0 7675 }
Daniel@0 7676
Daniel@0 7677 if (match('[')) {
Daniel@0 7678 return parseArrayInitialiser();
Daniel@0 7679 }
Daniel@0 7680
Daniel@0 7681 if (match('{')) {
Daniel@0 7682 return parseObjectInitialiser();
Daniel@0 7683 }
Daniel@0 7684
Daniel@0 7685 type = lookahead.type;
Daniel@0 7686 node = new Node();
Daniel@0 7687
Daniel@0 7688 if (type === Token.Identifier || legalKeywords[lookahead.value]) {
Daniel@0 7689 expr = node.finishIdentifier(lex().value);
Daniel@0 7690 } else if (type === Token.StringLiteral || type === Token.NumericLiteral) {
Daniel@0 7691 if (strict && lookahead.octal) {
Daniel@0 7692 throwErrorTolerant(lookahead, Messages.StrictOctalLiteral);
Daniel@0 7693 }
Daniel@0 7694 expr = node.finishLiteral(lex());
Daniel@0 7695 } else if (type === Token.Keyword) {
Daniel@0 7696 throw new Error("Disabled.");
Daniel@0 7697 } else if (type === Token.BooleanLiteral) {
Daniel@0 7698 token = lex();
Daniel@0 7699 token.value = (token.value === 'true');
Daniel@0 7700 expr = node.finishLiteral(token);
Daniel@0 7701 } else if (type === Token.NullLiteral) {
Daniel@0 7702 token = lex();
Daniel@0 7703 token.value = null;
Daniel@0 7704 expr = node.finishLiteral(token);
Daniel@0 7705 } else if (match('/') || match('/=')) {
Daniel@0 7706 if (typeof extra.tokens !== 'undefined') {
Daniel@0 7707 expr = node.finishLiteral(collectRegex());
Daniel@0 7708 } else {
Daniel@0 7709 expr = node.finishLiteral(scanRegExp());
Daniel@0 7710 }
Daniel@0 7711 peek();
Daniel@0 7712 } else {
Daniel@0 7713 throwUnexpected(lex());
Daniel@0 7714 }
Daniel@0 7715
Daniel@0 7716 return expr;
Daniel@0 7717 }
Daniel@0 7718
Daniel@0 7719 // 11.2 Left-Hand-Side Expressions
Daniel@0 7720
Daniel@0 7721 function parseArguments() {
Daniel@0 7722 var args = [];
Daniel@0 7723
Daniel@0 7724 expect('(');
Daniel@0 7725
Daniel@0 7726 if (!match(')')) {
Daniel@0 7727 while (index < length) {
Daniel@0 7728 args.push(parseAssignmentExpression());
Daniel@0 7729 if (match(')')) {
Daniel@0 7730 break;
Daniel@0 7731 }
Daniel@0 7732 expectTolerant(',');
Daniel@0 7733 }
Daniel@0 7734 }
Daniel@0 7735
Daniel@0 7736 expect(')');
Daniel@0 7737
Daniel@0 7738 return args;
Daniel@0 7739 }
Daniel@0 7740
Daniel@0 7741 function parseNonComputedProperty() {
Daniel@0 7742 var token, node = new Node();
Daniel@0 7743
Daniel@0 7744 token = lex();
Daniel@0 7745
Daniel@0 7746 if (!isIdentifierName(token)) {
Daniel@0 7747 throwUnexpected(token);
Daniel@0 7748 }
Daniel@0 7749
Daniel@0 7750 return node.finishIdentifier(token.value);
Daniel@0 7751 }
Daniel@0 7752
Daniel@0 7753 function parseNonComputedMember() {
Daniel@0 7754 expect('.');
Daniel@0 7755
Daniel@0 7756 return parseNonComputedProperty();
Daniel@0 7757 }
Daniel@0 7758
Daniel@0 7759 function parseComputedMember() {
Daniel@0 7760 var expr;
Daniel@0 7761
Daniel@0 7762 expect('[');
Daniel@0 7763
Daniel@0 7764 expr = parseExpression();
Daniel@0 7765
Daniel@0 7766 expect(']');
Daniel@0 7767
Daniel@0 7768 return expr;
Daniel@0 7769 }
Daniel@0 7770
Daniel@0 7771 function parseLeftHandSideExpressionAllowCall() {
Daniel@0 7772 var expr, args, property, startToken, previousAllowIn = state.allowIn;
Daniel@0 7773
Daniel@0 7774 startToken = lookahead;
Daniel@0 7775 state.allowIn = true;
Daniel@0 7776 expr = parsePrimaryExpression();
Daniel@0 7777
Daniel@0 7778 for (;;) {
Daniel@0 7779 if (match('.')) {
Daniel@0 7780 property = parseNonComputedMember();
Daniel@0 7781 expr = new WrappingNode(startToken).finishMemberExpression('.', expr, property);
Daniel@0 7782 } else if (match('(')) {
Daniel@0 7783 args = parseArguments();
Daniel@0 7784 expr = new WrappingNode(startToken).finishCallExpression(expr, args);
Daniel@0 7785 } else if (match('[')) {
Daniel@0 7786 property = parseComputedMember();
Daniel@0 7787 expr = new WrappingNode(startToken).finishMemberExpression('[', expr, property);
Daniel@0 7788 } else {
Daniel@0 7789 break;
Daniel@0 7790 }
Daniel@0 7791 }
Daniel@0 7792 state.allowIn = previousAllowIn;
Daniel@0 7793
Daniel@0 7794 return expr;
Daniel@0 7795 }
Daniel@0 7796
Daniel@0 7797 // 11.3 Postfix Expressions
Daniel@0 7798
Daniel@0 7799 function parsePostfixExpression() {
Daniel@0 7800 var expr = parseLeftHandSideExpressionAllowCall();
Daniel@0 7801
Daniel@0 7802 if (lookahead.type === Token.Punctuator) {
Daniel@0 7803 if ((match('++') || match('--')) && !peekLineTerminator()) {
Daniel@0 7804 throw new Error("Disabled.");
Daniel@0 7805 }
Daniel@0 7806 }
Daniel@0 7807
Daniel@0 7808 return expr;
Daniel@0 7809 }
Daniel@0 7810
Daniel@0 7811 // 11.4 Unary Operators
Daniel@0 7812
Daniel@0 7813 function parseUnaryExpression() {
Daniel@0 7814 var token, expr, startToken;
Daniel@0 7815
Daniel@0 7816 if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) {
Daniel@0 7817 expr = parsePostfixExpression();
Daniel@0 7818 } else if (match('++') || match('--')) {
Daniel@0 7819 throw new Error("Disabled.");
Daniel@0 7820 } else if (match('+') || match('-') || match('~') || match('!')) {
Daniel@0 7821 startToken = lookahead;
Daniel@0 7822 token = lex();
Daniel@0 7823 expr = parseUnaryExpression();
Daniel@0 7824 expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr);
Daniel@0 7825 } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
Daniel@0 7826 throw new Error("Disabled.");
Daniel@0 7827 } else {
Daniel@0 7828 expr = parsePostfixExpression();
Daniel@0 7829 }
Daniel@0 7830
Daniel@0 7831 return expr;
Daniel@0 7832 }
Daniel@0 7833
Daniel@0 7834 function binaryPrecedence(token, allowIn) {
Daniel@0 7835 var prec = 0;
Daniel@0 7836
Daniel@0 7837 if (token.type !== Token.Punctuator && token.type !== Token.Keyword) {
Daniel@0 7838 return 0;
Daniel@0 7839 }
Daniel@0 7840
Daniel@0 7841 switch (token.value) {
Daniel@0 7842 case '||':
Daniel@0 7843 prec = 1;
Daniel@0 7844 break;
Daniel@0 7845
Daniel@0 7846 case '&&':
Daniel@0 7847 prec = 2;
Daniel@0 7848 break;
Daniel@0 7849
Daniel@0 7850 case '|':
Daniel@0 7851 prec = 3;
Daniel@0 7852 break;
Daniel@0 7853
Daniel@0 7854 case '^':
Daniel@0 7855 prec = 4;
Daniel@0 7856 break;
Daniel@0 7857
Daniel@0 7858 case '&':
Daniel@0 7859 prec = 5;
Daniel@0 7860 break;
Daniel@0 7861
Daniel@0 7862 case '==':
Daniel@0 7863 case '!=':
Daniel@0 7864 case '===':
Daniel@0 7865 case '!==':
Daniel@0 7866 prec = 6;
Daniel@0 7867 break;
Daniel@0 7868
Daniel@0 7869 case '<':
Daniel@0 7870 case '>':
Daniel@0 7871 case '<=':
Daniel@0 7872 case '>=':
Daniel@0 7873 case 'instanceof':
Daniel@0 7874 prec = 7;
Daniel@0 7875 break;
Daniel@0 7876
Daniel@0 7877 case 'in':
Daniel@0 7878 prec = allowIn ? 7 : 0;
Daniel@0 7879 break;
Daniel@0 7880
Daniel@0 7881 case '<<':
Daniel@0 7882 case '>>':
Daniel@0 7883 case '>>>':
Daniel@0 7884 prec = 8;
Daniel@0 7885 break;
Daniel@0 7886
Daniel@0 7887 case '+':
Daniel@0 7888 case '-':
Daniel@0 7889 prec = 9;
Daniel@0 7890 break;
Daniel@0 7891
Daniel@0 7892 case '*':
Daniel@0 7893 case '/':
Daniel@0 7894 case '%':
Daniel@0 7895 prec = 11;
Daniel@0 7896 break;
Daniel@0 7897
Daniel@0 7898 default:
Daniel@0 7899 break;
Daniel@0 7900 }
Daniel@0 7901
Daniel@0 7902 return prec;
Daniel@0 7903 }
Daniel@0 7904
Daniel@0 7905 // 11.5 Multiplicative Operators
Daniel@0 7906 // 11.6 Additive Operators
Daniel@0 7907 // 11.7 Bitwise Shift Operators
Daniel@0 7908 // 11.8 Relational Operators
Daniel@0 7909 // 11.9 Equality Operators
Daniel@0 7910 // 11.10 Binary Bitwise Operators
Daniel@0 7911 // 11.11 Binary Logical Operators
Daniel@0 7912
Daniel@0 7913 function parseBinaryExpression() {
Daniel@0 7914 var marker, markers, expr, token, prec, stack, right, operator, left, i;
Daniel@0 7915
Daniel@0 7916 marker = lookahead;
Daniel@0 7917 left = parseUnaryExpression();
Daniel@0 7918
Daniel@0 7919 token = lookahead;
Daniel@0 7920 prec = binaryPrecedence(token, state.allowIn);
Daniel@0 7921 if (prec === 0) {
Daniel@0 7922 return left;
Daniel@0 7923 }
Daniel@0 7924 token.prec = prec;
Daniel@0 7925 lex();
Daniel@0 7926
Daniel@0 7927 markers = [marker, lookahead];
Daniel@0 7928 right = parseUnaryExpression();
Daniel@0 7929
Daniel@0 7930 stack = [left, token, right];
Daniel@0 7931
Daniel@0 7932 while ((prec = binaryPrecedence(lookahead, state.allowIn)) > 0) {
Daniel@0 7933
Daniel@0 7934 // Reduce: make a binary expression from the three topmost entries.
Daniel@0 7935 while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) {
Daniel@0 7936 right = stack.pop();
Daniel@0 7937 operator = stack.pop().value;
Daniel@0 7938 left = stack.pop();
Daniel@0 7939 markers.pop();
Daniel@0 7940 expr = new WrappingNode(markers[markers.length - 1]).finishBinaryExpression(operator, left, right);
Daniel@0 7941 stack.push(expr);
Daniel@0 7942 }
Daniel@0 7943
Daniel@0 7944 // Shift.
Daniel@0 7945 token = lex();
Daniel@0 7946 token.prec = prec;
Daniel@0 7947 stack.push(token);
Daniel@0 7948 markers.push(lookahead);
Daniel@0 7949 expr = parseUnaryExpression();
Daniel@0 7950 stack.push(expr);
Daniel@0 7951 }
Daniel@0 7952
Daniel@0 7953 // Final reduce to clean-up the stack.
Daniel@0 7954 i = stack.length - 1;
Daniel@0 7955 expr = stack[i];
Daniel@0 7956 markers.pop();
Daniel@0 7957 while (i > 1) {
Daniel@0 7958 expr = new WrappingNode(markers.pop()).finishBinaryExpression(stack[i - 1].value, stack[i - 2], expr);
Daniel@0 7959 i -= 2;
Daniel@0 7960 }
Daniel@0 7961
Daniel@0 7962 return expr;
Daniel@0 7963 }
Daniel@0 7964
Daniel@0 7965 // 11.12 Conditional Operator
Daniel@0 7966
Daniel@0 7967 function parseConditionalExpression() {
Daniel@0 7968 var expr, previousAllowIn, consequent, alternate, startToken;
Daniel@0 7969
Daniel@0 7970 startToken = lookahead;
Daniel@0 7971
Daniel@0 7972 expr = parseBinaryExpression();
Daniel@0 7973
Daniel@0 7974 if (match('?')) {
Daniel@0 7975 lex();
Daniel@0 7976 previousAllowIn = state.allowIn;
Daniel@0 7977 state.allowIn = true;
Daniel@0 7978 consequent = parseAssignmentExpression();
Daniel@0 7979 state.allowIn = previousAllowIn;
Daniel@0 7980 expect(':');
Daniel@0 7981 alternate = parseAssignmentExpression();
Daniel@0 7982
Daniel@0 7983 expr = new WrappingNode(startToken).finishConditionalExpression(expr, consequent, alternate);
Daniel@0 7984 }
Daniel@0 7985
Daniel@0 7986 return expr;
Daniel@0 7987 }
Daniel@0 7988
Daniel@0 7989 // 11.13 Assignment Operators
Daniel@0 7990
Daniel@0 7991 function parseAssignmentExpression() {
Daniel@0 7992 var oldParenthesisCount, token, expr, startToken;
Daniel@0 7993
Daniel@0 7994 oldParenthesisCount = state.parenthesisCount;
Daniel@0 7995
Daniel@0 7996 startToken = lookahead;
Daniel@0 7997 token = lookahead;
Daniel@0 7998
Daniel@0 7999 expr = parseConditionalExpression();
Daniel@0 8000
Daniel@0 8001 return expr;
Daniel@0 8002 }
Daniel@0 8003
Daniel@0 8004 // 11.14 Comma Operator
Daniel@0 8005
Daniel@0 8006 function parseExpression() {
Daniel@0 8007 var expr = parseAssignmentExpression();
Daniel@0 8008
Daniel@0 8009 if (match(',')) {
Daniel@0 8010 throw new Error("Disabled."); // no sequence expressions
Daniel@0 8011 }
Daniel@0 8012
Daniel@0 8013 return expr;
Daniel@0 8014 }
Daniel@0 8015
Daniel@0 8016 // 12.4 Expression Statement
Daniel@0 8017
Daniel@0 8018 function parseExpressionStatement(node) {
Daniel@0 8019 var expr = parseExpression();
Daniel@0 8020 consumeSemicolon();
Daniel@0 8021 return node.finishExpressionStatement(expr);
Daniel@0 8022 }
Daniel@0 8023
Daniel@0 8024 // 12 Statements
Daniel@0 8025
Daniel@0 8026 function parseStatement() {
Daniel@0 8027 var type = lookahead.type,
Daniel@0 8028 expr,
Daniel@0 8029 node;
Daniel@0 8030
Daniel@0 8031 if (type === Token.EOF) {
Daniel@0 8032 throwUnexpected(lookahead);
Daniel@0 8033 }
Daniel@0 8034
Daniel@0 8035 if (type === Token.Punctuator && lookahead.value === '{') {
Daniel@0 8036 throw new Error("Disabled."); // block statement
Daniel@0 8037 }
Daniel@0 8038
Daniel@0 8039 node = new Node();
Daniel@0 8040
Daniel@0 8041 if (type === Token.Punctuator) {
Daniel@0 8042 switch (lookahead.value) {
Daniel@0 8043 case ';':
Daniel@0 8044 throw new Error("Disabled."); // empty statement
Daniel@0 8045 case '(':
Daniel@0 8046 return parseExpressionStatement(node);
Daniel@0 8047 default:
Daniel@0 8048 break;
Daniel@0 8049 }
Daniel@0 8050 } else if (type === Token.Keyword) {
Daniel@0 8051 throw new Error("Disabled."); // keyword
Daniel@0 8052 }
Daniel@0 8053
Daniel@0 8054 expr = parseExpression();
Daniel@0 8055 consumeSemicolon();
Daniel@0 8056 return node.finishExpressionStatement(expr);
Daniel@0 8057 }
Daniel@0 8058
Daniel@0 8059 // 14 Program
Daniel@0 8060
Daniel@0 8061 function parseSourceElement() {
Daniel@0 8062 if (lookahead.type === Token.Keyword) {
Daniel@0 8063 switch (lookahead.value) {
Daniel@0 8064 case 'const':
Daniel@0 8065 case 'let':
Daniel@0 8066 throw new Error("Disabled.");
Daniel@0 8067 case 'function':
Daniel@0 8068 throw new Error("Disabled.");
Daniel@0 8069 default:
Daniel@0 8070 return parseStatement();
Daniel@0 8071 }
Daniel@0 8072 }
Daniel@0 8073
Daniel@0 8074 if (lookahead.type !== Token.EOF) {
Daniel@0 8075 return parseStatement();
Daniel@0 8076 }
Daniel@0 8077 }
Daniel@0 8078
Daniel@0 8079 function parseSourceElements() {
Daniel@0 8080 var sourceElement, sourceElements = [], token, directive, firstRestricted;
Daniel@0 8081
Daniel@0 8082 while (index < length) {
Daniel@0 8083 token = lookahead;
Daniel@0 8084 if (token.type !== Token.StringLiteral) {
Daniel@0 8085 break;
Daniel@0 8086 }
Daniel@0 8087
Daniel@0 8088 sourceElement = parseSourceElement();
Daniel@0 8089 sourceElements.push(sourceElement);
Daniel@0 8090 if (sourceElement.expression.type !== Syntax.Literal) {
Daniel@0 8091 // this is not directive
Daniel@0 8092 break;
Daniel@0 8093 }
Daniel@0 8094 directive = source.slice(token.start + 1, token.end - 1);
Daniel@0 8095 if (directive === 'use strict') {
Daniel@0 8096 strict = true;
Daniel@0 8097 if (firstRestricted) {
Daniel@0 8098 throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral);
Daniel@0 8099 }
Daniel@0 8100 } else {
Daniel@0 8101 if (!firstRestricted && token.octal) {
Daniel@0 8102 firstRestricted = token;
Daniel@0 8103 }
Daniel@0 8104 }
Daniel@0 8105 }
Daniel@0 8106
Daniel@0 8107 while (index < length) {
Daniel@0 8108 sourceElement = parseSourceElement();
Daniel@0 8109 if (typeof sourceElement === 'undefined') {
Daniel@0 8110 break;
Daniel@0 8111 }
Daniel@0 8112 sourceElements.push(sourceElement);
Daniel@0 8113 }
Daniel@0 8114 return sourceElements;
Daniel@0 8115 }
Daniel@0 8116
Daniel@0 8117 function parseProgram() {
Daniel@0 8118 var body, node;
Daniel@0 8119
Daniel@0 8120 skipComment();
Daniel@0 8121 peek();
Daniel@0 8122 node = new Node();
Daniel@0 8123 strict = true; // assume strict
Daniel@0 8124
Daniel@0 8125 body = parseSourceElements();
Daniel@0 8126 return node.finishProgram(body);
Daniel@0 8127 }
Daniel@0 8128
Daniel@0 8129 function filterTokenLocation() {
Daniel@0 8130 var i, entry, token, tokens = [];
Daniel@0 8131
Daniel@0 8132 for (i = 0; i < extra.tokens.length; ++i) {
Daniel@0 8133 entry = extra.tokens[i];
Daniel@0 8134 token = {
Daniel@0 8135 type: entry.type,
Daniel@0 8136 value: entry.value
Daniel@0 8137 };
Daniel@0 8138 if (entry.regex) {
Daniel@0 8139 token.regex = {
Daniel@0 8140 pattern: entry.regex.pattern,
Daniel@0 8141 flags: entry.regex.flags
Daniel@0 8142 };
Daniel@0 8143 }
Daniel@0 8144 if (extra.range) {
Daniel@0 8145 token.range = entry.range;
Daniel@0 8146 }
Daniel@0 8147 if (extra.loc) {
Daniel@0 8148 token.loc = entry.loc;
Daniel@0 8149 }
Daniel@0 8150 tokens.push(token);
Daniel@0 8151 }
Daniel@0 8152
Daniel@0 8153 extra.tokens = tokens;
Daniel@0 8154 }
Daniel@0 8155
Daniel@0 8156 function tokenize(code, options) {
Daniel@0 8157 var toString,
Daniel@0 8158 tokens;
Daniel@0 8159
Daniel@0 8160 toString = String;
Daniel@0 8161 if (typeof code !== 'string' && !(code instanceof String)) {
Daniel@0 8162 code = toString(code);
Daniel@0 8163 }
Daniel@0 8164
Daniel@0 8165 source = code;
Daniel@0 8166 index = 0;
Daniel@0 8167 lineNumber = (source.length > 0) ? 1 : 0;
Daniel@0 8168 lineStart = 0;
Daniel@0 8169 length = source.length;
Daniel@0 8170 lookahead = null;
Daniel@0 8171 state = {
Daniel@0 8172 allowIn: true,
Daniel@0 8173 labelSet: {},
Daniel@0 8174 inFunctionBody: false,
Daniel@0 8175 inIteration: false,
Daniel@0 8176 inSwitch: false,
Daniel@0 8177 lastCommentStart: -1
Daniel@0 8178 };
Daniel@0 8179
Daniel@0 8180 extra = {};
Daniel@0 8181
Daniel@0 8182 // Options matching.
Daniel@0 8183 options = options || {};
Daniel@0 8184
Daniel@0 8185 // Of course we collect tokens here.
Daniel@0 8186 options.tokens = true;
Daniel@0 8187 extra.tokens = [];
Daniel@0 8188 extra.tokenize = true;
Daniel@0 8189 // The following two fields are necessary to compute the Regex tokens.
Daniel@0 8190 extra.openParenToken = -1;
Daniel@0 8191 extra.openCurlyToken = -1;
Daniel@0 8192
Daniel@0 8193 extra.range = (typeof options.range === 'boolean') && options.range;
Daniel@0 8194 extra.loc = (typeof options.loc === 'boolean') && options.loc;
Daniel@0 8195
Daniel@0 8196 if (typeof options.tolerant === 'boolean' && options.tolerant) {
Daniel@0 8197 extra.errors = [];
Daniel@0 8198 }
Daniel@0 8199
Daniel@0 8200 try {
Daniel@0 8201 peek();
Daniel@0 8202 if (lookahead.type === Token.EOF) {
Daniel@0 8203 return extra.tokens;
Daniel@0 8204 }
Daniel@0 8205
Daniel@0 8206 lex();
Daniel@0 8207 while (lookahead.type !== Token.EOF) {
Daniel@0 8208 try {
Daniel@0 8209 lex();
Daniel@0 8210 } catch (lexError) {
Daniel@0 8211 if (extra.errors) {
Daniel@0 8212 extra.errors.push(lexError);
Daniel@0 8213 // We have to break on the first error
Daniel@0 8214 // to avoid infinite loops.
Daniel@0 8215 break;
Daniel@0 8216 } else {
Daniel@0 8217 throw lexError;
Daniel@0 8218 }
Daniel@0 8219 }
Daniel@0 8220 }
Daniel@0 8221
Daniel@0 8222 filterTokenLocation();
Daniel@0 8223 tokens = extra.tokens;
Daniel@0 8224 if (typeof extra.errors !== 'undefined') {
Daniel@0 8225 tokens.errors = extra.errors;
Daniel@0 8226 }
Daniel@0 8227 } catch (e) {
Daniel@0 8228 throw e;
Daniel@0 8229 } finally {
Daniel@0 8230 extra = {};
Daniel@0 8231 }
Daniel@0 8232 return tokens;
Daniel@0 8233 }
Daniel@0 8234
Daniel@0 8235 function parse(code, options) {
Daniel@0 8236 var program, toString;
Daniel@0 8237
Daniel@0 8238 toString = String;
Daniel@0 8239 if (typeof code !== 'string' && !(code instanceof String)) {
Daniel@0 8240 code = toString(code);
Daniel@0 8241 }
Daniel@0 8242
Daniel@0 8243 source = code;
Daniel@0 8244 index = 0;
Daniel@0 8245 lineNumber = (source.length > 0) ? 1 : 0;
Daniel@0 8246 lineStart = 0;
Daniel@0 8247 length = source.length;
Daniel@0 8248 lookahead = null;
Daniel@0 8249 state = {
Daniel@0 8250 allowIn: true,
Daniel@0 8251 labelSet: {},
Daniel@0 8252 parenthesisCount: 0,
Daniel@0 8253 inFunctionBody: false,
Daniel@0 8254 inIteration: false,
Daniel@0 8255 inSwitch: false,
Daniel@0 8256 lastCommentStart: -1
Daniel@0 8257 };
Daniel@0 8258
Daniel@0 8259 extra = {};
Daniel@0 8260 if (typeof options !== 'undefined') {
Daniel@0 8261 extra.range = (typeof options.range === 'boolean') && options.range;
Daniel@0 8262 extra.loc = (typeof options.loc === 'boolean') && options.loc;
Daniel@0 8263
Daniel@0 8264 if (extra.loc && options.source !== null && options.source !== undefined) {
Daniel@0 8265 extra.source = toString(options.source);
Daniel@0 8266 }
Daniel@0 8267
Daniel@0 8268 if (typeof options.tokens === 'boolean' && options.tokens) {
Daniel@0 8269 extra.tokens = [];
Daniel@0 8270 }
Daniel@0 8271 if (typeof options.tolerant === 'boolean' && options.tolerant) {
Daniel@0 8272 extra.errors = [];
Daniel@0 8273 }
Daniel@0 8274 }
Daniel@0 8275
Daniel@0 8276 try {
Daniel@0 8277 program = parseProgram();
Daniel@0 8278 if (typeof extra.tokens !== 'undefined') {
Daniel@0 8279 filterTokenLocation();
Daniel@0 8280 program.tokens = extra.tokens;
Daniel@0 8281 }
Daniel@0 8282 if (typeof extra.errors !== 'undefined') {
Daniel@0 8283 program.errors = extra.errors;
Daniel@0 8284 }
Daniel@0 8285 } catch (e) {
Daniel@0 8286 throw e;
Daniel@0 8287 } finally {
Daniel@0 8288 extra = {};
Daniel@0 8289 }
Daniel@0 8290
Daniel@0 8291 return program;
Daniel@0 8292 }
Daniel@0 8293
Daniel@0 8294 return {
Daniel@0 8295 tokenize: tokenize,
Daniel@0 8296 parse: parse
Daniel@0 8297 };
Daniel@0 8298
Daniel@0 8299 })();
Daniel@0 8300 },{}],45:[function(require,module,exports){
Daniel@0 8301 var ts = Date.now();
Daniel@0 8302
Daniel@0 8303 function write(msg) {
Daniel@0 8304 msg = '[Vega Log] ' + msg;
Daniel@0 8305 console.log(msg);
Daniel@0 8306 }
Daniel@0 8307
Daniel@0 8308 function error(msg) {
Daniel@0 8309 msg = '[Vega Err] ' + msg;
Daniel@0 8310 console.error(msg);
Daniel@0 8311 }
Daniel@0 8312
Daniel@0 8313 function debug(input, args) {
Daniel@0 8314 if (!debug.enable) return;
Daniel@0 8315 var log = Function.prototype.bind.call(console.log, console);
Daniel@0 8316 var state = {
Daniel@0 8317 prevTime: Date.now() - ts,
Daniel@0 8318 stamp: input.stamp
Daniel@0 8319 };
Daniel@0 8320
Daniel@0 8321 if (input.add) {
Daniel@0 8322 state.add = input.add.length;
Daniel@0 8323 state.mod = input.mod.length;
Daniel@0 8324 state.rem = input.rem.length;
Daniel@0 8325 state.reflow = !!input.reflow;
Daniel@0 8326 }
Daniel@0 8327
Daniel@0 8328 log.apply(console, (args.push(JSON.stringify(state)), args));
Daniel@0 8329 ts = Date.now();
Daniel@0 8330 }
Daniel@0 8331
Daniel@0 8332 module.exports = {
Daniel@0 8333 log: write,
Daniel@0 8334 error: error,
Daniel@0 8335 debug: (debug.enable = false, debug)
Daniel@0 8336 };
Daniel@0 8337
Daniel@0 8338 },{}],46:[function(require,module,exports){
Daniel@0 8339 module.exports = {
Daniel@0 8340 path: require('./path'),
Daniel@0 8341 render: require('./render'),
Daniel@0 8342 Item: require('./util/Item'),
Daniel@0 8343 bound: require('./util/bound'),
Daniel@0 8344 Bounds: require('./util/Bounds'),
Daniel@0 8345 Gradient: require('./util/Gradient'),
Daniel@0 8346 toJSON: require('./util/scene').toJSON,
Daniel@0 8347 fromJSON: require('./util/scene').fromJSON
Daniel@0 8348 };
Daniel@0 8349 },{"./path":48,"./render":68,"./util/Bounds":74,"./util/Gradient":76,"./util/Item":78,"./util/bound":79,"./util/scene":82}],47:[function(require,module,exports){
Daniel@0 8350 var segmentCache = {},
Daniel@0 8351 bezierCache = {},
Daniel@0 8352 join = [].join;
Daniel@0 8353
Daniel@0 8354 // Copied from Inkscape svgtopdf, thanks!
Daniel@0 8355 function segments(x, y, rx, ry, large, sweep, rotateX, ox, oy) {
Daniel@0 8356 var key = join.call(arguments);
Daniel@0 8357 if (segmentCache[key]) {
Daniel@0 8358 return segmentCache[key];
Daniel@0 8359 }
Daniel@0 8360
Daniel@0 8361 var th = rotateX * (Math.PI/180);
Daniel@0 8362 var sin_th = Math.sin(th);
Daniel@0 8363 var cos_th = Math.cos(th);
Daniel@0 8364 rx = Math.abs(rx);
Daniel@0 8365 ry = Math.abs(ry);
Daniel@0 8366 var px = cos_th * (ox - x) * 0.5 + sin_th * (oy - y) * 0.5;
Daniel@0 8367 var py = cos_th * (oy - y) * 0.5 - sin_th * (ox - x) * 0.5;
Daniel@0 8368 var pl = (px*px) / (rx*rx) + (py*py) / (ry*ry);
Daniel@0 8369 if (pl > 1) {
Daniel@0 8370 pl = Math.sqrt(pl);
Daniel@0 8371 rx *= pl;
Daniel@0 8372 ry *= pl;
Daniel@0 8373 }
Daniel@0 8374
Daniel@0 8375 var a00 = cos_th / rx;
Daniel@0 8376 var a01 = sin_th / rx;
Daniel@0 8377 var a10 = (-sin_th) / ry;
Daniel@0 8378 var a11 = (cos_th) / ry;
Daniel@0 8379 var x0 = a00 * ox + a01 * oy;
Daniel@0 8380 var y0 = a10 * ox + a11 * oy;
Daniel@0 8381 var x1 = a00 * x + a01 * y;
Daniel@0 8382 var y1 = a10 * x + a11 * y;
Daniel@0 8383
Daniel@0 8384 var d = (x1-x0) * (x1-x0) + (y1-y0) * (y1-y0);
Daniel@0 8385 var sfactor_sq = 1 / d - 0.25;
Daniel@0 8386 if (sfactor_sq < 0) sfactor_sq = 0;
Daniel@0 8387 var sfactor = Math.sqrt(sfactor_sq);
Daniel@0 8388 if (sweep == large) sfactor = -sfactor;
Daniel@0 8389 var xc = 0.5 * (x0 + x1) - sfactor * (y1-y0);
Daniel@0 8390 var yc = 0.5 * (y0 + y1) + sfactor * (x1-x0);
Daniel@0 8391
Daniel@0 8392 var th0 = Math.atan2(y0-yc, x0-xc);
Daniel@0 8393 var th1 = Math.atan2(y1-yc, x1-xc);
Daniel@0 8394
Daniel@0 8395 var th_arc = th1-th0;
Daniel@0 8396 if (th_arc < 0 && sweep === 1){
Daniel@0 8397 th_arc += 2 * Math.PI;
Daniel@0 8398 } else if (th_arc > 0 && sweep === 0) {
Daniel@0 8399 th_arc -= 2 * Math.PI;
Daniel@0 8400 }
Daniel@0 8401
Daniel@0 8402 var segs = Math.ceil(Math.abs(th_arc / (Math.PI * 0.5 + 0.001)));
Daniel@0 8403 var result = [];
Daniel@0 8404 for (var i=0; i<segs; ++i) {
Daniel@0 8405 var th2 = th0 + i * th_arc / segs;
Daniel@0 8406 var th3 = th0 + (i+1) * th_arc / segs;
Daniel@0 8407 result[i] = [xc, yc, th2, th3, rx, ry, sin_th, cos_th];
Daniel@0 8408 }
Daniel@0 8409
Daniel@0 8410 return (segmentCache[key] = result);
Daniel@0 8411 }
Daniel@0 8412
Daniel@0 8413 function bezier(params) {
Daniel@0 8414 var key = join.call(params);
Daniel@0 8415 if (bezierCache[key]) {
Daniel@0 8416 return bezierCache[key];
Daniel@0 8417 }
Daniel@0 8418
Daniel@0 8419 var cx = params[0],
Daniel@0 8420 cy = params[1],
Daniel@0 8421 th0 = params[2],
Daniel@0 8422 th1 = params[3],
Daniel@0 8423 rx = params[4],
Daniel@0 8424 ry = params[5],
Daniel@0 8425 sin_th = params[6],
Daniel@0 8426 cos_th = params[7];
Daniel@0 8427
Daniel@0 8428 var a00 = cos_th * rx;
Daniel@0 8429 var a01 = -sin_th * ry;
Daniel@0 8430 var a10 = sin_th * rx;
Daniel@0 8431 var a11 = cos_th * ry;
Daniel@0 8432
Daniel@0 8433 var cos_th0 = Math.cos(th0);
Daniel@0 8434 var sin_th0 = Math.sin(th0);
Daniel@0 8435 var cos_th1 = Math.cos(th1);
Daniel@0 8436 var sin_th1 = Math.sin(th1);
Daniel@0 8437
Daniel@0 8438 var th_half = 0.5 * (th1 - th0);
Daniel@0 8439 var sin_th_h2 = Math.sin(th_half * 0.5);
Daniel@0 8440 var t = (8/3) * sin_th_h2 * sin_th_h2 / Math.sin(th_half);
Daniel@0 8441 var x1 = cx + cos_th0 - t * sin_th0;
Daniel@0 8442 var y1 = cy + sin_th0 + t * cos_th0;
Daniel@0 8443 var x3 = cx + cos_th1;
Daniel@0 8444 var y3 = cy + sin_th1;
Daniel@0 8445 var x2 = x3 + t * sin_th1;
Daniel@0 8446 var y2 = y3 - t * cos_th1;
Daniel@0 8447
Daniel@0 8448 return (bezierCache[key] = [
Daniel@0 8449 a00 * x1 + a01 * y1, a10 * x1 + a11 * y1,
Daniel@0 8450 a00 * x2 + a01 * y2, a10 * x2 + a11 * y2,
Daniel@0 8451 a00 * x3 + a01 * y3, a10 * x3 + a11 * y3
Daniel@0 8452 ]);
Daniel@0 8453 }
Daniel@0 8454
Daniel@0 8455 module.exports = {
Daniel@0 8456 segments: segments,
Daniel@0 8457 bezier: bezier,
Daniel@0 8458 cache: {
Daniel@0 8459 segments: segmentCache,
Daniel@0 8460 bezier: bezierCache
Daniel@0 8461 }
Daniel@0 8462 };
Daniel@0 8463
Daniel@0 8464 },{}],48:[function(require,module,exports){
Daniel@0 8465 module.exports = {
Daniel@0 8466 parse: require('./parse'),
Daniel@0 8467 render: require('./render')
Daniel@0 8468 };
Daniel@0 8469
Daniel@0 8470 },{"./parse":49,"./render":50}],49:[function(require,module,exports){
Daniel@0 8471 // Path parsing and rendering code adapted from fabric.js -- Thanks!
Daniel@0 8472 var cmdlen = { m:2, l:2, h:1, v:1, c:6, s:4, q:4, t:2, a:7 },
Daniel@0 8473 regexp = [/([MLHVCSQTAZmlhvcsqtaz])/g, /###/, /(\d)([-+])/g, /\s|,|###/];
Daniel@0 8474
Daniel@0 8475 module.exports = function(pathstr) {
Daniel@0 8476 var result = [],
Daniel@0 8477 path,
Daniel@0 8478 curr,
Daniel@0 8479 chunks,
Daniel@0 8480 parsed, param,
Daniel@0 8481 cmd, len, i, j, n, m;
Daniel@0 8482
Daniel@0 8483 // First, break path into command sequence
Daniel@0 8484 path = pathstr
Daniel@0 8485 .slice()
Daniel@0 8486 .replace(regexp[0], '###$1')
Daniel@0 8487 .split(regexp[1])
Daniel@0 8488 .slice(1);
Daniel@0 8489
Daniel@0 8490 // Next, parse each command in turn
Daniel@0 8491 for (i=0, n=path.length; i<n; ++i) {
Daniel@0 8492 curr = path[i];
Daniel@0 8493 chunks = curr
Daniel@0 8494 .slice(1)
Daniel@0 8495 .trim()
Daniel@0 8496 .replace(regexp[2],'$1###$2')
Daniel@0 8497 .split(regexp[3]);
Daniel@0 8498 cmd = curr.charAt(0);
Daniel@0 8499
Daniel@0 8500 parsed = [cmd];
Daniel@0 8501 for (j=0, m=chunks.length; j<m; ++j) {
Daniel@0 8502 if ((param = +chunks[j]) === param) { // not NaN
Daniel@0 8503 parsed.push(param);
Daniel@0 8504 }
Daniel@0 8505 }
Daniel@0 8506
Daniel@0 8507 len = cmdlen[cmd.toLowerCase()];
Daniel@0 8508 if (parsed.length-1 > len) {
Daniel@0 8509 for (j=1, m=parsed.length; j<m; j+=len) {
Daniel@0 8510 result.push([cmd].concat(parsed.slice(j, j+len)));
Daniel@0 8511 }
Daniel@0 8512 }
Daniel@0 8513 else {
Daniel@0 8514 result.push(parsed);
Daniel@0 8515 }
Daniel@0 8516 }
Daniel@0 8517
Daniel@0 8518 return result;
Daniel@0 8519 };
Daniel@0 8520
Daniel@0 8521 },{}],50:[function(require,module,exports){
Daniel@0 8522 var arc = require('./arc');
Daniel@0 8523
Daniel@0 8524 module.exports = function(g, path, l, t) {
Daniel@0 8525 var current, // current instruction
Daniel@0 8526 previous = null,
Daniel@0 8527 x = 0, // current x
Daniel@0 8528 y = 0, // current y
Daniel@0 8529 controlX = 0, // current control point x
Daniel@0 8530 controlY = 0, // current control point y
Daniel@0 8531 tempX,
Daniel@0 8532 tempY,
Daniel@0 8533 tempControlX,
Daniel@0 8534 tempControlY;
Daniel@0 8535
Daniel@0 8536 if (l == null) l = 0;
Daniel@0 8537 if (t == null) t = 0;
Daniel@0 8538
Daniel@0 8539 g.beginPath();
Daniel@0 8540
Daniel@0 8541 for (var i=0, len=path.length; i<len; ++i) {
Daniel@0 8542 current = path[i];
Daniel@0 8543
Daniel@0 8544 switch (current[0]) { // first letter
Daniel@0 8545
Daniel@0 8546 case 'l': // lineto, relative
Daniel@0 8547 x += current[1];
Daniel@0 8548 y += current[2];
Daniel@0 8549 g.lineTo(x + l, y + t);
Daniel@0 8550 break;
Daniel@0 8551
Daniel@0 8552 case 'L': // lineto, absolute
Daniel@0 8553 x = current[1];
Daniel@0 8554 y = current[2];
Daniel@0 8555 g.lineTo(x + l, y + t);
Daniel@0 8556 break;
Daniel@0 8557
Daniel@0 8558 case 'h': // horizontal lineto, relative
Daniel@0 8559 x += current[1];
Daniel@0 8560 g.lineTo(x + l, y + t);
Daniel@0 8561 break;
Daniel@0 8562
Daniel@0 8563 case 'H': // horizontal lineto, absolute
Daniel@0 8564 x = current[1];
Daniel@0 8565 g.lineTo(x + l, y + t);
Daniel@0 8566 break;
Daniel@0 8567
Daniel@0 8568 case 'v': // vertical lineto, relative
Daniel@0 8569 y += current[1];
Daniel@0 8570 g.lineTo(x + l, y + t);
Daniel@0 8571 break;
Daniel@0 8572
Daniel@0 8573 case 'V': // verical lineto, absolute
Daniel@0 8574 y = current[1];
Daniel@0 8575 g.lineTo(x + l, y + t);
Daniel@0 8576 break;
Daniel@0 8577
Daniel@0 8578 case 'm': // moveTo, relative
Daniel@0 8579 x += current[1];
Daniel@0 8580 y += current[2];
Daniel@0 8581 g.moveTo(x + l, y + t);
Daniel@0 8582 break;
Daniel@0 8583
Daniel@0 8584 case 'M': // moveTo, absolute
Daniel@0 8585 x = current[1];
Daniel@0 8586 y = current[2];
Daniel@0 8587 g.moveTo(x + l, y + t);
Daniel@0 8588 break;
Daniel@0 8589
Daniel@0 8590 case 'c': // bezierCurveTo, relative
Daniel@0 8591 tempX = x + current[5];
Daniel@0 8592 tempY = y + current[6];
Daniel@0 8593 controlX = x + current[3];
Daniel@0 8594 controlY = y + current[4];
Daniel@0 8595 g.bezierCurveTo(
Daniel@0 8596 x + current[1] + l, // x1
Daniel@0 8597 y + current[2] + t, // y1
Daniel@0 8598 controlX + l, // x2
Daniel@0 8599 controlY + t, // y2
Daniel@0 8600 tempX + l,
Daniel@0 8601 tempY + t
Daniel@0 8602 );
Daniel@0 8603 x = tempX;
Daniel@0 8604 y = tempY;
Daniel@0 8605 break;
Daniel@0 8606
Daniel@0 8607 case 'C': // bezierCurveTo, absolute
Daniel@0 8608 x = current[5];
Daniel@0 8609 y = current[6];
Daniel@0 8610 controlX = current[3];
Daniel@0 8611 controlY = current[4];
Daniel@0 8612 g.bezierCurveTo(
Daniel@0 8613 current[1] + l,
Daniel@0 8614 current[2] + t,
Daniel@0 8615 controlX + l,
Daniel@0 8616 controlY + t,
Daniel@0 8617 x + l,
Daniel@0 8618 y + t
Daniel@0 8619 );
Daniel@0 8620 break;
Daniel@0 8621
Daniel@0 8622 case 's': // shorthand cubic bezierCurveTo, relative
Daniel@0 8623 // transform to absolute x,y
Daniel@0 8624 tempX = x + current[3];
Daniel@0 8625 tempY = y + current[4];
Daniel@0 8626 // calculate reflection of previous control points
Daniel@0 8627 controlX = 2 * x - controlX;
Daniel@0 8628 controlY = 2 * y - controlY;
Daniel@0 8629 g.bezierCurveTo(
Daniel@0 8630 controlX + l,
Daniel@0 8631 controlY + t,
Daniel@0 8632 x + current[1] + l,
Daniel@0 8633 y + current[2] + t,
Daniel@0 8634 tempX + l,
Daniel@0 8635 tempY + t
Daniel@0 8636 );
Daniel@0 8637
Daniel@0 8638 // set control point to 2nd one of this command
Daniel@0 8639 // the first control point is assumed to be the reflection of
Daniel@0 8640 // the second control point on the previous command relative
Daniel@0 8641 // to the current point.
Daniel@0 8642 controlX = x + current[1];
Daniel@0 8643 controlY = y + current[2];
Daniel@0 8644
Daniel@0 8645 x = tempX;
Daniel@0 8646 y = tempY;
Daniel@0 8647 break;
Daniel@0 8648
Daniel@0 8649 case 'S': // shorthand cubic bezierCurveTo, absolute
Daniel@0 8650 tempX = current[3];
Daniel@0 8651 tempY = current[4];
Daniel@0 8652 // calculate reflection of previous control points
Daniel@0 8653 controlX = 2*x - controlX;
Daniel@0 8654 controlY = 2*y - controlY;
Daniel@0 8655 g.bezierCurveTo(
Daniel@0 8656 controlX + l,
Daniel@0 8657 controlY + t,
Daniel@0 8658 current[1] + l,
Daniel@0 8659 current[2] + t,
Daniel@0 8660 tempX + l,
Daniel@0 8661 tempY + t
Daniel@0 8662 );
Daniel@0 8663 x = tempX;
Daniel@0 8664 y = tempY;
Daniel@0 8665 // set control point to 2nd one of this command
Daniel@0 8666 // the first control point is assumed to be the reflection of
Daniel@0 8667 // the second control point on the previous command relative
Daniel@0 8668 // to the current point.
Daniel@0 8669 controlX = current[1];
Daniel@0 8670 controlY = current[2];
Daniel@0 8671
Daniel@0 8672 break;
Daniel@0 8673
Daniel@0 8674 case 'q': // quadraticCurveTo, relative
Daniel@0 8675 // transform to absolute x,y
Daniel@0 8676 tempX = x + current[3];
Daniel@0 8677 tempY = y + current[4];
Daniel@0 8678
Daniel@0 8679 controlX = x + current[1];
Daniel@0 8680 controlY = y + current[2];
Daniel@0 8681
Daniel@0 8682 g.quadraticCurveTo(
Daniel@0 8683 controlX + l,
Daniel@0 8684 controlY + t,
Daniel@0 8685 tempX + l,
Daniel@0 8686 tempY + t
Daniel@0 8687 );
Daniel@0 8688 x = tempX;
Daniel@0 8689 y = tempY;
Daniel@0 8690 break;
Daniel@0 8691
Daniel@0 8692 case 'Q': // quadraticCurveTo, absolute
Daniel@0 8693 tempX = current[3];
Daniel@0 8694 tempY = current[4];
Daniel@0 8695
Daniel@0 8696 g.quadraticCurveTo(
Daniel@0 8697 current[1] + l,
Daniel@0 8698 current[2] + t,
Daniel@0 8699 tempX + l,
Daniel@0 8700 tempY + t
Daniel@0 8701 );
Daniel@0 8702 x = tempX;
Daniel@0 8703 y = tempY;
Daniel@0 8704 controlX = current[1];
Daniel@0 8705 controlY = current[2];
Daniel@0 8706 break;
Daniel@0 8707
Daniel@0 8708 case 't': // shorthand quadraticCurveTo, relative
Daniel@0 8709
Daniel@0 8710 // transform to absolute x,y
Daniel@0 8711 tempX = x + current[1];
Daniel@0 8712 tempY = y + current[2];
Daniel@0 8713
Daniel@0 8714 if (previous[0].match(/[QqTt]/) === null) {
Daniel@0 8715 // If there is no previous command or if the previous command was not a Q, q, T or t,
Daniel@0 8716 // assume the control point is coincident with the current point
Daniel@0 8717 controlX = x;
Daniel@0 8718 controlY = y;
Daniel@0 8719 }
Daniel@0 8720 else if (previous[0] === 't') {
Daniel@0 8721 // calculate reflection of previous control points for t
Daniel@0 8722 controlX = 2 * x - tempControlX;
Daniel@0 8723 controlY = 2 * y - tempControlY;
Daniel@0 8724 }
Daniel@0 8725 else if (previous[0] === 'q') {
Daniel@0 8726 // calculate reflection of previous control points for q
Daniel@0 8727 controlX = 2 * x - controlX;
Daniel@0 8728 controlY = 2 * y - controlY;
Daniel@0 8729 }
Daniel@0 8730
Daniel@0 8731 tempControlX = controlX;
Daniel@0 8732 tempControlY = controlY;
Daniel@0 8733
Daniel@0 8734 g.quadraticCurveTo(
Daniel@0 8735 controlX + l,
Daniel@0 8736 controlY + t,
Daniel@0 8737 tempX + l,
Daniel@0 8738 tempY + t
Daniel@0 8739 );
Daniel@0 8740 x = tempX;
Daniel@0 8741 y = tempY;
Daniel@0 8742 controlX = x + current[1];
Daniel@0 8743 controlY = y + current[2];
Daniel@0 8744 break;
Daniel@0 8745
Daniel@0 8746 case 'T':
Daniel@0 8747 tempX = current[1];
Daniel@0 8748 tempY = current[2];
Daniel@0 8749
Daniel@0 8750 // calculate reflection of previous control points
Daniel@0 8751 controlX = 2 * x - controlX;
Daniel@0 8752 controlY = 2 * y - controlY;
Daniel@0 8753 g.quadraticCurveTo(
Daniel@0 8754 controlX + l,
Daniel@0 8755 controlY + t,
Daniel@0 8756 tempX + l,
Daniel@0 8757 tempY + t
Daniel@0 8758 );
Daniel@0 8759 x = tempX;
Daniel@0 8760 y = tempY;
Daniel@0 8761 break;
Daniel@0 8762
Daniel@0 8763 case 'a':
Daniel@0 8764 drawArc(g, x + l, y + t, [
Daniel@0 8765 current[1],
Daniel@0 8766 current[2],
Daniel@0 8767 current[3],
Daniel@0 8768 current[4],
Daniel@0 8769 current[5],
Daniel@0 8770 current[6] + x + l,
Daniel@0 8771 current[7] + y + t
Daniel@0 8772 ]);
Daniel@0 8773 x += current[6];
Daniel@0 8774 y += current[7];
Daniel@0 8775 break;
Daniel@0 8776
Daniel@0 8777 case 'A':
Daniel@0 8778 drawArc(g, x + l, y + t, [
Daniel@0 8779 current[1],
Daniel@0 8780 current[2],
Daniel@0 8781 current[3],
Daniel@0 8782 current[4],
Daniel@0 8783 current[5],
Daniel@0 8784 current[6] + l,
Daniel@0 8785 current[7] + t
Daniel@0 8786 ]);
Daniel@0 8787 x = current[6];
Daniel@0 8788 y = current[7];
Daniel@0 8789 break;
Daniel@0 8790
Daniel@0 8791 case 'z':
Daniel@0 8792 case 'Z':
Daniel@0 8793 g.closePath();
Daniel@0 8794 break;
Daniel@0 8795 }
Daniel@0 8796 previous = current;
Daniel@0 8797 }
Daniel@0 8798 };
Daniel@0 8799
Daniel@0 8800 function drawArc(g, x, y, coords) {
Daniel@0 8801 var seg = arc.segments(
Daniel@0 8802 coords[5], // end x
Daniel@0 8803 coords[6], // end y
Daniel@0 8804 coords[0], // radius x
Daniel@0 8805 coords[1], // radius y
Daniel@0 8806 coords[3], // large flag
Daniel@0 8807 coords[4], // sweep flag
Daniel@0 8808 coords[2], // rotation
Daniel@0 8809 x, y
Daniel@0 8810 );
Daniel@0 8811 for (var i=0; i<seg.length; ++i) {
Daniel@0 8812 var bez = arc.bezier(seg[i]);
Daniel@0 8813 g.bezierCurveTo.apply(g, bez);
Daniel@0 8814 }
Daniel@0 8815 }
Daniel@0 8816
Daniel@0 8817 },{"./arc":47}],51:[function(require,module,exports){
Daniel@0 8818 function Handler() {
Daniel@0 8819 this._active = null;
Daniel@0 8820 this._handlers = {};
Daniel@0 8821 }
Daniel@0 8822
Daniel@0 8823 var prototype = Handler.prototype;
Daniel@0 8824
Daniel@0 8825 prototype.initialize = function(el, pad, obj) {
Daniel@0 8826 this._el = el;
Daniel@0 8827 this._obj = obj || null;
Daniel@0 8828 return this.padding(pad);
Daniel@0 8829 };
Daniel@0 8830
Daniel@0 8831 prototype.element = function() {
Daniel@0 8832 return this._el;
Daniel@0 8833 };
Daniel@0 8834
Daniel@0 8835 prototype.padding = function(pad) {
Daniel@0 8836 this._padding = pad || {top:0, left:0, bottom:0, right:0};
Daniel@0 8837 return this;
Daniel@0 8838 };
Daniel@0 8839
Daniel@0 8840 prototype.scene = function(scene) {
Daniel@0 8841 if (!arguments.length) return this._scene;
Daniel@0 8842 this._scene = scene;
Daniel@0 8843 return this;
Daniel@0 8844 };
Daniel@0 8845
Daniel@0 8846 // add an event handler
Daniel@0 8847 // subclasses should override
Daniel@0 8848 prototype.on = function(/*type, handler*/) {};
Daniel@0 8849
Daniel@0 8850 // remove an event handler
Daniel@0 8851 // subclasses should override
Daniel@0 8852 prototype.off = function(/*type, handler*/) {};
Daniel@0 8853
Daniel@0 8854 // return an array with all registered event handlers
Daniel@0 8855 prototype.handlers = function() {
Daniel@0 8856 var h = this._handlers, a = [], k;
Daniel@0 8857 for (k in h) { a.push.apply(a, h[k]); }
Daniel@0 8858 return a;
Daniel@0 8859 };
Daniel@0 8860
Daniel@0 8861 prototype.eventName = function(name) {
Daniel@0 8862 var i = name.indexOf('.');
Daniel@0 8863 return i < 0 ? name : name.slice(0,i);
Daniel@0 8864 };
Daniel@0 8865
Daniel@0 8866 module.exports = Handler;
Daniel@0 8867 },{}],52:[function(require,module,exports){
Daniel@0 8868 function Renderer() {
Daniel@0 8869 this._el = null;
Daniel@0 8870 this._bgcolor = null;
Daniel@0 8871 }
Daniel@0 8872
Daniel@0 8873 var prototype = Renderer.prototype;
Daniel@0 8874
Daniel@0 8875 prototype.initialize = function(el, width, height, padding) {
Daniel@0 8876 this._el = el;
Daniel@0 8877 return this.resize(width, height, padding);
Daniel@0 8878 };
Daniel@0 8879
Daniel@0 8880 // Returns the parent container element for a visualization
Daniel@0 8881 prototype.element = function() {
Daniel@0 8882 return this._el;
Daniel@0 8883 };
Daniel@0 8884
Daniel@0 8885 // Returns the scene element (e.g., canvas or SVG) of the visualization
Daniel@0 8886 // Subclasses must override if the first child is not the scene element
Daniel@0 8887 prototype.scene = function() {
Daniel@0 8888 return this._el && this._el.firstChild;
Daniel@0 8889 };
Daniel@0 8890
Daniel@0 8891 prototype.background = function(bgcolor) {
Daniel@0 8892 if (arguments.length === 0) return this._bgcolor;
Daniel@0 8893 this._bgcolor = bgcolor;
Daniel@0 8894 return this;
Daniel@0 8895 };
Daniel@0 8896
Daniel@0 8897 prototype.resize = function(width, height, padding) {
Daniel@0 8898 this._width = width;
Daniel@0 8899 this._height = height;
Daniel@0 8900 this._padding = padding || {top:0, left:0, bottom:0, right:0};
Daniel@0 8901 return this;
Daniel@0 8902 };
Daniel@0 8903
Daniel@0 8904 prototype.render = function(/*scene, items*/) {
Daniel@0 8905 return this;
Daniel@0 8906 };
Daniel@0 8907
Daniel@0 8908 module.exports = Renderer;
Daniel@0 8909 },{}],53:[function(require,module,exports){
Daniel@0 8910 var DOM = require('../../util/dom'),
Daniel@0 8911 Handler = require('../Handler'),
Daniel@0 8912 marks = require('./marks');
Daniel@0 8913
Daniel@0 8914 function CanvasHandler() {
Daniel@0 8915 Handler.call(this);
Daniel@0 8916 this._down = null;
Daniel@0 8917 this._touch = null;
Daniel@0 8918 this._first = true;
Daniel@0 8919 }
Daniel@0 8920
Daniel@0 8921 var base = Handler.prototype;
Daniel@0 8922 var prototype = (CanvasHandler.prototype = Object.create(base));
Daniel@0 8923 prototype.constructor = CanvasHandler;
Daniel@0 8924
Daniel@0 8925 prototype.initialize = function(el, pad, obj) {
Daniel@0 8926 // add event listeners
Daniel@0 8927 var canvas = this._canvas = DOM.find(el, 'canvas'),
Daniel@0 8928 that = this;
Daniel@0 8929 this.events.forEach(function(type) {
Daniel@0 8930 canvas.addEventListener(type, function(evt) {
Daniel@0 8931 if (prototype[type]) {
Daniel@0 8932 prototype[type].call(that, evt);
Daniel@0 8933 } else {
Daniel@0 8934 that.fire(type, evt);
Daniel@0 8935 }
Daniel@0 8936 });
Daniel@0 8937 });
Daniel@0 8938
Daniel@0 8939 return base.initialize.call(this, el, pad, obj);
Daniel@0 8940 };
Daniel@0 8941
Daniel@0 8942 prototype.canvas = function() {
Daniel@0 8943 return this._canvas;
Daniel@0 8944 };
Daniel@0 8945
Daniel@0 8946 // retrieve the current canvas context
Daniel@0 8947 prototype.context = function() {
Daniel@0 8948 return this._canvas.getContext('2d');
Daniel@0 8949 };
Daniel@0 8950
Daniel@0 8951 // supported events
Daniel@0 8952 prototype.events = [
Daniel@0 8953 'keydown',
Daniel@0 8954 'keypress',
Daniel@0 8955 'keyup',
Daniel@0 8956 'mousedown',
Daniel@0 8957 'mouseup',
Daniel@0 8958 'mousemove',
Daniel@0 8959 'mouseout',
Daniel@0 8960 'mouseover',
Daniel@0 8961 'click',
Daniel@0 8962 'dblclick',
Daniel@0 8963 'wheel',
Daniel@0 8964 'mousewheel',
Daniel@0 8965 'touchstart',
Daniel@0 8966 'touchmove',
Daniel@0 8967 'touchend'
Daniel@0 8968 ];
Daniel@0 8969
Daniel@0 8970 // to keep firefox happy
Daniel@0 8971 prototype.DOMMouseScroll = function(evt) {
Daniel@0 8972 this.fire('mousewheel', evt);
Daniel@0 8973 };
Daniel@0 8974
Daniel@0 8975 prototype.mousemove = function(evt) {
Daniel@0 8976 var a = this._active,
Daniel@0 8977 p = this.pickEvent(evt);
Daniel@0 8978
Daniel@0 8979 if (p === a) {
Daniel@0 8980 // active item and picked item are the same
Daniel@0 8981 this.fire('mousemove', evt); // fire move
Daniel@0 8982 } else {
Daniel@0 8983 // active item and picked item are different
Daniel@0 8984 this.fire('mouseout', evt); // fire out for prior active item
Daniel@0 8985 this._active = p; // set new active item
Daniel@0 8986 this.fire('mouseover', evt); // fire over for new active item
Daniel@0 8987 this.fire('mousemove', evt); // fire move for new active item
Daniel@0 8988 }
Daniel@0 8989 };
Daniel@0 8990
Daniel@0 8991 prototype.mouseout = function(evt) {
Daniel@0 8992 this.fire('mouseout', evt);
Daniel@0 8993 this._active = null;
Daniel@0 8994 };
Daniel@0 8995
Daniel@0 8996 prototype.mousedown = function(evt) {
Daniel@0 8997 this._down = this._active;
Daniel@0 8998 this.fire('mousedown', evt);
Daniel@0 8999 };
Daniel@0 9000
Daniel@0 9001 prototype.click = function(evt) {
Daniel@0 9002 if (this._down === this._active) {
Daniel@0 9003 this.fire('click', evt);
Daniel@0 9004 this._down = null;
Daniel@0 9005 }
Daniel@0 9006 };
Daniel@0 9007
Daniel@0 9008 prototype.touchstart = function(evt) {
Daniel@0 9009 this._touch = this.pickEvent(evt.changedTouches[0]);
Daniel@0 9010
Daniel@0 9011 if (this._first) {
Daniel@0 9012 this._active = this._touch;
Daniel@0 9013 this._first = false;
Daniel@0 9014 }
Daniel@0 9015
Daniel@0 9016 this.fire('touchstart', evt, true);
Daniel@0 9017 };
Daniel@0 9018
Daniel@0 9019 prototype.touchmove = function(evt) {
Daniel@0 9020 this.fire('touchmove', evt, true);
Daniel@0 9021 };
Daniel@0 9022
Daniel@0 9023 prototype.touchend = function(evt) {
Daniel@0 9024 this.fire('touchend', evt, true);
Daniel@0 9025 this._touch = null;
Daniel@0 9026 };
Daniel@0 9027
Daniel@0 9028 // fire an event
Daniel@0 9029 prototype.fire = function(type, evt, touch) {
Daniel@0 9030 var a = touch ? this._touch : this._active,
Daniel@0 9031 h = this._handlers[type], i, len;
Daniel@0 9032 if (h) {
Daniel@0 9033 evt.vegaType = type;
Daniel@0 9034 for (i=0, len=h.length; i<len; ++i) {
Daniel@0 9035 h[i].handler.call(this._obj, evt, a);
Daniel@0 9036 }
Daniel@0 9037 }
Daniel@0 9038 };
Daniel@0 9039
Daniel@0 9040 // add an event handler
Daniel@0 9041 prototype.on = function(type, handler) {
Daniel@0 9042 var name = this.eventName(type),
Daniel@0 9043 h = this._handlers;
Daniel@0 9044 (h[name] || (h[name] = [])).push({
Daniel@0 9045 type: type,
Daniel@0 9046 handler: handler
Daniel@0 9047 });
Daniel@0 9048 return this;
Daniel@0 9049 };
Daniel@0 9050
Daniel@0 9051 // remove an event handler
Daniel@0 9052 prototype.off = function(type, handler) {
Daniel@0 9053 var name = this.eventName(type),
Daniel@0 9054 h = this._handlers[name], i;
Daniel@0 9055 if (!h) return;
Daniel@0 9056 for (i=h.length; --i>=0;) {
Daniel@0 9057 if (h[i].type !== type) continue;
Daniel@0 9058 if (!handler || h[i].handler === handler) h.splice(i, 1);
Daniel@0 9059 }
Daniel@0 9060 return this;
Daniel@0 9061 };
Daniel@0 9062
Daniel@0 9063 prototype.pickEvent = function(evt) {
Daniel@0 9064 var rect = this._canvas.getBoundingClientRect(),
Daniel@0 9065 pad = this._padding, x, y;
Daniel@0 9066 return this.pick(this._scene,
Daniel@0 9067 x = (evt.clientX - rect.left),
Daniel@0 9068 y = (evt.clientY - rect.top),
Daniel@0 9069 x - pad.left, y - pad.top);
Daniel@0 9070 };
Daniel@0 9071
Daniel@0 9072 // find the scenegraph item at the current mouse position
Daniel@0 9073 // x, y -- the absolute x, y mouse coordinates on the canvas element
Daniel@0 9074 // gx, gy -- the relative coordinates within the current group
Daniel@0 9075 prototype.pick = function(scene, x, y, gx, gy) {
Daniel@0 9076 var g = this.context(),
Daniel@0 9077 mark = marks[scene.marktype];
Daniel@0 9078 return mark.pick.call(this, g, scene, x, y, gx, gy);
Daniel@0 9079 };
Daniel@0 9080
Daniel@0 9081 module.exports = CanvasHandler;
Daniel@0 9082
Daniel@0 9083 },{"../../util/dom":81,"../Handler":51,"./marks":60}],54:[function(require,module,exports){
Daniel@0 9084 var DOM = require('../../util/dom'),
Daniel@0 9085 Bounds = require('../../util/Bounds'),
Daniel@0 9086 ImageLoader = require('../../util/ImageLoader'),
Daniel@0 9087 Canvas = require('../../util/canvas'),
Daniel@0 9088 Renderer = require('../Renderer'),
Daniel@0 9089 marks = require('./marks');
Daniel@0 9090
Daniel@0 9091 function CanvasRenderer(loadConfig) {
Daniel@0 9092 Renderer.call(this);
Daniel@0 9093 this._loader = new ImageLoader(loadConfig);
Daniel@0 9094 }
Daniel@0 9095
Daniel@0 9096 CanvasRenderer.RETINA = true;
Daniel@0 9097
Daniel@0 9098 var base = Renderer.prototype;
Daniel@0 9099 var prototype = (CanvasRenderer.prototype = Object.create(base));
Daniel@0 9100 prototype.constructor = CanvasRenderer;
Daniel@0 9101
Daniel@0 9102 prototype.initialize = function(el, width, height, padding) {
Daniel@0 9103 this._canvas = Canvas.instance(width, height);
Daniel@0 9104 if (el) {
Daniel@0 9105 DOM.clear(el, 0).appendChild(this._canvas);
Daniel@0 9106 this._canvas.setAttribute('class', 'marks');
Daniel@0 9107 }
Daniel@0 9108 return base.initialize.call(this, el, width, height, padding);
Daniel@0 9109 };
Daniel@0 9110
Daniel@0 9111 prototype.resize = function(width, height, padding) {
Daniel@0 9112 base.resize.call(this, width, height, padding);
Daniel@0 9113 Canvas.resize(this._canvas, this._width, this._height,
Daniel@0 9114 this._padding, CanvasRenderer.RETINA);
Daniel@0 9115 return this;
Daniel@0 9116 };
Daniel@0 9117
Daniel@0 9118 prototype.canvas = function() {
Daniel@0 9119 return this._canvas;
Daniel@0 9120 };
Daniel@0 9121
Daniel@0 9122 prototype.context = function() {
Daniel@0 9123 return this._canvas ? this._canvas.getContext('2d') : null;
Daniel@0 9124 };
Daniel@0 9125
Daniel@0 9126 prototype.pendingImages = function() {
Daniel@0 9127 return this._loader.pending();
Daniel@0 9128 };
Daniel@0 9129
Daniel@0 9130 function clipToBounds(g, items) {
Daniel@0 9131 if (!items) return null;
Daniel@0 9132
Daniel@0 9133 var b = new Bounds(), i, n, item, mark, group;
Daniel@0 9134 for (i=0, n=items.length; i<n; ++i) {
Daniel@0 9135 item = items[i];
Daniel@0 9136 mark = item.mark;
Daniel@0 9137 group = mark.group;
Daniel@0 9138 item = marks[mark.marktype].nested ? mark : item;
Daniel@0 9139 b.union(translate(item.bounds, group));
Daniel@0 9140 if (item['bounds:prev']) {
Daniel@0 9141 b.union(translate(item['bounds:prev'], group));
Daniel@0 9142 }
Daniel@0 9143 }
Daniel@0 9144 b.round();
Daniel@0 9145
Daniel@0 9146 g.beginPath();
Daniel@0 9147 g.rect(b.x1, b.y1, b.width(), b.height());
Daniel@0 9148 g.clip();
Daniel@0 9149
Daniel@0 9150 return b;
Daniel@0 9151 }
Daniel@0 9152
Daniel@0 9153 function translate(bounds, group) {
Daniel@0 9154 if (group == null) return bounds;
Daniel@0 9155 var b = bounds.clone();
Daniel@0 9156 for (; group != null; group = group.mark.group) {
Daniel@0 9157 b.translate(group.x || 0, group.y || 0);
Daniel@0 9158 }
Daniel@0 9159 return b;
Daniel@0 9160 }
Daniel@0 9161
Daniel@0 9162 prototype.render = function(scene, items) {
Daniel@0 9163 var g = this.context(),
Daniel@0 9164 p = this._padding,
Daniel@0 9165 w = this._width + p.left + p.right,
Daniel@0 9166 h = this._height + p.top + p.bottom,
Daniel@0 9167 b;
Daniel@0 9168
Daniel@0 9169 // setup
Daniel@0 9170 this._scene = scene; // cache scene for async redraw
Daniel@0 9171 g.save();
Daniel@0 9172 b = clipToBounds(g, items);
Daniel@0 9173 this.clear(-p.left, -p.top, w, h);
Daniel@0 9174
Daniel@0 9175 // render
Daniel@0 9176 this.draw(g, scene, b);
Daniel@0 9177
Daniel@0 9178 // takedown
Daniel@0 9179 g.restore();
Daniel@0 9180 this._scene = null; // clear scene cache
Daniel@0 9181
Daniel@0 9182 return this;
Daniel@0 9183 };
Daniel@0 9184
Daniel@0 9185 prototype.draw = function(ctx, scene, bounds) {
Daniel@0 9186 var mark = marks[scene.marktype];
Daniel@0 9187 mark.draw.call(this, ctx, scene, bounds);
Daniel@0 9188 };
Daniel@0 9189
Daniel@0 9190 prototype.clear = function(x, y, w, h) {
Daniel@0 9191 var g = this.context();
Daniel@0 9192 g.clearRect(x, y, w, h);
Daniel@0 9193 if (this._bgcolor != null) {
Daniel@0 9194 g.fillStyle = this._bgcolor;
Daniel@0 9195 g.fillRect(x, y, w, h);
Daniel@0 9196 }
Daniel@0 9197 };
Daniel@0 9198
Daniel@0 9199 prototype.loadImage = function(uri) {
Daniel@0 9200 var renderer = this,
Daniel@0 9201 scene = this._scene;
Daniel@0 9202 return this._loader.loadImage(uri, function() {
Daniel@0 9203 renderer.renderAsync(scene);
Daniel@0 9204 });
Daniel@0 9205 };
Daniel@0 9206
Daniel@0 9207 prototype.renderAsync = function(scene) {
Daniel@0 9208 // TODO make safe for multiple scene rendering?
Daniel@0 9209 var renderer = this;
Daniel@0 9210 if (renderer._async_id) {
Daniel@0 9211 clearTimeout(renderer._async_id);
Daniel@0 9212 }
Daniel@0 9213 renderer._async_id = setTimeout(function() {
Daniel@0 9214 renderer.render(scene);
Daniel@0 9215 delete renderer._async_id;
Daniel@0 9216 }, 10);
Daniel@0 9217 };
Daniel@0 9218
Daniel@0 9219 module.exports = CanvasRenderer;
Daniel@0 9220
Daniel@0 9221 },{"../../util/Bounds":74,"../../util/ImageLoader":77,"../../util/canvas":80,"../../util/dom":81,"../Renderer":52,"./marks":60}],55:[function(require,module,exports){
Daniel@0 9222 module.exports = {
Daniel@0 9223 Handler: require('./CanvasHandler'),
Daniel@0 9224 Renderer: require('./CanvasRenderer')
Daniel@0 9225 };
Daniel@0 9226 },{"./CanvasHandler":53,"./CanvasRenderer":54}],56:[function(require,module,exports){
Daniel@0 9227 var util = require('./util');
Daniel@0 9228 var halfpi = Math.PI / 2;
Daniel@0 9229
Daniel@0 9230 function path(g, o) {
Daniel@0 9231 var x = o.x || 0,
Daniel@0 9232 y = o.y || 0,
Daniel@0 9233 ir = o.innerRadius || 0,
Daniel@0 9234 or = o.outerRadius || 0,
Daniel@0 9235 sa = (o.startAngle || 0) - halfpi,
Daniel@0 9236 ea = (o.endAngle || 0) - halfpi;
Daniel@0 9237 g.beginPath();
Daniel@0 9238 if (ir === 0) g.moveTo(x, y);
Daniel@0 9239 else g.arc(x, y, ir, sa, ea, 0);
Daniel@0 9240 g.arc(x, y, or, ea, sa, 1);
Daniel@0 9241 g.closePath();
Daniel@0 9242 }
Daniel@0 9243
Daniel@0 9244 module.exports = {
Daniel@0 9245 draw: util.drawAll(path),
Daniel@0 9246 pick: util.pickPath(path)
Daniel@0 9247 };
Daniel@0 9248 },{"./util":67}],57:[function(require,module,exports){
Daniel@0 9249 var util = require('./util'),
Daniel@0 9250 parse = require('../../../path/parse'),
Daniel@0 9251 render = require('../../../path/render'),
Daniel@0 9252 areaPath = require('../../../util/svg').path.area;
Daniel@0 9253
Daniel@0 9254 function path(g, items) {
Daniel@0 9255 var o = items[0],
Daniel@0 9256 p = o.pathCache || (o.pathCache = parse(areaPath(items)));
Daniel@0 9257 render(g, p);
Daniel@0 9258 }
Daniel@0 9259
Daniel@0 9260 function pick(g, scene, x, y, gx, gy) {
Daniel@0 9261 var items = scene.items,
Daniel@0 9262 b = scene.bounds;
Daniel@0 9263
Daniel@0 9264 if (!items || !items.length || b && !b.contains(gx, gy)) {
Daniel@0 9265 return null;
Daniel@0 9266 }
Daniel@0 9267
Daniel@0 9268 if (g.pixelratio != null && g.pixelratio !== 1) {
Daniel@0 9269 x *= g.pixelratio;
Daniel@0 9270 y *= g.pixelratio;
Daniel@0 9271 }
Daniel@0 9272 return hit(g, items, x, y) ? items[0] : null;
Daniel@0 9273 }
Daniel@0 9274
Daniel@0 9275 var hit = util.testPath(path);
Daniel@0 9276
Daniel@0 9277 module.exports = {
Daniel@0 9278 draw: util.drawOne(path),
Daniel@0 9279 pick: pick,
Daniel@0 9280 nested: true
Daniel@0 9281 };
Daniel@0 9282
Daniel@0 9283 },{"../../../path/parse":49,"../../../path/render":50,"../../../util/svg":83,"./util":67}],58:[function(require,module,exports){
Daniel@0 9284 var util = require('./util'),
Daniel@0 9285 rect = require('./rect');
Daniel@0 9286
Daniel@0 9287 function draw(g, scene, bounds) {
Daniel@0 9288 if (!scene.items || !scene.items.length) return;
Daniel@0 9289
Daniel@0 9290 var groups = scene.items,
Daniel@0 9291 renderer = this,
Daniel@0 9292 group, items, axes, legends, gx, gy, i, n, j, m;
Daniel@0 9293
Daniel@0 9294 rect.draw.call(renderer, g, scene, bounds);
Daniel@0 9295
Daniel@0 9296 for (i=0, n=groups.length; i<n; ++i) {
Daniel@0 9297 group = groups[i];
Daniel@0 9298 axes = group.axisItems || [];
Daniel@0 9299 items = group.items || [];
Daniel@0 9300 legends = group.legendItems || [];
Daniel@0 9301 gx = group.x || 0;
Daniel@0 9302 gy = group.y || 0;
Daniel@0 9303
Daniel@0 9304 // render group contents
Daniel@0 9305 g.save();
Daniel@0 9306 g.translate(gx, gy);
Daniel@0 9307 if (group.clip) {
Daniel@0 9308 g.beginPath();
Daniel@0 9309 g.rect(0, 0, group.width || 0, group.height || 0);
Daniel@0 9310 g.clip();
Daniel@0 9311 }
Daniel@0 9312
Daniel@0 9313 if (bounds) bounds.translate(-gx, -gy);
Daniel@0 9314
Daniel@0 9315 for (j=0, m=axes.length; j<m; ++j) {
Daniel@0 9316 if (axes[j].layer === 'back') {
Daniel@0 9317 renderer.draw(g, axes[j], bounds);
Daniel@0 9318 }
Daniel@0 9319 }
Daniel@0 9320 for (j=0, m=items.length; j<m; ++j) {
Daniel@0 9321 renderer.draw(g, items[j], bounds);
Daniel@0 9322 }
Daniel@0 9323 for (j=0, m=axes.length; j<m; ++j) {
Daniel@0 9324 if (axes[j].layer !== 'back') {
Daniel@0 9325 renderer.draw(g, axes[j], bounds);
Daniel@0 9326 }
Daniel@0 9327 }
Daniel@0 9328 for (j=0, m=legends.length; j<m; ++j) {
Daniel@0 9329 renderer.draw(g, legends[j], bounds);
Daniel@0 9330 }
Daniel@0 9331
Daniel@0 9332 if (bounds) bounds.translate(gx, gy);
Daniel@0 9333 g.restore();
Daniel@0 9334 }
Daniel@0 9335 }
Daniel@0 9336
Daniel@0 9337 function hit(g, o) {
Daniel@0 9338 return o.fill || o.stroke;
Daniel@0 9339 }
Daniel@0 9340
Daniel@0 9341 function pick(g, scene, x, y, gx, gy) {
Daniel@0 9342 if (scene.bounds && !scene.bounds.contains(gx, gy)) {
Daniel@0 9343 return null;
Daniel@0 9344 }
Daniel@0 9345 var items = scene.items || [],
Daniel@0 9346 subscene, group, hits, dx, dy, i, j;
Daniel@0 9347
Daniel@0 9348 for (i=items.length; --i>=0;) {
Daniel@0 9349 group = items[i];
Daniel@0 9350 dx = group.x || 0;
Daniel@0 9351 dy = group.y || 0;
Daniel@0 9352
Daniel@0 9353 g.save();
Daniel@0 9354 g.translate(dx, dy);
Daniel@0 9355 for (j=group.items.length; --j >= 0;) {
Daniel@0 9356 subscene = group.items[j];
Daniel@0 9357 if (subscene.interactive === false) continue;
Daniel@0 9358 hits = this.pick(subscene, x, y, gx-dx, gy-dy);
Daniel@0 9359 if (hits) {
Daniel@0 9360 g.restore();
Daniel@0 9361 return hits;
Daniel@0 9362 }
Daniel@0 9363 }
Daniel@0 9364 g.restore();
Daniel@0 9365 }
Daniel@0 9366
Daniel@0 9367 return scene.interactive !== false ? pickSelf(g, scene, x, y, gx, gy) : null;
Daniel@0 9368 }
Daniel@0 9369
Daniel@0 9370 var pickSelf = util.pick(hit);
Daniel@0 9371
Daniel@0 9372 module.exports = {
Daniel@0 9373 draw: draw,
Daniel@0 9374 pick: pick
Daniel@0 9375 };
Daniel@0 9376
Daniel@0 9377 },{"./rect":63,"./util":67}],59:[function(require,module,exports){
Daniel@0 9378 var util = require('./util');
Daniel@0 9379
Daniel@0 9380 function draw(g, scene, bounds) {
Daniel@0 9381 if (!scene.items || !scene.items.length) return;
Daniel@0 9382
Daniel@0 9383 var renderer = this,
Daniel@0 9384 items = scene.items, o;
Daniel@0 9385
Daniel@0 9386 for (var i=0, len=items.length; i<len; ++i) {
Daniel@0 9387 o = items[i];
Daniel@0 9388 if (bounds && !bounds.intersects(o.bounds))
Daniel@0 9389 continue; // bounds check
Daniel@0 9390
Daniel@0 9391 if (!(o.image && o.image.url === o.url)) {
Daniel@0 9392 o.image = renderer.loadImage(o.url);
Daniel@0 9393 o.image.url = o.url;
Daniel@0 9394 }
Daniel@0 9395
Daniel@0 9396 var x = o.x || 0,
Daniel@0 9397 y = o.y || 0,
Daniel@0 9398 w = o.width || (o.image && o.image.width) || 0,
Daniel@0 9399 h = o.height || (o.image && o.image.height) || 0,
Daniel@0 9400 opac;
Daniel@0 9401 x = x - (o.align==='center' ? w/2 : o.align==='right' ? w : 0);
Daniel@0 9402 y = y - (o.baseline==='middle' ? h/2 : o.baseline==='bottom' ? h : 0);
Daniel@0 9403
Daniel@0 9404 if (o.image.loaded) {
Daniel@0 9405 g.globalAlpha = (opac = o.opacity) != null ? opac : 1;
Daniel@0 9406 g.drawImage(o.image, x, y, w, h);
Daniel@0 9407 }
Daniel@0 9408 }
Daniel@0 9409 }
Daniel@0 9410
Daniel@0 9411 module.exports = {
Daniel@0 9412 draw: draw,
Daniel@0 9413 pick: util.pick()
Daniel@0 9414 };
Daniel@0 9415 },{"./util":67}],60:[function(require,module,exports){
Daniel@0 9416 module.exports = {
Daniel@0 9417 arc: require('./arc'),
Daniel@0 9418 area: require('./area'),
Daniel@0 9419 group: require('./group'),
Daniel@0 9420 image: require('./image'),
Daniel@0 9421 line: require('./line'),
Daniel@0 9422 path: require('./path'),
Daniel@0 9423 rect: require('./rect'),
Daniel@0 9424 rule: require('./rule'),
Daniel@0 9425 symbol: require('./symbol'),
Daniel@0 9426 text: require('./text')
Daniel@0 9427 };
Daniel@0 9428
Daniel@0 9429 },{"./arc":56,"./area":57,"./group":58,"./image":59,"./line":61,"./path":62,"./rect":63,"./rule":64,"./symbol":65,"./text":66}],61:[function(require,module,exports){
Daniel@0 9430 var util = require('./util'),
Daniel@0 9431 parse = require('../../../path/parse'),
Daniel@0 9432 render = require('../../../path/render'),
Daniel@0 9433 linePath = require('../../../util/svg').path.line;
Daniel@0 9434
Daniel@0 9435 function path(g, items) {
Daniel@0 9436 var o = items[0],
Daniel@0 9437 p = o.pathCache || (o.pathCache = parse(linePath(items)));
Daniel@0 9438 render(g, p);
Daniel@0 9439 }
Daniel@0 9440
Daniel@0 9441 function pick(g, scene, x, y, gx, gy) {
Daniel@0 9442 var items = scene.items,
Daniel@0 9443 b = scene.bounds;
Daniel@0 9444
Daniel@0 9445 if (!items || !items.length || b && !b.contains(gx, gy)) {
Daniel@0 9446 return null;
Daniel@0 9447 }
Daniel@0 9448
Daniel@0 9449 if (g.pixelratio != null && g.pixelratio !== 1) {
Daniel@0 9450 x *= g.pixelratio;
Daniel@0 9451 y *= g.pixelratio;
Daniel@0 9452 }
Daniel@0 9453 return hit(g, items, x, y) ? items[0] : null;
Daniel@0 9454 }
Daniel@0 9455
Daniel@0 9456 var hit = util.testPath(path, false);
Daniel@0 9457
Daniel@0 9458 module.exports = {
Daniel@0 9459 draw: util.drawOne(path),
Daniel@0 9460 pick: pick,
Daniel@0 9461 nested: true
Daniel@0 9462 };
Daniel@0 9463
Daniel@0 9464 },{"../../../path/parse":49,"../../../path/render":50,"../../../util/svg":83,"./util":67}],62:[function(require,module,exports){
Daniel@0 9465 var util = require('./util'),
Daniel@0 9466 parse = require('../../../path/parse'),
Daniel@0 9467 render = require('../../../path/render');
Daniel@0 9468
Daniel@0 9469 function path(g, o) {
Daniel@0 9470 if (o.path == null) return true;
Daniel@0 9471 var p = o.pathCache || (o.pathCache = parse(o.path));
Daniel@0 9472 render(g, p, o.x, o.y);
Daniel@0 9473 }
Daniel@0 9474
Daniel@0 9475 module.exports = {
Daniel@0 9476 draw: util.drawAll(path),
Daniel@0 9477 pick: util.pickPath(path)
Daniel@0 9478 };
Daniel@0 9479
Daniel@0 9480 },{"../../../path/parse":49,"../../../path/render":50,"./util":67}],63:[function(require,module,exports){
Daniel@0 9481 var util = require('./util');
Daniel@0 9482
Daniel@0 9483 function draw(g, scene, bounds) {
Daniel@0 9484 if (!scene.items || !scene.items.length) return;
Daniel@0 9485
Daniel@0 9486 var items = scene.items,
Daniel@0 9487 o, opac, x, y, w, h;
Daniel@0 9488
Daniel@0 9489 for (var i=0, len=items.length; i<len; ++i) {
Daniel@0 9490 o = items[i];
Daniel@0 9491 if (bounds && !bounds.intersects(o.bounds))
Daniel@0 9492 continue; // bounds check
Daniel@0 9493
Daniel@0 9494 opac = o.opacity == null ? 1 : o.opacity;
Daniel@0 9495 if (opac === 0) continue;
Daniel@0 9496
Daniel@0 9497 x = o.x || 0;
Daniel@0 9498 y = o.y || 0;
Daniel@0 9499 w = o.width || 0;
Daniel@0 9500 h = o.height || 0;
Daniel@0 9501
Daniel@0 9502 if (o.fill && util.fill(g, o, opac)) {
Daniel@0 9503 g.fillRect(x, y, w, h);
Daniel@0 9504 }
Daniel@0 9505 if (o.stroke && util.stroke(g, o, opac)) {
Daniel@0 9506 g.strokeRect(x, y, w, h);
Daniel@0 9507 }
Daniel@0 9508 }
Daniel@0 9509 }
Daniel@0 9510
Daniel@0 9511 module.exports = {
Daniel@0 9512 draw: draw,
Daniel@0 9513 pick: util.pick()
Daniel@0 9514 };
Daniel@0 9515 },{"./util":67}],64:[function(require,module,exports){
Daniel@0 9516 var util = require('./util');
Daniel@0 9517
Daniel@0 9518 function draw(g, scene, bounds) {
Daniel@0 9519 if (!scene.items || !scene.items.length) return;
Daniel@0 9520
Daniel@0 9521 var items = scene.items,
Daniel@0 9522 o, opac, x1, y1, x2, y2;
Daniel@0 9523
Daniel@0 9524 for (var i=0, len=items.length; i<len; ++i) {
Daniel@0 9525 o = items[i];
Daniel@0 9526 if (bounds && !bounds.intersects(o.bounds))
Daniel@0 9527 continue; // bounds check
Daniel@0 9528
Daniel@0 9529 opac = o.opacity == null ? 1 : o.opacity;
Daniel@0 9530 if (opac === 0) continue;
Daniel@0 9531
Daniel@0 9532 x1 = o.x || 0;
Daniel@0 9533 y1 = o.y || 0;
Daniel@0 9534 x2 = o.x2 != null ? o.x2 : x1;
Daniel@0 9535 y2 = o.y2 != null ? o.y2 : y1;
Daniel@0 9536
Daniel@0 9537 if (o.stroke && util.stroke(g, o, opac)) {
Daniel@0 9538 g.beginPath();
Daniel@0 9539 g.moveTo(x1, y1);
Daniel@0 9540 g.lineTo(x2, y2);
Daniel@0 9541 g.stroke();
Daniel@0 9542 }
Daniel@0 9543 }
Daniel@0 9544 }
Daniel@0 9545
Daniel@0 9546 function stroke(g, o) {
Daniel@0 9547 var x1 = o.x || 0,
Daniel@0 9548 y1 = o.y || 0,
Daniel@0 9549 x2 = o.x2 != null ? o.x2 : x1,
Daniel@0 9550 y2 = o.y2 != null ? o.y2 : y1,
Daniel@0 9551 lw = o.strokeWidth,
Daniel@0 9552 lc = o.strokeCap;
Daniel@0 9553
Daniel@0 9554 g.lineWidth = lw != null ? lw : 1;
Daniel@0 9555 g.lineCap = lc != null ? lc : 'butt';
Daniel@0 9556 g.beginPath();
Daniel@0 9557 g.moveTo(x1, y1);
Daniel@0 9558 g.lineTo(x2, y2);
Daniel@0 9559 }
Daniel@0 9560
Daniel@0 9561 function hit(g, o, x, y) {
Daniel@0 9562 if (!g.isPointInStroke) return false;
Daniel@0 9563 stroke(g, o);
Daniel@0 9564 return g.isPointInStroke(x, y);
Daniel@0 9565 }
Daniel@0 9566
Daniel@0 9567 module.exports = {
Daniel@0 9568 draw: draw,
Daniel@0 9569 pick: util.pick(hit)
Daniel@0 9570 };
Daniel@0 9571
Daniel@0 9572 },{"./util":67}],65:[function(require,module,exports){
Daniel@0 9573 var util = require('./util');
Daniel@0 9574
Daniel@0 9575 var sqrt3 = Math.sqrt(3),
Daniel@0 9576 tan30 = Math.tan(30 * Math.PI / 180);
Daniel@0 9577
Daniel@0 9578 function path(g, o) {
Daniel@0 9579 var size = o.size != null ? o.size : 100,
Daniel@0 9580 x = o.x, y = o.y, r, t, rx, ry;
Daniel@0 9581
Daniel@0 9582 g.beginPath();
Daniel@0 9583
Daniel@0 9584 if (o.shape == null || o.shape === 'circle') {
Daniel@0 9585 r = Math.sqrt(size / Math.PI);
Daniel@0 9586 g.arc(x, y, r, 0, 2*Math.PI, 0);
Daniel@0 9587 g.closePath();
Daniel@0 9588 return;
Daniel@0 9589 }
Daniel@0 9590
Daniel@0 9591 switch (o.shape) {
Daniel@0 9592 case 'cross':
Daniel@0 9593 r = Math.sqrt(size / 5) / 2;
Daniel@0 9594 t = 3*r;
Daniel@0 9595 g.moveTo(x-t, y-r);
Daniel@0 9596 g.lineTo(x-r, y-r);
Daniel@0 9597 g.lineTo(x-r, y-t);
Daniel@0 9598 g.lineTo(x+r, y-t);
Daniel@0 9599 g.lineTo(x+r, y-r);
Daniel@0 9600 g.lineTo(x+t, y-r);
Daniel@0 9601 g.lineTo(x+t, y+r);
Daniel@0 9602 g.lineTo(x+r, y+r);
Daniel@0 9603 g.lineTo(x+r, y+t);
Daniel@0 9604 g.lineTo(x-r, y+t);
Daniel@0 9605 g.lineTo(x-r, y+r);
Daniel@0 9606 g.lineTo(x-t, y+r);
Daniel@0 9607 break;
Daniel@0 9608
Daniel@0 9609 case 'diamond':
Daniel@0 9610 ry = Math.sqrt(size / (2 * tan30));
Daniel@0 9611 rx = ry * tan30;
Daniel@0 9612 g.moveTo(x, y-ry);
Daniel@0 9613 g.lineTo(x+rx, y);
Daniel@0 9614 g.lineTo(x, y+ry);
Daniel@0 9615 g.lineTo(x-rx, y);
Daniel@0 9616 break;
Daniel@0 9617
Daniel@0 9618 case 'square':
Daniel@0 9619 t = Math.sqrt(size);
Daniel@0 9620 r = t / 2;
Daniel@0 9621 g.rect(x-r, y-r, t, t);
Daniel@0 9622 break;
Daniel@0 9623
Daniel@0 9624 case 'triangle-down':
Daniel@0 9625 rx = Math.sqrt(size / sqrt3);
Daniel@0 9626 ry = rx * sqrt3 / 2;
Daniel@0 9627 g.moveTo(x, y+ry);
Daniel@0 9628 g.lineTo(x+rx, y-ry);
Daniel@0 9629 g.lineTo(x-rx, y-ry);
Daniel@0 9630 break;
Daniel@0 9631
Daniel@0 9632 case 'triangle-up':
Daniel@0 9633 rx = Math.sqrt(size / sqrt3);
Daniel@0 9634 ry = rx * sqrt3 / 2;
Daniel@0 9635 g.moveTo(x, y-ry);
Daniel@0 9636 g.lineTo(x+rx, y+ry);
Daniel@0 9637 g.lineTo(x-rx, y+ry);
Daniel@0 9638 }
Daniel@0 9639 g.closePath();
Daniel@0 9640 }
Daniel@0 9641
Daniel@0 9642 module.exports = {
Daniel@0 9643 draw: util.drawAll(path),
Daniel@0 9644 pick: util.pickPath(path)
Daniel@0 9645 };
Daniel@0 9646 },{"./util":67}],66:[function(require,module,exports){
Daniel@0 9647 var Bounds = require('../../../util/Bounds'),
Daniel@0 9648 textBounds = require('../../../util/bound').text,
Daniel@0 9649 text = require('../../../util/text'),
Daniel@0 9650 util = require('./util'),
Daniel@0 9651 tempBounds = new Bounds();
Daniel@0 9652
Daniel@0 9653 function draw(g, scene, bounds) {
Daniel@0 9654 if (!scene.items || !scene.items.length) return;
Daniel@0 9655
Daniel@0 9656 var items = scene.items,
Daniel@0 9657 o, opac, x, y, r, t, str;
Daniel@0 9658
Daniel@0 9659 for (var i=0, len=items.length; i<len; ++i) {
Daniel@0 9660 o = items[i];
Daniel@0 9661 if (bounds && !bounds.intersects(o.bounds))
Daniel@0 9662 continue; // bounds check
Daniel@0 9663
Daniel@0 9664 str = text.value(o.text);
Daniel@0 9665 if (!str) continue;
Daniel@0 9666 opac = o.opacity == null ? 1 : o.opacity;
Daniel@0 9667 if (opac === 0) continue;
Daniel@0 9668
Daniel@0 9669 g.font = text.font(o);
Daniel@0 9670 g.textAlign = o.align || 'left';
Daniel@0 9671
Daniel@0 9672 x = (o.x || 0);
Daniel@0 9673 y = (o.y || 0);
Daniel@0 9674 if ((r = o.radius)) {
Daniel@0 9675 t = (o.theta || 0) - Math.PI/2;
Daniel@0 9676 x += r * Math.cos(t);
Daniel@0 9677 y += r * Math.sin(t);
Daniel@0 9678 }
Daniel@0 9679
Daniel@0 9680 if (o.angle) {
Daniel@0 9681 g.save();
Daniel@0 9682 g.translate(x, y);
Daniel@0 9683 g.rotate(o.angle * Math.PI/180);
Daniel@0 9684 x = y = 0; // reset x, y
Daniel@0 9685 }
Daniel@0 9686 x += (o.dx || 0);
Daniel@0 9687 y += (o.dy || 0) + text.offset(o);
Daniel@0 9688
Daniel@0 9689 if (o.fill && util.fill(g, o, opac)) {
Daniel@0 9690 g.fillText(str, x, y);
Daniel@0 9691 }
Daniel@0 9692 if (o.stroke && util.stroke(g, o, opac)) {
Daniel@0 9693 g.strokeText(str, x, y);
Daniel@0 9694 }
Daniel@0 9695 if (o.angle) g.restore();
Daniel@0 9696 }
Daniel@0 9697 }
Daniel@0 9698
Daniel@0 9699 function hit(g, o, x, y, gx, gy) {
Daniel@0 9700 if (o.fontSize <= 0) return false;
Daniel@0 9701 if (!o.angle) return true; // bounds sufficient if no rotation
Daniel@0 9702
Daniel@0 9703 // project point into space of unrotated bounds
Daniel@0 9704 var b = textBounds(o, tempBounds, true),
Daniel@0 9705 a = -o.angle * Math.PI / 180,
Daniel@0 9706 cos = Math.cos(a),
Daniel@0 9707 sin = Math.sin(a),
Daniel@0 9708 ox = o.x,
Daniel@0 9709 oy = o.y,
Daniel@0 9710 px = cos*gx - sin*gy + (ox - ox*cos + oy*sin),
Daniel@0 9711 py = sin*gx + cos*gy + (oy - ox*sin - oy*cos);
Daniel@0 9712
Daniel@0 9713 return b.contains(px, py);
Daniel@0 9714 }
Daniel@0 9715
Daniel@0 9716 module.exports = {
Daniel@0 9717 draw: draw,
Daniel@0 9718 pick: util.pick(hit)
Daniel@0 9719 };
Daniel@0 9720
Daniel@0 9721 },{"../../../util/Bounds":74,"../../../util/bound":79,"../../../util/text":84,"./util":67}],67:[function(require,module,exports){
Daniel@0 9722 function drawPathOne(path, g, o, items) {
Daniel@0 9723 if (path(g, items)) return;
Daniel@0 9724
Daniel@0 9725 var opac = o.opacity == null ? 1 : o.opacity;
Daniel@0 9726 if (opac===0) return;
Daniel@0 9727
Daniel@0 9728 if (o.fill && fill(g, o, opac)) { g.fill(); }
Daniel@0 9729 if (o.stroke && stroke(g, o, opac)) { g.stroke(); }
Daniel@0 9730 }
Daniel@0 9731
Daniel@0 9732 function drawPathAll(path, g, scene, bounds) {
Daniel@0 9733 var i, len, item;
Daniel@0 9734 for (i=0, len=scene.items.length; i<len; ++i) {
Daniel@0 9735 item = scene.items[i];
Daniel@0 9736 if (!bounds || bounds.intersects(item.bounds)) {
Daniel@0 9737 drawPathOne(path, g, item, item);
Daniel@0 9738 }
Daniel@0 9739 }
Daniel@0 9740 }
Daniel@0 9741
Daniel@0 9742 function drawAll(pathFunc) {
Daniel@0 9743 return function(g, scene, bounds) {
Daniel@0 9744 drawPathAll(pathFunc, g, scene, bounds);
Daniel@0 9745 };
Daniel@0 9746 }
Daniel@0 9747
Daniel@0 9748 function drawOne(pathFunc) {
Daniel@0 9749 return function(g, scene, bounds) {
Daniel@0 9750 if (!scene.items.length) return;
Daniel@0 9751 if (!bounds || bounds.intersects(scene.bounds)) {
Daniel@0 9752 drawPathOne(pathFunc, g, scene.items[0], scene.items);
Daniel@0 9753 }
Daniel@0 9754 };
Daniel@0 9755 }
Daniel@0 9756
Daniel@0 9757 var trueFunc = function() { return true; };
Daniel@0 9758
Daniel@0 9759 function pick(test) {
Daniel@0 9760 if (!test) test = trueFunc;
Daniel@0 9761
Daniel@0 9762 return function(g, scene, x, y, gx, gy) {
Daniel@0 9763 if (!scene.items.length) return null;
Daniel@0 9764
Daniel@0 9765 var o, b, i;
Daniel@0 9766
Daniel@0 9767 if (g.pixelratio != null && g.pixelratio !== 1) {
Daniel@0 9768 x *= g.pixelratio;
Daniel@0 9769 y *= g.pixelratio;
Daniel@0 9770 }
Daniel@0 9771
Daniel@0 9772 for (i=scene.items.length; --i >= 0;) {
Daniel@0 9773 o = scene.items[i]; b = o.bounds;
Daniel@0 9774 // first hit test against bounding box
Daniel@0 9775 if ((b && !b.contains(gx, gy)) || !b) continue;
Daniel@0 9776 // if in bounding box, perform more careful test
Daniel@0 9777 if (test(g, o, x, y, gx, gy)) return o;
Daniel@0 9778 }
Daniel@0 9779 return null;
Daniel@0 9780 };
Daniel@0 9781 }
Daniel@0 9782
Daniel@0 9783 function testPath(path, filled) {
Daniel@0 9784 return function(g, o, x, y) {
Daniel@0 9785 var item = Array.isArray(o) ? o[0] : o,
Daniel@0 9786 fill = (filled == null) ? item.fill : filled,
Daniel@0 9787 stroke = item.stroke && g.isPointInStroke, lw, lc;
Daniel@0 9788
Daniel@0 9789 if (stroke) {
Daniel@0 9790 lw = item.strokeWidth;
Daniel@0 9791 lc = item.strokeCap;
Daniel@0 9792 g.lineWidth = lw != null ? lw : 1;
Daniel@0 9793 g.lineCap = lc != null ? lc : 'butt';
Daniel@0 9794 }
Daniel@0 9795
Daniel@0 9796 return path(g, o) ? false :
Daniel@0 9797 (fill && g.isPointInPath(x, y)) ||
Daniel@0 9798 (stroke && g.isPointInStroke(x, y));
Daniel@0 9799 };
Daniel@0 9800 }
Daniel@0 9801
Daniel@0 9802 function pickPath(path) {
Daniel@0 9803 return pick(testPath(path));
Daniel@0 9804 }
Daniel@0 9805
Daniel@0 9806 function fill(g, o, opacity) {
Daniel@0 9807 opacity *= (o.fillOpacity==null ? 1 : o.fillOpacity);
Daniel@0 9808 if (opacity > 0) {
Daniel@0 9809 g.globalAlpha = opacity;
Daniel@0 9810 g.fillStyle = color(g, o, o.fill);
Daniel@0 9811 return true;
Daniel@0 9812 } else {
Daniel@0 9813 return false;
Daniel@0 9814 }
Daniel@0 9815 }
Daniel@0 9816
Daniel@0 9817 function stroke(g, o, opacity) {
Daniel@0 9818 var lw = (lw = o.strokeWidth) != null ? lw : 1, lc;
Daniel@0 9819 if (lw <= 0) return false;
Daniel@0 9820
Daniel@0 9821 opacity *= (o.strokeOpacity==null ? 1 : o.strokeOpacity);
Daniel@0 9822 if (opacity > 0) {
Daniel@0 9823 g.globalAlpha = opacity;
Daniel@0 9824 g.strokeStyle = color(g, o, o.stroke);
Daniel@0 9825 g.lineWidth = lw;
Daniel@0 9826 g.lineCap = (lc = o.strokeCap) != null ? lc : 'butt';
Daniel@0 9827 g.vgLineDash(o.strokeDash || null);
Daniel@0 9828 g.vgLineDashOffset(o.strokeDashOffset || 0);
Daniel@0 9829 return true;
Daniel@0 9830 } else {
Daniel@0 9831 return false;
Daniel@0 9832 }
Daniel@0 9833 }
Daniel@0 9834
Daniel@0 9835 function color(g, o, value) {
Daniel@0 9836 return (value.id) ?
Daniel@0 9837 gradient(g, value, o.bounds) :
Daniel@0 9838 value;
Daniel@0 9839 }
Daniel@0 9840
Daniel@0 9841 function gradient(g, p, b) {
Daniel@0 9842 var w = b.width(),
Daniel@0 9843 h = b.height(),
Daniel@0 9844 x1 = b.x1 + p.x1 * w,
Daniel@0 9845 y1 = b.y1 + p.y1 * h,
Daniel@0 9846 x2 = b.x1 + p.x2 * w,
Daniel@0 9847 y2 = b.y1 + p.y2 * h,
Daniel@0 9848 grad = g.createLinearGradient(x1, y1, x2, y2),
Daniel@0 9849 stop = p.stops,
Daniel@0 9850 i, n;
Daniel@0 9851
Daniel@0 9852 for (i=0, n=stop.length; i<n; ++i) {
Daniel@0 9853 grad.addColorStop(stop[i].offset, stop[i].color);
Daniel@0 9854 }
Daniel@0 9855 return grad;
Daniel@0 9856 }
Daniel@0 9857
Daniel@0 9858 module.exports = {
Daniel@0 9859 drawOne: drawOne,
Daniel@0 9860 drawAll: drawAll,
Daniel@0 9861 pick: pick,
Daniel@0 9862 pickPath: pickPath,
Daniel@0 9863 testPath: testPath,
Daniel@0 9864 stroke: stroke,
Daniel@0 9865 fill: fill,
Daniel@0 9866 color: color,
Daniel@0 9867 gradient: gradient
Daniel@0 9868 };
Daniel@0 9869
Daniel@0 9870 },{}],68:[function(require,module,exports){
Daniel@0 9871 module.exports = {
Daniel@0 9872 'canvas': require('./canvas'),
Daniel@0 9873 'svg': require('./svg')
Daniel@0 9874 };
Daniel@0 9875
Daniel@0 9876 },{"./canvas":55,"./svg":72}],69:[function(require,module,exports){
Daniel@0 9877 var DOM = require('../../util/dom'),
Daniel@0 9878 Handler = require('../Handler');
Daniel@0 9879
Daniel@0 9880 function SVGHandler() {
Daniel@0 9881 Handler.call(this);
Daniel@0 9882 }
Daniel@0 9883
Daniel@0 9884 var base = Handler.prototype;
Daniel@0 9885 var prototype = (SVGHandler.prototype = Object.create(base));
Daniel@0 9886 prototype.constructor = SVGHandler;
Daniel@0 9887
Daniel@0 9888 prototype.initialize = function(el, pad, obj) {
Daniel@0 9889 this._svg = DOM.find(el, 'svg');
Daniel@0 9890 return base.initialize.call(this, el, pad, obj);
Daniel@0 9891 };
Daniel@0 9892
Daniel@0 9893 prototype.svg = function() {
Daniel@0 9894 return this._svg;
Daniel@0 9895 };
Daniel@0 9896
Daniel@0 9897 // wrap an event listener for the SVG DOM
Daniel@0 9898 prototype.listener = function(handler) {
Daniel@0 9899 var that = this;
Daniel@0 9900 return function(evt) {
Daniel@0 9901 var target = evt.target,
Daniel@0 9902 item = target.__data__;
Daniel@0 9903 evt.vegaType = evt.type;
Daniel@0 9904 item = Array.isArray(item) ? item[0] : item;
Daniel@0 9905 handler.call(that._obj, evt, item);
Daniel@0 9906 };
Daniel@0 9907 };
Daniel@0 9908
Daniel@0 9909 // add an event handler
Daniel@0 9910 prototype.on = function(type, handler) {
Daniel@0 9911 var name = this.eventName(type),
Daniel@0 9912 svg = this._svg,
Daniel@0 9913 h = this._handlers,
Daniel@0 9914 x = {
Daniel@0 9915 type: type,
Daniel@0 9916 handler: handler,
Daniel@0 9917 listener: this.listener(handler)
Daniel@0 9918 };
Daniel@0 9919
Daniel@0 9920 (h[name] || (h[name] = [])).push(x);
Daniel@0 9921 svg.addEventListener(name, x.listener);
Daniel@0 9922 return this;
Daniel@0 9923 };
Daniel@0 9924
Daniel@0 9925 // remove an event handler
Daniel@0 9926 prototype.off = function(type, handler) {
Daniel@0 9927 var name = this.eventName(type),
Daniel@0 9928 svg = this._svg,
Daniel@0 9929 h = this._handlers[name], i;
Daniel@0 9930 if (!h) return;
Daniel@0 9931 for (i=h.length; --i>=0;) {
Daniel@0 9932 if (h[i].type === type && !handler || h[i].handler === handler) {
Daniel@0 9933 svg.removeEventListener(name, h[i].listener);
Daniel@0 9934 h.splice(i, 1);
Daniel@0 9935 }
Daniel@0 9936 }
Daniel@0 9937 return this;
Daniel@0 9938 };
Daniel@0 9939
Daniel@0 9940 module.exports = SVGHandler;
Daniel@0 9941
Daniel@0 9942 },{"../../util/dom":81,"../Handler":51}],70:[function(require,module,exports){
Daniel@0 9943 var ImageLoader = require('../../util/ImageLoader'),
Daniel@0 9944 Renderer = require('../Renderer'),
Daniel@0 9945 text = require('../../util/text'),
Daniel@0 9946 DOM = require('../../util/dom'),
Daniel@0 9947 SVG = require('../../util/svg'),
Daniel@0 9948 ns = SVG.metadata.xmlns,
Daniel@0 9949 marks = require('./marks');
Daniel@0 9950
Daniel@0 9951 function SVGRenderer(loadConfig) {
Daniel@0 9952 Renderer.call(this);
Daniel@0 9953 this._loader = new ImageLoader(loadConfig);
Daniel@0 9954 this._dirtyID = 0;
Daniel@0 9955 }
Daniel@0 9956
Daniel@0 9957 var base = Renderer.prototype;
Daniel@0 9958 var prototype = (SVGRenderer.prototype = Object.create(base));
Daniel@0 9959 prototype.constructor = SVGRenderer;
Daniel@0 9960
Daniel@0 9961 prototype.initialize = function(el, width, height, padding) {
Daniel@0 9962 if (el) {
Daniel@0 9963 this._svg = DOM.child(el, 0, 'svg', ns, 'marks');
Daniel@0 9964 DOM.clear(el, 1);
Daniel@0 9965 // set the svg root group
Daniel@0 9966 this._root = DOM.child(this._svg, 0, 'g', ns);
Daniel@0 9967 DOM.clear(this._svg, 1);
Daniel@0 9968 }
Daniel@0 9969
Daniel@0 9970 // create the svg definitions cache
Daniel@0 9971 this._defs = {
Daniel@0 9972 clip_id: 1,
Daniel@0 9973 gradient: {},
Daniel@0 9974 clipping: {}
Daniel@0 9975 };
Daniel@0 9976
Daniel@0 9977 // set background color if defined
Daniel@0 9978 this.background(this._bgcolor);
Daniel@0 9979
Daniel@0 9980 return base.initialize.call(this, el, width, height, padding);
Daniel@0 9981 };
Daniel@0 9982
Daniel@0 9983 prototype.background = function(bgcolor) {
Daniel@0 9984 if (arguments.length && this._svg) {
Daniel@0 9985 this._svg.style.setProperty('background-color', bgcolor);
Daniel@0 9986 }
Daniel@0 9987 return base.background.apply(this, arguments);
Daniel@0 9988 };
Daniel@0 9989
Daniel@0 9990 prototype.resize = function(width, height, padding) {
Daniel@0 9991 base.resize.call(this, width, height, padding);
Daniel@0 9992
Daniel@0 9993 if (this._svg) {
Daniel@0 9994 var w = this._width,
Daniel@0 9995 h = this._height,
Daniel@0 9996 p = this._padding;
Daniel@0 9997
Daniel@0 9998 this._svg.setAttribute('width', w + p.left + p.right);
Daniel@0 9999 this._svg.setAttribute('height', h + p.top + p.bottom);
Daniel@0 10000
Daniel@0 10001 this._root.setAttribute('transform', 'translate('+p.left+','+p.top+')');
Daniel@0 10002 }
Daniel@0 10003
Daniel@0 10004 return this;
Daniel@0 10005 };
Daniel@0 10006
Daniel@0 10007 prototype.svg = function() {
Daniel@0 10008 if (!this._svg) return null;
Daniel@0 10009
Daniel@0 10010 var attr = {
Daniel@0 10011 'class': 'marks',
Daniel@0 10012 'width': this._width + this._padding.left + this._padding.right,
Daniel@0 10013 'height': this._height + this._padding.top + this._padding.bottom,
Daniel@0 10014 };
Daniel@0 10015 for (var key in SVG.metadata) {
Daniel@0 10016 attr[key] = SVG.metadata[key];
Daniel@0 10017 }
Daniel@0 10018
Daniel@0 10019 return DOM.openTag('svg', attr) + this._svg.innerHTML + DOM.closeTag('svg');
Daniel@0 10020 };
Daniel@0 10021
Daniel@0 10022 prototype.imageURL = function(url) {
Daniel@0 10023 return this._loader.imageURL(url);
Daniel@0 10024 };
Daniel@0 10025
Daniel@0 10026
Daniel@0 10027 // -- Render entry point --
Daniel@0 10028
Daniel@0 10029 prototype.render = function(scene, items) {
Daniel@0 10030 if (this._dirtyCheck(items)) {
Daniel@0 10031 if (this._dirtyAll) this._resetDefs();
Daniel@0 10032 this.draw(this._root, scene, -1);
Daniel@0 10033 DOM.clear(this._root, 1);
Daniel@0 10034 }
Daniel@0 10035 this.updateDefs();
Daniel@0 10036 return this;
Daniel@0 10037 };
Daniel@0 10038
Daniel@0 10039 prototype.draw = function(el, scene, index) {
Daniel@0 10040 this.drawMark(el, scene, index, marks[scene.marktype]);
Daniel@0 10041 };
Daniel@0 10042
Daniel@0 10043
Daniel@0 10044 // -- Manage SVG definitions ('defs') block --
Daniel@0 10045
Daniel@0 10046 prototype.updateDefs = function() {
Daniel@0 10047 var svg = this._svg,
Daniel@0 10048 defs = this._defs,
Daniel@0 10049 el = defs.el,
Daniel@0 10050 index = 0, id;
Daniel@0 10051
Daniel@0 10052 for (id in defs.gradient) {
Daniel@0 10053 if (!el) el = (defs.el = DOM.child(svg, 0, 'defs', ns));
Daniel@0 10054 updateGradient(el, defs.gradient[id], index++);
Daniel@0 10055 }
Daniel@0 10056
Daniel@0 10057 for (id in defs.clipping) {
Daniel@0 10058 if (!el) el = (defs.el = DOM.child(svg, 0, 'defs', ns));
Daniel@0 10059 updateClipping(el, defs.clipping[id], index++);
Daniel@0 10060 }
Daniel@0 10061
Daniel@0 10062 // clean-up
Daniel@0 10063 if (el) {
Daniel@0 10064 if (index === 0) {
Daniel@0 10065 svg.removeChild(el);
Daniel@0 10066 defs.el = null;
Daniel@0 10067 } else {
Daniel@0 10068 DOM.clear(el, index);
Daniel@0 10069 }
Daniel@0 10070 }
Daniel@0 10071 };
Daniel@0 10072
Daniel@0 10073 function updateGradient(el, grad, index) {
Daniel@0 10074 var i, n, stop;
Daniel@0 10075
Daniel@0 10076 el = DOM.child(el, index, 'linearGradient', ns);
Daniel@0 10077 el.setAttribute('id', grad.id);
Daniel@0 10078 el.setAttribute('x1', grad.x1);
Daniel@0 10079 el.setAttribute('x2', grad.x2);
Daniel@0 10080 el.setAttribute('y1', grad.y1);
Daniel@0 10081 el.setAttribute('y2', grad.y2);
Daniel@0 10082
Daniel@0 10083 for (i=0, n=grad.stops.length; i<n; ++i) {
Daniel@0 10084 stop = DOM.child(el, i, 'stop', ns);
Daniel@0 10085 stop.setAttribute('offset', grad.stops[i].offset);
Daniel@0 10086 stop.setAttribute('stop-color', grad.stops[i].color);
Daniel@0 10087 }
Daniel@0 10088 DOM.clear(el, i);
Daniel@0 10089 }
Daniel@0 10090
Daniel@0 10091 function updateClipping(el, clip, index) {
Daniel@0 10092 var rect;
Daniel@0 10093
Daniel@0 10094 el = DOM.child(el, index, 'clipPath', ns);
Daniel@0 10095 el.setAttribute('id', clip.id);
Daniel@0 10096 rect = DOM.child(el, 0, 'rect', ns);
Daniel@0 10097 rect.setAttribute('x', 0);
Daniel@0 10098 rect.setAttribute('y', 0);
Daniel@0 10099 rect.setAttribute('width', clip.width);
Daniel@0 10100 rect.setAttribute('height', clip.height);
Daniel@0 10101 }
Daniel@0 10102
Daniel@0 10103 prototype._resetDefs = function() {
Daniel@0 10104 var def = this._defs;
Daniel@0 10105 def.clip_id = 1;
Daniel@0 10106 def.gradient = {};
Daniel@0 10107 def.clipping = {};
Daniel@0 10108 };
Daniel@0 10109
Daniel@0 10110
Daniel@0 10111 // -- Manage rendering of items marked as dirty --
Daniel@0 10112
Daniel@0 10113 prototype.isDirty = function(item) {
Daniel@0 10114 return this._dirtyAll || item.dirty === this._dirtyID;
Daniel@0 10115 };
Daniel@0 10116
Daniel@0 10117 prototype._dirtyCheck = function(items) {
Daniel@0 10118 this._dirtyAll = true;
Daniel@0 10119 if (!items) return true;
Daniel@0 10120
Daniel@0 10121 var id = ++this._dirtyID,
Daniel@0 10122 item, mark, type, mdef, i, n, o;
Daniel@0 10123
Daniel@0 10124 for (i=0, n=items.length; i<n; ++i) {
Daniel@0 10125 item = items[i];
Daniel@0 10126 mark = item.mark;
Daniel@0 10127 if (mark.marktype !== type) {
Daniel@0 10128 // memoize mark instance lookup
Daniel@0 10129 type = mark.marktype;
Daniel@0 10130 mdef = marks[type];
Daniel@0 10131 }
Daniel@0 10132
Daniel@0 10133 if (item.status === 'exit') { // EXIT
Daniel@0 10134 if (item._svg) {
Daniel@0 10135 if (mdef.nest && item.mark.items.length) {
Daniel@0 10136 // if nested mark with remaining points, update instead
Daniel@0 10137 this._update(mdef, item._svg, item.mark.items[0]);
Daniel@0 10138 o = item.mark.items[0];
Daniel@0 10139 o._svg = item._svg;
Daniel@0 10140 o._update = id;
Daniel@0 10141 } else {
Daniel@0 10142 // otherwise remove from DOM
Daniel@0 10143 DOM.remove(item._svg);
Daniel@0 10144 }
Daniel@0 10145 item._svg = null;
Daniel@0 10146 }
Daniel@0 10147 continue;
Daniel@0 10148 }
Daniel@0 10149
Daniel@0 10150 item = (mdef.nest ? mark.items[0] : item);
Daniel@0 10151 if (item._update === id) { // Already processed
Daniel@0 10152 continue;
Daniel@0 10153 } else if (item._svg) { // UPDATE
Daniel@0 10154 this._update(mdef, item._svg, item);
Daniel@0 10155 } else { // ENTER
Daniel@0 10156 this._dirtyAll = false;
Daniel@0 10157 dirtyParents(item, id);
Daniel@0 10158 }
Daniel@0 10159 item._update = id;
Daniel@0 10160 }
Daniel@0 10161 return !this._dirtyAll;
Daniel@0 10162 };
Daniel@0 10163
Daniel@0 10164 function dirtyParents(item, id) {
Daniel@0 10165 for (; item && item.dirty !== id; item=item.mark.group) {
Daniel@0 10166 item.dirty = id;
Daniel@0 10167 if (item.mark && item.mark.dirty !== id) {
Daniel@0 10168 item.mark.dirty = id;
Daniel@0 10169 } else return;
Daniel@0 10170 }
Daniel@0 10171 }
Daniel@0 10172
Daniel@0 10173
Daniel@0 10174 // -- Construct & maintain scenegraph to SVG mapping ---
Daniel@0 10175
Daniel@0 10176 // Draw a mark container.
Daniel@0 10177 prototype.drawMark = function(el, scene, index, mdef) {
Daniel@0 10178 if (!this.isDirty(scene)) return;
Daniel@0 10179
Daniel@0 10180 var items = mdef.nest ?
Daniel@0 10181 (scene.items && scene.items.length ? [scene.items[0]] : []) :
Daniel@0 10182 scene.items || [],
Daniel@0 10183 events = scene.interactive === false ? 'none' : null,
Daniel@0 10184 isGroup = (mdef.tag === 'g'),
Daniel@0 10185 className = DOM.cssClass(scene),
Daniel@0 10186 p, i, n, c, d, insert;
Daniel@0 10187
Daniel@0 10188 p = DOM.child(el, index+1, 'g', ns, className);
Daniel@0 10189 p.setAttribute('class', className);
Daniel@0 10190 scene._svg = p;
Daniel@0 10191 if (!isGroup && events) {
Daniel@0 10192 p.style.setProperty('pointer-events', events);
Daniel@0 10193 }
Daniel@0 10194
Daniel@0 10195 for (i=0, n=items.length; i<n; ++i) {
Daniel@0 10196 if (this.isDirty(d = items[i])) {
Daniel@0 10197 insert = !(this._dirtyAll || d._svg);
Daniel@0 10198 c = insert ? bind(p, mdef, d, i, true)
Daniel@0 10199 : (p.childNodes[i] || bind(p, mdef, d, i));
Daniel@0 10200 this._update(mdef, c, d);
Daniel@0 10201 if (isGroup) {
Daniel@0 10202 if (insert) this._dirtyAll = true;
Daniel@0 10203 this._recurse(c, d);
Daniel@0 10204 if (insert) this._dirtyAll = false;
Daniel@0 10205 }
Daniel@0 10206 }
Daniel@0 10207 }
Daniel@0 10208 DOM.clear(p, i);
Daniel@0 10209 return p;
Daniel@0 10210 };
Daniel@0 10211
Daniel@0 10212 // Recursively process group contents.
Daniel@0 10213 prototype._recurse = function(el, group) {
Daniel@0 10214 var items = group.items || [],
Daniel@0 10215 legends = group.legendItems || [],
Daniel@0 10216 axes = group.axisItems || [],
Daniel@0 10217 idx = 0, j, m;
Daniel@0 10218
Daniel@0 10219 for (j=0, m=axes.length; j<m; ++j) {
Daniel@0 10220 if (axes[j].layer === 'back') {
Daniel@0 10221 this.drawMark(el, axes[j], idx++, marks.group);
Daniel@0 10222 }
Daniel@0 10223 }
Daniel@0 10224 for (j=0, m=items.length; j<m; ++j) {
Daniel@0 10225 this.draw(el, items[j], idx++);
Daniel@0 10226 }
Daniel@0 10227 for (j=0, m=axes.length; j<m; ++j) {
Daniel@0 10228 if (axes[j].layer !== 'back') {
Daniel@0 10229 this.drawMark(el, axes[j], idx++, marks.group);
Daniel@0 10230 }
Daniel@0 10231 }
Daniel@0 10232 for (j=0, m=legends.length; j<m; ++j) {
Daniel@0 10233 this.drawMark(el, legends[j], idx++, marks.group);
Daniel@0 10234 }
Daniel@0 10235
Daniel@0 10236 // remove any extraneous DOM elements
Daniel@0 10237 DOM.clear(el, 1 + idx);
Daniel@0 10238 };
Daniel@0 10239
Daniel@0 10240 // Bind a scenegraph item to an SVG DOM element.
Daniel@0 10241 // Create new SVG elements as needed.
Daniel@0 10242 function bind(el, mdef, item, index, insert) {
Daniel@0 10243 // create svg element, bind item data for D3 compatibility
Daniel@0 10244 var node = DOM.child(el, index, mdef.tag, ns, null, insert);
Daniel@0 10245 node.__data__ = item;
Daniel@0 10246 node.__values__ = {fill: 'default'};
Daniel@0 10247
Daniel@0 10248 // create background rect
Daniel@0 10249 if (mdef.tag === 'g') {
Daniel@0 10250 var bg = DOM.child(node, 0, 'rect', ns, 'background');
Daniel@0 10251 bg.__data__ = item;
Daniel@0 10252 }
Daniel@0 10253
Daniel@0 10254 // add pointer from scenegraph item to svg element
Daniel@0 10255 return (item._svg = node);
Daniel@0 10256 }
Daniel@0 10257
Daniel@0 10258
Daniel@0 10259 // -- Set attributes & styles on SVG elements ---
Daniel@0 10260
Daniel@0 10261 var href = (typeof window !== 'undefined' ? window.location.href : ''),
Daniel@0 10262 element = null, // temp var for current SVG element
Daniel@0 10263 values = null; // temp var for current values hash
Daniel@0 10264
Daniel@0 10265 // Extra configuration for certain mark types
Daniel@0 10266 var mark_extras = {
Daniel@0 10267 group: function(mdef, el, item) {
Daniel@0 10268 element = el.childNodes[0];
Daniel@0 10269 values = el.__values__; // use parent's values hash
Daniel@0 10270 mdef.background(emit, item, this);
Daniel@0 10271
Daniel@0 10272 var value = item.mark.interactive === false ? 'none' : null;
Daniel@0 10273 if (value !== values.events) {
Daniel@0 10274 element.style.setProperty('pointer-events', value);
Daniel@0 10275 values.events = value;
Daniel@0 10276 }
Daniel@0 10277 },
Daniel@0 10278 text: function(mdef, el, item) {
Daniel@0 10279 var str = text.value(item.text);
Daniel@0 10280 if (str !== values.text) {
Daniel@0 10281 el.textContent = str;
Daniel@0 10282 values.text = str;
Daniel@0 10283 }
Daniel@0 10284 str = text.font(item);
Daniel@0 10285 if (str !== values.font) {
Daniel@0 10286 el.style.setProperty('font', str);
Daniel@0 10287 values.font = str;
Daniel@0 10288 }
Daniel@0 10289 }
Daniel@0 10290 };
Daniel@0 10291
Daniel@0 10292 prototype._update = function(mdef, el, item) {
Daniel@0 10293 // set dom element and values cache
Daniel@0 10294 // provides access to emit method
Daniel@0 10295 element = el;
Daniel@0 10296 values = el.__values__;
Daniel@0 10297
Daniel@0 10298 // apply svg attributes
Daniel@0 10299 mdef.attr(emit, item, this);
Daniel@0 10300
Daniel@0 10301 // some marks need special treatment
Daniel@0 10302 var extra = mark_extras[mdef.type];
Daniel@0 10303 if (extra) extra(mdef, el, item);
Daniel@0 10304
Daniel@0 10305 // apply svg css styles
Daniel@0 10306 // note: element may be modified by 'extra' method
Daniel@0 10307 this.style(element, item);
Daniel@0 10308 };
Daniel@0 10309
Daniel@0 10310 function emit(name, value, ns) {
Daniel@0 10311 // early exit if value is unchanged
Daniel@0 10312 if (value === values[name]) return;
Daniel@0 10313
Daniel@0 10314 if (value != null) {
Daniel@0 10315 // if value is provided, update DOM attribute
Daniel@0 10316 if (ns) {
Daniel@0 10317 element.setAttributeNS(ns, name, value);
Daniel@0 10318 } else {
Daniel@0 10319 element.setAttribute(name, value);
Daniel@0 10320 }
Daniel@0 10321 } else {
Daniel@0 10322 // else remove DOM attribute
Daniel@0 10323 if (ns) {
Daniel@0 10324 element.removeAttributeNS(ns, name);
Daniel@0 10325 } else {
Daniel@0 10326 element.removeAttribute(name);
Daniel@0 10327 }
Daniel@0 10328 }
Daniel@0 10329
Daniel@0 10330 // note current value for future comparison
Daniel@0 10331 values[name] = value;
Daniel@0 10332 }
Daniel@0 10333
Daniel@0 10334 prototype.style = function(el, o) {
Daniel@0 10335 if (o == null) return;
Daniel@0 10336 var i, n, prop, name, value;
Daniel@0 10337
Daniel@0 10338 for (i=0, n=SVG.styleProperties.length; i<n; ++i) {
Daniel@0 10339 prop = SVG.styleProperties[i];
Daniel@0 10340 value = o[prop];
Daniel@0 10341 if (value === values[prop]) continue;
Daniel@0 10342
Daniel@0 10343 name = SVG.styles[prop];
Daniel@0 10344 if (value == null) {
Daniel@0 10345 if (name === 'fill') {
Daniel@0 10346 el.style.setProperty(name, 'none');
Daniel@0 10347 } else {
Daniel@0 10348 el.style.removeProperty(name);
Daniel@0 10349 }
Daniel@0 10350 } else {
Daniel@0 10351 if (value.id) {
Daniel@0 10352 // ensure definition is included
Daniel@0 10353 this._defs.gradient[value.id] = value;
Daniel@0 10354 value = 'url(' + href + '#' + value.id + ')';
Daniel@0 10355 }
Daniel@0 10356 el.style.setProperty(name, value+'');
Daniel@0 10357 }
Daniel@0 10358
Daniel@0 10359 values[prop] = value;
Daniel@0 10360 }
Daniel@0 10361 };
Daniel@0 10362
Daniel@0 10363 module.exports = SVGRenderer;
Daniel@0 10364
Daniel@0 10365 },{"../../util/ImageLoader":77,"../../util/dom":81,"../../util/svg":83,"../../util/text":84,"../Renderer":52,"./marks":73}],71:[function(require,module,exports){
Daniel@0 10366 var Renderer = require('../Renderer'),
Daniel@0 10367 ImageLoader = require('../../util/ImageLoader'),
Daniel@0 10368 SVG = require('../../util/svg'),
Daniel@0 10369 text = require('../../util/text'),
Daniel@0 10370 DOM = require('../../util/dom'),
Daniel@0 10371 openTag = DOM.openTag,
Daniel@0 10372 closeTag = DOM.closeTag,
Daniel@0 10373 MARKS = require('./marks');
Daniel@0 10374
Daniel@0 10375 function SVGStringRenderer(loadConfig) {
Daniel@0 10376 Renderer.call(this);
Daniel@0 10377
Daniel@0 10378 this._loader = new ImageLoader(loadConfig);
Daniel@0 10379
Daniel@0 10380 this._text = {
Daniel@0 10381 head: '',
Daniel@0 10382 root: '',
Daniel@0 10383 foot: '',
Daniel@0 10384 defs: '',
Daniel@0 10385 body: ''
Daniel@0 10386 };
Daniel@0 10387
Daniel@0 10388 this._defs = {
Daniel@0 10389 clip_id: 1,
Daniel@0 10390 gradient: {},
Daniel@0 10391 clipping: {}
Daniel@0 10392 };
Daniel@0 10393 }
Daniel@0 10394
Daniel@0 10395 var base = Renderer.prototype;
Daniel@0 10396 var prototype = (SVGStringRenderer.prototype = Object.create(base));
Daniel@0 10397 prototype.constructor = SVGStringRenderer;
Daniel@0 10398
Daniel@0 10399 prototype.resize = function(width, height, padding) {
Daniel@0 10400 base.resize.call(this, width, height, padding);
Daniel@0 10401 var p = this._padding,
Daniel@0 10402 t = this._text;
Daniel@0 10403
Daniel@0 10404 var attr = {
Daniel@0 10405 'class': 'marks',
Daniel@0 10406 'width': this._width + p.left + p.right,
Daniel@0 10407 'height': this._height + p.top + p.bottom,
Daniel@0 10408 };
Daniel@0 10409 for (var key in SVG.metadata) {
Daniel@0 10410 attr[key] = SVG.metadata[key];
Daniel@0 10411 }
Daniel@0 10412
Daniel@0 10413 t.head = openTag('svg', attr);
Daniel@0 10414 t.root = openTag('g', {
Daniel@0 10415 transform: 'translate(' + p.left + ',' + p.top + ')'
Daniel@0 10416 });
Daniel@0 10417 t.foot = closeTag('g') + closeTag('svg');
Daniel@0 10418
Daniel@0 10419 return this;
Daniel@0 10420 };
Daniel@0 10421
Daniel@0 10422 prototype.svg = function() {
Daniel@0 10423 var t = this._text;
Daniel@0 10424 return t.head + t.defs + t.root + t.body + t.foot;
Daniel@0 10425 };
Daniel@0 10426
Daniel@0 10427 prototype.render = function(scene) {
Daniel@0 10428 this._text.body = this.mark(scene);
Daniel@0 10429 this._text.defs = this.buildDefs();
Daniel@0 10430 return this;
Daniel@0 10431 };
Daniel@0 10432
Daniel@0 10433 prototype.reset = function() {
Daniel@0 10434 this._defs.clip_id = 0;
Daniel@0 10435 return this;
Daniel@0 10436 };
Daniel@0 10437
Daniel@0 10438 prototype.buildDefs = function() {
Daniel@0 10439 var all = this._defs,
Daniel@0 10440 defs = '',
Daniel@0 10441 i, id, def, stops;
Daniel@0 10442
Daniel@0 10443 for (id in all.gradient) {
Daniel@0 10444 def = all.gradient[id];
Daniel@0 10445 stops = def.stops;
Daniel@0 10446
Daniel@0 10447 defs += openTag('linearGradient', {
Daniel@0 10448 id: id,
Daniel@0 10449 x1: def.x1,
Daniel@0 10450 x2: def.x2,
Daniel@0 10451 y1: def.y1,
Daniel@0 10452 y2: def.y2
Daniel@0 10453 });
Daniel@0 10454
Daniel@0 10455 for (i=0; i<stops.length; ++i) {
Daniel@0 10456 defs += openTag('stop', {
Daniel@0 10457 offset: stops[i].offset,
Daniel@0 10458 'stop-color': stops[i].color
Daniel@0 10459 }) + closeTag('stop');
Daniel@0 10460 }
Daniel@0 10461
Daniel@0 10462 defs += closeTag('linearGradient');
Daniel@0 10463 }
Daniel@0 10464
Daniel@0 10465 for (id in all.clipping) {
Daniel@0 10466 def = all.clipping[id];
Daniel@0 10467
Daniel@0 10468 defs += openTag('clipPath', {id: id});
Daniel@0 10469
Daniel@0 10470 defs += openTag('rect', {
Daniel@0 10471 x: 0,
Daniel@0 10472 y: 0,
Daniel@0 10473 width: def.width,
Daniel@0 10474 height: def.height
Daniel@0 10475 }) + closeTag('rect');
Daniel@0 10476
Daniel@0 10477 defs += closeTag('clipPath');
Daniel@0 10478 }
Daniel@0 10479
Daniel@0 10480 return (defs.length > 0) ? openTag('defs') + defs + closeTag('defs') : '';
Daniel@0 10481 };
Daniel@0 10482
Daniel@0 10483 prototype.imageURL = function(url) {
Daniel@0 10484 return this._loader.imageURL(url);
Daniel@0 10485 };
Daniel@0 10486
Daniel@0 10487 var object;
Daniel@0 10488
Daniel@0 10489 function emit(name, value, ns, prefixed) {
Daniel@0 10490 object[prefixed || name] = value;
Daniel@0 10491 }
Daniel@0 10492
Daniel@0 10493 prototype.attributes = function(attr, item) {
Daniel@0 10494 object = {};
Daniel@0 10495 attr(emit, item, this);
Daniel@0 10496 return object;
Daniel@0 10497 };
Daniel@0 10498
Daniel@0 10499 prototype.mark = function(scene) {
Daniel@0 10500 var mdef = MARKS[scene.marktype],
Daniel@0 10501 tag = mdef.tag,
Daniel@0 10502 attr = mdef.attr,
Daniel@0 10503 nest = mdef.nest || false,
Daniel@0 10504 data = nest ?
Daniel@0 10505 (scene.items && scene.items.length ? [scene.items[0]] : []) :
Daniel@0 10506 (scene.items || []),
Daniel@0 10507 defs = this._defs,
Daniel@0 10508 str = '',
Daniel@0 10509 style, i, item;
Daniel@0 10510
Daniel@0 10511 if (tag !== 'g' && scene.interactive === false) {
Daniel@0 10512 style = 'style="pointer-events: none;"';
Daniel@0 10513 }
Daniel@0 10514
Daniel@0 10515 // render opening group tag
Daniel@0 10516 str += openTag('g', {
Daniel@0 10517 'class': DOM.cssClass(scene)
Daniel@0 10518 }, style);
Daniel@0 10519
Daniel@0 10520 // render contained elements
Daniel@0 10521 for (i=0; i<data.length; ++i) {
Daniel@0 10522 item = data[i];
Daniel@0 10523 style = (tag !== 'g') ? styles(item, scene, tag, defs) : null;
Daniel@0 10524 str += openTag(tag, this.attributes(attr, item), style);
Daniel@0 10525 if (tag === 'text') {
Daniel@0 10526 str += escape_text(text.value(item.text));
Daniel@0 10527 } else if (tag === 'g') {
Daniel@0 10528 str += openTag('rect',
Daniel@0 10529 this.attributes(mdef.background, item),
Daniel@0 10530 styles(item, scene, 'bgrect', defs)) + closeTag('rect');
Daniel@0 10531 str += this.markGroup(item);
Daniel@0 10532 }
Daniel@0 10533 str += closeTag(tag);
Daniel@0 10534 }
Daniel@0 10535
Daniel@0 10536 // render closing group tag
Daniel@0 10537 return str + closeTag('g');
Daniel@0 10538 };
Daniel@0 10539
Daniel@0 10540 prototype.markGroup = function(scene) {
Daniel@0 10541 var str = '',
Daniel@0 10542 axes = scene.axisItems || [],
Daniel@0 10543 items = scene.items || [],
Daniel@0 10544 legends = scene.legendItems || [],
Daniel@0 10545 j, m;
Daniel@0 10546
Daniel@0 10547 for (j=0, m=axes.length; j<m; ++j) {
Daniel@0 10548 if (axes[j].layer === 'back') {
Daniel@0 10549 str += this.mark(axes[j]);
Daniel@0 10550 }
Daniel@0 10551 }
Daniel@0 10552 for (j=0, m=items.length; j<m; ++j) {
Daniel@0 10553 str += this.mark(items[j]);
Daniel@0 10554 }
Daniel@0 10555 for (j=0, m=axes.length; j<m; ++j) {
Daniel@0 10556 if (axes[j].layer !== 'back') {
Daniel@0 10557 str += this.mark(axes[j]);
Daniel@0 10558 }
Daniel@0 10559 }
Daniel@0 10560 for (j=0, m=legends.length; j<m; ++j) {
Daniel@0 10561 str += this.mark(legends[j]);
Daniel@0 10562 }
Daniel@0 10563
Daniel@0 10564 return str;
Daniel@0 10565 };
Daniel@0 10566
Daniel@0 10567 function styles(o, mark, tag, defs) {
Daniel@0 10568 if (o == null) return '';
Daniel@0 10569 var i, n, prop, name, value, s = '';
Daniel@0 10570
Daniel@0 10571 if (tag === 'bgrect' && mark.interactive === false) {
Daniel@0 10572 s += 'pointer-events: none;';
Daniel@0 10573 }
Daniel@0 10574
Daniel@0 10575 if (tag === 'text') {
Daniel@0 10576 s += 'font: ' + text.font(o) + ';';
Daniel@0 10577 }
Daniel@0 10578
Daniel@0 10579 for (i=0, n=SVG.styleProperties.length; i<n; ++i) {
Daniel@0 10580 prop = SVG.styleProperties[i];
Daniel@0 10581 name = SVG.styles[prop];
Daniel@0 10582 value = o[prop];
Daniel@0 10583
Daniel@0 10584 if (value == null) {
Daniel@0 10585 if (name === 'fill') {
Daniel@0 10586 s += (s.length ? ' ' : '') + 'fill: none;';
Daniel@0 10587 }
Daniel@0 10588 } else {
Daniel@0 10589 if (value.id) {
Daniel@0 10590 // ensure definition is included
Daniel@0 10591 defs.gradient[value.id] = value;
Daniel@0 10592 value = 'url(#' + value.id + ')';
Daniel@0 10593 }
Daniel@0 10594 s += (s.length ? ' ' : '') + name + ': ' + value + ';';
Daniel@0 10595 }
Daniel@0 10596 }
Daniel@0 10597
Daniel@0 10598 return s ? 'style="' + s + '"' : null;
Daniel@0 10599 }
Daniel@0 10600
Daniel@0 10601 function escape_text(s) {
Daniel@0 10602 return s.replace(/&/g, '&amp;')
Daniel@0 10603 .replace(/</g, '&lt;')
Daniel@0 10604 .replace(/>/g, '&gt;');
Daniel@0 10605 }
Daniel@0 10606
Daniel@0 10607 module.exports = SVGStringRenderer;
Daniel@0 10608
Daniel@0 10609 },{"../../util/ImageLoader":77,"../../util/dom":81,"../../util/svg":83,"../../util/text":84,"../Renderer":52,"./marks":73}],72:[function(require,module,exports){
Daniel@0 10610 module.exports = {
Daniel@0 10611 Handler: require('./SVGHandler'),
Daniel@0 10612 Renderer: require('./SVGRenderer'),
Daniel@0 10613 string: {
Daniel@0 10614 Renderer : require('./SVGStringRenderer')
Daniel@0 10615 }
Daniel@0 10616 };
Daniel@0 10617 },{"./SVGHandler":69,"./SVGRenderer":70,"./SVGStringRenderer":71}],73:[function(require,module,exports){
Daniel@0 10618 var text = require('../../util/text'),
Daniel@0 10619 SVG = require('../../util/svg'),
Daniel@0 10620 textAlign = SVG.textAlign,
Daniel@0 10621 path = SVG.path;
Daniel@0 10622
Daniel@0 10623 function translateItem(o) {
Daniel@0 10624 return translate(o.x || 0, o.y || 0);
Daniel@0 10625 }
Daniel@0 10626
Daniel@0 10627 function translate(x, y) {
Daniel@0 10628 return 'translate(' + x + ',' + y + ')';
Daniel@0 10629 }
Daniel@0 10630
Daniel@0 10631 module.exports = {
Daniel@0 10632 arc: {
Daniel@0 10633 tag: 'path',
Daniel@0 10634 type: 'arc',
Daniel@0 10635 attr: function(emit, o) {
Daniel@0 10636 emit('transform', translateItem(o));
Daniel@0 10637 emit('d', path.arc(o));
Daniel@0 10638 }
Daniel@0 10639 },
Daniel@0 10640 area: {
Daniel@0 10641 tag: 'path',
Daniel@0 10642 type: 'area',
Daniel@0 10643 nest: true,
Daniel@0 10644 attr: function(emit, o) {
Daniel@0 10645 var items = o.mark.items;
Daniel@0 10646 if (items.length) emit('d', path.area(items));
Daniel@0 10647 }
Daniel@0 10648 },
Daniel@0 10649 group: {
Daniel@0 10650 tag: 'g',
Daniel@0 10651 type: 'group',
Daniel@0 10652 attr: function(emit, o, renderer) {
Daniel@0 10653 var id = null, defs, c;
Daniel@0 10654 emit('transform', translateItem(o));
Daniel@0 10655 if (o.clip) {
Daniel@0 10656 defs = renderer._defs;
Daniel@0 10657 id = o.clip_id || (o.clip_id = 'clip' + defs.clip_id++);
Daniel@0 10658 c = defs.clipping[id] || (defs.clipping[id] = {id: id});
Daniel@0 10659 c.width = o.width || 0;
Daniel@0 10660 c.height = o.height || 0;
Daniel@0 10661 }
Daniel@0 10662 emit('clip-path', id ? ('url(#' + id + ')') : null);
Daniel@0 10663 },
Daniel@0 10664 background: function(emit, o) {
Daniel@0 10665 emit('class', 'background');
Daniel@0 10666 emit('width', o.width || 0);
Daniel@0 10667 emit('height', o.height || 0);
Daniel@0 10668 }
Daniel@0 10669 },
Daniel@0 10670 image: {
Daniel@0 10671 tag: 'image',
Daniel@0 10672 type: 'image',
Daniel@0 10673 attr: function(emit, o, renderer) {
Daniel@0 10674 var x = o.x || 0,
Daniel@0 10675 y = o.y || 0,
Daniel@0 10676 w = o.width || 0,
Daniel@0 10677 h = o.height || 0,
Daniel@0 10678 url = renderer.imageURL(o.url);
Daniel@0 10679
Daniel@0 10680 x = x - (o.align === 'center' ? w/2 : o.align === 'right' ? w : 0);
Daniel@0 10681 y = y - (o.baseline === 'middle' ? h/2 : o.baseline === 'bottom' ? h : 0);
Daniel@0 10682
Daniel@0 10683 emit('href', url, 'http://www.w3.org/1999/xlink', 'xlink:href');
Daniel@0 10684 emit('transform', translate(x, y));
Daniel@0 10685 emit('width', w);
Daniel@0 10686 emit('height', h);
Daniel@0 10687 }
Daniel@0 10688 },
Daniel@0 10689 line: {
Daniel@0 10690 tag: 'path',
Daniel@0 10691 type: 'line',
Daniel@0 10692 nest: true,
Daniel@0 10693 attr: function(emit, o) {
Daniel@0 10694 var items = o.mark.items;
Daniel@0 10695 if (items.length) emit('d', path.line(items));
Daniel@0 10696 }
Daniel@0 10697 },
Daniel@0 10698 path: {
Daniel@0 10699 tag: 'path',
Daniel@0 10700 type: 'path',
Daniel@0 10701 attr: function(emit, o) {
Daniel@0 10702 emit('transform', translateItem(o));
Daniel@0 10703 emit('d', o.path);
Daniel@0 10704 }
Daniel@0 10705 },
Daniel@0 10706 rect: {
Daniel@0 10707 tag: 'rect',
Daniel@0 10708 type: 'rect',
Daniel@0 10709 nest: false,
Daniel@0 10710 attr: function(emit, o) {
Daniel@0 10711 emit('transform', translateItem(o));
Daniel@0 10712 emit('width', o.width || 0);
Daniel@0 10713 emit('height', o.height || 0);
Daniel@0 10714 }
Daniel@0 10715 },
Daniel@0 10716 rule: {
Daniel@0 10717 tag: 'line',
Daniel@0 10718 type: 'rule',
Daniel@0 10719 attr: function(emit, o) {
Daniel@0 10720 emit('transform', translateItem(o));
Daniel@0 10721 emit('x2', o.x2 != null ? o.x2 - (o.x||0) : 0);
Daniel@0 10722 emit('y2', o.y2 != null ? o.y2 - (o.y||0) : 0);
Daniel@0 10723 }
Daniel@0 10724 },
Daniel@0 10725 symbol: {
Daniel@0 10726 tag: 'path',
Daniel@0 10727 type: 'symbol',
Daniel@0 10728 attr: function(emit, o) {
Daniel@0 10729 emit('transform', translateItem(o));
Daniel@0 10730 emit('d', path.symbol(o));
Daniel@0 10731 }
Daniel@0 10732 },
Daniel@0 10733 text: {
Daniel@0 10734 tag: 'text',
Daniel@0 10735 type: 'text',
Daniel@0 10736 nest: false,
Daniel@0 10737 attr: function(emit, o) {
Daniel@0 10738 var dx = (o.dx || 0),
Daniel@0 10739 dy = (o.dy || 0) + text.offset(o),
Daniel@0 10740 x = (o.x || 0),
Daniel@0 10741 y = (o.y || 0),
Daniel@0 10742 a = o.angle || 0,
Daniel@0 10743 r = o.radius || 0, t;
Daniel@0 10744
Daniel@0 10745 if (r) {
Daniel@0 10746 t = (o.theta || 0) - Math.PI/2;
Daniel@0 10747 x += r * Math.cos(t);
Daniel@0 10748 y += r * Math.sin(t);
Daniel@0 10749 }
Daniel@0 10750
Daniel@0 10751 emit('text-anchor', textAlign[o.align] || 'start');
Daniel@0 10752
Daniel@0 10753 if (a) {
Daniel@0 10754 t = translate(x, y) + ' rotate('+a+')';
Daniel@0 10755 if (dx || dy) t += ' ' + translate(dx, dy);
Daniel@0 10756 } else {
Daniel@0 10757 t = translate(x+dx, y+dy);
Daniel@0 10758 }
Daniel@0 10759 emit('transform', t);
Daniel@0 10760 }
Daniel@0 10761 }
Daniel@0 10762 };
Daniel@0 10763
Daniel@0 10764 },{"../../util/svg":83,"../../util/text":84}],74:[function(require,module,exports){
Daniel@0 10765 function Bounds(b) {
Daniel@0 10766 this.clear();
Daniel@0 10767 if (b) this.union(b);
Daniel@0 10768 }
Daniel@0 10769
Daniel@0 10770 var prototype = Bounds.prototype;
Daniel@0 10771
Daniel@0 10772 prototype.clone = function() {
Daniel@0 10773 return new Bounds(this);
Daniel@0 10774 };
Daniel@0 10775
Daniel@0 10776 prototype.clear = function() {
Daniel@0 10777 this.x1 = +Number.MAX_VALUE;
Daniel@0 10778 this.y1 = +Number.MAX_VALUE;
Daniel@0 10779 this.x2 = -Number.MAX_VALUE;
Daniel@0 10780 this.y2 = -Number.MAX_VALUE;
Daniel@0 10781 return this;
Daniel@0 10782 };
Daniel@0 10783
Daniel@0 10784 prototype.set = function(x1, y1, x2, y2) {
Daniel@0 10785 this.x1 = x1;
Daniel@0 10786 this.y1 = y1;
Daniel@0 10787 this.x2 = x2;
Daniel@0 10788 this.y2 = y2;
Daniel@0 10789 return this;
Daniel@0 10790 };
Daniel@0 10791
Daniel@0 10792 prototype.add = function(x, y) {
Daniel@0 10793 if (x < this.x1) this.x1 = x;
Daniel@0 10794 if (y < this.y1) this.y1 = y;
Daniel@0 10795 if (x > this.x2) this.x2 = x;
Daniel@0 10796 if (y > this.y2) this.y2 = y;
Daniel@0 10797 return this;
Daniel@0 10798 };
Daniel@0 10799
Daniel@0 10800 prototype.expand = function(d) {
Daniel@0 10801 this.x1 -= d;
Daniel@0 10802 this.y1 -= d;
Daniel@0 10803 this.x2 += d;
Daniel@0 10804 this.y2 += d;
Daniel@0 10805 return this;
Daniel@0 10806 };
Daniel@0 10807
Daniel@0 10808 prototype.round = function() {
Daniel@0 10809 this.x1 = Math.floor(this.x1);
Daniel@0 10810 this.y1 = Math.floor(this.y1);
Daniel@0 10811 this.x2 = Math.ceil(this.x2);
Daniel@0 10812 this.y2 = Math.ceil(this.y2);
Daniel@0 10813 return this;
Daniel@0 10814 };
Daniel@0 10815
Daniel@0 10816 prototype.translate = function(dx, dy) {
Daniel@0 10817 this.x1 += dx;
Daniel@0 10818 this.x2 += dx;
Daniel@0 10819 this.y1 += dy;
Daniel@0 10820 this.y2 += dy;
Daniel@0 10821 return this;
Daniel@0 10822 };
Daniel@0 10823
Daniel@0 10824 prototype.rotate = function(angle, x, y) {
Daniel@0 10825 var cos = Math.cos(angle),
Daniel@0 10826 sin = Math.sin(angle),
Daniel@0 10827 cx = x - x*cos + y*sin,
Daniel@0 10828 cy = y - x*sin - y*cos,
Daniel@0 10829 x1 = this.x1, x2 = this.x2,
Daniel@0 10830 y1 = this.y1, y2 = this.y2;
Daniel@0 10831
Daniel@0 10832 return this.clear()
Daniel@0 10833 .add(cos*x1 - sin*y1 + cx, sin*x1 + cos*y1 + cy)
Daniel@0 10834 .add(cos*x1 - sin*y2 + cx, sin*x1 + cos*y2 + cy)
Daniel@0 10835 .add(cos*x2 - sin*y1 + cx, sin*x2 + cos*y1 + cy)
Daniel@0 10836 .add(cos*x2 - sin*y2 + cx, sin*x2 + cos*y2 + cy);
Daniel@0 10837 };
Daniel@0 10838
Daniel@0 10839 prototype.union = function(b) {
Daniel@0 10840 if (b.x1 < this.x1) this.x1 = b.x1;
Daniel@0 10841 if (b.y1 < this.y1) this.y1 = b.y1;
Daniel@0 10842 if (b.x2 > this.x2) this.x2 = b.x2;
Daniel@0 10843 if (b.y2 > this.y2) this.y2 = b.y2;
Daniel@0 10844 return this;
Daniel@0 10845 };
Daniel@0 10846
Daniel@0 10847 prototype.encloses = function(b) {
Daniel@0 10848 return b && (
Daniel@0 10849 this.x1 <= b.x1 &&
Daniel@0 10850 this.x2 >= b.x2 &&
Daniel@0 10851 this.y1 <= b.y1 &&
Daniel@0 10852 this.y2 >= b.y2
Daniel@0 10853 );
Daniel@0 10854 };
Daniel@0 10855
Daniel@0 10856 prototype.intersects = function(b) {
Daniel@0 10857 return b && !(
Daniel@0 10858 this.x2 < b.x1 ||
Daniel@0 10859 this.x1 > b.x2 ||
Daniel@0 10860 this.y2 < b.y1 ||
Daniel@0 10861 this.y1 > b.y2
Daniel@0 10862 );
Daniel@0 10863 };
Daniel@0 10864
Daniel@0 10865 prototype.contains = function(x, y) {
Daniel@0 10866 return !(
Daniel@0 10867 x < this.x1 ||
Daniel@0 10868 x > this.x2 ||
Daniel@0 10869 y < this.y1 ||
Daniel@0 10870 y > this.y2
Daniel@0 10871 );
Daniel@0 10872 };
Daniel@0 10873
Daniel@0 10874 prototype.width = function() {
Daniel@0 10875 return this.x2 - this.x1;
Daniel@0 10876 };
Daniel@0 10877
Daniel@0 10878 prototype.height = function() {
Daniel@0 10879 return this.y2 - this.y1;
Daniel@0 10880 };
Daniel@0 10881
Daniel@0 10882 module.exports = Bounds;
Daniel@0 10883
Daniel@0 10884 },{}],75:[function(require,module,exports){
Daniel@0 10885 module.exports = function(b) {
Daniel@0 10886 function noop() { }
Daniel@0 10887 function add(x,y) { b.add(x, y); }
Daniel@0 10888
Daniel@0 10889 return {
Daniel@0 10890 bounds: function(_) {
Daniel@0 10891 if (!arguments.length) return b;
Daniel@0 10892 return (b = _, this);
Daniel@0 10893 },
Daniel@0 10894 beginPath: noop,
Daniel@0 10895 closePath: noop,
Daniel@0 10896 moveTo: add,
Daniel@0 10897 lineTo: add,
Daniel@0 10898 quadraticCurveTo: function(x1, y1, x2, y2) {
Daniel@0 10899 b.add(x1, y1);
Daniel@0 10900 b.add(x2, y2);
Daniel@0 10901 },
Daniel@0 10902 bezierCurveTo: function(x1, y1, x2, y2, x3, y3) {
Daniel@0 10903 b.add(x1, y1);
Daniel@0 10904 b.add(x2, y2);
Daniel@0 10905 b.add(x3, y3);
Daniel@0 10906 }
Daniel@0 10907 };
Daniel@0 10908 };
Daniel@0 10909
Daniel@0 10910 },{}],76:[function(require,module,exports){
Daniel@0 10911 var gradient_id = 0;
Daniel@0 10912
Daniel@0 10913 function Gradient(type) {
Daniel@0 10914 this.id = 'gradient_' + (gradient_id++);
Daniel@0 10915 this.type = type || 'linear';
Daniel@0 10916 this.stops = [];
Daniel@0 10917 this.x1 = 0;
Daniel@0 10918 this.x2 = 1;
Daniel@0 10919 this.y1 = 0;
Daniel@0 10920 this.y2 = 0;
Daniel@0 10921 }
Daniel@0 10922
Daniel@0 10923 var prototype = Gradient.prototype;
Daniel@0 10924
Daniel@0 10925 prototype.stop = function(offset, color) {
Daniel@0 10926 this.stops.push({
Daniel@0 10927 offset: offset,
Daniel@0 10928 color: color
Daniel@0 10929 });
Daniel@0 10930 return this;
Daniel@0 10931 };
Daniel@0 10932
Daniel@0 10933 module.exports = Gradient;
Daniel@0 10934 },{}],77:[function(require,module,exports){
Daniel@0 10935 (function (global){
Daniel@0 10936 var load = require('datalib/src/import/load');
Daniel@0 10937
Daniel@0 10938 function ImageLoader(loadConfig) {
Daniel@0 10939 this._pending = 0;
Daniel@0 10940 this._config = loadConfig || ImageLoader.Config;
Daniel@0 10941 }
Daniel@0 10942
Daniel@0 10943 // Overridable global default load configuration
Daniel@0 10944 ImageLoader.Config = null;
Daniel@0 10945
Daniel@0 10946 var prototype = ImageLoader.prototype;
Daniel@0 10947
Daniel@0 10948 prototype.pending = function() {
Daniel@0 10949 return this._pending;
Daniel@0 10950 };
Daniel@0 10951
Daniel@0 10952 prototype.params = function(uri) {
Daniel@0 10953 var p = {url: uri}, k;
Daniel@0 10954 for (k in this._config) { p[k] = this._config[k]; }
Daniel@0 10955 return p;
Daniel@0 10956 };
Daniel@0 10957
Daniel@0 10958 prototype.imageURL = function(uri) {
Daniel@0 10959 return load.sanitizeUrl(this.params(uri));
Daniel@0 10960 };
Daniel@0 10961
Daniel@0 10962 function browser(uri, callback) {
Daniel@0 10963 var url = load.sanitizeUrl(this.params(uri));
Daniel@0 10964 if (!url) { // error
Daniel@0 10965 if (callback) callback(uri, null);
Daniel@0 10966 return null;
Daniel@0 10967 }
Daniel@0 10968
Daniel@0 10969 var loader = this,
Daniel@0 10970 image = new Image();
Daniel@0 10971
Daniel@0 10972 loader._pending += 1;
Daniel@0 10973
Daniel@0 10974 image.onload = function() {
Daniel@0 10975 loader._pending -= 1;
Daniel@0 10976 image.loaded = true;
Daniel@0 10977 if (callback) callback(null, image);
Daniel@0 10978 };
Daniel@0 10979 image.src = url;
Daniel@0 10980
Daniel@0 10981 return image;
Daniel@0 10982 }
Daniel@0 10983
Daniel@0 10984 function server(uri, callback) {
Daniel@0 10985 var loader = this,
Daniel@0 10986 image = new ((typeof window !== "undefined" ? window['canvas'] : typeof global !== "undefined" ? global['canvas'] : null).Image)();
Daniel@0 10987
Daniel@0 10988 loader._pending += 1;
Daniel@0 10989
Daniel@0 10990 load(this.params(uri), function(err, data) {
Daniel@0 10991 loader._pending -= 1;
Daniel@0 10992 if (err) {
Daniel@0 10993 if (callback) callback(err, null);
Daniel@0 10994 return null;
Daniel@0 10995 }
Daniel@0 10996 image.src = data;
Daniel@0 10997 image.loaded = true;
Daniel@0 10998 if (callback) callback(null, image);
Daniel@0 10999 });
Daniel@0 11000
Daniel@0 11001 return image;
Daniel@0 11002 }
Daniel@0 11003
Daniel@0 11004 prototype.loadImage = function(uri, callback) {
Daniel@0 11005 return load.useXHR ?
Daniel@0 11006 browser.call(this, uri, callback) :
Daniel@0 11007 server.call(this, uri, callback);
Daniel@0 11008 };
Daniel@0 11009
Daniel@0 11010 module.exports = ImageLoader;
Daniel@0 11011
Daniel@0 11012 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
Daniel@0 11013
Daniel@0 11014 },{"datalib/src/import/load":20}],78:[function(require,module,exports){
Daniel@0 11015 function Item(mark) {
Daniel@0 11016 this.mark = mark;
Daniel@0 11017 }
Daniel@0 11018
Daniel@0 11019 var prototype = Item.prototype;
Daniel@0 11020
Daniel@0 11021 prototype.hasPropertySet = function(name) {
Daniel@0 11022 var props = this.mark.def.properties;
Daniel@0 11023 return props && props[name] != null;
Daniel@0 11024 };
Daniel@0 11025
Daniel@0 11026 prototype.cousin = function(offset, index) {
Daniel@0 11027 if (offset === 0) return this;
Daniel@0 11028 offset = offset || -1;
Daniel@0 11029 var mark = this.mark,
Daniel@0 11030 group = mark.group,
Daniel@0 11031 iidx = index==null ? mark.items.indexOf(this) : index,
Daniel@0 11032 midx = group.items.indexOf(mark) + offset;
Daniel@0 11033 return group.items[midx].items[iidx];
Daniel@0 11034 };
Daniel@0 11035
Daniel@0 11036 prototype.sibling = function(offset) {
Daniel@0 11037 if (offset === 0) return this;
Daniel@0 11038 offset = offset || -1;
Daniel@0 11039 var mark = this.mark,
Daniel@0 11040 iidx = mark.items.indexOf(this) + offset;
Daniel@0 11041 return mark.items[iidx];
Daniel@0 11042 };
Daniel@0 11043
Daniel@0 11044 prototype.remove = function() {
Daniel@0 11045 var item = this,
Daniel@0 11046 list = item.mark.items,
Daniel@0 11047 i = list.indexOf(item);
Daniel@0 11048 if (i >= 0) {
Daniel@0 11049 if (i===list.length-1) {
Daniel@0 11050 list.pop();
Daniel@0 11051 } else {
Daniel@0 11052 list.splice(i, 1);
Daniel@0 11053 }
Daniel@0 11054 }
Daniel@0 11055 return item;
Daniel@0 11056 };
Daniel@0 11057
Daniel@0 11058 prototype.touch = function() {
Daniel@0 11059 if (this.pathCache) this.pathCache = null;
Daniel@0 11060 };
Daniel@0 11061
Daniel@0 11062 module.exports = Item;
Daniel@0 11063 },{}],79:[function(require,module,exports){
Daniel@0 11064 var BoundsContext = require('./BoundsContext'),
Daniel@0 11065 Bounds = require('./Bounds'),
Daniel@0 11066 canvas = require('./canvas'),
Daniel@0 11067 svg = require('./svg'),
Daniel@0 11068 text = require('./text'),
Daniel@0 11069 paths = require('../path'),
Daniel@0 11070 parse = paths.parse,
Daniel@0 11071 drawPath = paths.render,
Daniel@0 11072 areaPath = svg.path.area,
Daniel@0 11073 linePath = svg.path.line,
Daniel@0 11074 halfpi = Math.PI / 2,
Daniel@0 11075 sqrt3 = Math.sqrt(3),
Daniel@0 11076 tan30 = Math.tan(30 * Math.PI / 180),
Daniel@0 11077 g2D = null,
Daniel@0 11078 bc = BoundsContext();
Daniel@0 11079
Daniel@0 11080 function context() {
Daniel@0 11081 return g2D || (g2D = canvas.instance(1,1).getContext('2d'));
Daniel@0 11082 }
Daniel@0 11083
Daniel@0 11084 function strokeBounds(o, bounds) {
Daniel@0 11085 if (o.stroke && o.opacity !== 0 && o.stokeOpacity !== 0) {
Daniel@0 11086 bounds.expand(o.strokeWidth != null ? o.strokeWidth : 1);
Daniel@0 11087 }
Daniel@0 11088 return bounds;
Daniel@0 11089 }
Daniel@0 11090
Daniel@0 11091 function pathBounds(o, path, bounds, x, y) {
Daniel@0 11092 if (path == null) {
Daniel@0 11093 bounds.set(0, 0, 0, 0);
Daniel@0 11094 } else {
Daniel@0 11095 drawPath(bc.bounds(bounds), path, x, y);
Daniel@0 11096 strokeBounds(o, bounds);
Daniel@0 11097 }
Daniel@0 11098 return bounds;
Daniel@0 11099 }
Daniel@0 11100
Daniel@0 11101 function path(o, bounds) {
Daniel@0 11102 var p = o.path ? o.pathCache || (o.pathCache = parse(o.path)) : null;
Daniel@0 11103 return pathBounds(o, p, bounds, o.x, o.y);
Daniel@0 11104 }
Daniel@0 11105
Daniel@0 11106 function area(mark, bounds) {
Daniel@0 11107 if (mark.items.length === 0) return bounds;
Daniel@0 11108 var items = mark.items,
Daniel@0 11109 item = items[0],
Daniel@0 11110 p = item.pathCache || (item.pathCache = parse(areaPath(items)));
Daniel@0 11111 return pathBounds(item, p, bounds);
Daniel@0 11112 }
Daniel@0 11113
Daniel@0 11114 function line(mark, bounds) {
Daniel@0 11115 if (mark.items.length === 0) return bounds;
Daniel@0 11116 var items = mark.items,
Daniel@0 11117 item = items[0],
Daniel@0 11118 p = item.pathCache || (item.pathCache = parse(linePath(items)));
Daniel@0 11119 return pathBounds(item, p, bounds);
Daniel@0 11120 }
Daniel@0 11121
Daniel@0 11122 function rect(o, bounds) {
Daniel@0 11123 var x, y;
Daniel@0 11124 return strokeBounds(o, bounds.set(
Daniel@0 11125 x = o.x || 0,
Daniel@0 11126 y = o.y || 0,
Daniel@0 11127 (x + o.width) || 0,
Daniel@0 11128 (y + o.height) || 0
Daniel@0 11129 ));
Daniel@0 11130 }
Daniel@0 11131
Daniel@0 11132 function image(o, bounds) {
Daniel@0 11133 var x = o.x || 0,
Daniel@0 11134 y = o.y || 0,
Daniel@0 11135 w = o.width || 0,
Daniel@0 11136 h = o.height || 0;
Daniel@0 11137 x = x - (o.align === 'center' ? w/2 : (o.align === 'right' ? w : 0));
Daniel@0 11138 y = y - (o.baseline === 'middle' ? h/2 : (o.baseline === 'bottom' ? h : 0));
Daniel@0 11139 return bounds.set(x, y, x+w, y+h);
Daniel@0 11140 }
Daniel@0 11141
Daniel@0 11142 function rule(o, bounds) {
Daniel@0 11143 var x1, y1;
Daniel@0 11144 return strokeBounds(o, bounds.set(
Daniel@0 11145 x1 = o.x || 0,
Daniel@0 11146 y1 = o.y || 0,
Daniel@0 11147 o.x2 != null ? o.x2 : x1,
Daniel@0 11148 o.y2 != null ? o.y2 : y1
Daniel@0 11149 ));
Daniel@0 11150 }
Daniel@0 11151
Daniel@0 11152 function arc(o, bounds) {
Daniel@0 11153 var cx = o.x || 0,
Daniel@0 11154 cy = o.y || 0,
Daniel@0 11155 ir = o.innerRadius || 0,
Daniel@0 11156 or = o.outerRadius || 0,
Daniel@0 11157 sa = (o.startAngle || 0) - halfpi,
Daniel@0 11158 ea = (o.endAngle || 0) - halfpi,
Daniel@0 11159 xmin = Infinity, xmax = -Infinity,
Daniel@0 11160 ymin = Infinity, ymax = -Infinity,
Daniel@0 11161 a, i, n, x, y, ix, iy, ox, oy;
Daniel@0 11162
Daniel@0 11163 var angles = [sa, ea],
Daniel@0 11164 s = sa - (sa % halfpi);
Daniel@0 11165 for (i=0; i<4 && s<ea; ++i, s+=halfpi) {
Daniel@0 11166 angles.push(s);
Daniel@0 11167 }
Daniel@0 11168
Daniel@0 11169 for (i=0, n=angles.length; i<n; ++i) {
Daniel@0 11170 a = angles[i];
Daniel@0 11171 x = Math.cos(a); ix = ir*x; ox = or*x;
Daniel@0 11172 y = Math.sin(a); iy = ir*y; oy = or*y;
Daniel@0 11173 xmin = Math.min(xmin, ix, ox);
Daniel@0 11174 xmax = Math.max(xmax, ix, ox);
Daniel@0 11175 ymin = Math.min(ymin, iy, oy);
Daniel@0 11176 ymax = Math.max(ymax, iy, oy);
Daniel@0 11177 }
Daniel@0 11178
Daniel@0 11179 return strokeBounds(o, bounds.set(
Daniel@0 11180 cx + xmin,
Daniel@0 11181 cy + ymin,
Daniel@0 11182 cx + xmax,
Daniel@0 11183 cy + ymax
Daniel@0 11184 ));
Daniel@0 11185 }
Daniel@0 11186
Daniel@0 11187 function symbol(o, bounds) {
Daniel@0 11188 var size = o.size != null ? o.size : 100,
Daniel@0 11189 x = o.x || 0,
Daniel@0 11190 y = o.y || 0,
Daniel@0 11191 r, t, rx, ry;
Daniel@0 11192
Daniel@0 11193 switch (o.shape) {
Daniel@0 11194 case 'cross':
Daniel@0 11195 t = 3 * Math.sqrt(size / 5) / 2;
Daniel@0 11196 bounds.set(x-t, y-t, x+t, y+t);
Daniel@0 11197 break;
Daniel@0 11198
Daniel@0 11199 case 'diamond':
Daniel@0 11200 ry = Math.sqrt(size / (2 * tan30));
Daniel@0 11201 rx = ry * tan30;
Daniel@0 11202 bounds.set(x-rx, y-ry, x+rx, y+ry);
Daniel@0 11203 break;
Daniel@0 11204
Daniel@0 11205 case 'square':
Daniel@0 11206 t = Math.sqrt(size);
Daniel@0 11207 r = t / 2;
Daniel@0 11208 bounds.set(x-r, y-r, x+r, y+r);
Daniel@0 11209 break;
Daniel@0 11210
Daniel@0 11211 case 'triangle-down':
Daniel@0 11212 rx = Math.sqrt(size / sqrt3);
Daniel@0 11213 ry = rx * sqrt3 / 2;
Daniel@0 11214 bounds.set(x-rx, y-ry, x+rx, y+ry);
Daniel@0 11215 break;
Daniel@0 11216
Daniel@0 11217 case 'triangle-up':
Daniel@0 11218 rx = Math.sqrt(size / sqrt3);
Daniel@0 11219 ry = rx * sqrt3 / 2;
Daniel@0 11220 bounds.set(x-rx, y-ry, x+rx, y+ry);
Daniel@0 11221 break;
Daniel@0 11222
Daniel@0 11223 default:
Daniel@0 11224 r = Math.sqrt(size/Math.PI);
Daniel@0 11225 bounds.set(x-r, y-r, x+r, y+r);
Daniel@0 11226 }
Daniel@0 11227
Daniel@0 11228 return strokeBounds(o, bounds);
Daniel@0 11229 }
Daniel@0 11230
Daniel@0 11231 function textMark(o, bounds, noRotate) {
Daniel@0 11232 var g = context(),
Daniel@0 11233 h = text.size(o),
Daniel@0 11234 a = o.align,
Daniel@0 11235 r = o.radius || 0,
Daniel@0 11236 x = (o.x || 0),
Daniel@0 11237 y = (o.y || 0),
Daniel@0 11238 dx = (o.dx || 0),
Daniel@0 11239 dy = (o.dy || 0) + text.offset(o) - Math.round(0.8*h), // use 4/5 offset
Daniel@0 11240 w, t;
Daniel@0 11241
Daniel@0 11242 if (r) {
Daniel@0 11243 t = (o.theta || 0) - Math.PI/2;
Daniel@0 11244 x += r * Math.cos(t);
Daniel@0 11245 y += r * Math.sin(t);
Daniel@0 11246 }
Daniel@0 11247
Daniel@0 11248 // horizontal alignment
Daniel@0 11249 g.font = text.font(o);
Daniel@0 11250 w = g.measureText(text.value(o.text)).width;
Daniel@0 11251 if (a === 'center') {
Daniel@0 11252 dx -= (w / 2);
Daniel@0 11253 } else if (a === 'right') {
Daniel@0 11254 dx -= w;
Daniel@0 11255 } else {
Daniel@0 11256 // left by default, do nothing
Daniel@0 11257 }
Daniel@0 11258
Daniel@0 11259 bounds.set(dx+=x, dy+=y, dx+w, dy+h);
Daniel@0 11260 if (o.angle && !noRotate) {
Daniel@0 11261 bounds.rotate(o.angle*Math.PI/180, x, y);
Daniel@0 11262 }
Daniel@0 11263 return bounds.expand(noRotate ? 0 : 1);
Daniel@0 11264 }
Daniel@0 11265
Daniel@0 11266 function group(g, bounds, includeLegends) {
Daniel@0 11267 var axes = g.axisItems || [],
Daniel@0 11268 items = g.items || [],
Daniel@0 11269 legends = g.legendItems || [],
Daniel@0 11270 j, m;
Daniel@0 11271
Daniel@0 11272 for (j=0, m=axes.length; j<m; ++j) {
Daniel@0 11273 bounds.union(axes[j].bounds);
Daniel@0 11274 }
Daniel@0 11275 for (j=0, m=items.length; j<m; ++j) {
Daniel@0 11276 bounds.union(items[j].bounds);
Daniel@0 11277 }
Daniel@0 11278 if (includeLegends) {
Daniel@0 11279 for (j=0, m=legends.length; j<m; ++j) {
Daniel@0 11280 bounds.union(legends[j].bounds);
Daniel@0 11281 }
Daniel@0 11282 }
Daniel@0 11283 if (g.width || g.height) {
Daniel@0 11284 strokeBounds(g, bounds
Daniel@0 11285 .add(0, 0)
Daniel@0 11286 .add(g.width || 0, g.height || 0));
Daniel@0 11287 }
Daniel@0 11288 return bounds.translate(g.x || 0, g.y || 0);
Daniel@0 11289 }
Daniel@0 11290
Daniel@0 11291 var methods = {
Daniel@0 11292 group: group,
Daniel@0 11293 symbol: symbol,
Daniel@0 11294 image: image,
Daniel@0 11295 rect: rect,
Daniel@0 11296 rule: rule,
Daniel@0 11297 arc: arc,
Daniel@0 11298 text: textMark,
Daniel@0 11299 path: path,
Daniel@0 11300 area: area,
Daniel@0 11301 line: line
Daniel@0 11302 };
Daniel@0 11303 methods.area.nest = true;
Daniel@0 11304 methods.line.nest = true;
Daniel@0 11305
Daniel@0 11306 function itemBounds(item, func, opt) {
Daniel@0 11307 var type = item.mark.marktype;
Daniel@0 11308 func = func || methods[type];
Daniel@0 11309 if (func.nest) item = item.mark;
Daniel@0 11310
Daniel@0 11311 var curr = item.bounds,
Daniel@0 11312 prev = item['bounds:prev'] || (item['bounds:prev'] = new Bounds());
Daniel@0 11313
Daniel@0 11314 if (curr) {
Daniel@0 11315 prev.clear().union(curr);
Daniel@0 11316 curr.clear();
Daniel@0 11317 } else {
Daniel@0 11318 item.bounds = new Bounds();
Daniel@0 11319 }
Daniel@0 11320 func(item, item.bounds, opt);
Daniel@0 11321 if (!curr) prev.clear().union(item.bounds);
Daniel@0 11322 return item.bounds;
Daniel@0 11323 }
Daniel@0 11324
Daniel@0 11325 var DUMMY_ITEM = {mark: null};
Daniel@0 11326
Daniel@0 11327 function markBounds(mark, bounds, opt) {
Daniel@0 11328 var type = mark.marktype,
Daniel@0 11329 func = methods[type],
Daniel@0 11330 items = mark.items,
Daniel@0 11331 hasi = items && items.length,
Daniel@0 11332 i, n, o, b;
Daniel@0 11333
Daniel@0 11334 if (func.nest) {
Daniel@0 11335 o = hasi ? items[0]
Daniel@0 11336 : (DUMMY_ITEM.mark = mark, DUMMY_ITEM); // no items, so fake it
Daniel@0 11337 b = itemBounds(o, func, opt);
Daniel@0 11338 bounds = bounds && bounds.union(b) || b;
Daniel@0 11339 return bounds;
Daniel@0 11340 }
Daniel@0 11341
Daniel@0 11342 bounds = bounds || mark.bounds && mark.bounds.clear() || new Bounds();
Daniel@0 11343 if (hasi) {
Daniel@0 11344 for (i=0, n=items.length; i<n; ++i) {
Daniel@0 11345 bounds.union(itemBounds(items[i], func, opt));
Daniel@0 11346 }
Daniel@0 11347 }
Daniel@0 11348 return (mark.bounds = bounds);
Daniel@0 11349 }
Daniel@0 11350
Daniel@0 11351 module.exports = {
Daniel@0 11352 mark: markBounds,
Daniel@0 11353 item: itemBounds,
Daniel@0 11354 text: textMark,
Daniel@0 11355 group: group
Daniel@0 11356 };
Daniel@0 11357
Daniel@0 11358 },{"../path":48,"./Bounds":74,"./BoundsContext":75,"./canvas":80,"./svg":83,"./text":84}],80:[function(require,module,exports){
Daniel@0 11359 (function (global){
Daniel@0 11360 function instance(w, h) {
Daniel@0 11361 w = w || 1;
Daniel@0 11362 h = h || 1;
Daniel@0 11363 var canvas;
Daniel@0 11364
Daniel@0 11365 if (typeof document !== 'undefined' && document.createElement) {
Daniel@0 11366 canvas = document.createElement('canvas');
Daniel@0 11367 canvas.width = w;
Daniel@0 11368 canvas.height = h;
Daniel@0 11369 } else {
Daniel@0 11370 var Canvas = (typeof window !== "undefined" ? window['canvas'] : typeof global !== "undefined" ? global['canvas'] : null);
Daniel@0 11371 if (!Canvas.prototype) return null;
Daniel@0 11372 canvas = new Canvas(w, h);
Daniel@0 11373 }
Daniel@0 11374 return lineDash(canvas);
Daniel@0 11375 }
Daniel@0 11376
Daniel@0 11377 function resize(canvas, w, h, p, retina) {
Daniel@0 11378 var g = this._ctx = canvas.getContext('2d'),
Daniel@0 11379 s = 1;
Daniel@0 11380
Daniel@0 11381 canvas.width = w + p.left + p.right;
Daniel@0 11382 canvas.height = h + p.top + p.bottom;
Daniel@0 11383
Daniel@0 11384 // if browser canvas, attempt to modify for retina display
Daniel@0 11385 if (retina && typeof HTMLElement !== 'undefined' &&
Daniel@0 11386 canvas instanceof HTMLElement)
Daniel@0 11387 {
Daniel@0 11388 g.pixelratio = (s = pixelRatio(canvas) || 1);
Daniel@0 11389 }
Daniel@0 11390
Daniel@0 11391 g.setTransform(s, 0, 0, s, s*p.left, s*p.top);
Daniel@0 11392 return canvas;
Daniel@0 11393 }
Daniel@0 11394
Daniel@0 11395 function pixelRatio(canvas) {
Daniel@0 11396 var g = canvas.getContext('2d');
Daniel@0 11397
Daniel@0 11398 // get canvas pixel data
Daniel@0 11399 var devicePixelRatio = window && window.devicePixelRatio || 1,
Daniel@0 11400 backingStoreRatio = (
Daniel@0 11401 g.webkitBackingStorePixelRatio ||
Daniel@0 11402 g.mozBackingStorePixelRatio ||
Daniel@0 11403 g.msBackingStorePixelRatio ||
Daniel@0 11404 g.oBackingStorePixelRatio ||
Daniel@0 11405 g.backingStorePixelRatio) || 1,
Daniel@0 11406 ratio = devicePixelRatio / backingStoreRatio;
Daniel@0 11407
Daniel@0 11408 if (devicePixelRatio !== backingStoreRatio) {
Daniel@0 11409 // set actual and visible canvas size
Daniel@0 11410 var w = canvas.width,
Daniel@0 11411 h = canvas.height;
Daniel@0 11412 canvas.width = w * ratio;
Daniel@0 11413 canvas.height = h * ratio;
Daniel@0 11414 canvas.style.width = w + 'px';
Daniel@0 11415 canvas.style.height = h + 'px';
Daniel@0 11416 }
Daniel@0 11417
Daniel@0 11418 return ratio;
Daniel@0 11419 }
Daniel@0 11420
Daniel@0 11421 function lineDash(canvas) {
Daniel@0 11422 var g = canvas.getContext('2d');
Daniel@0 11423 if (g.vgLineDash) return; // already initialized!
Daniel@0 11424
Daniel@0 11425 var NOOP = function() {},
Daniel@0 11426 NODASH = [];
Daniel@0 11427
Daniel@0 11428 if (g.setLineDash) {
Daniel@0 11429 g.vgLineDash = function(dash) { this.setLineDash(dash || NODASH); };
Daniel@0 11430 g.vgLineDashOffset = function(off) { this.lineDashOffset = off; };
Daniel@0 11431 } else if (g.webkitLineDash !== undefined) {
Daniel@0 11432 g.vgLineDash = function(dash) { this.webkitLineDash = dash || NODASH; };
Daniel@0 11433 g.vgLineDashOffset = function(off) { this.webkitLineDashOffset = off; };
Daniel@0 11434 } else if (g.mozDash !== undefined) {
Daniel@0 11435 g.vgLineDash = function(dash) { this.mozDash = dash; };
Daniel@0 11436 g.vgLineDashOffset = NOOP;
Daniel@0 11437 } else {
Daniel@0 11438 g.vgLineDash = NOOP;
Daniel@0 11439 g.vgLineDashOffset = NOOP;
Daniel@0 11440 }
Daniel@0 11441 return canvas;
Daniel@0 11442 }
Daniel@0 11443
Daniel@0 11444 module.exports = {
Daniel@0 11445 instance: instance,
Daniel@0 11446 resize: resize,
Daniel@0 11447 lineDash: lineDash
Daniel@0 11448 };
Daniel@0 11449
Daniel@0 11450 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
Daniel@0 11451
Daniel@0 11452 },{}],81:[function(require,module,exports){
Daniel@0 11453 // create a new DOM element
Daniel@0 11454 function create(doc, tag, ns) {
Daniel@0 11455 return ns ? doc.createElementNS(ns, tag) : doc.createElement(tag);
Daniel@0 11456 }
Daniel@0 11457
Daniel@0 11458 // remove element from DOM
Daniel@0 11459 // recursively remove parent elements if empty
Daniel@0 11460 function remove(el) {
Daniel@0 11461 if (!el) return;
Daniel@0 11462 var p = el.parentNode;
Daniel@0 11463 if (p) {
Daniel@0 11464 p.removeChild(el);
Daniel@0 11465 if (!p.childNodes || !p.childNodes.length) remove(p);
Daniel@0 11466 }
Daniel@0 11467 }
Daniel@0 11468
Daniel@0 11469 module.exports = {
Daniel@0 11470 // find first child element with matching tag
Daniel@0 11471 find: function(el, tag) {
Daniel@0 11472 tag = tag.toLowerCase();
Daniel@0 11473 for (var i=0, n=el.childNodes.length; i<n; ++i) {
Daniel@0 11474 if (el.childNodes[i].tagName.toLowerCase() === tag) {
Daniel@0 11475 return el.childNodes[i];
Daniel@0 11476 }
Daniel@0 11477 }
Daniel@0 11478 },
Daniel@0 11479 // retrieve child element at given index
Daniel@0 11480 // create & insert if doesn't exist or if tag/className do not match
Daniel@0 11481 child: function(el, index, tag, ns, className, insert) {
Daniel@0 11482 var a, b;
Daniel@0 11483 a = b = el.childNodes[index];
Daniel@0 11484 if (!a || insert ||
Daniel@0 11485 a.tagName.toLowerCase() !== tag.toLowerCase() ||
Daniel@0 11486 className && a.getAttribute('class') != className) {
Daniel@0 11487 a = create(el.ownerDocument, tag, ns);
Daniel@0 11488 el.insertBefore(a, b);
Daniel@0 11489 if (className) a.setAttribute('class', className);
Daniel@0 11490 }
Daniel@0 11491 return a;
Daniel@0 11492 },
Daniel@0 11493 // remove all child elements at or above the given index
Daniel@0 11494 clear: function(el, index) {
Daniel@0 11495 var curr = el.childNodes.length;
Daniel@0 11496 while (curr > index) {
Daniel@0 11497 el.removeChild(el.childNodes[--curr]);
Daniel@0 11498 }
Daniel@0 11499 return el;
Daniel@0 11500 },
Daniel@0 11501 remove: remove,
Daniel@0 11502 // generate css class name for mark
Daniel@0 11503 cssClass: function(mark) {
Daniel@0 11504 return 'mark-' + mark.marktype + (mark.name ? ' '+mark.name : '');
Daniel@0 11505 },
Daniel@0 11506 // generate string for an opening xml tag
Daniel@0 11507 // tag: the name of the xml tag
Daniel@0 11508 // attr: hash of attribute name-value pairs to include
Daniel@0 11509 // raw: additional raw string to include in tag markup
Daniel@0 11510 openTag: function(tag, attr, raw) {
Daniel@0 11511 var s = '<' + tag, key, val;
Daniel@0 11512 if (attr) {
Daniel@0 11513 for (key in attr) {
Daniel@0 11514 val = attr[key];
Daniel@0 11515 if (val != null) {
Daniel@0 11516 s += ' ' + key + '="' + val + '"';
Daniel@0 11517 }
Daniel@0 11518 }
Daniel@0 11519 }
Daniel@0 11520 if (raw) s += ' ' + raw;
Daniel@0 11521 return s + '>';
Daniel@0 11522 },
Daniel@0 11523 // generate string for closing xml tag
Daniel@0 11524 // tag: the name of the xml tag
Daniel@0 11525 closeTag: function(tag) {
Daniel@0 11526 return '</' + tag + '>';
Daniel@0 11527 }
Daniel@0 11528 };
Daniel@0 11529
Daniel@0 11530 },{}],82:[function(require,module,exports){
Daniel@0 11531 var bound = require('../util/bound');
Daniel@0 11532
Daniel@0 11533 var sets = [
Daniel@0 11534 'items',
Daniel@0 11535 'axisItems',
Daniel@0 11536 'legendItems'
Daniel@0 11537 ];
Daniel@0 11538
Daniel@0 11539 var keys = [
Daniel@0 11540 'marktype', 'name', 'interactive', 'clip',
Daniel@0 11541 'items', 'axisItems', 'legendItems', 'layer',
Daniel@0 11542 'x', 'y', 'width', 'height', 'align', 'baseline', // layout
Daniel@0 11543 'fill', 'fillOpacity', 'opacity', // fill
Daniel@0 11544 'stroke', 'strokeOpacity', 'strokeWidth', 'strokeCap', // stroke
Daniel@0 11545 'strokeDash', 'strokeDashOffset', // stroke dash
Daniel@0 11546 'startAngle', 'endAngle', 'innerRadius', 'outerRadius', // arc
Daniel@0 11547 'interpolate', 'tension', 'orient', // area, line
Daniel@0 11548 'url', // image
Daniel@0 11549 'path', // path
Daniel@0 11550 'x2', 'y2', // rule
Daniel@0 11551 'size', 'shape', // symbol
Daniel@0 11552 'text', 'angle', 'theta', 'radius', 'dx', 'dy', // text
Daniel@0 11553 'font', 'fontSize', 'fontWeight', 'fontStyle', 'fontVariant' // font
Daniel@0 11554 ];
Daniel@0 11555
Daniel@0 11556 function toJSON(scene, indent) {
Daniel@0 11557 return JSON.stringify(scene, keys, indent);
Daniel@0 11558 }
Daniel@0 11559
Daniel@0 11560 function fromJSON(json) {
Daniel@0 11561 var scene = (typeof json === 'string' ? JSON.parse(json) : json);
Daniel@0 11562 return initialize(scene);
Daniel@0 11563 }
Daniel@0 11564
Daniel@0 11565 function initialize(scene) {
Daniel@0 11566 var type = scene.marktype,
Daniel@0 11567 i, n, s, m, items;
Daniel@0 11568
Daniel@0 11569 for (s=0, m=sets.length; s<m; ++s) {
Daniel@0 11570 if ((items = scene[sets[s]])) {
Daniel@0 11571 for (i=0, n=items.length; i<n; ++i) {
Daniel@0 11572 items[i][type ? 'mark' : 'group'] = scene;
Daniel@0 11573 if (!type || type === 'group') {
Daniel@0 11574 initialize(items[i]);
Daniel@0 11575 }
Daniel@0 11576 }
Daniel@0 11577 }
Daniel@0 11578 }
Daniel@0 11579
Daniel@0 11580 if (type) bound.mark(scene);
Daniel@0 11581 return scene;
Daniel@0 11582 }
Daniel@0 11583
Daniel@0 11584 module.exports = {
Daniel@0 11585 toJSON: toJSON,
Daniel@0 11586 fromJSON: fromJSON
Daniel@0 11587 };
Daniel@0 11588 },{"../util/bound":79}],83:[function(require,module,exports){
Daniel@0 11589 (function (global){
Daniel@0 11590 var d3_svg = (typeof window !== "undefined" ? window['d3'] : typeof global !== "undefined" ? global['d3'] : null).svg;
Daniel@0 11591
Daniel@0 11592 function x(o) { return o.x || 0; }
Daniel@0 11593 function y(o) { return o.y || 0; }
Daniel@0 11594 function xw(o) { return (o.x || 0) + (o.width || 0); }
Daniel@0 11595 function yh(o) { return (o.y || 0) + (o.height || 0); }
Daniel@0 11596 function size(o) { return o.size == null ? 100 : o.size; }
Daniel@0 11597 function shape(o) { return o.shape || 'circle'; }
Daniel@0 11598
Daniel@0 11599 var areav = d3_svg.area().x(x).y1(y).y0(yh),
Daniel@0 11600 areah = d3_svg.area().y(y).x1(x).x0(xw),
Daniel@0 11601 line = d3_svg.line().x(x).y(y);
Daniel@0 11602
Daniel@0 11603 module.exports = {
Daniel@0 11604 metadata: {
Daniel@0 11605 'version': '1.1',
Daniel@0 11606 'xmlns': 'http://www.w3.org/2000/svg',
Daniel@0 11607 'xmlns:xlink': 'http://www.w3.org/1999/xlink'
Daniel@0 11608 },
Daniel@0 11609 path: {
Daniel@0 11610 arc: d3_svg.arc(),
Daniel@0 11611 symbol: d3_svg.symbol().type(shape).size(size),
Daniel@0 11612 area: function(items) {
Daniel@0 11613 var o = items[0];
Daniel@0 11614 return (o.orient === 'horizontal' ? areah : areav)
Daniel@0 11615 .interpolate(o.interpolate || 'linear')
Daniel@0 11616 .tension(o.tension || 0.7)
Daniel@0 11617 (items);
Daniel@0 11618 },
Daniel@0 11619 line: function(items) {
Daniel@0 11620 var o = items[0];
Daniel@0 11621 return line
Daniel@0 11622 .interpolate(o.interpolate || 'linear')
Daniel@0 11623 .tension(o.tension || 0.7)
Daniel@0 11624 (items);
Daniel@0 11625 }
Daniel@0 11626 },
Daniel@0 11627 textAlign: {
Daniel@0 11628 'left': 'start',
Daniel@0 11629 'center': 'middle',
Daniel@0 11630 'right': 'end'
Daniel@0 11631 },
Daniel@0 11632 textBaseline: {
Daniel@0 11633 'top': 'before-edge',
Daniel@0 11634 'bottom': 'after-edge',
Daniel@0 11635 'middle': 'central'
Daniel@0 11636 },
Daniel@0 11637 styles: {
Daniel@0 11638 'fill': 'fill',
Daniel@0 11639 'fillOpacity': 'fill-opacity',
Daniel@0 11640 'stroke': 'stroke',
Daniel@0 11641 'strokeWidth': 'stroke-width',
Daniel@0 11642 'strokeOpacity': 'stroke-opacity',
Daniel@0 11643 'strokeCap': 'stroke-linecap',
Daniel@0 11644 'strokeDash': 'stroke-dasharray',
Daniel@0 11645 'strokeDashOffset': 'stroke-dashoffset',
Daniel@0 11646 'opacity': 'opacity'
Daniel@0 11647 },
Daniel@0 11648 styleProperties: [
Daniel@0 11649 'fill',
Daniel@0 11650 'fillOpacity',
Daniel@0 11651 'stroke',
Daniel@0 11652 'strokeWidth',
Daniel@0 11653 'strokeOpacity',
Daniel@0 11654 'strokeCap',
Daniel@0 11655 'strokeDash',
Daniel@0 11656 'strokeDashOffset',
Daniel@0 11657 'opacity'
Daniel@0 11658 ]
Daniel@0 11659 };
Daniel@0 11660
Daniel@0 11661 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
Daniel@0 11662
Daniel@0 11663 },{}],84:[function(require,module,exports){
Daniel@0 11664 function size(item) {
Daniel@0 11665 return item.fontSize != null ? item.fontSize : 11;
Daniel@0 11666 }
Daniel@0 11667
Daniel@0 11668 module.exports = {
Daniel@0 11669 size: size,
Daniel@0 11670 value: function(s) {
Daniel@0 11671 return s != null ? String(s) : '';
Daniel@0 11672 },
Daniel@0 11673 font: function(item, quote) {
Daniel@0 11674 var font = item.font;
Daniel@0 11675 if (quote && font) {
Daniel@0 11676 font = String(font).replace(/\"/g, '\'');
Daniel@0 11677 }
Daniel@0 11678 return '' +
Daniel@0 11679 (item.fontStyle ? item.fontStyle + ' ' : '') +
Daniel@0 11680 (item.fontVariant ? item.fontVariant + ' ' : '') +
Daniel@0 11681 (item.fontWeight ? item.fontWeight + ' ' : '') +
Daniel@0 11682 size(item) + 'px ' +
Daniel@0 11683 (font || 'sans-serif');
Daniel@0 11684 },
Daniel@0 11685 offset: function(item) {
Daniel@0 11686 // perform our own font baseline calculation
Daniel@0 11687 // why? not all browsers support SVG 1.1 'alignment-baseline' :(
Daniel@0 11688 var baseline = item.baseline,
Daniel@0 11689 h = size(item);
Daniel@0 11690 return Math.round(
Daniel@0 11691 baseline === 'top' ? 0.93*h :
Daniel@0 11692 baseline === 'middle' ? 0.30*h :
Daniel@0 11693 baseline === 'bottom' ? -0.21*h : 0
Daniel@0 11694 );
Daniel@0 11695 }
Daniel@0 11696 };
Daniel@0 11697
Daniel@0 11698 },{}],85:[function(require,module,exports){
Daniel@0 11699 var sg = require('vega-scenegraph').render,
Daniel@0 11700 canvas = sg.canvas,
Daniel@0 11701 svg = sg.svg.string,
Daniel@0 11702 View = require('./View');
Daniel@0 11703
Daniel@0 11704 function HeadlessView(width, height, model) {
Daniel@0 11705 View.call(null, width, height, model);
Daniel@0 11706 this._type = 'canvas';
Daniel@0 11707 this._renderers = {canvas: canvas, svg: svg};
Daniel@0 11708 }
Daniel@0 11709
Daniel@0 11710 var prototype = (HeadlessView.prototype = new View());
Daniel@0 11711
Daniel@0 11712 prototype.renderer = function(type) {
Daniel@0 11713 if(type) this._type = type;
Daniel@0 11714 return View.prototype.renderer.apply(this, arguments);
Daniel@0 11715 };
Daniel@0 11716
Daniel@0 11717 prototype.canvas = function() {
Daniel@0 11718 return (this._type === 'canvas') ? this._renderer.canvas() : null;
Daniel@0 11719 };
Daniel@0 11720
Daniel@0 11721 prototype.canvasAsync = function(callback) {
Daniel@0 11722 var r = this._renderer, view = this;
Daniel@0 11723
Daniel@0 11724 function wait() {
Daniel@0 11725 if (r.pendingImages() === 0) {
Daniel@0 11726 view.render(); // re-render with all images
Daniel@0 11727 callback(view.canvas());
Daniel@0 11728 } else {
Daniel@0 11729 setTimeout(wait, 10);
Daniel@0 11730 }
Daniel@0 11731 }
Daniel@0 11732
Daniel@0 11733 // if images loading, poll until ready
Daniel@0 11734 if (this._type !== 'canvas') return null;
Daniel@0 11735 if (r.pendingImages() > 0) { wait(); } else { callback(this.canvas()); }
Daniel@0 11736 };
Daniel@0 11737
Daniel@0 11738 prototype.svg = function() {
Daniel@0 11739 return (this._type === 'svg') ? this._renderer.svg() : null;
Daniel@0 11740 };
Daniel@0 11741
Daniel@0 11742 prototype.initialize = function() {
Daniel@0 11743 var w = this._width,
Daniel@0 11744 h = this._height,
Daniel@0 11745 bg = this._bgcolor,
Daniel@0 11746 pad = this._padding,
Daniel@0 11747 config = this.model().config();
Daniel@0 11748
Daniel@0 11749 if (this._viewport) {
Daniel@0 11750 w = this._viewport[0] - (pad ? pad.left + pad.right : 0);
Daniel@0 11751 h = this._viewport[1] - (pad ? pad.top + pad.bottom : 0);
Daniel@0 11752 }
Daniel@0 11753
Daniel@0 11754 this._renderer = (this._renderer || new this._io.Renderer(config.load))
Daniel@0 11755 .initialize(null, w, h, pad)
Daniel@0 11756 .background(bg);
Daniel@0 11757
Daniel@0 11758 return this;
Daniel@0 11759 };
Daniel@0 11760
Daniel@0 11761 module.exports = HeadlessView;
Daniel@0 11762 },{"./View":87,"vega-scenegraph":46}],86:[function(require,module,exports){
Daniel@0 11763 var dl = require('datalib'),
Daniel@0 11764 df = require('vega-dataflow'),
Daniel@0 11765 ChangeSet = df.ChangeSet,
Daniel@0 11766 Base = df.Graph.prototype,
Daniel@0 11767 Node = df.Node, // jshint ignore:line
Daniel@0 11768 GroupBuilder = require('../scene/GroupBuilder'),
Daniel@0 11769 visit = require('../scene/visit'),
Daniel@0 11770 config = require('./config');
Daniel@0 11771
Daniel@0 11772 function Model(cfg) {
Daniel@0 11773 this._defs = {};
Daniel@0 11774 this._predicates = {};
Daniel@0 11775 this._scene = null;
Daniel@0 11776
Daniel@0 11777 this._node = null;
Daniel@0 11778 this._builder = null; // Top-level scenegraph builder
Daniel@0 11779
Daniel@0 11780 this._reset = {axes: false, legends: false};
Daniel@0 11781
Daniel@0 11782 this.config(cfg);
Daniel@0 11783 Base.init.call(this);
Daniel@0 11784 }
Daniel@0 11785
Daniel@0 11786 var prototype = (Model.prototype = Object.create(Base));
Daniel@0 11787 prototype.constructor = Model;
Daniel@0 11788
Daniel@0 11789 prototype.defs = function(defs) {
Daniel@0 11790 if (!arguments.length) return this._defs;
Daniel@0 11791 this._defs = defs;
Daniel@0 11792 return this;
Daniel@0 11793 };
Daniel@0 11794
Daniel@0 11795 prototype.config = function(cfg) {
Daniel@0 11796 if (!arguments.length) return this._config;
Daniel@0 11797 this._config = Object.create(config);
Daniel@0 11798 for (var name in cfg) {
Daniel@0 11799 var x = cfg[name], y = this._config[name];
Daniel@0 11800 if (dl.isObject(x) && dl.isObject(y)) {
Daniel@0 11801 dl.extend(y, x);
Daniel@0 11802 } else {
Daniel@0 11803 this._config[name] = x;
Daniel@0 11804 }
Daniel@0 11805 }
Daniel@0 11806
Daniel@0 11807 return this;
Daniel@0 11808 };
Daniel@0 11809
Daniel@0 11810 prototype.width = function(width) {
Daniel@0 11811 if (this._defs) this._defs.width = width;
Daniel@0 11812 if (this._defs && this._defs.marks) this._defs.marks.width = width;
Daniel@0 11813 if (this._scene) {
Daniel@0 11814 this._scene.items[0].width = width;
Daniel@0 11815 this._scene.items[0]._dirty = true;
Daniel@0 11816 }
Daniel@0 11817 this._reset.axes = true;
Daniel@0 11818 return this;
Daniel@0 11819 };
Daniel@0 11820
Daniel@0 11821 prototype.height = function(height) {
Daniel@0 11822 if (this._defs) this._defs.height = height;
Daniel@0 11823 if (this._defs && this._defs.marks) this._defs.marks.height = height;
Daniel@0 11824 if (this._scene) {
Daniel@0 11825 this._scene.items[0].height = height;
Daniel@0 11826 this._scene.items[0]._dirty = true;
Daniel@0 11827 }
Daniel@0 11828 this._reset.axes = true;
Daniel@0 11829 return this;
Daniel@0 11830 };
Daniel@0 11831
Daniel@0 11832 prototype.node = function() {
Daniel@0 11833 return this._node || (this._node = new Node(this));
Daniel@0 11834 };
Daniel@0 11835
Daniel@0 11836 prototype.data = function() {
Daniel@0 11837 var data = Base.data.apply(this, arguments);
Daniel@0 11838 if (arguments.length > 1) { // new Datasource
Daniel@0 11839 this.node().addListener(data.pipeline()[0]);
Daniel@0 11840 }
Daniel@0 11841 return data;
Daniel@0 11842 };
Daniel@0 11843
Daniel@0 11844 function predicates(name) {
Daniel@0 11845 var m = this, pred = {};
Daniel@0 11846 if (!dl.isArray(name)) return this._predicates[name];
Daniel@0 11847 name.forEach(function(n) { pred[n] = m._predicates[n]; });
Daniel@0 11848 return pred;
Daniel@0 11849 }
Daniel@0 11850
Daniel@0 11851 prototype.predicate = function(name, predicate) {
Daniel@0 11852 if (arguments.length === 1) return predicates.call(this, name);
Daniel@0 11853 return (this._predicates[name] = predicate);
Daniel@0 11854 };
Daniel@0 11855
Daniel@0 11856 prototype.predicates = function() { return this._predicates; };
Daniel@0 11857
Daniel@0 11858 prototype.scene = function(renderer) {
Daniel@0 11859 if (!arguments.length) return this._scene;
Daniel@0 11860 if (this._builder) this.node().removeListener(this._builder.disconnect());
Daniel@0 11861 this._builder = new GroupBuilder(this, this._defs.marks, this._scene={});
Daniel@0 11862 this.node().addListener(this._builder.connect());
Daniel@0 11863 var p = this._builder.pipeline();
Daniel@0 11864 p[p.length-1].addListener(renderer);
Daniel@0 11865 return this;
Daniel@0 11866 };
Daniel@0 11867
Daniel@0 11868 prototype.reset = function() {
Daniel@0 11869 if (this._scene && this._reset.axes) {
Daniel@0 11870 visit(this._scene, function(item) {
Daniel@0 11871 if (item.axes) item.axes.forEach(function(axis) { axis.reset(); });
Daniel@0 11872 });
Daniel@0 11873 this._reset.axes = false;
Daniel@0 11874 }
Daniel@0 11875 if (this._scene && this._reset.legends) {
Daniel@0 11876 visit(this._scene, function(item) {
Daniel@0 11877 if (item.legends) item.legends.forEach(function(l) { l.reset(); });
Daniel@0 11878 });
Daniel@0 11879 this._reset.legends = false;
Daniel@0 11880 }
Daniel@0 11881 return this;
Daniel@0 11882 };
Daniel@0 11883
Daniel@0 11884 prototype.addListener = function(l) {
Daniel@0 11885 this.node().addListener(l);
Daniel@0 11886 };
Daniel@0 11887
Daniel@0 11888 prototype.removeListener = function(l) {
Daniel@0 11889 this.node().removeListener(l);
Daniel@0 11890 };
Daniel@0 11891
Daniel@0 11892 prototype.fire = function(cs) {
Daniel@0 11893 if (!cs) cs = ChangeSet.create();
Daniel@0 11894 this.propagate(cs, this.node());
Daniel@0 11895 };
Daniel@0 11896
Daniel@0 11897 module.exports = Model;
Daniel@0 11898 },{"../scene/GroupBuilder":110,"../scene/visit":115,"./config":88,"datalib":24,"vega-dataflow":39}],87:[function(require,module,exports){
Daniel@0 11899 (function (global){
Daniel@0 11900 var d3 = (typeof window !== "undefined" ? window['d3'] : typeof global !== "undefined" ? global['d3'] : null),
Daniel@0 11901 dl = require('datalib'),
Daniel@0 11902 df = require('vega-dataflow'),
Daniel@0 11903 sg = require('vega-scenegraph').render,
Daniel@0 11904 log = require('vega-logging'),
Daniel@0 11905 Deps = df.Dependencies,
Daniel@0 11906 parseStreams = require('../parse/streams'),
Daniel@0 11907 Encoder = require('../scene/Encoder'),
Daniel@0 11908 Transition = require('../scene/Transition');
Daniel@0 11909
Daniel@0 11910 function View(el, width, height) {
Daniel@0 11911 this._el = null;
Daniel@0 11912 this._model = null;
Daniel@0 11913 this._width = this.__width = width || 500;
Daniel@0 11914 this._height = this.__height = height || 300;
Daniel@0 11915 this._bgcolor = null;
Daniel@0 11916 this._autopad = 1;
Daniel@0 11917 this._padding = {top:0, left:0, bottom:0, right:0};
Daniel@0 11918 this._viewport = null;
Daniel@0 11919 this._renderer = null;
Daniel@0 11920 this._handler = null;
Daniel@0 11921 this._streamer = null; // Targeted update for streaming changes
Daniel@0 11922 this._changeset = null;
Daniel@0 11923 this._repaint = true; // Full re-render on every re-init
Daniel@0 11924 this._renderers = sg;
Daniel@0 11925 this._io = null;
Daniel@0 11926 this._api = {}; // Stash streaming data API sandboxes.
Daniel@0 11927 }
Daniel@0 11928
Daniel@0 11929 var prototype = View.prototype;
Daniel@0 11930
Daniel@0 11931 prototype.model = function(model) {
Daniel@0 11932 if (!arguments.length) return this._model;
Daniel@0 11933 if (this._model !== model) {
Daniel@0 11934 this._model = model;
Daniel@0 11935 this._streamer = new df.Node(model);
Daniel@0 11936 this._streamer._rank = -1; // HACK: To reduce re-ranking churn.
Daniel@0 11937 this._changeset = df.ChangeSet.create();
Daniel@0 11938 if (this._handler) this._handler.model(model);
Daniel@0 11939 }
Daniel@0 11940 return this;
Daniel@0 11941 };
Daniel@0 11942
Daniel@0 11943 // Sandboxed streaming data API
Daniel@0 11944 function streaming(src) {
Daniel@0 11945 var view = this,
Daniel@0 11946 ds = this._model.data(src),
Daniel@0 11947 name = ds.name(),
Daniel@0 11948 listener = ds.pipeline()[0],
Daniel@0 11949 streamer = this._streamer,
Daniel@0 11950 api = {};
Daniel@0 11951
Daniel@0 11952 // If we have it stashed, don't create a new closure.
Daniel@0 11953 if (this._api[src]) return this._api[src];
Daniel@0 11954
Daniel@0 11955 api.insert = function(vals) {
Daniel@0 11956 ds.insert(dl.duplicate(vals)); // Don't pollute the environment
Daniel@0 11957 streamer.addListener(listener);
Daniel@0 11958 view._changeset.data[name] = 1;
Daniel@0 11959 return api;
Daniel@0 11960 };
Daniel@0 11961
Daniel@0 11962 api.update = function() {
Daniel@0 11963 streamer.addListener(listener);
Daniel@0 11964 view._changeset.data[name] = 1;
Daniel@0 11965 return (ds.update.apply(ds, arguments), api);
Daniel@0 11966 };
Daniel@0 11967
Daniel@0 11968 api.remove = function() {
Daniel@0 11969 streamer.addListener(listener);
Daniel@0 11970 view._changeset.data[name] = 1;
Daniel@0 11971 return (ds.remove.apply(ds, arguments), api);
Daniel@0 11972 };
Daniel@0 11973
Daniel@0 11974 api.values = function() { return ds.values(); };
Daniel@0 11975
Daniel@0 11976 return (this._api[src] = api);
Daniel@0 11977 }
Daniel@0 11978
Daniel@0 11979 prototype.data = function(data) {
Daniel@0 11980 var v = this;
Daniel@0 11981 if (!arguments.length) return v._model.values();
Daniel@0 11982 else if (dl.isString(data)) return streaming.call(v, data);
Daniel@0 11983 else if (dl.isObject(data)) {
Daniel@0 11984 dl.keys(data).forEach(function(k) {
Daniel@0 11985 var api = streaming.call(v, k);
Daniel@0 11986 data[k](api);
Daniel@0 11987 });
Daniel@0 11988 }
Daniel@0 11989 return this;
Daniel@0 11990 };
Daniel@0 11991
Daniel@0 11992 prototype.signal = function(name, value) {
Daniel@0 11993 var m = this._model,
Daniel@0 11994 cs = this._changeset,
Daniel@0 11995 streamer = this._streamer,
Daniel@0 11996 setter = name;
Daniel@0 11997
Daniel@0 11998 if (!arguments.length) {
Daniel@0 11999 return m.values(Deps.SIGNALS);
Daniel@0 12000 } else if (arguments.length == 1 && dl.isString(name)) {
Daniel@0 12001 return m.values(Deps.SIGNALS, name);
Daniel@0 12002 }
Daniel@0 12003
Daniel@0 12004 if (arguments.length == 2) {
Daniel@0 12005 setter = {};
Daniel@0 12006 setter[name] = value;
Daniel@0 12007 }
Daniel@0 12008
Daniel@0 12009 dl.keys(setter).forEach(function(k) {
Daniel@0 12010 streamer.addListener(m.signal(k).value(setter[k]));
Daniel@0 12011 cs.signals[k] = 1;
Daniel@0 12012 cs.reflow = true;
Daniel@0 12013 });
Daniel@0 12014
Daniel@0 12015 return this;
Daniel@0 12016 };
Daniel@0 12017
Daniel@0 12018 prototype.width = function(width) {
Daniel@0 12019 if (!arguments.length) return this.__width;
Daniel@0 12020 if (this.__width !== width) {
Daniel@0 12021 this._width = this.__width = width;
Daniel@0 12022 this.model().width(width);
Daniel@0 12023 this.initialize();
Daniel@0 12024 if (this._strict) this._autopad = 1;
Daniel@0 12025 }
Daniel@0 12026 return this;
Daniel@0 12027 };
Daniel@0 12028
Daniel@0 12029 prototype.height = function(height) {
Daniel@0 12030 if (!arguments.length) return this.__height;
Daniel@0 12031 if (this.__height !== height) {
Daniel@0 12032 this._height = this.__height = height;
Daniel@0 12033 this.model().height(height);
Daniel@0 12034 this.initialize();
Daniel@0 12035 if (this._strict) this._autopad = 1;
Daniel@0 12036 }
Daniel@0 12037 return this;
Daniel@0 12038 };
Daniel@0 12039
Daniel@0 12040 prototype.background = function(bgcolor) {
Daniel@0 12041 if (!arguments.length) return this._bgcolor;
Daniel@0 12042 if (this._bgcolor !== bgcolor) {
Daniel@0 12043 this._bgcolor = bgcolor;
Daniel@0 12044 this.initialize();
Daniel@0 12045 }
Daniel@0 12046 return this;
Daniel@0 12047 };
Daniel@0 12048
Daniel@0 12049 prototype.padding = function(pad) {
Daniel@0 12050 if (!arguments.length) return this._padding;
Daniel@0 12051 if (this._padding !== pad) {
Daniel@0 12052 if (dl.isString(pad)) {
Daniel@0 12053 this._autopad = 1;
Daniel@0 12054 this._padding = {top:0, left:0, bottom:0, right:0};
Daniel@0 12055 this._strict = (pad === 'strict');
Daniel@0 12056 } else {
Daniel@0 12057 this._autopad = 0;
Daniel@0 12058 this._padding = pad;
Daniel@0 12059 this._strict = false;
Daniel@0 12060 }
Daniel@0 12061 if (this._renderer) this._renderer.resize(this._width, this._height, pad);
Daniel@0 12062 if (this._handler) this._handler.padding(pad);
Daniel@0 12063 }
Daniel@0 12064 return (this._repaint = true, this);
Daniel@0 12065 };
Daniel@0 12066
Daniel@0 12067 prototype.autopad = function(opt) {
Daniel@0 12068 if (this._autopad < 1) return this;
Daniel@0 12069 else this._autopad = 0;
Daniel@0 12070
Daniel@0 12071 var b = this.model().scene().bounds,
Daniel@0 12072 pad = this._padding,
Daniel@0 12073 config = this.model().config(),
Daniel@0 12074 inset = config.autopadInset,
Daniel@0 12075 l = b.x1 < 0 ? Math.ceil(-b.x1) + inset : 0,
Daniel@0 12076 t = b.y1 < 0 ? Math.ceil(-b.y1) + inset : 0,
Daniel@0 12077 r = b.x2 > this._width ? Math.ceil(+b.x2 - this._width) + inset : 0;
Daniel@0 12078 b = b.y2 > this._height ? Math.ceil(+b.y2 - this._height) + inset : 0;
Daniel@0 12079 pad = {left:l, top:t, right:r, bottom:b};
Daniel@0 12080
Daniel@0 12081 if (this._strict) {
Daniel@0 12082 this._autopad = 0;
Daniel@0 12083 this._padding = pad;
Daniel@0 12084 this._width = Math.max(0, this.__width - (l+r));
Daniel@0 12085 this._height = Math.max(0, this.__height - (t+b));
Daniel@0 12086
Daniel@0 12087 this._model.width(this._width)
Daniel@0 12088 .height(this._height).reset();
Daniel@0 12089
Daniel@0 12090 this.initialize()
Daniel@0 12091 .update({props:'enter'}).update({props:'update'});
Daniel@0 12092 } else {
Daniel@0 12093 this.padding(pad).update(opt);
Daniel@0 12094 }
Daniel@0 12095 return this;
Daniel@0 12096 };
Daniel@0 12097
Daniel@0 12098 prototype.viewport = function(size) {
Daniel@0 12099 if (!arguments.length) return this._viewport;
Daniel@0 12100 if (this._viewport !== size) {
Daniel@0 12101 this._viewport = size;
Daniel@0 12102 this.initialize();
Daniel@0 12103 }
Daniel@0 12104 return this;
Daniel@0 12105 };
Daniel@0 12106
Daniel@0 12107 prototype.renderer = function(type) {
Daniel@0 12108 if (!arguments.length) return this._renderer;
Daniel@0 12109 if (this._renderers[type]) type = this._renderers[type];
Daniel@0 12110 else if (dl.isString(type)) throw new Error('Unknown renderer: ' + type);
Daniel@0 12111 else if (!type) throw new Error('No renderer specified');
Daniel@0 12112
Daniel@0 12113 if (this._io !== type) {
Daniel@0 12114 this._io = type;
Daniel@0 12115 this._renderer = null;
Daniel@0 12116 this.initialize();
Daniel@0 12117 if (this._build) this.render();
Daniel@0 12118 }
Daniel@0 12119 return this;
Daniel@0 12120 };
Daniel@0 12121
Daniel@0 12122 prototype.initialize = function(el) {
Daniel@0 12123 var v = this, prevHandler,
Daniel@0 12124 w = v._width, h = v._height, pad = v._padding, bg = v._bgcolor,
Daniel@0 12125 config = this.model().config();
Daniel@0 12126
Daniel@0 12127 if (!arguments.length || el === null) {
Daniel@0 12128 el = this._el ? this._el.parentNode : null;
Daniel@0 12129 if (!el) return this; // This View cannot init w/o an
Daniel@0 12130 }
Daniel@0 12131
Daniel@0 12132 // clear pre-existing container
Daniel@0 12133 d3.select(el).select('div.vega').remove();
Daniel@0 12134
Daniel@0 12135 // add div container
Daniel@0 12136 this._el = el = d3.select(el)
Daniel@0 12137 .append('div')
Daniel@0 12138 .attr('class', 'vega')
Daniel@0 12139 .style('position', 'relative')
Daniel@0 12140 .node();
Daniel@0 12141 if (v._viewport) {
Daniel@0 12142 d3.select(el)
Daniel@0 12143 .style('width', (v._viewport[0] || w)+'px')
Daniel@0 12144 .style('height', (v._viewport[1] || h)+'px')
Daniel@0 12145 .style('overflow', 'auto');
Daniel@0 12146 }
Daniel@0 12147
Daniel@0 12148 // renderer
Daniel@0 12149 sg.canvas.Renderer.RETINA = config.render.retina;
Daniel@0 12150 v._renderer = (v._renderer || new this._io.Renderer(config.load))
Daniel@0 12151 .initialize(el, w, h, pad)
Daniel@0 12152 .background(bg);
Daniel@0 12153
Daniel@0 12154 // input handler
Daniel@0 12155 prevHandler = v._handler;
Daniel@0 12156 v._handler = new this._io.Handler()
Daniel@0 12157 .initialize(el, pad, v);
Daniel@0 12158
Daniel@0 12159 if (prevHandler) {
Daniel@0 12160 prevHandler.handlers().forEach(function(h) {
Daniel@0 12161 v._handler.on(h.type, h.handler);
Daniel@0 12162 });
Daniel@0 12163 } else {
Daniel@0 12164 // Register event listeners for signal stream definitions.
Daniel@0 12165 v._detach = parseStreams(this);
Daniel@0 12166 }
Daniel@0 12167
Daniel@0 12168 return (this._repaint = true, this);
Daniel@0 12169 };
Daniel@0 12170
Daniel@0 12171 prototype.destroy = function() {
Daniel@0 12172 if (this._detach) this._detach();
Daniel@0 12173 };
Daniel@0 12174
Daniel@0 12175 function build() {
Daniel@0 12176 var v = this;
Daniel@0 12177 v._renderNode = new df.Node(v._model)
Daniel@0 12178 .router(true);
Daniel@0 12179
Daniel@0 12180 v._renderNode.evaluate = function(input) {
Daniel@0 12181 log.debug(input, ['rendering']);
Daniel@0 12182
Daniel@0 12183 var s = v._model.scene(),
Daniel@0 12184 h = v._handler;
Daniel@0 12185
Daniel@0 12186 if (h && h.scene) h.scene(s);
Daniel@0 12187
Daniel@0 12188 if (input.trans) {
Daniel@0 12189 input.trans.start(function(items) { v._renderer.render(s, items); });
Daniel@0 12190 } else if (v._repaint) {
Daniel@0 12191 v._renderer.render(s);
Daniel@0 12192 v._repaint = false;
Daniel@0 12193 } else if (input.dirty.length) {
Daniel@0 12194 v._renderer.render(s, input.dirty);
Daniel@0 12195 }
Daniel@0 12196
Daniel@0 12197 if (input.dirty.length) {
Daniel@0 12198 input.dirty.forEach(function(i) { i._dirty = false; });
Daniel@0 12199 s.items[0]._dirty = false;
Daniel@0 12200 }
Daniel@0 12201
Daniel@0 12202 // For all updated datasources, clear their previous values.
Daniel@0 12203 for (var d in input.data) { v._model.data(d).synchronize(); }
Daniel@0 12204 return input;
Daniel@0 12205 };
Daniel@0 12206
Daniel@0 12207 return (v._model.scene(v._renderNode), true);
Daniel@0 12208 }
Daniel@0 12209
Daniel@0 12210 prototype.update = function(opt) {
Daniel@0 12211 opt = opt || {};
Daniel@0 12212 var v = this,
Daniel@0 12213 trans = opt.duration ? new Transition(opt.duration, opt.ease) : null;
Daniel@0 12214
Daniel@0 12215 var cs = v._changeset;
Daniel@0 12216 if (trans) cs.trans = trans;
Daniel@0 12217 if (opt.props !== undefined) {
Daniel@0 12218 if (dl.keys(cs.data).length > 0) {
Daniel@0 12219 throw Error(
Daniel@0 12220 'New data values are not reflected in the visualization.' +
Daniel@0 12221 ' Please call view.update() before updating a specified property set.'
Daniel@0 12222 );
Daniel@0 12223 }
Daniel@0 12224
Daniel@0 12225 cs.reflow = true;
Daniel@0 12226 cs.request = opt.props;
Daniel@0 12227 }
Daniel@0 12228
Daniel@0 12229 var built = v._build;
Daniel@0 12230 v._build = v._build || build.call(this);
Daniel@0 12231
Daniel@0 12232 // If specific items are specified, short-circuit dataflow graph.
Daniel@0 12233 // Else-If there are streaming updates, perform a targeted propagation.
Daniel@0 12234 // Otherwise, reevaluate the entire model (datasources + scene).
Daniel@0 12235 if (opt.items && built) {
Daniel@0 12236 Encoder.update(this._model, opt.trans, opt.props, opt.items, cs.dirty);
Daniel@0 12237 v._renderNode.evaluate(cs);
Daniel@0 12238 } else if (v._streamer.listeners().length && built) {
Daniel@0 12239 v._model.propagate(cs, v._streamer);
Daniel@0 12240 v._streamer.disconnect();
Daniel@0 12241 } else {
Daniel@0 12242 v._model.fire(cs);
Daniel@0 12243 }
Daniel@0 12244
Daniel@0 12245 v._changeset = df.ChangeSet.create();
Daniel@0 12246
Daniel@0 12247 return v.autopad(opt);
Daniel@0 12248 };
Daniel@0 12249
Daniel@0 12250 prototype.toImageURL = function(type) {
Daniel@0 12251 var v = this, Renderer;
Daniel@0 12252
Daniel@0 12253 // lookup appropriate renderer
Daniel@0 12254 switch (type || 'png') {
Daniel@0 12255 case 'canvas':
Daniel@0 12256 case 'png':
Daniel@0 12257 Renderer = sg.canvas.Renderer; break;
Daniel@0 12258 case 'svg':
Daniel@0 12259 Renderer = sg.svg.string.Renderer; break;
Daniel@0 12260 default: throw Error('Unrecognized renderer type: ' + type);
Daniel@0 12261 }
Daniel@0 12262
Daniel@0 12263 var retina = sg.canvas.Renderer.RETINA;
Daniel@0 12264 sg.canvas.Renderer.RETINA = false; // ignore retina screen
Daniel@0 12265
Daniel@0 12266 // render the scenegraph
Daniel@0 12267 var ren = new Renderer(v._model.config.load)
Daniel@0 12268 .initialize(null, v._width, v._height, v._padding)
Daniel@0 12269 .render(v._model.scene());
Daniel@0 12270
Daniel@0 12271 sg.canvas.Renderer.RETINA = retina; // restore retina settings
Daniel@0 12272
Daniel@0 12273 // return data url
Daniel@0 12274 if (type === 'svg') {
Daniel@0 12275 var blob = new Blob([ren.svg()], {type: 'image/svg+xml'});
Daniel@0 12276 return window.URL.createObjectURL(blob);
Daniel@0 12277 } else {
Daniel@0 12278 return ren.canvas().toDataURL('image/png');
Daniel@0 12279 }
Daniel@0 12280 };
Daniel@0 12281
Daniel@0 12282 prototype.render = function(items) {
Daniel@0 12283 this._renderer.render(this._model.scene(), items);
Daniel@0 12284 return this;
Daniel@0 12285 };
Daniel@0 12286
Daniel@0 12287 prototype.on = function() {
Daniel@0 12288 this._handler.on.apply(this._handler, arguments);
Daniel@0 12289 return this;
Daniel@0 12290 };
Daniel@0 12291
Daniel@0 12292 prototype.onSignal = function(name, handler) {
Daniel@0 12293 this._model.signal(name).on(handler);
Daniel@0 12294 return this;
Daniel@0 12295 };
Daniel@0 12296
Daniel@0 12297 prototype.off = function() {
Daniel@0 12298 this._handler.off.apply(this._handler, arguments);
Daniel@0 12299 return this;
Daniel@0 12300 };
Daniel@0 12301
Daniel@0 12302 prototype.offSignal = function(name, handler) {
Daniel@0 12303 this._model.signal(name).off(handler);
Daniel@0 12304 return this;
Daniel@0 12305 };
Daniel@0 12306
Daniel@0 12307 View.factory = function(model) {
Daniel@0 12308 var HeadlessView = require('./HeadlessView');
Daniel@0 12309 return function(opt) {
Daniel@0 12310 opt = opt || {};
Daniel@0 12311 var defs = model.defs();
Daniel@0 12312 var v = (opt.el ? new View() : new HeadlessView())
Daniel@0 12313 .model(model)
Daniel@0 12314 .renderer(opt.renderer || 'canvas')
Daniel@0 12315 .width(defs.width)
Daniel@0 12316 .height(defs.height)
Daniel@0 12317 .background(defs.background)
Daniel@0 12318 .padding(defs.padding)
Daniel@0 12319 .viewport(defs.viewport)
Daniel@0 12320 .initialize(opt.el);
Daniel@0 12321
Daniel@0 12322 if (opt.data) v.data(opt.data);
Daniel@0 12323
Daniel@0 12324 if (opt.hover !== false && opt.el) {
Daniel@0 12325 v.on('mouseover', function(evt, item) {
Daniel@0 12326 if (item && item.hasPropertySet('hover')) {
Daniel@0 12327 this.update({props:'hover', items:item});
Daniel@0 12328 }
Daniel@0 12329 })
Daniel@0 12330 .on('mouseout', function(evt, item) {
Daniel@0 12331 if (item && item.hasPropertySet('hover')) {
Daniel@0 12332 this.update({props:'update', items:item});
Daniel@0 12333 }
Daniel@0 12334 });
Daniel@0 12335 }
Daniel@0 12336
Daniel@0 12337 return v;
Daniel@0 12338 };
Daniel@0 12339 };
Daniel@0 12340
Daniel@0 12341 module.exports = View;
Daniel@0 12342 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
Daniel@0 12343
Daniel@0 12344 },{"../parse/streams":105,"../scene/Encoder":109,"../scene/Transition":112,"./HeadlessView":85,"datalib":24,"vega-dataflow":39,"vega-logging":45,"vega-scenegraph":46}],88:[function(require,module,exports){
Daniel@0 12345 (function (global){
Daniel@0 12346 var d3 = (typeof window !== "undefined" ? window['d3'] : typeof global !== "undefined" ? global['d3'] : null),
Daniel@0 12347 config = {};
Daniel@0 12348
Daniel@0 12349 config.load = {
Daniel@0 12350 // base url for loading external data files
Daniel@0 12351 // used only for server-side operation
Daniel@0 12352 baseURL: '',
Daniel@0 12353 // Allows domain restriction when using data loading via XHR.
Daniel@0 12354 // To enable, set it to a list of allowed domains
Daniel@0 12355 // e.g., ['wikipedia.org', 'eff.org']
Daniel@0 12356 domainWhiteList: false
Daniel@0 12357 };
Daniel@0 12358
Daniel@0 12359 // inset padding for automatic padding calculation
Daniel@0 12360 config.autopadInset = 5;
Daniel@0 12361
Daniel@0 12362 // extensible scale lookup table
Daniel@0 12363 // all d3.scale.* instances also supported
Daniel@0 12364 config.scale = {
Daniel@0 12365 time: d3.time.scale,
Daniel@0 12366 utc: d3.time.scale.utc
Daniel@0 12367 };
Daniel@0 12368
Daniel@0 12369 // default rendering settings
Daniel@0 12370 config.render = {
Daniel@0 12371 retina: true
Daniel@0 12372 };
Daniel@0 12373
Daniel@0 12374 // default axis properties
Daniel@0 12375 config.axis = {
Daniel@0 12376 orient: 'bottom',
Daniel@0 12377 ticks: 10,
Daniel@0 12378 padding: 3,
Daniel@0 12379 axisColor: '#000',
Daniel@0 12380 gridColor: '#000',
Daniel@0 12381 gridOpacity: 0.15,
Daniel@0 12382 tickColor: '#000',
Daniel@0 12383 tickLabelColor: '#000',
Daniel@0 12384 axisWidth: 1,
Daniel@0 12385 tickWidth: 1,
Daniel@0 12386 tickSize: 6,
Daniel@0 12387 tickLabelFontSize: 11,
Daniel@0 12388 tickLabelFont: 'sans-serif',
Daniel@0 12389 titleColor: '#000',
Daniel@0 12390 titleFont: 'sans-serif',
Daniel@0 12391 titleFontSize: 11,
Daniel@0 12392 titleFontWeight: 'bold',
Daniel@0 12393 titleOffset: 35
Daniel@0 12394 };
Daniel@0 12395
Daniel@0 12396 // default legend properties
Daniel@0 12397 config.legend = {
Daniel@0 12398 orient: 'right',
Daniel@0 12399 offset: 20,
Daniel@0 12400 padding: 3,
Daniel@0 12401 gradientStrokeColor: '#888',
Daniel@0 12402 gradientStrokeWidth: 1,
Daniel@0 12403 gradientHeight: 16,
Daniel@0 12404 gradientWidth: 100,
Daniel@0 12405 labelColor: '#000',
Daniel@0 12406 labelFontSize: 10,
Daniel@0 12407 labelFont: 'sans-serif',
Daniel@0 12408 labelAlign: 'left',
Daniel@0 12409 labelBaseline: 'middle',
Daniel@0 12410 labelOffset: 8,
Daniel@0 12411 symbolShape: 'circle',
Daniel@0 12412 symbolSize: 50,
Daniel@0 12413 symbolColor: '#888',
Daniel@0 12414 symbolStrokeWidth: 1,
Daniel@0 12415 titleColor: '#000',
Daniel@0 12416 titleFont: 'sans-serif',
Daniel@0 12417 titleFontSize: 11,
Daniel@0 12418 titleFontWeight: 'bold'
Daniel@0 12419 };
Daniel@0 12420
Daniel@0 12421 // default color values
Daniel@0 12422 config.color = {
Daniel@0 12423 rgb: [128, 128, 128],
Daniel@0 12424 lab: [50, 0, 0],
Daniel@0 12425 hcl: [0, 0, 50],
Daniel@0 12426 hsl: [0, 0, 0.5]
Daniel@0 12427 };
Daniel@0 12428
Daniel@0 12429 // default scale ranges
Daniel@0 12430 config.range = {
Daniel@0 12431 category10: d3.scale.category10().range(),
Daniel@0 12432 category20: d3.scale.category20().range(),
Daniel@0 12433 category20b: d3.scale.category20b().range(),
Daniel@0 12434 category20c: d3.scale.category20c().range(),
Daniel@0 12435 shapes: [
Daniel@0 12436 'circle',
Daniel@0 12437 'cross',
Daniel@0 12438 'diamond',
Daniel@0 12439 'square',
Daniel@0 12440 'triangle-down',
Daniel@0 12441 'triangle-up'
Daniel@0 12442 ]
Daniel@0 12443 };
Daniel@0 12444
Daniel@0 12445 module.exports = config;
Daniel@0 12446 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
Daniel@0 12447
Daniel@0 12448 },{}],89:[function(require,module,exports){
Daniel@0 12449 var dl = require('datalib'),
Daniel@0 12450 parse = require('../parse'),
Daniel@0 12451 Scale = require('../scene/Scale'),
Daniel@0 12452 config = require('./config');
Daniel@0 12453
Daniel@0 12454 function compile(module, opt, schema) {
Daniel@0 12455 var s = module.schema;
Daniel@0 12456 if (!s) return;
Daniel@0 12457 if (s.refs) dl.extend(schema.refs, s.refs);
Daniel@0 12458 if (s.defs) dl.extend(schema.defs, s.defs);
Daniel@0 12459 }
Daniel@0 12460
Daniel@0 12461 module.exports = function(opt) {
Daniel@0 12462 var schema = null;
Daniel@0 12463 opt = opt || {};
Daniel@0 12464
Daniel@0 12465 // Compile if we're not loading the schema from a URL.
Daniel@0 12466 // Load from a URL to extend the existing base schema.
Daniel@0 12467 if (opt.url) {
Daniel@0 12468 schema = dl.json(dl.extend({url: opt.url}, config.load));
Daniel@0 12469 } else {
Daniel@0 12470 schema = {
Daniel@0 12471 "$schema": "http://json-schema.org/draft-04/schema#",
Daniel@0 12472 "title": "Vega Visualization Specification Language",
Daniel@0 12473 "defs": {},
Daniel@0 12474 "refs": {},
Daniel@0 12475 "$ref": "#/defs/spec"
Daniel@0 12476 };
Daniel@0 12477
Daniel@0 12478 dl.keys(parse).forEach(function(k) { compile(parse[k], opt, schema); });
Daniel@0 12479
Daniel@0 12480 // Scales aren't in the parser, add schema manually
Daniel@0 12481 compile(Scale, opt, schema);
Daniel@0 12482 }
Daniel@0 12483
Daniel@0 12484 // Extend schema to support custom mark properties or property sets.
Daniel@0 12485 if (opt.properties) dl.keys(opt.properties).forEach(function(k) {
Daniel@0 12486 schema.defs.propset.properties[k] = {"$ref": "#/refs/"+opt.properties[k]+"Value"};
Daniel@0 12487 });
Daniel@0 12488
Daniel@0 12489 if (opt.propertySets) dl.keys(opt.propertySets).forEach(function(k) {
Daniel@0 12490 schema.defs.mark.properties.properties.properties[k] = {"$ref": "#/defs/propset"};
Daniel@0 12491 });
Daniel@0 12492
Daniel@0 12493 return schema;
Daniel@0 12494 };
Daniel@0 12495 },{"../parse":95,"../scene/Scale":111,"./config":88,"datalib":24}],90:[function(require,module,exports){
Daniel@0 12496 var dl = require('datalib'),
Daniel@0 12497 axs = require('../scene/axis');
Daniel@0 12498
Daniel@0 12499 var ORIENT = {
Daniel@0 12500 "x": "bottom",
Daniel@0 12501 "y": "left",
Daniel@0 12502 "top": "top",
Daniel@0 12503 "bottom": "bottom",
Daniel@0 12504 "left": "left",
Daniel@0 12505 "right": "right"
Daniel@0 12506 };
Daniel@0 12507
Daniel@0 12508 function parseAxes(model, spec, axes, group) {
Daniel@0 12509 var config = model.config();
Daniel@0 12510 (spec || []).forEach(function(def, index) {
Daniel@0 12511 axes[index] = axes[index] || axs(model);
Daniel@0 12512 parseAxis(config, def, index, axes[index], group);
Daniel@0 12513 });
Daniel@0 12514 }
Daniel@0 12515
Daniel@0 12516 function parseAxis(config, def, index, axis, group) {
Daniel@0 12517 // axis scale
Daniel@0 12518 if (def.scale !== undefined) {
Daniel@0 12519 axis.scale(group.scale(def.scale));
Daniel@0 12520 }
Daniel@0 12521
Daniel@0 12522 // axis orientation
Daniel@0 12523 axis.orient(def.orient || ORIENT[def.type]);
Daniel@0 12524 // axis offset
Daniel@0 12525 axis.offset(def.offset || 0);
Daniel@0 12526 // axis layer
Daniel@0 12527 axis.layer(def.layer || "front");
Daniel@0 12528 // axis grid lines
Daniel@0 12529 axis.grid(def.grid || false);
Daniel@0 12530 // axis title
Daniel@0 12531 axis.title(def.title || null);
Daniel@0 12532 // axis title offset
Daniel@0 12533 axis.titleOffset(def.titleOffset != null ?
Daniel@0 12534 def.titleOffset : config.axis.titleOffset);
Daniel@0 12535 // axis values
Daniel@0 12536 axis.tickValues(def.values || null);
Daniel@0 12537 // axis label formatting
Daniel@0 12538 axis.tickFormat(def.format || null);
Daniel@0 12539 axis.tickFormatType(def.formatType || null);
Daniel@0 12540 // axis tick subdivision
Daniel@0 12541 axis.tickSubdivide(def.subdivide || 0);
Daniel@0 12542 // axis tick padding
Daniel@0 12543 axis.tickPadding(def.tickPadding || config.axis.padding);
Daniel@0 12544
Daniel@0 12545 // axis tick size(s)
Daniel@0 12546 var size = [];
Daniel@0 12547 if (def.tickSize !== undefined) {
Daniel@0 12548 for (var i=0; i<3; ++i) size.push(def.tickSize);
Daniel@0 12549 } else {
Daniel@0 12550 var ts = config.axis.tickSize;
Daniel@0 12551 size = [ts, ts, ts];
Daniel@0 12552 }
Daniel@0 12553 if (def.tickSizeMajor != null) size[0] = def.tickSizeMajor;
Daniel@0 12554 if (def.tickSizeMinor != null) size[1] = def.tickSizeMinor;
Daniel@0 12555 if (def.tickSizeEnd != null) size[2] = def.tickSizeEnd;
Daniel@0 12556 if (size.length) {
Daniel@0 12557 axis.tickSize.apply(axis, size);
Daniel@0 12558 }
Daniel@0 12559
Daniel@0 12560 // axis tick count
Daniel@0 12561 axis.tickCount(def.ticks || config.axis.ticks);
Daniel@0 12562
Daniel@0 12563 // style properties
Daniel@0 12564 var p = def.properties;
Daniel@0 12565 if (p && p.ticks) {
Daniel@0 12566 axis.majorTickProperties(p.majorTicks ?
Daniel@0 12567 dl.extend({}, p.ticks, p.majorTicks) : p.ticks);
Daniel@0 12568 axis.minorTickProperties(p.minorTicks ?
Daniel@0 12569 dl.extend({}, p.ticks, p.minorTicks) : p.ticks);
Daniel@0 12570 } else {
Daniel@0 12571 axis.majorTickProperties(p && p.majorTicks || {});
Daniel@0 12572 axis.minorTickProperties(p && p.minorTicks || {});
Daniel@0 12573 }
Daniel@0 12574 axis.tickLabelProperties(p && p.labels || {});
Daniel@0 12575 axis.titleProperties(p && p.title || {});
Daniel@0 12576 axis.gridLineProperties(p && p.grid || {});
Daniel@0 12577 axis.domainProperties(p && p.axis || {});
Daniel@0 12578 }
Daniel@0 12579
Daniel@0 12580 module.exports = parseAxes;
Daniel@0 12581 },{"../scene/axis":113,"datalib":24}],91:[function(require,module,exports){
Daniel@0 12582 (function (global){
Daniel@0 12583 var d3 = (typeof window !== "undefined" ? window['d3'] : typeof global !== "undefined" ? global['d3'] : null);
Daniel@0 12584
Daniel@0 12585 function parseBg(bg) {
Daniel@0 12586 // return null if input is null or undefined
Daniel@0 12587 if (bg == null) return null;
Daniel@0 12588 // run through d3 rgb to sanity check
Daniel@0 12589 return d3.rgb(bg) + "";
Daniel@0 12590 }
Daniel@0 12591
Daniel@0 12592 module.exports = parseBg;
Daniel@0 12593 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
Daniel@0 12594
Daniel@0 12595 },{}],92:[function(require,module,exports){
Daniel@0 12596 var dl = require('datalib'),
Daniel@0 12597 log = require('vega-logging'),
Daniel@0 12598 parseTransforms = require('./transforms'),
Daniel@0 12599 parseModify = require('./modify');
Daniel@0 12600
Daniel@0 12601 function parseData(model, spec, callback) {
Daniel@0 12602 var config = model.config(),
Daniel@0 12603 count = 0;
Daniel@0 12604
Daniel@0 12605 function loaded(d) {
Daniel@0 12606 return function(error, data) {
Daniel@0 12607 if (error) {
Daniel@0 12608 log.error('LOADING FAILED: ' + d.url + ' ' + error);
Daniel@0 12609 } else {
Daniel@0 12610 model.data(d.name).values(dl.read(data, d.format));
Daniel@0 12611 }
Daniel@0 12612 if (--count === 0) callback();
Daniel@0 12613 };
Daniel@0 12614 }
Daniel@0 12615
Daniel@0 12616 // process each data set definition
Daniel@0 12617 (spec || []).forEach(function(d) {
Daniel@0 12618 if (d.url) {
Daniel@0 12619 count += 1;
Daniel@0 12620 dl.load(dl.extend({url: d.url}, config.load), loaded(d));
Daniel@0 12621 }
Daniel@0 12622 parseData.datasource(model, d);
Daniel@0 12623 });
Daniel@0 12624
Daniel@0 12625 if (count === 0) setTimeout(callback, 1);
Daniel@0 12626 return spec;
Daniel@0 12627 }
Daniel@0 12628
Daniel@0 12629 parseData.datasource = function(model, d) {
Daniel@0 12630 var transform = (d.transform || []).map(function(t) {
Daniel@0 12631 return parseTransforms(model, t);
Daniel@0 12632 }),
Daniel@0 12633 mod = (d.modify || []).map(function(m) {
Daniel@0 12634 return parseModify(model, m, d);
Daniel@0 12635 }),
Daniel@0 12636 ds = model.data(d.name, mod.concat(transform));
Daniel@0 12637
Daniel@0 12638 if (d.values) {
Daniel@0 12639 ds.values(dl.read(d.values, d.format));
Daniel@0 12640 } else if (d.source) {
Daniel@0 12641 // Derived ds will be pulsed by its src rather than the model.
Daniel@0 12642 ds.source(d.source).addListener(ds);
Daniel@0 12643 model.removeListener(ds.pipeline()[0]);
Daniel@0 12644 }
Daniel@0 12645
Daniel@0 12646 return ds;
Daniel@0 12647 };
Daniel@0 12648
Daniel@0 12649 module.exports = parseData;
Daniel@0 12650 },{"./modify":99,"./transforms":106,"datalib":24,"vega-logging":45}],93:[function(require,module,exports){
Daniel@0 12651 module.exports = (function() {
Daniel@0 12652 /*
Daniel@0 12653 * Generated by PEG.js 0.8.0.
Daniel@0 12654 *
Daniel@0 12655 * http://pegjs.majda.cz/
Daniel@0 12656 */
Daniel@0 12657
Daniel@0 12658 function peg$subclass(child, parent) {
Daniel@0 12659 function ctor() { this.constructor = child; }
Daniel@0 12660 ctor.prototype = parent.prototype;
Daniel@0 12661 child.prototype = new ctor();
Daniel@0 12662 }
Daniel@0 12663
Daniel@0 12664 function SyntaxError(message, expected, found, offset, line, column) {
Daniel@0 12665 this.message = message;
Daniel@0 12666 this.expected = expected;
Daniel@0 12667 this.found = found;
Daniel@0 12668 this.offset = offset;
Daniel@0 12669 this.line = line;
Daniel@0 12670 this.column = column;
Daniel@0 12671
Daniel@0 12672 this.name = "SyntaxError";
Daniel@0 12673 }
Daniel@0 12674
Daniel@0 12675 peg$subclass(SyntaxError, Error);
Daniel@0 12676
Daniel@0 12677 function parse(input) {
Daniel@0 12678 var options = arguments.length > 1 ? arguments[1] : {},
Daniel@0 12679
Daniel@0 12680 peg$FAILED = {},
Daniel@0 12681
Daniel@0 12682 peg$startRuleFunctions = { start: peg$parsestart },
Daniel@0 12683 peg$startRuleFunction = peg$parsestart,
Daniel@0 12684
Daniel@0 12685 peg$c0 = peg$FAILED,
Daniel@0 12686 peg$c1 = ",",
Daniel@0 12687 peg$c2 = { type: "literal", value: ",", description: "\",\"" },
Daniel@0 12688 peg$c3 = function(o, m) { return [o].concat(m); },
Daniel@0 12689 peg$c4 = function(o) { return [o]; },
Daniel@0 12690 peg$c5 = "[",
Daniel@0 12691 peg$c6 = { type: "literal", value: "[", description: "\"[\"" },
Daniel@0 12692 peg$c7 = "]",
Daniel@0 12693 peg$c8 = { type: "literal", value: "]", description: "\"]\"" },
Daniel@0 12694 peg$c9 = ">",
Daniel@0 12695 peg$c10 = { type: "literal", value: ">", description: "\">\"" },
Daniel@0 12696 peg$c11 = function(f1, f2, o) { return {start: f1, end: f2, middle: o}; },
Daniel@0 12697 peg$c12 = [],
Daniel@0 12698 peg$c13 = function(s, f) { return (s.filters = f, s); },
Daniel@0 12699 peg$c14 = function(s) { return s; },
Daniel@0 12700 peg$c15 = "(",
Daniel@0 12701 peg$c16 = { type: "literal", value: "(", description: "\"(\"" },
Daniel@0 12702 peg$c17 = ")",
Daniel@0 12703 peg$c18 = { type: "literal", value: ")", description: "\")\"" },
Daniel@0 12704 peg$c19 = function(m) { return {stream: m}; },
Daniel@0 12705 peg$c20 = "@",
Daniel@0 12706 peg$c21 = { type: "literal", value: "@", description: "\"@\"" },
Daniel@0 12707 peg$c22 = ":",
Daniel@0 12708 peg$c23 = { type: "literal", value: ":", description: "\":\"" },
Daniel@0 12709 peg$c24 = function(n, e) { return {event: e, name: n}; },
Daniel@0 12710 peg$c25 = function(m, e) { return {event: e, mark: m}; },
Daniel@0 12711 peg$c26 = function(t, e) { return {event: e, target: t}; },
Daniel@0 12712 peg$c27 = function(e) { return {event: e}; },
Daniel@0 12713 peg$c28 = function(s) { return {signal: s}; },
Daniel@0 12714 peg$c29 = "rect",
Daniel@0 12715 peg$c30 = { type: "literal", value: "rect", description: "\"rect\"" },
Daniel@0 12716 peg$c31 = "symbol",
Daniel@0 12717 peg$c32 = { type: "literal", value: "symbol", description: "\"symbol\"" },
Daniel@0 12718 peg$c33 = "path",
Daniel@0 12719 peg$c34 = { type: "literal", value: "path", description: "\"path\"" },
Daniel@0 12720 peg$c35 = "arc",
Daniel@0 12721 peg$c36 = { type: "literal", value: "arc", description: "\"arc\"" },
Daniel@0 12722 peg$c37 = "area",
Daniel@0 12723 peg$c38 = { type: "literal", value: "area", description: "\"area\"" },
Daniel@0 12724 peg$c39 = "line",
Daniel@0 12725 peg$c40 = { type: "literal", value: "line", description: "\"line\"" },
Daniel@0 12726 peg$c41 = "rule",
Daniel@0 12727 peg$c42 = { type: "literal", value: "rule", description: "\"rule\"" },
Daniel@0 12728 peg$c43 = "image",
Daniel@0 12729 peg$c44 = { type: "literal", value: "image", description: "\"image\"" },
Daniel@0 12730 peg$c45 = "text",
Daniel@0 12731 peg$c46 = { type: "literal", value: "text", description: "\"text\"" },
Daniel@0 12732 peg$c47 = "group",
Daniel@0 12733 peg$c48 = { type: "literal", value: "group", description: "\"group\"" },
Daniel@0 12734 peg$c49 = "mousedown",
Daniel@0 12735 peg$c50 = { type: "literal", value: "mousedown", description: "\"mousedown\"" },
Daniel@0 12736 peg$c51 = "mouseup",
Daniel@0 12737 peg$c52 = { type: "literal", value: "mouseup", description: "\"mouseup\"" },
Daniel@0 12738 peg$c53 = "click",
Daniel@0 12739 peg$c54 = { type: "literal", value: "click", description: "\"click\"" },
Daniel@0 12740 peg$c55 = "dblclick",
Daniel@0 12741 peg$c56 = { type: "literal", value: "dblclick", description: "\"dblclick\"" },
Daniel@0 12742 peg$c57 = "wheel",
Daniel@0 12743 peg$c58 = { type: "literal", value: "wheel", description: "\"wheel\"" },
Daniel@0 12744 peg$c59 = "keydown",
Daniel@0 12745 peg$c60 = { type: "literal", value: "keydown", description: "\"keydown\"" },
Daniel@0 12746 peg$c61 = "keypress",
Daniel@0 12747 peg$c62 = { type: "literal", value: "keypress", description: "\"keypress\"" },
Daniel@0 12748 peg$c63 = "keyup",
Daniel@0 12749 peg$c64 = { type: "literal", value: "keyup", description: "\"keyup\"" },
Daniel@0 12750 peg$c65 = "mousewheel",
Daniel@0 12751 peg$c66 = { type: "literal", value: "mousewheel", description: "\"mousewheel\"" },
Daniel@0 12752 peg$c67 = "mousemove",
Daniel@0 12753 peg$c68 = { type: "literal", value: "mousemove", description: "\"mousemove\"" },
Daniel@0 12754 peg$c69 = "mouseout",
Daniel@0 12755 peg$c70 = { type: "literal", value: "mouseout", description: "\"mouseout\"" },
Daniel@0 12756 peg$c71 = "mouseover",
Daniel@0 12757 peg$c72 = { type: "literal", value: "mouseover", description: "\"mouseover\"" },
Daniel@0 12758 peg$c73 = "mouseenter",
Daniel@0 12759 peg$c74 = { type: "literal", value: "mouseenter", description: "\"mouseenter\"" },
Daniel@0 12760 peg$c75 = "touchstart",
Daniel@0 12761 peg$c76 = { type: "literal", value: "touchstart", description: "\"touchstart\"" },
Daniel@0 12762 peg$c77 = "touchmove",
Daniel@0 12763 peg$c78 = { type: "literal", value: "touchmove", description: "\"touchmove\"" },
Daniel@0 12764 peg$c79 = "touchend",
Daniel@0 12765 peg$c80 = { type: "literal", value: "touchend", description: "\"touchend\"" },
Daniel@0 12766 peg$c81 = function(e) { return e; },
Daniel@0 12767 peg$c82 = /^[a-zA-Z0-9_\-]/,
Daniel@0 12768 peg$c83 = { type: "class", value: "[a-zA-Z0-9_\\-]", description: "[a-zA-Z0-9_\\-]" },
Daniel@0 12769 peg$c84 = function(n) { return n.join(""); },
Daniel@0 12770 peg$c85 = /^[a-zA-Z0-9\-_ #.>+~[\]=|\^$*]/,
Daniel@0 12771 peg$c86 = { type: "class", value: "[a-zA-Z0-9\\-_ #.>+~[\\]=|\\^$*]", description: "[a-zA-Z0-9\\-_ #.>+~[\\]=|\\^$*]" },
Daniel@0 12772 peg$c87 = function(c) { return c.join(""); },
Daniel@0 12773 peg$c88 = /^['"a-zA-Z0-9_().><=! \t-&|~]/,
Daniel@0 12774 peg$c89 = { type: "class", value: "['\"a-zA-Z0-9_().><=! \\t-&|~]", description: "['\"a-zA-Z0-9_().><=! \\t-&|~]" },
Daniel@0 12775 peg$c90 = function(v) { return v.join(""); },
Daniel@0 12776 peg$c91 = /^[ \t\r\n]/,
Daniel@0 12777 peg$c92 = { type: "class", value: "[ \\t\\r\\n]", description: "[ \\t\\r\\n]" },
Daniel@0 12778
Daniel@0 12779 peg$currPos = 0,
Daniel@0 12780 peg$reportedPos = 0,
Daniel@0 12781 peg$cachedPos = 0,
Daniel@0 12782 peg$cachedPosDetails = { line: 1, column: 1, seenCR: false },
Daniel@0 12783 peg$maxFailPos = 0,
Daniel@0 12784 peg$maxFailExpected = [],
Daniel@0 12785 peg$silentFails = 0,
Daniel@0 12786
Daniel@0 12787 peg$result;
Daniel@0 12788
Daniel@0 12789 if ("startRule" in options) {
Daniel@0 12790 if (!(options.startRule in peg$startRuleFunctions)) {
Daniel@0 12791 throw new Error("Can't start parsing from rule \"" + options.startRule + "\".");
Daniel@0 12792 }
Daniel@0 12793
Daniel@0 12794 peg$startRuleFunction = peg$startRuleFunctions[options.startRule];
Daniel@0 12795 }
Daniel@0 12796
Daniel@0 12797 function text() {
Daniel@0 12798 return input.substring(peg$reportedPos, peg$currPos);
Daniel@0 12799 }
Daniel@0 12800
Daniel@0 12801 function offset() {
Daniel@0 12802 return peg$reportedPos;
Daniel@0 12803 }
Daniel@0 12804
Daniel@0 12805 function line() {
Daniel@0 12806 return peg$computePosDetails(peg$reportedPos).line;
Daniel@0 12807 }
Daniel@0 12808
Daniel@0 12809 function column() {
Daniel@0 12810 return peg$computePosDetails(peg$reportedPos).column;
Daniel@0 12811 }
Daniel@0 12812
Daniel@0 12813 function expected(description) {
Daniel@0 12814 throw peg$buildException(
Daniel@0 12815 null,
Daniel@0 12816 [{ type: "other", description: description }],
Daniel@0 12817 peg$reportedPos
Daniel@0 12818 );
Daniel@0 12819 }
Daniel@0 12820
Daniel@0 12821 function error(message) {
Daniel@0 12822 throw peg$buildException(message, null, peg$reportedPos);
Daniel@0 12823 }
Daniel@0 12824
Daniel@0 12825 function peg$computePosDetails(pos) {
Daniel@0 12826 function advance(details, startPos, endPos) {
Daniel@0 12827 var p, ch;
Daniel@0 12828
Daniel@0 12829 for (p = startPos; p < endPos; p++) {
Daniel@0 12830 ch = input.charAt(p);
Daniel@0 12831 if (ch === "\n") {
Daniel@0 12832 if (!details.seenCR) { details.line++; }
Daniel@0 12833 details.column = 1;
Daniel@0 12834 details.seenCR = false;
Daniel@0 12835 } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") {
Daniel@0 12836 details.line++;
Daniel@0 12837 details.column = 1;
Daniel@0 12838 details.seenCR = true;
Daniel@0 12839 } else {
Daniel@0 12840 details.column++;
Daniel@0 12841 details.seenCR = false;
Daniel@0 12842 }
Daniel@0 12843 }
Daniel@0 12844 }
Daniel@0 12845
Daniel@0 12846 if (peg$cachedPos !== pos) {
Daniel@0 12847 if (peg$cachedPos > pos) {
Daniel@0 12848 peg$cachedPos = 0;
Daniel@0 12849 peg$cachedPosDetails = { line: 1, column: 1, seenCR: false };
Daniel@0 12850 }
Daniel@0 12851 advance(peg$cachedPosDetails, peg$cachedPos, pos);
Daniel@0 12852 peg$cachedPos = pos;
Daniel@0 12853 }
Daniel@0 12854
Daniel@0 12855 return peg$cachedPosDetails;
Daniel@0 12856 }
Daniel@0 12857
Daniel@0 12858 function peg$fail(expected) {
Daniel@0 12859 if (peg$currPos < peg$maxFailPos) { return; }
Daniel@0 12860
Daniel@0 12861 if (peg$currPos > peg$maxFailPos) {
Daniel@0 12862 peg$maxFailPos = peg$currPos;
Daniel@0 12863 peg$maxFailExpected = [];
Daniel@0 12864 }
Daniel@0 12865
Daniel@0 12866 peg$maxFailExpected.push(expected);
Daniel@0 12867 }
Daniel@0 12868
Daniel@0 12869 function peg$buildException(message, expected, pos) {
Daniel@0 12870 function cleanupExpected(expected) {
Daniel@0 12871 var i = 1;
Daniel@0 12872
Daniel@0 12873 expected.sort(function(a, b) {
Daniel@0 12874 if (a.description < b.description) {
Daniel@0 12875 return -1;
Daniel@0 12876 } else if (a.description > b.description) {
Daniel@0 12877 return 1;
Daniel@0 12878 } else {
Daniel@0 12879 return 0;
Daniel@0 12880 }
Daniel@0 12881 });
Daniel@0 12882
Daniel@0 12883 while (i < expected.length) {
Daniel@0 12884 if (expected[i - 1] === expected[i]) {
Daniel@0 12885 expected.splice(i, 1);
Daniel@0 12886 } else {
Daniel@0 12887 i++;
Daniel@0 12888 }
Daniel@0 12889 }
Daniel@0 12890 }
Daniel@0 12891
Daniel@0 12892 function buildMessage(expected, found) {
Daniel@0 12893 function stringEscape(s) {
Daniel@0 12894 function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); }
Daniel@0 12895
Daniel@0 12896 return s
Daniel@0 12897 .replace(/\\/g, '\\\\')
Daniel@0 12898 .replace(/"/g, '\\"')
Daniel@0 12899 .replace(/\x08/g, '\\b')
Daniel@0 12900 .replace(/\t/g, '\\t')
Daniel@0 12901 .replace(/\n/g, '\\n')
Daniel@0 12902 .replace(/\f/g, '\\f')
Daniel@0 12903 .replace(/\r/g, '\\r')
Daniel@0 12904 .replace(/[\x00-\x07\x0B\x0E\x0F]/g, function(ch) { return '\\x0' + hex(ch); })
Daniel@0 12905 .replace(/[\x10-\x1F\x80-\xFF]/g, function(ch) { return '\\x' + hex(ch); })
Daniel@0 12906 .replace(/[\u0180-\u0FFF]/g, function(ch) { return '\\u0' + hex(ch); })
Daniel@0 12907 .replace(/[\u1080-\uFFFF]/g, function(ch) { return '\\u' + hex(ch); });
Daniel@0 12908 }
Daniel@0 12909
Daniel@0 12910 var expectedDescs = new Array(expected.length),
Daniel@0 12911 expectedDesc, foundDesc, i;
Daniel@0 12912
Daniel@0 12913 for (i = 0; i < expected.length; i++) {
Daniel@0 12914 expectedDescs[i] = expected[i].description;
Daniel@0 12915 }
Daniel@0 12916
Daniel@0 12917 expectedDesc = expected.length > 1
Daniel@0 12918 ? expectedDescs.slice(0, -1).join(", ")
Daniel@0 12919 + " or "
Daniel@0 12920 + expectedDescs[expected.length - 1]
Daniel@0 12921 : expectedDescs[0];
Daniel@0 12922
Daniel@0 12923 foundDesc = found ? "\"" + stringEscape(found) + "\"" : "end of input";
Daniel@0 12924
Daniel@0 12925 return "Expected " + expectedDesc + " but " + foundDesc + " found.";
Daniel@0 12926 }
Daniel@0 12927
Daniel@0 12928 var posDetails = peg$computePosDetails(pos),
Daniel@0 12929 found = pos < input.length ? input.charAt(pos) : null;
Daniel@0 12930
Daniel@0 12931 if (expected !== null) {
Daniel@0 12932 cleanupExpected(expected);
Daniel@0 12933 }
Daniel@0 12934
Daniel@0 12935 return new SyntaxError(
Daniel@0 12936 message !== null ? message : buildMessage(expected, found),
Daniel@0 12937 expected,
Daniel@0 12938 found,
Daniel@0 12939 pos,
Daniel@0 12940 posDetails.line,
Daniel@0 12941 posDetails.column
Daniel@0 12942 );
Daniel@0 12943 }
Daniel@0 12944
Daniel@0 12945 function peg$parsestart() {
Daniel@0 12946 var s0;
Daniel@0 12947
Daniel@0 12948 s0 = peg$parsemerged();
Daniel@0 12949
Daniel@0 12950 return s0;
Daniel@0 12951 }
Daniel@0 12952
Daniel@0 12953 function peg$parsemerged() {
Daniel@0 12954 var s0, s1, s2, s3, s4, s5;
Daniel@0 12955
Daniel@0 12956 s0 = peg$currPos;
Daniel@0 12957 s1 = peg$parseordered();
Daniel@0 12958 if (s1 !== peg$FAILED) {
Daniel@0 12959 s2 = peg$parsesep();
Daniel@0 12960 if (s2 !== peg$FAILED) {
Daniel@0 12961 if (input.charCodeAt(peg$currPos) === 44) {
Daniel@0 12962 s3 = peg$c1;
Daniel@0 12963 peg$currPos++;
Daniel@0 12964 } else {
Daniel@0 12965 s3 = peg$FAILED;
Daniel@0 12966 if (peg$silentFails === 0) { peg$fail(peg$c2); }
Daniel@0 12967 }
Daniel@0 12968 if (s3 !== peg$FAILED) {
Daniel@0 12969 s4 = peg$parsesep();
Daniel@0 12970 if (s4 !== peg$FAILED) {
Daniel@0 12971 s5 = peg$parsemerged();
Daniel@0 12972 if (s5 !== peg$FAILED) {
Daniel@0 12973 peg$reportedPos = s0;
Daniel@0 12974 s1 = peg$c3(s1, s5);
Daniel@0 12975 s0 = s1;
Daniel@0 12976 } else {
Daniel@0 12977 peg$currPos = s0;
Daniel@0 12978 s0 = peg$c0;
Daniel@0 12979 }
Daniel@0 12980 } else {
Daniel@0 12981 peg$currPos = s0;
Daniel@0 12982 s0 = peg$c0;
Daniel@0 12983 }
Daniel@0 12984 } else {
Daniel@0 12985 peg$currPos = s0;
Daniel@0 12986 s0 = peg$c0;
Daniel@0 12987 }
Daniel@0 12988 } else {
Daniel@0 12989 peg$currPos = s0;
Daniel@0 12990 s0 = peg$c0;
Daniel@0 12991 }
Daniel@0 12992 } else {
Daniel@0 12993 peg$currPos = s0;
Daniel@0 12994 s0 = peg$c0;
Daniel@0 12995 }
Daniel@0 12996 if (s0 === peg$FAILED) {
Daniel@0 12997 s0 = peg$currPos;
Daniel@0 12998 s1 = peg$parseordered();
Daniel@0 12999 if (s1 !== peg$FAILED) {
Daniel@0 13000 peg$reportedPos = s0;
Daniel@0 13001 s1 = peg$c4(s1);
Daniel@0 13002 }
Daniel@0 13003 s0 = s1;
Daniel@0 13004 }
Daniel@0 13005
Daniel@0 13006 return s0;
Daniel@0 13007 }
Daniel@0 13008
Daniel@0 13009 function peg$parseordered() {
Daniel@0 13010 var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13;
Daniel@0 13011
Daniel@0 13012 s0 = peg$currPos;
Daniel@0 13013 if (input.charCodeAt(peg$currPos) === 91) {
Daniel@0 13014 s1 = peg$c5;
Daniel@0 13015 peg$currPos++;
Daniel@0 13016 } else {
Daniel@0 13017 s1 = peg$FAILED;
Daniel@0 13018 if (peg$silentFails === 0) { peg$fail(peg$c6); }
Daniel@0 13019 }
Daniel@0 13020 if (s1 !== peg$FAILED) {
Daniel@0 13021 s2 = peg$parsesep();
Daniel@0 13022 if (s2 !== peg$FAILED) {
Daniel@0 13023 s3 = peg$parsefiltered();
Daniel@0 13024 if (s3 !== peg$FAILED) {
Daniel@0 13025 s4 = peg$parsesep();
Daniel@0 13026 if (s4 !== peg$FAILED) {
Daniel@0 13027 if (input.charCodeAt(peg$currPos) === 44) {
Daniel@0 13028 s5 = peg$c1;
Daniel@0 13029 peg$currPos++;
Daniel@0 13030 } else {
Daniel@0 13031 s5 = peg$FAILED;
Daniel@0 13032 if (peg$silentFails === 0) { peg$fail(peg$c2); }
Daniel@0 13033 }
Daniel@0 13034 if (s5 !== peg$FAILED) {
Daniel@0 13035 s6 = peg$parsesep();
Daniel@0 13036 if (s6 !== peg$FAILED) {
Daniel@0 13037 s7 = peg$parsefiltered();
Daniel@0 13038 if (s7 !== peg$FAILED) {
Daniel@0 13039 s8 = peg$parsesep();
Daniel@0 13040 if (s8 !== peg$FAILED) {
Daniel@0 13041 if (input.charCodeAt(peg$currPos) === 93) {
Daniel@0 13042 s9 = peg$c7;
Daniel@0 13043 peg$currPos++;
Daniel@0 13044 } else {
Daniel@0 13045 s9 = peg$FAILED;
Daniel@0 13046 if (peg$silentFails === 0) { peg$fail(peg$c8); }
Daniel@0 13047 }
Daniel@0 13048 if (s9 !== peg$FAILED) {
Daniel@0 13049 s10 = peg$parsesep();
Daniel@0 13050 if (s10 !== peg$FAILED) {
Daniel@0 13051 if (input.charCodeAt(peg$currPos) === 62) {
Daniel@0 13052 s11 = peg$c9;
Daniel@0 13053 peg$currPos++;
Daniel@0 13054 } else {
Daniel@0 13055 s11 = peg$FAILED;
Daniel@0 13056 if (peg$silentFails === 0) { peg$fail(peg$c10); }
Daniel@0 13057 }
Daniel@0 13058 if (s11 !== peg$FAILED) {
Daniel@0 13059 s12 = peg$parsesep();
Daniel@0 13060 if (s12 !== peg$FAILED) {
Daniel@0 13061 s13 = peg$parseordered();
Daniel@0 13062 if (s13 !== peg$FAILED) {
Daniel@0 13063 peg$reportedPos = s0;
Daniel@0 13064 s1 = peg$c11(s3, s7, s13);
Daniel@0 13065 s0 = s1;
Daniel@0 13066 } else {
Daniel@0 13067 peg$currPos = s0;
Daniel@0 13068 s0 = peg$c0;
Daniel@0 13069 }
Daniel@0 13070 } else {
Daniel@0 13071 peg$currPos = s0;
Daniel@0 13072 s0 = peg$c0;
Daniel@0 13073 }
Daniel@0 13074 } else {
Daniel@0 13075 peg$currPos = s0;
Daniel@0 13076 s0 = peg$c0;
Daniel@0 13077 }
Daniel@0 13078 } else {
Daniel@0 13079 peg$currPos = s0;
Daniel@0 13080 s0 = peg$c0;
Daniel@0 13081 }
Daniel@0 13082 } else {
Daniel@0 13083 peg$currPos = s0;
Daniel@0 13084 s0 = peg$c0;
Daniel@0 13085 }
Daniel@0 13086 } else {
Daniel@0 13087 peg$currPos = s0;
Daniel@0 13088 s0 = peg$c0;
Daniel@0 13089 }
Daniel@0 13090 } else {
Daniel@0 13091 peg$currPos = s0;
Daniel@0 13092 s0 = peg$c0;
Daniel@0 13093 }
Daniel@0 13094 } else {
Daniel@0 13095 peg$currPos = s0;
Daniel@0 13096 s0 = peg$c0;
Daniel@0 13097 }
Daniel@0 13098 } else {
Daniel@0 13099 peg$currPos = s0;
Daniel@0 13100 s0 = peg$c0;
Daniel@0 13101 }
Daniel@0 13102 } else {
Daniel@0 13103 peg$currPos = s0;
Daniel@0 13104 s0 = peg$c0;
Daniel@0 13105 }
Daniel@0 13106 } else {
Daniel@0 13107 peg$currPos = s0;
Daniel@0 13108 s0 = peg$c0;
Daniel@0 13109 }
Daniel@0 13110 } else {
Daniel@0 13111 peg$currPos = s0;
Daniel@0 13112 s0 = peg$c0;
Daniel@0 13113 }
Daniel@0 13114 } else {
Daniel@0 13115 peg$currPos = s0;
Daniel@0 13116 s0 = peg$c0;
Daniel@0 13117 }
Daniel@0 13118 if (s0 === peg$FAILED) {
Daniel@0 13119 s0 = peg$parsefiltered();
Daniel@0 13120 }
Daniel@0 13121
Daniel@0 13122 return s0;
Daniel@0 13123 }
Daniel@0 13124
Daniel@0 13125 function peg$parsefiltered() {
Daniel@0 13126 var s0, s1, s2, s3;
Daniel@0 13127
Daniel@0 13128 s0 = peg$currPos;
Daniel@0 13129 s1 = peg$parsestream();
Daniel@0 13130 if (s1 !== peg$FAILED) {
Daniel@0 13131 s2 = [];
Daniel@0 13132 s3 = peg$parsefilter();
Daniel@0 13133 if (s3 !== peg$FAILED) {
Daniel@0 13134 while (s3 !== peg$FAILED) {
Daniel@0 13135 s2.push(s3);
Daniel@0 13136 s3 = peg$parsefilter();
Daniel@0 13137 }
Daniel@0 13138 } else {
Daniel@0 13139 s2 = peg$c0;
Daniel@0 13140 }
Daniel@0 13141 if (s2 !== peg$FAILED) {
Daniel@0 13142 peg$reportedPos = s0;
Daniel@0 13143 s1 = peg$c13(s1, s2);
Daniel@0 13144 s0 = s1;
Daniel@0 13145 } else {
Daniel@0 13146 peg$currPos = s0;
Daniel@0 13147 s0 = peg$c0;
Daniel@0 13148 }
Daniel@0 13149 } else {
Daniel@0 13150 peg$currPos = s0;
Daniel@0 13151 s0 = peg$c0;
Daniel@0 13152 }
Daniel@0 13153 if (s0 === peg$FAILED) {
Daniel@0 13154 s0 = peg$currPos;
Daniel@0 13155 s1 = peg$parsestream();
Daniel@0 13156 if (s1 !== peg$FAILED) {
Daniel@0 13157 peg$reportedPos = s0;
Daniel@0 13158 s1 = peg$c14(s1);
Daniel@0 13159 }
Daniel@0 13160 s0 = s1;
Daniel@0 13161 }
Daniel@0 13162
Daniel@0 13163 return s0;
Daniel@0 13164 }
Daniel@0 13165
Daniel@0 13166 function peg$parsestream() {
Daniel@0 13167 var s0, s1, s2, s3, s4;
Daniel@0 13168
Daniel@0 13169 s0 = peg$currPos;
Daniel@0 13170 if (input.charCodeAt(peg$currPos) === 40) {
Daniel@0 13171 s1 = peg$c15;
Daniel@0 13172 peg$currPos++;
Daniel@0 13173 } else {
Daniel@0 13174 s1 = peg$FAILED;
Daniel@0 13175 if (peg$silentFails === 0) { peg$fail(peg$c16); }
Daniel@0 13176 }
Daniel@0 13177 if (s1 !== peg$FAILED) {
Daniel@0 13178 s2 = peg$parsemerged();
Daniel@0 13179 if (s2 !== peg$FAILED) {
Daniel@0 13180 if (input.charCodeAt(peg$currPos) === 41) {
Daniel@0 13181 s3 = peg$c17;
Daniel@0 13182 peg$currPos++;
Daniel@0 13183 } else {
Daniel@0 13184 s3 = peg$FAILED;
Daniel@0 13185 if (peg$silentFails === 0) { peg$fail(peg$c18); }
Daniel@0 13186 }
Daniel@0 13187 if (s3 !== peg$FAILED) {
Daniel@0 13188 peg$reportedPos = s0;
Daniel@0 13189 s1 = peg$c19(s2);
Daniel@0 13190 s0 = s1;
Daniel@0 13191 } else {
Daniel@0 13192 peg$currPos = s0;
Daniel@0 13193 s0 = peg$c0;
Daniel@0 13194 }
Daniel@0 13195 } else {
Daniel@0 13196 peg$currPos = s0;
Daniel@0 13197 s0 = peg$c0;
Daniel@0 13198 }
Daniel@0 13199 } else {
Daniel@0 13200 peg$currPos = s0;
Daniel@0 13201 s0 = peg$c0;
Daniel@0 13202 }
Daniel@0 13203 if (s0 === peg$FAILED) {
Daniel@0 13204 s0 = peg$currPos;
Daniel@0 13205 if (input.charCodeAt(peg$currPos) === 64) {
Daniel@0 13206 s1 = peg$c20;
Daniel@0 13207 peg$currPos++;
Daniel@0 13208 } else {
Daniel@0 13209 s1 = peg$FAILED;
Daniel@0 13210 if (peg$silentFails === 0) { peg$fail(peg$c21); }
Daniel@0 13211 }
Daniel@0 13212 if (s1 !== peg$FAILED) {
Daniel@0 13213 s2 = peg$parsename();
Daniel@0 13214 if (s2 !== peg$FAILED) {
Daniel@0 13215 if (input.charCodeAt(peg$currPos) === 58) {
Daniel@0 13216 s3 = peg$c22;
Daniel@0 13217 peg$currPos++;
Daniel@0 13218 } else {
Daniel@0 13219 s3 = peg$FAILED;
Daniel@0 13220 if (peg$silentFails === 0) { peg$fail(peg$c23); }
Daniel@0 13221 }
Daniel@0 13222 if (s3 !== peg$FAILED) {
Daniel@0 13223 s4 = peg$parseeventType();
Daniel@0 13224 if (s4 !== peg$FAILED) {
Daniel@0 13225 peg$reportedPos = s0;
Daniel@0 13226 s1 = peg$c24(s2, s4);
Daniel@0 13227 s0 = s1;
Daniel@0 13228 } else {
Daniel@0 13229 peg$currPos = s0;
Daniel@0 13230 s0 = peg$c0;
Daniel@0 13231 }
Daniel@0 13232 } else {
Daniel@0 13233 peg$currPos = s0;
Daniel@0 13234 s0 = peg$c0;
Daniel@0 13235 }
Daniel@0 13236 } else {
Daniel@0 13237 peg$currPos = s0;
Daniel@0 13238 s0 = peg$c0;
Daniel@0 13239 }
Daniel@0 13240 } else {
Daniel@0 13241 peg$currPos = s0;
Daniel@0 13242 s0 = peg$c0;
Daniel@0 13243 }
Daniel@0 13244 if (s0 === peg$FAILED) {
Daniel@0 13245 s0 = peg$currPos;
Daniel@0 13246 s1 = peg$parsemarkType();
Daniel@0 13247 if (s1 !== peg$FAILED) {
Daniel@0 13248 if (input.charCodeAt(peg$currPos) === 58) {
Daniel@0 13249 s2 = peg$c22;
Daniel@0 13250 peg$currPos++;
Daniel@0 13251 } else {
Daniel@0 13252 s2 = peg$FAILED;
Daniel@0 13253 if (peg$silentFails === 0) { peg$fail(peg$c23); }
Daniel@0 13254 }
Daniel@0 13255 if (s2 !== peg$FAILED) {
Daniel@0 13256 s3 = peg$parseeventType();
Daniel@0 13257 if (s3 !== peg$FAILED) {
Daniel@0 13258 peg$reportedPos = s0;
Daniel@0 13259 s1 = peg$c25(s1, s3);
Daniel@0 13260 s0 = s1;
Daniel@0 13261 } else {
Daniel@0 13262 peg$currPos = s0;
Daniel@0 13263 s0 = peg$c0;
Daniel@0 13264 }
Daniel@0 13265 } else {
Daniel@0 13266 peg$currPos = s0;
Daniel@0 13267 s0 = peg$c0;
Daniel@0 13268 }
Daniel@0 13269 } else {
Daniel@0 13270 peg$currPos = s0;
Daniel@0 13271 s0 = peg$c0;
Daniel@0 13272 }
Daniel@0 13273 if (s0 === peg$FAILED) {
Daniel@0 13274 s0 = peg$currPos;
Daniel@0 13275 s1 = peg$parsecss();
Daniel@0 13276 if (s1 !== peg$FAILED) {
Daniel@0 13277 if (input.charCodeAt(peg$currPos) === 58) {
Daniel@0 13278 s2 = peg$c22;
Daniel@0 13279 peg$currPos++;
Daniel@0 13280 } else {
Daniel@0 13281 s2 = peg$FAILED;
Daniel@0 13282 if (peg$silentFails === 0) { peg$fail(peg$c23); }
Daniel@0 13283 }
Daniel@0 13284 if (s2 !== peg$FAILED) {
Daniel@0 13285 s3 = peg$parseeventType();
Daniel@0 13286 if (s3 !== peg$FAILED) {
Daniel@0 13287 peg$reportedPos = s0;
Daniel@0 13288 s1 = peg$c26(s1, s3);
Daniel@0 13289 s0 = s1;
Daniel@0 13290 } else {
Daniel@0 13291 peg$currPos = s0;
Daniel@0 13292 s0 = peg$c0;
Daniel@0 13293 }
Daniel@0 13294 } else {
Daniel@0 13295 peg$currPos = s0;
Daniel@0 13296 s0 = peg$c0;
Daniel@0 13297 }
Daniel@0 13298 } else {
Daniel@0 13299 peg$currPos = s0;
Daniel@0 13300 s0 = peg$c0;
Daniel@0 13301 }
Daniel@0 13302 if (s0 === peg$FAILED) {
Daniel@0 13303 s0 = peg$currPos;
Daniel@0 13304 s1 = peg$parseeventType();
Daniel@0 13305 if (s1 !== peg$FAILED) {
Daniel@0 13306 peg$reportedPos = s0;
Daniel@0 13307 s1 = peg$c27(s1);
Daniel@0 13308 }
Daniel@0 13309 s0 = s1;
Daniel@0 13310 if (s0 === peg$FAILED) {
Daniel@0 13311 s0 = peg$currPos;
Daniel@0 13312 s1 = peg$parsename();
Daniel@0 13313 if (s1 !== peg$FAILED) {
Daniel@0 13314 peg$reportedPos = s0;
Daniel@0 13315 s1 = peg$c28(s1);
Daniel@0 13316 }
Daniel@0 13317 s0 = s1;
Daniel@0 13318 }
Daniel@0 13319 }
Daniel@0 13320 }
Daniel@0 13321 }
Daniel@0 13322 }
Daniel@0 13323
Daniel@0 13324 return s0;
Daniel@0 13325 }
Daniel@0 13326
Daniel@0 13327 function peg$parsemarkType() {
Daniel@0 13328 var s0;
Daniel@0 13329
Daniel@0 13330 if (input.substr(peg$currPos, 4) === peg$c29) {
Daniel@0 13331 s0 = peg$c29;
Daniel@0 13332 peg$currPos += 4;
Daniel@0 13333 } else {
Daniel@0 13334 s0 = peg$FAILED;
Daniel@0 13335 if (peg$silentFails === 0) { peg$fail(peg$c30); }
Daniel@0 13336 }
Daniel@0 13337 if (s0 === peg$FAILED) {
Daniel@0 13338 if (input.substr(peg$currPos, 6) === peg$c31) {
Daniel@0 13339 s0 = peg$c31;
Daniel@0 13340 peg$currPos += 6;
Daniel@0 13341 } else {
Daniel@0 13342 s0 = peg$FAILED;
Daniel@0 13343 if (peg$silentFails === 0) { peg$fail(peg$c32); }
Daniel@0 13344 }
Daniel@0 13345 if (s0 === peg$FAILED) {
Daniel@0 13346 if (input.substr(peg$currPos, 4) === peg$c33) {
Daniel@0 13347 s0 = peg$c33;
Daniel@0 13348 peg$currPos += 4;
Daniel@0 13349 } else {
Daniel@0 13350 s0 = peg$FAILED;
Daniel@0 13351 if (peg$silentFails === 0) { peg$fail(peg$c34); }
Daniel@0 13352 }
Daniel@0 13353 if (s0 === peg$FAILED) {
Daniel@0 13354 if (input.substr(peg$currPos, 3) === peg$c35) {
Daniel@0 13355 s0 = peg$c35;
Daniel@0 13356 peg$currPos += 3;
Daniel@0 13357 } else {
Daniel@0 13358 s0 = peg$FAILED;
Daniel@0 13359 if (peg$silentFails === 0) { peg$fail(peg$c36); }
Daniel@0 13360 }
Daniel@0 13361 if (s0 === peg$FAILED) {
Daniel@0 13362 if (input.substr(peg$currPos, 4) === peg$c37) {
Daniel@0 13363 s0 = peg$c37;
Daniel@0 13364 peg$currPos += 4;
Daniel@0 13365 } else {
Daniel@0 13366 s0 = peg$FAILED;
Daniel@0 13367 if (peg$silentFails === 0) { peg$fail(peg$c38); }
Daniel@0 13368 }
Daniel@0 13369 if (s0 === peg$FAILED) {
Daniel@0 13370 if (input.substr(peg$currPos, 4) === peg$c39) {
Daniel@0 13371 s0 = peg$c39;
Daniel@0 13372 peg$currPos += 4;
Daniel@0 13373 } else {
Daniel@0 13374 s0 = peg$FAILED;
Daniel@0 13375 if (peg$silentFails === 0) { peg$fail(peg$c40); }
Daniel@0 13376 }
Daniel@0 13377 if (s0 === peg$FAILED) {
Daniel@0 13378 if (input.substr(peg$currPos, 4) === peg$c41) {
Daniel@0 13379 s0 = peg$c41;
Daniel@0 13380 peg$currPos += 4;
Daniel@0 13381 } else {
Daniel@0 13382 s0 = peg$FAILED;
Daniel@0 13383 if (peg$silentFails === 0) { peg$fail(peg$c42); }
Daniel@0 13384 }
Daniel@0 13385 if (s0 === peg$FAILED) {
Daniel@0 13386 if (input.substr(peg$currPos, 5) === peg$c43) {
Daniel@0 13387 s0 = peg$c43;
Daniel@0 13388 peg$currPos += 5;
Daniel@0 13389 } else {
Daniel@0 13390 s0 = peg$FAILED;
Daniel@0 13391 if (peg$silentFails === 0) { peg$fail(peg$c44); }
Daniel@0 13392 }
Daniel@0 13393 if (s0 === peg$FAILED) {
Daniel@0 13394 if (input.substr(peg$currPos, 4) === peg$c45) {
Daniel@0 13395 s0 = peg$c45;
Daniel@0 13396 peg$currPos += 4;
Daniel@0 13397 } else {
Daniel@0 13398 s0 = peg$FAILED;
Daniel@0 13399 if (peg$silentFails === 0) { peg$fail(peg$c46); }
Daniel@0 13400 }
Daniel@0 13401 if (s0 === peg$FAILED) {
Daniel@0 13402 if (input.substr(peg$currPos, 5) === peg$c47) {
Daniel@0 13403 s0 = peg$c47;
Daniel@0 13404 peg$currPos += 5;
Daniel@0 13405 } else {
Daniel@0 13406 s0 = peg$FAILED;
Daniel@0 13407 if (peg$silentFails === 0) { peg$fail(peg$c48); }
Daniel@0 13408 }
Daniel@0 13409 }
Daniel@0 13410 }
Daniel@0 13411 }
Daniel@0 13412 }
Daniel@0 13413 }
Daniel@0 13414 }
Daniel@0 13415 }
Daniel@0 13416 }
Daniel@0 13417 }
Daniel@0 13418
Daniel@0 13419 return s0;
Daniel@0 13420 }
Daniel@0 13421
Daniel@0 13422 function peg$parseeventType() {
Daniel@0 13423 var s0;
Daniel@0 13424
Daniel@0 13425 if (input.substr(peg$currPos, 9) === peg$c49) {
Daniel@0 13426 s0 = peg$c49;
Daniel@0 13427 peg$currPos += 9;
Daniel@0 13428 } else {
Daniel@0 13429 s0 = peg$FAILED;
Daniel@0 13430 if (peg$silentFails === 0) { peg$fail(peg$c50); }
Daniel@0 13431 }
Daniel@0 13432 if (s0 === peg$FAILED) {
Daniel@0 13433 if (input.substr(peg$currPos, 7) === peg$c51) {
Daniel@0 13434 s0 = peg$c51;
Daniel@0 13435 peg$currPos += 7;
Daniel@0 13436 } else {
Daniel@0 13437 s0 = peg$FAILED;
Daniel@0 13438 if (peg$silentFails === 0) { peg$fail(peg$c52); }
Daniel@0 13439 }
Daniel@0 13440 if (s0 === peg$FAILED) {
Daniel@0 13441 if (input.substr(peg$currPos, 5) === peg$c53) {
Daniel@0 13442 s0 = peg$c53;
Daniel@0 13443 peg$currPos += 5;
Daniel@0 13444 } else {
Daniel@0 13445 s0 = peg$FAILED;
Daniel@0 13446 if (peg$silentFails === 0) { peg$fail(peg$c54); }
Daniel@0 13447 }
Daniel@0 13448 if (s0 === peg$FAILED) {
Daniel@0 13449 if (input.substr(peg$currPos, 8) === peg$c55) {
Daniel@0 13450 s0 = peg$c55;
Daniel@0 13451 peg$currPos += 8;
Daniel@0 13452 } else {
Daniel@0 13453 s0 = peg$FAILED;
Daniel@0 13454 if (peg$silentFails === 0) { peg$fail(peg$c56); }
Daniel@0 13455 }
Daniel@0 13456 if (s0 === peg$FAILED) {
Daniel@0 13457 if (input.substr(peg$currPos, 5) === peg$c57) {
Daniel@0 13458 s0 = peg$c57;
Daniel@0 13459 peg$currPos += 5;
Daniel@0 13460 } else {
Daniel@0 13461 s0 = peg$FAILED;
Daniel@0 13462 if (peg$silentFails === 0) { peg$fail(peg$c58); }
Daniel@0 13463 }
Daniel@0 13464 if (s0 === peg$FAILED) {
Daniel@0 13465 if (input.substr(peg$currPos, 7) === peg$c59) {
Daniel@0 13466 s0 = peg$c59;
Daniel@0 13467 peg$currPos += 7;
Daniel@0 13468 } else {
Daniel@0 13469 s0 = peg$FAILED;
Daniel@0 13470 if (peg$silentFails === 0) { peg$fail(peg$c60); }
Daniel@0 13471 }
Daniel@0 13472 if (s0 === peg$FAILED) {
Daniel@0 13473 if (input.substr(peg$currPos, 8) === peg$c61) {
Daniel@0 13474 s0 = peg$c61;
Daniel@0 13475 peg$currPos += 8;
Daniel@0 13476 } else {
Daniel@0 13477 s0 = peg$FAILED;
Daniel@0 13478 if (peg$silentFails === 0) { peg$fail(peg$c62); }
Daniel@0 13479 }
Daniel@0 13480 if (s0 === peg$FAILED) {
Daniel@0 13481 if (input.substr(peg$currPos, 5) === peg$c63) {
Daniel@0 13482 s0 = peg$c63;
Daniel@0 13483 peg$currPos += 5;
Daniel@0 13484 } else {
Daniel@0 13485 s0 = peg$FAILED;
Daniel@0 13486 if (peg$silentFails === 0) { peg$fail(peg$c64); }
Daniel@0 13487 }
Daniel@0 13488 if (s0 === peg$FAILED) {
Daniel@0 13489 if (input.substr(peg$currPos, 10) === peg$c65) {
Daniel@0 13490 s0 = peg$c65;
Daniel@0 13491 peg$currPos += 10;
Daniel@0 13492 } else {
Daniel@0 13493 s0 = peg$FAILED;
Daniel@0 13494 if (peg$silentFails === 0) { peg$fail(peg$c66); }
Daniel@0 13495 }
Daniel@0 13496 if (s0 === peg$FAILED) {
Daniel@0 13497 if (input.substr(peg$currPos, 9) === peg$c67) {
Daniel@0 13498 s0 = peg$c67;
Daniel@0 13499 peg$currPos += 9;
Daniel@0 13500 } else {
Daniel@0 13501 s0 = peg$FAILED;
Daniel@0 13502 if (peg$silentFails === 0) { peg$fail(peg$c68); }
Daniel@0 13503 }
Daniel@0 13504 if (s0 === peg$FAILED) {
Daniel@0 13505 if (input.substr(peg$currPos, 8) === peg$c69) {
Daniel@0 13506 s0 = peg$c69;
Daniel@0 13507 peg$currPos += 8;
Daniel@0 13508 } else {
Daniel@0 13509 s0 = peg$FAILED;
Daniel@0 13510 if (peg$silentFails === 0) { peg$fail(peg$c70); }
Daniel@0 13511 }
Daniel@0 13512 if (s0 === peg$FAILED) {
Daniel@0 13513 if (input.substr(peg$currPos, 9) === peg$c71) {
Daniel@0 13514 s0 = peg$c71;
Daniel@0 13515 peg$currPos += 9;
Daniel@0 13516 } else {
Daniel@0 13517 s0 = peg$FAILED;
Daniel@0 13518 if (peg$silentFails === 0) { peg$fail(peg$c72); }
Daniel@0 13519 }
Daniel@0 13520 if (s0 === peg$FAILED) {
Daniel@0 13521 if (input.substr(peg$currPos, 10) === peg$c73) {
Daniel@0 13522 s0 = peg$c73;
Daniel@0 13523 peg$currPos += 10;
Daniel@0 13524 } else {
Daniel@0 13525 s0 = peg$FAILED;
Daniel@0 13526 if (peg$silentFails === 0) { peg$fail(peg$c74); }
Daniel@0 13527 }
Daniel@0 13528 if (s0 === peg$FAILED) {
Daniel@0 13529 if (input.substr(peg$currPos, 10) === peg$c75) {
Daniel@0 13530 s0 = peg$c75;
Daniel@0 13531 peg$currPos += 10;
Daniel@0 13532 } else {
Daniel@0 13533 s0 = peg$FAILED;
Daniel@0 13534 if (peg$silentFails === 0) { peg$fail(peg$c76); }
Daniel@0 13535 }
Daniel@0 13536 if (s0 === peg$FAILED) {
Daniel@0 13537 if (input.substr(peg$currPos, 9) === peg$c77) {
Daniel@0 13538 s0 = peg$c77;
Daniel@0 13539 peg$currPos += 9;
Daniel@0 13540 } else {
Daniel@0 13541 s0 = peg$FAILED;
Daniel@0 13542 if (peg$silentFails === 0) { peg$fail(peg$c78); }
Daniel@0 13543 }
Daniel@0 13544 if (s0 === peg$FAILED) {
Daniel@0 13545 if (input.substr(peg$currPos, 8) === peg$c79) {
Daniel@0 13546 s0 = peg$c79;
Daniel@0 13547 peg$currPos += 8;
Daniel@0 13548 } else {
Daniel@0 13549 s0 = peg$FAILED;
Daniel@0 13550 if (peg$silentFails === 0) { peg$fail(peg$c80); }
Daniel@0 13551 }
Daniel@0 13552 }
Daniel@0 13553 }
Daniel@0 13554 }
Daniel@0 13555 }
Daniel@0 13556 }
Daniel@0 13557 }
Daniel@0 13558 }
Daniel@0 13559 }
Daniel@0 13560 }
Daniel@0 13561 }
Daniel@0 13562 }
Daniel@0 13563 }
Daniel@0 13564 }
Daniel@0 13565 }
Daniel@0 13566 }
Daniel@0 13567
Daniel@0 13568 return s0;
Daniel@0 13569 }
Daniel@0 13570
Daniel@0 13571 function peg$parsefilter() {
Daniel@0 13572 var s0, s1, s2, s3;
Daniel@0 13573
Daniel@0 13574 s0 = peg$currPos;
Daniel@0 13575 if (input.charCodeAt(peg$currPos) === 91) {
Daniel@0 13576 s1 = peg$c5;
Daniel@0 13577 peg$currPos++;
Daniel@0 13578 } else {
Daniel@0 13579 s1 = peg$FAILED;
Daniel@0 13580 if (peg$silentFails === 0) { peg$fail(peg$c6); }
Daniel@0 13581 }
Daniel@0 13582 if (s1 !== peg$FAILED) {
Daniel@0 13583 s2 = peg$parseexpr();
Daniel@0 13584 if (s2 !== peg$FAILED) {
Daniel@0 13585 if (input.charCodeAt(peg$currPos) === 93) {
Daniel@0 13586 s3 = peg$c7;
Daniel@0 13587 peg$currPos++;
Daniel@0 13588 } else {
Daniel@0 13589 s3 = peg$FAILED;
Daniel@0 13590 if (peg$silentFails === 0) { peg$fail(peg$c8); }
Daniel@0 13591 }
Daniel@0 13592 if (s3 !== peg$FAILED) {
Daniel@0 13593 peg$reportedPos = s0;
Daniel@0 13594 s1 = peg$c81(s2);
Daniel@0 13595 s0 = s1;
Daniel@0 13596 } else {
Daniel@0 13597 peg$currPos = s0;
Daniel@0 13598 s0 = peg$c0;
Daniel@0 13599 }
Daniel@0 13600 } else {
Daniel@0 13601 peg$currPos = s0;
Daniel@0 13602 s0 = peg$c0;
Daniel@0 13603 }
Daniel@0 13604 } else {
Daniel@0 13605 peg$currPos = s0;
Daniel@0 13606 s0 = peg$c0;
Daniel@0 13607 }
Daniel@0 13608
Daniel@0 13609 return s0;
Daniel@0 13610 }
Daniel@0 13611
Daniel@0 13612 function peg$parsename() {
Daniel@0 13613 var s0, s1, s2;
Daniel@0 13614
Daniel@0 13615 s0 = peg$currPos;
Daniel@0 13616 s1 = [];
Daniel@0 13617 if (peg$c82.test(input.charAt(peg$currPos))) {
Daniel@0 13618 s2 = input.charAt(peg$currPos);
Daniel@0 13619 peg$currPos++;
Daniel@0 13620 } else {
Daniel@0 13621 s2 = peg$FAILED;
Daniel@0 13622 if (peg$silentFails === 0) { peg$fail(peg$c83); }
Daniel@0 13623 }
Daniel@0 13624 if (s2 !== peg$FAILED) {
Daniel@0 13625 while (s2 !== peg$FAILED) {
Daniel@0 13626 s1.push(s2);
Daniel@0 13627 if (peg$c82.test(input.charAt(peg$currPos))) {
Daniel@0 13628 s2 = input.charAt(peg$currPos);
Daniel@0 13629 peg$currPos++;
Daniel@0 13630 } else {
Daniel@0 13631 s2 = peg$FAILED;
Daniel@0 13632 if (peg$silentFails === 0) { peg$fail(peg$c83); }
Daniel@0 13633 }
Daniel@0 13634 }
Daniel@0 13635 } else {
Daniel@0 13636 s1 = peg$c0;
Daniel@0 13637 }
Daniel@0 13638 if (s1 !== peg$FAILED) {
Daniel@0 13639 peg$reportedPos = s0;
Daniel@0 13640 s1 = peg$c84(s1);
Daniel@0 13641 }
Daniel@0 13642 s0 = s1;
Daniel@0 13643
Daniel@0 13644 return s0;
Daniel@0 13645 }
Daniel@0 13646
Daniel@0 13647 function peg$parsecss() {
Daniel@0 13648 var s0, s1, s2;
Daniel@0 13649
Daniel@0 13650 s0 = peg$currPos;
Daniel@0 13651 s1 = [];
Daniel@0 13652 if (peg$c85.test(input.charAt(peg$currPos))) {
Daniel@0 13653 s2 = input.charAt(peg$currPos);
Daniel@0 13654 peg$currPos++;
Daniel@0 13655 } else {
Daniel@0 13656 s2 = peg$FAILED;
Daniel@0 13657 if (peg$silentFails === 0) { peg$fail(peg$c86); }
Daniel@0 13658 }
Daniel@0 13659 if (s2 !== peg$FAILED) {
Daniel@0 13660 while (s2 !== peg$FAILED) {
Daniel@0 13661 s1.push(s2);
Daniel@0 13662 if (peg$c85.test(input.charAt(peg$currPos))) {
Daniel@0 13663 s2 = input.charAt(peg$currPos);
Daniel@0 13664 peg$currPos++;
Daniel@0 13665 } else {
Daniel@0 13666 s2 = peg$FAILED;
Daniel@0 13667 if (peg$silentFails === 0) { peg$fail(peg$c86); }
Daniel@0 13668 }
Daniel@0 13669 }
Daniel@0 13670 } else {
Daniel@0 13671 s1 = peg$c0;
Daniel@0 13672 }
Daniel@0 13673 if (s1 !== peg$FAILED) {
Daniel@0 13674 peg$reportedPos = s0;
Daniel@0 13675 s1 = peg$c87(s1);
Daniel@0 13676 }
Daniel@0 13677 s0 = s1;
Daniel@0 13678
Daniel@0 13679 return s0;
Daniel@0 13680 }
Daniel@0 13681
Daniel@0 13682 function peg$parseexpr() {
Daniel@0 13683 var s0, s1, s2;
Daniel@0 13684
Daniel@0 13685 s0 = peg$currPos;
Daniel@0 13686 s1 = [];
Daniel@0 13687 if (peg$c88.test(input.charAt(peg$currPos))) {
Daniel@0 13688 s2 = input.charAt(peg$currPos);
Daniel@0 13689 peg$currPos++;
Daniel@0 13690 } else {
Daniel@0 13691 s2 = peg$FAILED;
Daniel@0 13692 if (peg$silentFails === 0) { peg$fail(peg$c89); }
Daniel@0 13693 }
Daniel@0 13694 if (s2 !== peg$FAILED) {
Daniel@0 13695 while (s2 !== peg$FAILED) {
Daniel@0 13696 s1.push(s2);
Daniel@0 13697 if (peg$c88.test(input.charAt(peg$currPos))) {
Daniel@0 13698 s2 = input.charAt(peg$currPos);
Daniel@0 13699 peg$currPos++;
Daniel@0 13700 } else {
Daniel@0 13701 s2 = peg$FAILED;
Daniel@0 13702 if (peg$silentFails === 0) { peg$fail(peg$c89); }
Daniel@0 13703 }
Daniel@0 13704 }
Daniel@0 13705 } else {
Daniel@0 13706 s1 = peg$c0;
Daniel@0 13707 }
Daniel@0 13708 if (s1 !== peg$FAILED) {
Daniel@0 13709 peg$reportedPos = s0;
Daniel@0 13710 s1 = peg$c90(s1);
Daniel@0 13711 }
Daniel@0 13712 s0 = s1;
Daniel@0 13713
Daniel@0 13714 return s0;
Daniel@0 13715 }
Daniel@0 13716
Daniel@0 13717 function peg$parsesep() {
Daniel@0 13718 var s0, s1;
Daniel@0 13719
Daniel@0 13720 s0 = [];
Daniel@0 13721 if (peg$c91.test(input.charAt(peg$currPos))) {
Daniel@0 13722 s1 = input.charAt(peg$currPos);
Daniel@0 13723 peg$currPos++;
Daniel@0 13724 } else {
Daniel@0 13725 s1 = peg$FAILED;
Daniel@0 13726 if (peg$silentFails === 0) { peg$fail(peg$c92); }
Daniel@0 13727 }
Daniel@0 13728 while (s1 !== peg$FAILED) {
Daniel@0 13729 s0.push(s1);
Daniel@0 13730 if (peg$c91.test(input.charAt(peg$currPos))) {
Daniel@0 13731 s1 = input.charAt(peg$currPos);
Daniel@0 13732 peg$currPos++;
Daniel@0 13733 } else {
Daniel@0 13734 s1 = peg$FAILED;
Daniel@0 13735 if (peg$silentFails === 0) { peg$fail(peg$c92); }
Daniel@0 13736 }
Daniel@0 13737 }
Daniel@0 13738
Daniel@0 13739 return s0;
Daniel@0 13740 }
Daniel@0 13741
Daniel@0 13742 peg$result = peg$startRuleFunction();
Daniel@0 13743
Daniel@0 13744 if (peg$result !== peg$FAILED && peg$currPos === input.length) {
Daniel@0 13745 return peg$result;
Daniel@0 13746 } else {
Daniel@0 13747 if (peg$result !== peg$FAILED && peg$currPos < input.length) {
Daniel@0 13748 peg$fail({ type: "end", description: "end of input" });
Daniel@0 13749 }
Daniel@0 13750
Daniel@0 13751 throw peg$buildException(null, peg$maxFailExpected, peg$maxFailPos);
Daniel@0 13752 }
Daniel@0 13753 }
Daniel@0 13754
Daniel@0 13755 return {
Daniel@0 13756 SyntaxError: SyntaxError,
Daniel@0 13757 parse: parse
Daniel@0 13758 };
Daniel@0 13759 })();
Daniel@0 13760 },{}],94:[function(require,module,exports){
Daniel@0 13761 var expr = require('vega-expression'),
Daniel@0 13762 args = ['datum', 'event', 'signals'];
Daniel@0 13763
Daniel@0 13764 module.exports = expr.compiler(args, {
Daniel@0 13765 idWhiteList: args,
Daniel@0 13766 fieldVar: args[0],
Daniel@0 13767 globalVar: args[2],
Daniel@0 13768 functions: function(codegen) {
Daniel@0 13769 var fn = expr.functions(codegen);
Daniel@0 13770 fn.eventItem = function() { return 'event.vg.item'; };
Daniel@0 13771 fn.eventGroup = 'event.vg.getGroup';
Daniel@0 13772 fn.eventX = 'event.vg.getX';
Daniel@0 13773 fn.eventY = 'event.vg.getY';
Daniel@0 13774 fn.open = 'window.open';
Daniel@0 13775 return fn;
Daniel@0 13776 }
Daniel@0 13777 });
Daniel@0 13778 },{"vega-expression":43}],95:[function(require,module,exports){
Daniel@0 13779 module.exports = {
Daniel@0 13780 axes: require('./axes'),
Daniel@0 13781 background: require('./background'),
Daniel@0 13782 data: require('./data'),
Daniel@0 13783 events: require('./events'),
Daniel@0 13784 expr: require('./expr'),
Daniel@0 13785 legends: require('./legends'),
Daniel@0 13786 mark: require('./mark'),
Daniel@0 13787 marks: require('./marks'),
Daniel@0 13788 modify: require('./modify'),
Daniel@0 13789 padding: require('./padding'),
Daniel@0 13790 predicates: require('./predicates'),
Daniel@0 13791 properties: require('./properties'),
Daniel@0 13792 signals: require('./signals'),
Daniel@0 13793 spec: require('./spec'),
Daniel@0 13794 streams: require('./streams'),
Daniel@0 13795 transforms: require('./transforms')
Daniel@0 13796 };
Daniel@0 13797 },{"./axes":90,"./background":91,"./data":92,"./events":93,"./expr":94,"./legends":96,"./mark":97,"./marks":98,"./modify":99,"./padding":100,"./predicates":101,"./properties":102,"./signals":103,"./spec":104,"./streams":105,"./transforms":106}],96:[function(require,module,exports){
Daniel@0 13798 var lgnd = require('../scene/legend');
Daniel@0 13799
Daniel@0 13800 function parseLegends(model, spec, legends, group) {
Daniel@0 13801 (spec || []).forEach(function(def, index) {
Daniel@0 13802 legends[index] = legends[index] || lgnd(model);
Daniel@0 13803 parseLegend(def, index, legends[index], group);
Daniel@0 13804 });
Daniel@0 13805 }
Daniel@0 13806
Daniel@0 13807 function parseLegend(def, index, legend, group) {
Daniel@0 13808 // legend scales
Daniel@0 13809 legend.size (def.size ? group.scale(def.size) : null);
Daniel@0 13810 legend.shape (def.shape ? group.scale(def.shape) : null);
Daniel@0 13811 legend.fill (def.fill ? group.scale(def.fill) : null);
Daniel@0 13812 legend.stroke(def.stroke ? group.scale(def.stroke) : null);
Daniel@0 13813
Daniel@0 13814 // legend orientation
Daniel@0 13815 if (def.orient) legend.orient(def.orient);
Daniel@0 13816
Daniel@0 13817 // legend offset
Daniel@0 13818 if (def.offset != null) legend.offset(def.offset);
Daniel@0 13819
Daniel@0 13820 // legend title
Daniel@0 13821 legend.title(def.title || null);
Daniel@0 13822
Daniel@0 13823 // legend values
Daniel@0 13824 legend.values(def.values || null);
Daniel@0 13825
Daniel@0 13826 // legend label formatting
Daniel@0 13827 legend.format(def.format !== undefined ? def.format : null);
Daniel@0 13828
Daniel@0 13829 // style properties
Daniel@0 13830 var p = def.properties;
Daniel@0 13831 legend.titleProperties(p && p.title || {});
Daniel@0 13832 legend.labelProperties(p && p.labels || {});
Daniel@0 13833 legend.legendProperties(p && p.legend || {});
Daniel@0 13834 legend.symbolProperties(p && p.symbols || {});
Daniel@0 13835 legend.gradientProperties(p && p.gradient || {});
Daniel@0 13836 }
Daniel@0 13837
Daniel@0 13838 module.exports = parseLegends;
Daniel@0 13839 },{"../scene/legend":114}],97:[function(require,module,exports){
Daniel@0 13840 var dl = require('datalib'),
Daniel@0 13841 parseProperties = require('./properties');
Daniel@0 13842
Daniel@0 13843 function parseMark(model, mark) {
Daniel@0 13844 var props = mark.properties,
Daniel@0 13845 group = mark.marks;
Daniel@0 13846
Daniel@0 13847 // parse mark property definitions
Daniel@0 13848 dl.keys(props).forEach(function(k) {
Daniel@0 13849 props[k] = parseProperties(model, mark.type, props[k]);
Daniel@0 13850 });
Daniel@0 13851
Daniel@0 13852 // parse delay function
Daniel@0 13853 if (mark.delay) {
Daniel@0 13854 mark.delay = parseProperties(model, mark.type, {delay: mark.delay});
Daniel@0 13855 }
Daniel@0 13856
Daniel@0 13857 // recurse if group type
Daniel@0 13858 if (group) {
Daniel@0 13859 mark.marks = group.map(function(g) { return parseMark(model, g); });
Daniel@0 13860 }
Daniel@0 13861
Daniel@0 13862 return mark;
Daniel@0 13863 }
Daniel@0 13864
Daniel@0 13865 module.exports = parseMark;
Daniel@0 13866 },{"./properties":102,"datalib":24}],98:[function(require,module,exports){
Daniel@0 13867 var parseMark = require('./mark');
Daniel@0 13868
Daniel@0 13869 function parseRootMark(model, spec, width, height) {
Daniel@0 13870 return {
Daniel@0 13871 type: "group",
Daniel@0 13872 width: width,
Daniel@0 13873 height: height,
Daniel@0 13874 scales: spec.scales || [],
Daniel@0 13875 axes: spec.axes || [],
Daniel@0 13876 legends: spec.legends || [],
Daniel@0 13877 marks: (spec.marks || []).map(function(m) { return parseMark(model, m); })
Daniel@0 13878 };
Daniel@0 13879 }
Daniel@0 13880
Daniel@0 13881 module.exports = parseRootMark;
Daniel@0 13882 },{"./mark":97}],99:[function(require,module,exports){
Daniel@0 13883 var dl = require('datalib'),
Daniel@0 13884 log = require('vega-logging'),
Daniel@0 13885 df = require('vega-dataflow'),
Daniel@0 13886 Node = df.Node, // jshint ignore:line
Daniel@0 13887 Tuple = df.Tuple,
Daniel@0 13888 Deps = df.Dependencies;
Daniel@0 13889
Daniel@0 13890 var Types = {
Daniel@0 13891 INSERT: "insert",
Daniel@0 13892 REMOVE: "remove",
Daniel@0 13893 TOGGLE: "toggle",
Daniel@0 13894 CLEAR: "clear"
Daniel@0 13895 };
Daniel@0 13896
Daniel@0 13897 var EMPTY = [];
Daniel@0 13898
Daniel@0 13899 var filter = function(field, value, src, dest) {
Daniel@0 13900 for(var i = src.length-1; i >= 0; --i) {
Daniel@0 13901 if (src[i][field] == value)
Daniel@0 13902 dest.push.apply(dest, src.splice(i, 1));
Daniel@0 13903 }
Daniel@0 13904 };
Daniel@0 13905
Daniel@0 13906 function parseModify(model, def, ds) {
Daniel@0 13907 var signal = def.signal ? dl.field(def.signal) : null,
Daniel@0 13908 signalName = signal ? signal[0] : null,
Daniel@0 13909 predicate = def.predicate ? model.predicate(def.predicate.name || def.predicate) : null,
Daniel@0 13910 reeval = (predicate === null),
Daniel@0 13911 node = new Node(model).router(def.type === Types.CLEAR);
Daniel@0 13912
Daniel@0 13913 node.evaluate = function(input) {
Daniel@0 13914 if (predicate !== null) { // TODO: predicate args
Daniel@0 13915 var db = model.values(Deps.DATA, predicate.data || EMPTY),
Daniel@0 13916 sg = model.values(Deps.SIGNALS, predicate.signals || EMPTY);
Daniel@0 13917 reeval = predicate.call(predicate, {}, db, sg, model._predicates);
Daniel@0 13918 }
Daniel@0 13919
Daniel@0 13920 log.debug(input, [def.type+"ing", reeval]);
Daniel@0 13921 if (!reeval) return input;
Daniel@0 13922
Daniel@0 13923 var datum = {},
Daniel@0 13924 value = signal ? model.signalRef(def.signal) : null,
Daniel@0 13925 d = model.data(ds.name),
Daniel@0 13926 t = null;
Daniel@0 13927
Daniel@0 13928 datum[def.field] = value;
Daniel@0 13929
Daniel@0 13930 // We have to modify ds._data so that subsequent pulses contain
Daniel@0 13931 // our dynamic data. W/o modifying ds._data, only the output
Daniel@0 13932 // collector will contain dynamic tuples.
Daniel@0 13933 if (def.type === Types.INSERT) {
Daniel@0 13934 t = Tuple.ingest(datum);
Daniel@0 13935 input.add.push(t);
Daniel@0 13936 d._data.push(t);
Daniel@0 13937 } else if (def.type === Types.REMOVE) {
Daniel@0 13938 filter(def.field, value, input.add, input.rem);
Daniel@0 13939 filter(def.field, value, input.mod, input.rem);
Daniel@0 13940 d._data = d._data.filter(function(x) { return x[def.field] !== value; });
Daniel@0 13941 } else if (def.type === Types.TOGGLE) {
Daniel@0 13942 var add = [], rem = [];
Daniel@0 13943 filter(def.field, value, input.rem, add);
Daniel@0 13944 filter(def.field, value, input.add, rem);
Daniel@0 13945 filter(def.field, value, input.mod, rem);
Daniel@0 13946 if (!(add.length || rem.length)) add.push(Tuple.ingest(datum));
Daniel@0 13947
Daniel@0 13948 input.add.push.apply(input.add, add);
Daniel@0 13949 d._data.push.apply(d._data, add);
Daniel@0 13950 input.rem.push.apply(input.rem, rem);
Daniel@0 13951 d._data = d._data.filter(function(x) { return rem.indexOf(x) === -1; });
Daniel@0 13952 } else if (def.type === Types.CLEAR) {
Daniel@0 13953 input.rem.push.apply(input.rem, input.add);
Daniel@0 13954 input.rem.push.apply(input.rem, input.mod);
Daniel@0 13955 input.add = [];
Daniel@0 13956 input.mod = [];
Daniel@0 13957 d._data = [];
Daniel@0 13958 }
Daniel@0 13959
Daniel@0 13960 input.fields[def.field] = 1;
Daniel@0 13961 return input;
Daniel@0 13962 };
Daniel@0 13963
Daniel@0 13964 if (signalName) node.dependency(Deps.SIGNALS, signalName);
Daniel@0 13965
Daniel@0 13966 if (predicate) {
Daniel@0 13967 node.dependency(Deps.DATA, predicate.data);
Daniel@0 13968 node.dependency(Deps.SIGNALS, predicate.signals);
Daniel@0 13969 }
Daniel@0 13970
Daniel@0 13971 return node;
Daniel@0 13972 }
Daniel@0 13973
Daniel@0 13974 module.exports = parseModify;
Daniel@0 13975 },{"datalib":24,"vega-dataflow":39,"vega-logging":45}],100:[function(require,module,exports){
Daniel@0 13976 var dl = require('datalib');
Daniel@0 13977
Daniel@0 13978 function parsePadding(pad) {
Daniel@0 13979 if (pad == null) return "auto";
Daniel@0 13980 else if (dl.isString(pad)) return pad==="strict" ? "strict" : "auto";
Daniel@0 13981 else if (dl.isObject(pad)) return pad;
Daniel@0 13982 var p = dl.isNumber(pad) ? pad : 20;
Daniel@0 13983 return {top:p, left:p, right:p, bottom:p};
Daniel@0 13984 }
Daniel@0 13985
Daniel@0 13986 module.exports = parsePadding;
Daniel@0 13987 },{"datalib":24}],101:[function(require,module,exports){
Daniel@0 13988 var dl = require('datalib');
Daniel@0 13989
Daniel@0 13990 var types = {
Daniel@0 13991 '=': parseComparator,
Daniel@0 13992 '==': parseComparator,
Daniel@0 13993 '!=': parseComparator,
Daniel@0 13994 '>': parseComparator,
Daniel@0 13995 '>=': parseComparator,
Daniel@0 13996 '<': parseComparator,
Daniel@0 13997 '<=': parseComparator,
Daniel@0 13998 'and': parseLogical,
Daniel@0 13999 '&&': parseLogical,
Daniel@0 14000 'or': parseLogical,
Daniel@0 14001 '||': parseLogical,
Daniel@0 14002 'in': parseIn
Daniel@0 14003 };
Daniel@0 14004
Daniel@0 14005 var nullScale = function() { return 0; };
Daniel@0 14006 nullScale.invert = nullScale;
Daniel@0 14007
Daniel@0 14008 function parsePredicates(model, spec) {
Daniel@0 14009 (spec || []).forEach(function(s) {
Daniel@0 14010 var parse = types[s.type](model, s);
Daniel@0 14011
Daniel@0 14012 /* jshint evil:true */
Daniel@0 14013 var pred = Function("args", "db", "signals", "predicates", parse.code);
Daniel@0 14014 pred.root = function() { return model.scene().items[0]; }; // For global scales
Daniel@0 14015 pred.nullScale = nullScale;
Daniel@0 14016 pred.isFunction = dl.isFunction;
Daniel@0 14017 pred.signals = parse.signals;
Daniel@0 14018 pred.data = parse.data;
Daniel@0 14019
Daniel@0 14020 model.predicate(s.name, pred);
Daniel@0 14021 });
Daniel@0 14022
Daniel@0 14023 return spec;
Daniel@0 14024 }
Daniel@0 14025
Daniel@0 14026 function parseSignal(signal, signals) {
Daniel@0 14027 var s = dl.field(signal),
Daniel@0 14028 code = "signals["+s.map(dl.str).join("][")+"]";
Daniel@0 14029 signals[s[0]] = 1;
Daniel@0 14030 return code;
Daniel@0 14031 }
Daniel@0 14032
Daniel@0 14033 function parseOperands(model, operands) {
Daniel@0 14034 var decl = [], defs = [],
Daniel@0 14035 signals = {}, db = {};
Daniel@0 14036
Daniel@0 14037 function setSignal(s) { signals[s] = 1; }
Daniel@0 14038 function setData(d) { db[d] = 1; }
Daniel@0 14039
Daniel@0 14040 dl.array(operands).forEach(function(o, i) {
Daniel@0 14041 var name = "o" + i,
Daniel@0 14042 def = "";
Daniel@0 14043
Daniel@0 14044 if (o.value !== undefined) {
Daniel@0 14045 def = dl.str(o.value);
Daniel@0 14046 } else if (o.arg) {
Daniel@0 14047 def = "args["+dl.str(o.arg)+"]";
Daniel@0 14048 } else if (o.signal) {
Daniel@0 14049 def = parseSignal(o.signal, signals);
Daniel@0 14050 } else if (o.predicate) {
Daniel@0 14051 var ref = o.predicate,
Daniel@0 14052 predName = ref && (ref.name || ref),
Daniel@0 14053 pred = model.predicate(predName),
Daniel@0 14054 p = "predicates["+dl.str(predName)+"]";
Daniel@0 14055
Daniel@0 14056 pred.signals.forEach(setSignal);
Daniel@0 14057 pred.data.forEach(setData);
Daniel@0 14058
Daniel@0 14059 if (dl.isObject(ref)) {
Daniel@0 14060 dl.keys(ref).forEach(function(k) {
Daniel@0 14061 if (k === "name") return;
Daniel@0 14062 var i = ref[k];
Daniel@0 14063 def += "args["+dl.str(k)+"] = ";
Daniel@0 14064 if (i.signal) {
Daniel@0 14065 def += parseSignal(i.signal, signals);
Daniel@0 14066 } else if (i.arg) {
Daniel@0 14067 def += "args["+dl.str(i.arg)+"]";
Daniel@0 14068 }
Daniel@0 14069 def += ", ";
Daniel@0 14070 });
Daniel@0 14071 }
Daniel@0 14072
Daniel@0 14073 def += p+".call("+p+", args, db, signals, predicates)";
Daniel@0 14074 }
Daniel@0 14075
Daniel@0 14076 decl.push(name);
Daniel@0 14077 defs.push(name+"=("+def+")");
Daniel@0 14078 });
Daniel@0 14079
Daniel@0 14080 return {
Daniel@0 14081 code: "var " + decl.join(", ") + ";\n" + defs.join(";\n") + ";\n",
Daniel@0 14082 signals: dl.keys(signals),
Daniel@0 14083 data: dl.keys(db)
Daniel@0 14084 };
Daniel@0 14085 }
Daniel@0 14086
Daniel@0 14087 function parseComparator(model, spec) {
Daniel@0 14088 var ops = parseOperands(model, spec.operands);
Daniel@0 14089 if (spec.type === '=') spec.type = '==';
Daniel@0 14090
Daniel@0 14091 ops.code += "o0 = o0 instanceof Date ? o0.getTime() : o0;\n" +
Daniel@0 14092 "o1 = o1 instanceof Date ? o1.getTime() : o1;\n";
Daniel@0 14093
Daniel@0 14094 return {
Daniel@0 14095 code: ops.code + "return " + ["o0", "o1"].join(spec.type) + ";",
Daniel@0 14096 signals: ops.signals,
Daniel@0 14097 data: ops.data
Daniel@0 14098 };
Daniel@0 14099 }
Daniel@0 14100
Daniel@0 14101 function parseLogical(model, spec) {
Daniel@0 14102 var ops = parseOperands(model, spec.operands),
Daniel@0 14103 o = [], i = 0, len = spec.operands.length;
Daniel@0 14104
Daniel@0 14105 while (o.push("o"+i++) < len);
Daniel@0 14106 if (spec.type === 'and') spec.type = '&&';
Daniel@0 14107 else if (spec.type === 'or') spec.type = '||';
Daniel@0 14108
Daniel@0 14109 return {
Daniel@0 14110 code: ops.code + "return " + o.join(spec.type) + ";",
Daniel@0 14111 signals: ops.signals,
Daniel@0 14112 data: ops.data
Daniel@0 14113 };
Daniel@0 14114 }
Daniel@0 14115
Daniel@0 14116 function parseIn(model, spec) {
Daniel@0 14117 var o = [spec.item], code = "";
Daniel@0 14118 if (spec.range) o.push.apply(o, spec.range);
Daniel@0 14119 if (spec.scale) {
Daniel@0 14120 code = parseScale(spec.scale, o);
Daniel@0 14121 }
Daniel@0 14122
Daniel@0 14123 var ops = parseOperands(model, o);
Daniel@0 14124 code = ops.code + code + "\n var ordSet = null;\n";
Daniel@0 14125
Daniel@0 14126 if (spec.data) {
Daniel@0 14127 var field = dl.field(spec.field).map(dl.str);
Daniel@0 14128 code += "var where = function(d) { return d["+field.join("][")+"] == o0 };\n";
Daniel@0 14129 code += "return db["+dl.str(spec.data)+"].filter(where).length > 0;";
Daniel@0 14130 } else if (spec.range) {
Daniel@0 14131 // TODO: inclusive/exclusive range?
Daniel@0 14132 if (spec.scale) {
Daniel@0 14133 code += "if (scale.length == 2) {\n" + // inverting ordinal scales
Daniel@0 14134 " ordSet = scale(o1, o2);\n" +
Daniel@0 14135 "} else {\n" +
Daniel@0 14136 " o1 = scale(o1);\no2 = scale(o2);\n" +
Daniel@0 14137 "}";
Daniel@0 14138 }
Daniel@0 14139
Daniel@0 14140 code += "return ordSet !== null ? ordSet.indexOf(o0) !== -1 :\n" +
Daniel@0 14141 " o1 < o2 ? o1 <= o0 && o0 <= o2 : o2 <= o0 && o0 <= o1;";
Daniel@0 14142 }
Daniel@0 14143
Daniel@0 14144 return {
Daniel@0 14145 code: code,
Daniel@0 14146 signals: ops.signals,
Daniel@0 14147 data: ops.data.concat(spec.data ? [spec.data] : [])
Daniel@0 14148 };
Daniel@0 14149 }
Daniel@0 14150
Daniel@0 14151 // Populate ops such that ultimate scale/inversion function will be in `scale` var.
Daniel@0 14152 function parseScale(spec, ops) {
Daniel@0 14153 var code = "var scale = ",
Daniel@0 14154 idx = ops.length;
Daniel@0 14155
Daniel@0 14156 if (dl.isString(spec)) {
Daniel@0 14157 ops.push({ value: spec });
Daniel@0 14158 code += "this.root().scale(o"+idx+")";
Daniel@0 14159 } else if (spec.arg) { // Scale function is being passed as an arg
Daniel@0 14160 ops.push(spec);
Daniel@0 14161 code += "o"+idx;
Daniel@0 14162 } else if (spec.name) { // Full scale parameter {name: ..}
Daniel@0 14163 ops.push(dl.isString(spec.name) ? {value: spec.name} : spec.name);
Daniel@0 14164 code += "(this.isFunction(o"+idx+") ? o"+idx+" : ";
Daniel@0 14165 if (spec.scope) {
Daniel@0 14166 ops.push(spec.scope);
Daniel@0 14167 code += "((o"+(idx+1)+".scale || this.root().scale)(o"+idx+") || this.nullScale)";
Daniel@0 14168 } else {
Daniel@0 14169 code += "this.root().scale(o"+idx+")";
Daniel@0 14170 }
Daniel@0 14171 code += ")";
Daniel@0 14172 }
Daniel@0 14173
Daniel@0 14174 if (spec.invert === true) { // Allow spec.invert.arg?
Daniel@0 14175 code += ".invert";
Daniel@0 14176 }
Daniel@0 14177
Daniel@0 14178 return code+";\n";
Daniel@0 14179 }
Daniel@0 14180
Daniel@0 14181 module.exports = parsePredicates;
Daniel@0 14182 },{"datalib":24}],102:[function(require,module,exports){
Daniel@0 14183 (function (global){
Daniel@0 14184 var d3 = (typeof window !== "undefined" ? window['d3'] : typeof global !== "undefined" ? global['d3'] : null),
Daniel@0 14185 dl = require('datalib'),
Daniel@0 14186 log = require('vega-logging'),
Daniel@0 14187 Tuple = require('vega-dataflow').Tuple;
Daniel@0 14188
Daniel@0 14189 var DEPS = ["signals", "scales", "data", "fields"];
Daniel@0 14190
Daniel@0 14191 function properties(model, mark, spec) {
Daniel@0 14192 var config = model.config(),
Daniel@0 14193 code = "",
Daniel@0 14194 names = dl.keys(spec),
Daniel@0 14195 i, len, name, ref, vars = {},
Daniel@0 14196 deps = {
Daniel@0 14197 signals: {},
Daniel@0 14198 scales: {},
Daniel@0 14199 data: {},
Daniel@0 14200 fields: {},
Daniel@0 14201 nested: [],
Daniel@0 14202 _nRefs: {}, // Temp stash to de-dupe nested refs.
Daniel@0 14203 reflow: false
Daniel@0 14204 };
Daniel@0 14205
Daniel@0 14206 code += "var o = trans ? {} : item, d=0, set=this.tpl.set, tmpl=signals||{}, t;\n" +
Daniel@0 14207 // Stash for dl.template
Daniel@0 14208 "tmpl.datum = item.datum;\n" +
Daniel@0 14209 "tmpl.group = group;\n" +
Daniel@0 14210 "tmpl.parent = group.datum;\n";
Daniel@0 14211
Daniel@0 14212 function handleDep(p) {
Daniel@0 14213 if (ref[p] == null) return;
Daniel@0 14214 var k = dl.array(ref[p]), i, n;
Daniel@0 14215 for (i=0, n=k.length; i<n; ++i) {
Daniel@0 14216 deps[p][k[i]] = 1;
Daniel@0 14217 }
Daniel@0 14218 }
Daniel@0 14219
Daniel@0 14220 function handleNestedRefs(r) {
Daniel@0 14221 var k = (r.parent ? "parent_" : "group_")+r.level;
Daniel@0 14222 deps._nRefs[k] = r;
Daniel@0 14223 }
Daniel@0 14224
Daniel@0 14225 for (i=0, len=names.length; i<len; ++i) {
Daniel@0 14226 ref = spec[name = names[i]];
Daniel@0 14227 code += (i > 0) ? "\n " : " ";
Daniel@0 14228 if (ref.rule) {
Daniel@0 14229 ref = rule(model, name, ref.rule);
Daniel@0 14230 code += "\n " + ref.code;
Daniel@0 14231 } else {
Daniel@0 14232 ref = valueRef(config, name, ref);
Daniel@0 14233 code += "d += set(o, "+dl.str(name)+", "+ref.val+");";
Daniel@0 14234 }
Daniel@0 14235
Daniel@0 14236 vars[name] = true;
Daniel@0 14237 DEPS.forEach(handleDep);
Daniel@0 14238 deps.reflow = deps.reflow || ref.reflow;
Daniel@0 14239 if (ref.nested.length) ref.nested.forEach(handleNestedRefs);
Daniel@0 14240 }
Daniel@0 14241
Daniel@0 14242 // If nested references are present, sort them based on their level
Daniel@0 14243 // to speed up determination of whether encoders should be reeval'd.
Daniel@0 14244 dl.keys(deps._nRefs).forEach(function(k) { deps.nested.push(deps._nRefs[k]); });
Daniel@0 14245 deps.nested.sort(function(a, b) {
Daniel@0 14246 a = a.level;
Daniel@0 14247 b = b.level;
Daniel@0 14248 return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
Daniel@0 14249 });
Daniel@0 14250
Daniel@0 14251 if (vars.x2) {
Daniel@0 14252 if (vars.x) {
Daniel@0 14253 code += "\n if (o.x > o.x2) { " +
Daniel@0 14254 "\n t = o.x;" +
Daniel@0 14255 "\n d += set(o, 'x', o.x2);" +
Daniel@0 14256 "\n d += set(o, 'x2', t); " +
Daniel@0 14257 "\n };";
Daniel@0 14258 code += "\n d += set(o, 'width', (o.x2 - o.x));";
Daniel@0 14259 } else if (vars.width) {
Daniel@0 14260 code += "\n d += set(o, 'x', (o.x2 - o.width));";
Daniel@0 14261 } else {
Daniel@0 14262 code += "\n d += set(o, 'x', o.x2);";
Daniel@0 14263 }
Daniel@0 14264 }
Daniel@0 14265
Daniel@0 14266 if (vars.xc) {
Daniel@0 14267 if (vars.width) {
Daniel@0 14268 code += "\n d += set(o, 'x', (o.xc - o.width/2));" ;
Daniel@0 14269 } else {
Daniel@0 14270 code += "\n d += set(o, 'x', o.xc);" ;
Daniel@0 14271 }
Daniel@0 14272 }
Daniel@0 14273
Daniel@0 14274 if (vars.y2) {
Daniel@0 14275 if (vars.y) {
Daniel@0 14276 code += "\n if (o.y > o.y2) { " +
Daniel@0 14277 "\n t = o.y;" +
Daniel@0 14278 "\n d += set(o, 'y', o.y2);" +
Daniel@0 14279 "\n d += set(o, 'y2', t);" +
Daniel@0 14280 "\n };";
Daniel@0 14281 code += "\n d += set(o, 'height', (o.y2 - o.y));";
Daniel@0 14282 } else if (vars.height) {
Daniel@0 14283 code += "\n d += set(o, 'y', (o.y2 - o.height));";
Daniel@0 14284 } else {
Daniel@0 14285 code += "\n d += set(o, 'y', o.y2);";
Daniel@0 14286 }
Daniel@0 14287 }
Daniel@0 14288
Daniel@0 14289 if (vars.yc) {
Daniel@0 14290 if (vars.height) {
Daniel@0 14291 code += "\n d += set(o, 'y', (o.yc - o.height/2));" ;
Daniel@0 14292 } else {
Daniel@0 14293 code += "\n d += set(o, 'y', o.yc);" ;
Daniel@0 14294 }
Daniel@0 14295 }
Daniel@0 14296
Daniel@0 14297 if (hasPath(mark, vars)) code += "\n d += (item.touch(), 1);";
Daniel@0 14298 code += "\n if (trans) trans.interpolate(item, o);";
Daniel@0 14299 code += "\n return d > 0;";
Daniel@0 14300
Daniel@0 14301 try {
Daniel@0 14302 /* jshint evil:true */
Daniel@0 14303 var encoder = Function('item', 'group', 'trans', 'db',
Daniel@0 14304 'signals', 'predicates', code);
Daniel@0 14305 encoder.tpl = Tuple;
Daniel@0 14306 encoder.util = dl;
Daniel@0 14307 encoder.d3 = d3; // For color spaces
Daniel@0 14308 dl.extend(encoder, dl.template.context);
Daniel@0 14309 return {
Daniel@0 14310 encode: encoder,
Daniel@0 14311 signals: dl.keys(deps.signals),
Daniel@0 14312 scales: dl.keys(deps.scales),
Daniel@0 14313 data: dl.keys(deps.data),
Daniel@0 14314 fields: dl.keys(deps.fields),
Daniel@0 14315 nested: deps.nested,
Daniel@0 14316 reflow: deps.reflow
Daniel@0 14317 };
Daniel@0 14318 } catch (e) {
Daniel@0 14319 log.error(e);
Daniel@0 14320 log.log(code);
Daniel@0 14321 }
Daniel@0 14322 }
Daniel@0 14323
Daniel@0 14324 function dependencies(a, b) {
Daniel@0 14325 if (!dl.isObject(a)) {
Daniel@0 14326 a = {reflow: false, nested: []};
Daniel@0 14327 DEPS.forEach(function(d) { a[d] = []; });
Daniel@0 14328 }
Daniel@0 14329
Daniel@0 14330 if (dl.isObject(b)) {
Daniel@0 14331 a.reflow = a.reflow || b.reflow;
Daniel@0 14332 a.nested.push.apply(a.nested, b.nested);
Daniel@0 14333 DEPS.forEach(function(d) { a[d].push.apply(a[d], b[d]); });
Daniel@0 14334 }
Daniel@0 14335
Daniel@0 14336 return a;
Daniel@0 14337 }
Daniel@0 14338
Daniel@0 14339 function hasPath(mark, vars) {
Daniel@0 14340 return vars.path ||
Daniel@0 14341 ((mark==='area' || mark==='line') &&
Daniel@0 14342 (vars.x || vars.x2 || vars.width ||
Daniel@0 14343 vars.y || vars.y2 || vars.height ||
Daniel@0 14344 vars.tension || vars.interpolate));
Daniel@0 14345 }
Daniel@0 14346
Daniel@0 14347 function rule(model, name, rules) {
Daniel@0 14348 var config = model.config(),
Daniel@0 14349 deps = dependencies(),
Daniel@0 14350 inputs = [], code = '';
Daniel@0 14351
Daniel@0 14352 (rules||[]).forEach(function(r, i) {
Daniel@0 14353 var def = r.predicate,
Daniel@0 14354 predName = def && (def.name || def),
Daniel@0 14355 pred = model.predicate(predName),
Daniel@0 14356 p = 'predicates['+dl.str(predName)+']',
Daniel@0 14357 input = [], args = name+'_arg'+i,
Daniel@0 14358 ref;
Daniel@0 14359
Daniel@0 14360 if (dl.isObject(def)) {
Daniel@0 14361 dl.keys(def).forEach(function(k) {
Daniel@0 14362 if (k === 'name') return;
Daniel@0 14363 var ref = valueRef(config, i, def[k]);
Daniel@0 14364 input.push(dl.str(k)+': '+ref.val);
Daniel@0 14365 dependencies(deps, ref);
Daniel@0 14366 });
Daniel@0 14367 }
Daniel@0 14368
Daniel@0 14369 ref = valueRef(config, name, r);
Daniel@0 14370 dependencies(deps, ref);
Daniel@0 14371
Daniel@0 14372 if (predName) {
Daniel@0 14373 deps.signals.push.apply(deps.signals, pred.signals);
Daniel@0 14374 deps.data.push.apply(deps.data, pred.data);
Daniel@0 14375 inputs.push(args+" = {\n "+input.join(",\n ")+"\n }");
Daniel@0 14376 code += "if ("+p+".call("+p+","+args+", db, signals, predicates)) {" +
Daniel@0 14377 "\n d += set(o, "+dl.str(name)+", "+ref.val+");";
Daniel@0 14378 code += rules[i+1] ? "\n } else " : " }";
Daniel@0 14379 } else {
Daniel@0 14380 code += "{" +
Daniel@0 14381 "\n d += set(o, "+dl.str(name)+", "+ref.val+");"+
Daniel@0 14382 "\n }\n";
Daniel@0 14383 }
Daniel@0 14384 });
Daniel@0 14385
Daniel@0 14386 code = "var " + inputs.join(",\n ") + ";\n " + code;
Daniel@0 14387 return (deps.code = code, deps);
Daniel@0 14388 }
Daniel@0 14389
Daniel@0 14390 function valueRef(config, name, ref) {
Daniel@0 14391 if (ref == null) return null;
Daniel@0 14392
Daniel@0 14393 if (name==='fill' || name==='stroke') {
Daniel@0 14394 if (ref.c) {
Daniel@0 14395 return colorRef(config, 'hcl', ref.h, ref.c, ref.l);
Daniel@0 14396 } else if (ref.h || ref.s) {
Daniel@0 14397 return colorRef(config, 'hsl', ref.h, ref.s, ref.l);
Daniel@0 14398 } else if (ref.l || ref.a) {
Daniel@0 14399 return colorRef(config, 'lab', ref.l, ref.a, ref.b);
Daniel@0 14400 } else if (ref.r || ref.g || ref.b) {
Daniel@0 14401 return colorRef(config, 'rgb', ref.r, ref.g, ref.b);
Daniel@0 14402 }
Daniel@0 14403 }
Daniel@0 14404
Daniel@0 14405 // initialize value
Daniel@0 14406 var val = null, scale = null,
Daniel@0 14407 deps = dependencies(),
Daniel@0 14408 sgRef = null, fRef = null, sRef = null, tmpl = {};
Daniel@0 14409
Daniel@0 14410 if (ref.template !== undefined) {
Daniel@0 14411 val = dl.template.source(ref.template, 'tmpl', tmpl);
Daniel@0 14412 dl.keys(tmpl).forEach(function(k) {
Daniel@0 14413 var f = dl.field(k),
Daniel@0 14414 a = f.shift();
Daniel@0 14415 if (a === 'parent' || a === 'group') {
Daniel@0 14416 deps.nested.push({
Daniel@0 14417 parent: a === 'parent',
Daniel@0 14418 group: a === 'group',
Daniel@0 14419 level: 1
Daniel@0 14420 });
Daniel@0 14421 } else if (a === 'datum') {
Daniel@0 14422 deps.fields.push(f[0]);
Daniel@0 14423 } else {
Daniel@0 14424 deps.signals.push(a);
Daniel@0 14425 }
Daniel@0 14426 });
Daniel@0 14427 }
Daniel@0 14428
Daniel@0 14429 if (ref.value !== undefined) {
Daniel@0 14430 val = dl.str(ref.value);
Daniel@0 14431 }
Daniel@0 14432
Daniel@0 14433 if (ref.signal !== undefined) {
Daniel@0 14434 sgRef = dl.field(ref.signal);
Daniel@0 14435 val = 'signals['+sgRef.map(dl.str).join('][')+']';
Daniel@0 14436 deps.signals.push(sgRef.shift());
Daniel@0 14437 }
Daniel@0 14438
Daniel@0 14439 if (ref.field !== undefined) {
Daniel@0 14440 ref.field = dl.isString(ref.field) ? {datum: ref.field} : ref.field;
Daniel@0 14441 fRef = fieldRef(ref.field);
Daniel@0 14442 val = fRef.val;
Daniel@0 14443 dependencies(deps, fRef);
Daniel@0 14444 }
Daniel@0 14445
Daniel@0 14446 if (ref.scale !== undefined) {
Daniel@0 14447 sRef = scaleRef(ref.scale);
Daniel@0 14448 scale = sRef.val;
Daniel@0 14449 dependencies(deps, sRef);
Daniel@0 14450 deps.scales.push(ref.scale.name || ref.scale);
Daniel@0 14451
Daniel@0 14452 // run through scale function if val specified.
Daniel@0 14453 // if no val, scale function is predicate arg.
Daniel@0 14454 if (val !== null || ref.band || ref.mult || ref.offset) {
Daniel@0 14455 val = scale + (ref.band ? '.rangeBand()' :
Daniel@0 14456 '('+(val !== null ? val : 'item.datum.data')+')');
Daniel@0 14457 } else {
Daniel@0 14458 val = scale;
Daniel@0 14459 }
Daniel@0 14460 }
Daniel@0 14461
Daniel@0 14462 // multiply, offset, return value
Daniel@0 14463 val = '(' + (ref.mult?(dl.number(ref.mult)+' * '):'') + val + ')' +
Daniel@0 14464 (ref.offset ? ' + ' + dl.number(ref.offset) : '');
Daniel@0 14465
Daniel@0 14466 // Collate dependencies
Daniel@0 14467 return (deps.val = val, deps);
Daniel@0 14468 }
Daniel@0 14469
Daniel@0 14470 function colorRef(config, type, x, y, z) {
Daniel@0 14471 var xx = x ? valueRef(config, '', x) : config.color[type][0],
Daniel@0 14472 yy = y ? valueRef(config, '', y) : config.color[type][1],
Daniel@0 14473 zz = z ? valueRef(config, '', z) : config.color[type][2],
Daniel@0 14474 deps = dependencies();
Daniel@0 14475
Daniel@0 14476 [xx, yy, zz].forEach(function(v) {
Daniel@0 14477 if (dl.isArray) return;
Daniel@0 14478 dependencies(deps, v);
Daniel@0 14479 });
Daniel@0 14480
Daniel@0 14481 var val = '(this.d3.' + type + '(' + [xx.val, yy.val, zz.val].join(',') + ') + "")';
Daniel@0 14482 return (deps.val = val, deps);
Daniel@0 14483 }
Daniel@0 14484
Daniel@0 14485 // {field: {datum: "foo"} } -> item.datum.foo
Daniel@0 14486 // {field: {group: "foo"} } -> group.foo
Daniel@0 14487 // {field: {parent: "foo"} } -> group.datum.foo
Daniel@0 14488 function fieldRef(ref) {
Daniel@0 14489 if (dl.isString(ref)) {
Daniel@0 14490 return {val: dl.field(ref).map(dl.str).join('][')};
Daniel@0 14491 }
Daniel@0 14492
Daniel@0 14493 // Resolve nesting/parent lookups
Daniel@0 14494 var l = ref.level || 1,
Daniel@0 14495 nested = (ref.group || ref.parent) && l,
Daniel@0 14496 scope = nested ? Array(l).join('group.mark.') : '',
Daniel@0 14497 r = fieldRef(ref.datum || ref.group || ref.parent || ref.signal),
Daniel@0 14498 val = r.val,
Daniel@0 14499 deps = dependencies(null, r);
Daniel@0 14500
Daniel@0 14501 if (ref.datum) {
Daniel@0 14502 val = 'item.datum['+val+']';
Daniel@0 14503 deps.fields.push(ref.datum);
Daniel@0 14504 } else if (ref.group) {
Daniel@0 14505 val = scope+'group['+val+']';
Daniel@0 14506 deps.nested.push({ level: l, group: true });
Daniel@0 14507 } else if (ref.parent) {
Daniel@0 14508 val = scope+'group.datum['+val+']';
Daniel@0 14509 deps.nested.push({ level: l, parent: true });
Daniel@0 14510 } else if (ref.signal) {
Daniel@0 14511 val = 'signals['+val+']';
Daniel@0 14512 deps.signals.push(dl.field(ref.signal)[0]);
Daniel@0 14513 deps.reflow = true;
Daniel@0 14514 }
Daniel@0 14515
Daniel@0 14516 return (deps.val = val, deps);
Daniel@0 14517 }
Daniel@0 14518
Daniel@0 14519 // {scale: "x"}
Daniel@0 14520 // {scale: {name: "x"}},
Daniel@0 14521 // {scale: fieldRef}
Daniel@0 14522 function scaleRef(ref) {
Daniel@0 14523 var scale = null,
Daniel@0 14524 fr = null,
Daniel@0 14525 deps = dependencies();
Daniel@0 14526
Daniel@0 14527 if (dl.isString(ref)) {
Daniel@0 14528 scale = dl.str(ref);
Daniel@0 14529 } else if (ref.name) {
Daniel@0 14530 scale = dl.isString(ref.name) ? dl.str(ref.name) : (fr = fieldRef(ref.name)).val;
Daniel@0 14531 } else {
Daniel@0 14532 scale = (fr = fieldRef(ref)).val;
Daniel@0 14533 }
Daniel@0 14534
Daniel@0 14535 scale = '(item.mark._scaleRefs['+scale+'] = 1, group.scale('+scale+'))';
Daniel@0 14536 if (ref.invert) scale += '.invert';
Daniel@0 14537
Daniel@0 14538 // Mark scale refs as they're dealt with separately in mark._scaleRefs.
Daniel@0 14539 if (fr) fr.nested.forEach(function(g) { g.scale = true; });
Daniel@0 14540 return fr ? (fr.val = scale, fr) : (deps.val = scale, deps);
Daniel@0 14541 }
Daniel@0 14542
Daniel@0 14543 module.exports = properties;
Daniel@0 14544 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
Daniel@0 14545
Daniel@0 14546 },{"datalib":24,"vega-dataflow":39,"vega-logging":45}],103:[function(require,module,exports){
Daniel@0 14547 var dl = require('datalib'),
Daniel@0 14548 SIGNALS = require('vega-dataflow').Dependencies.SIGNALS,
Daniel@0 14549 expr = require('./expr');
Daniel@0 14550
Daniel@0 14551 var RESERVED = ['datum', 'event', 'signals']
Daniel@0 14552 .concat(dl.keys(expr.codegen.functions));
Daniel@0 14553
Daniel@0 14554 function parseSignals(model, spec) {
Daniel@0 14555 // process each signal definition
Daniel@0 14556 (spec || []).forEach(function(s) {
Daniel@0 14557 if (RESERVED.indexOf(s.name) !== -1) {
Daniel@0 14558 throw Error('Signal name "'+s.name+'" is a '+
Daniel@0 14559 'reserved keyword ('+RESERVED.join(', ')+').');
Daniel@0 14560 }
Daniel@0 14561
Daniel@0 14562 var signal = model.signal(s.name, s.init)
Daniel@0 14563 .verbose(s.verbose);
Daniel@0 14564
Daniel@0 14565 if (s.init && s.init.expr) {
Daniel@0 14566 s.init.expr = expr(s.init.expr);
Daniel@0 14567 signal.value(exprVal(model, s.init));
Daniel@0 14568 }
Daniel@0 14569
Daniel@0 14570 if (s.expr) {
Daniel@0 14571 s.expr = expr(s.expr);
Daniel@0 14572 signal.evaluate = function(input) {
Daniel@0 14573 var val = exprVal(model, s);
Daniel@0 14574 if (val !== signal.value() || signal.verbose()) {
Daniel@0 14575 signal.value(val);
Daniel@0 14576 input.signals[s.name] = 1;
Daniel@0 14577 return input;
Daniel@0 14578 }
Daniel@0 14579 return model.doNotPropagate;
Daniel@0 14580 };
Daniel@0 14581 signal.dependency(SIGNALS, s.expr.globals);
Daniel@0 14582 s.expr.globals.forEach(function(dep) {
Daniel@0 14583 model.signal(dep).addListener(signal);
Daniel@0 14584 });
Daniel@0 14585 }
Daniel@0 14586 });
Daniel@0 14587
Daniel@0 14588 return spec;
Daniel@0 14589 }
Daniel@0 14590
Daniel@0 14591 function exprVal(model, spec) {
Daniel@0 14592 var e = spec.expr,
Daniel@0 14593 val = e.fn(null, null, model.values(SIGNALS, e.globals));
Daniel@0 14594 return spec.scale ? parseSignals.scale(model, spec, val) : val;
Daniel@0 14595 }
Daniel@0 14596
Daniel@0 14597 parseSignals.scale = function scale(model, spec, value, datum, evt) {
Daniel@0 14598 var def = spec.scale,
Daniel@0 14599 name = def.name || def.signal || def,
Daniel@0 14600 scope = def.scope, e;
Daniel@0 14601
Daniel@0 14602 if (scope) {
Daniel@0 14603 if (scope.signal) {
Daniel@0 14604 scope = model.signalRef(scope.signal);
Daniel@0 14605 } else if (dl.isString(scope)) { // Scope is an expression
Daniel@0 14606 e = def._expr = (def._expr || expr(scope));
Daniel@0 14607 scope = e.fn(datum, evt, model.values(SIGNALS, e.globals));
Daniel@0 14608 }
Daniel@0 14609 }
Daniel@0 14610
Daniel@0 14611 if (!scope || !scope.scale) {
Daniel@0 14612 scope = (scope && scope.mark) ? scope.mark.group : model.scene().items[0];
Daniel@0 14613 }
Daniel@0 14614
Daniel@0 14615 var s = scope.scale(name);
Daniel@0 14616 return !s ? value : (def.invert ? s.invert(value) : s(value));
Daniel@0 14617 };
Daniel@0 14618
Daniel@0 14619 module.exports = parseSignals;
Daniel@0 14620 },{"./expr":94,"datalib":24,"vega-dataflow":39}],104:[function(require,module,exports){
Daniel@0 14621 var dl = require('datalib'),
Daniel@0 14622 log = require('vega-logging'),
Daniel@0 14623 Model = require('../core/Model'),
Daniel@0 14624 View = require('../core/View');
Daniel@0 14625
Daniel@0 14626 function parseSpec(spec, callback) {
Daniel@0 14627 var vf = arguments[arguments.length-1],
Daniel@0 14628 viewFactory = arguments.length > 2 && dl.isFunction(vf) ? vf : View.factory,
Daniel@0 14629 config = arguments[2] !== viewFactory ? arguments[2] : {},
Daniel@0 14630 model = new Model(config);
Daniel@0 14631
Daniel@0 14632 function parse(spec) {
Daniel@0 14633 // protect against subsequent spec modification
Daniel@0 14634 spec = dl.duplicate(spec);
Daniel@0 14635
Daniel@0 14636 var parsers = require('./'),
Daniel@0 14637 width = spec.width || 500,
Daniel@0 14638 height = spec.height || 500,
Daniel@0 14639 viewport = spec.viewport || null;
Daniel@0 14640
Daniel@0 14641 model.defs({
Daniel@0 14642 width: width,
Daniel@0 14643 height: height,
Daniel@0 14644 viewport: viewport,
Daniel@0 14645 background: parsers.background(spec.background),
Daniel@0 14646 padding: parsers.padding(spec.padding),
Daniel@0 14647 signals: parsers.signals(model, spec.signals),
Daniel@0 14648 predicates: parsers.predicates(model, spec.predicates),
Daniel@0 14649 marks: parsers.marks(model, spec, width, height),
Daniel@0 14650 data: parsers.data(model, spec.data, function() {
Daniel@0 14651 callback(viewFactory(model));
Daniel@0 14652 })
Daniel@0 14653 });
Daniel@0 14654 }
Daniel@0 14655
Daniel@0 14656 if (dl.isObject(spec)) {
Daniel@0 14657 parse(spec);
Daniel@0 14658 } else if (dl.isString(spec)) {
Daniel@0 14659 var opts = dl.extend({url: spec}, model.config().load);
Daniel@0 14660 dl.load(opts, function(err, data) {
Daniel@0 14661 if (err) {
Daniel@0 14662 log.error('LOADING SPECIFICATION FAILED: ' + err.statusText);
Daniel@0 14663 } else {
Daniel@0 14664 try {
Daniel@0 14665 parse(JSON.parse(data));
Daniel@0 14666 } catch (e) {
Daniel@0 14667 log.error('INVALID SPECIFICATION: Must be a valid JSON object. '+e);
Daniel@0 14668 }
Daniel@0 14669 }
Daniel@0 14670 });
Daniel@0 14671 } else {
Daniel@0 14672 log.error('INVALID SPECIFICATION: Must be a valid JSON object or URL.');
Daniel@0 14673 }
Daniel@0 14674 }
Daniel@0 14675
Daniel@0 14676 module.exports = parseSpec;
Daniel@0 14677 },{"../core/Model":86,"../core/View":87,"./":95,"datalib":24,"vega-logging":45}],105:[function(require,module,exports){
Daniel@0 14678 (function (global){
Daniel@0 14679 var d3 = (typeof window !== "undefined" ? window['d3'] : typeof global !== "undefined" ? global['d3'] : null),
Daniel@0 14680 dl = require('datalib'),
Daniel@0 14681 df = require('vega-dataflow'),
Daniel@0 14682 SIGNALS = df.Dependencies.SIGNALS,
Daniel@0 14683 parseSignals = require('./signals'),
Daniel@0 14684 selector = require('./events'),
Daniel@0 14685 expr = require('./expr');
Daniel@0 14686
Daniel@0 14687 var GATEKEEPER = '_vgGATEKEEPER';
Daniel@0 14688
Daniel@0 14689 var vgEvent = {
Daniel@0 14690 getGroup: function(name) { return name ? this.name[name] : this.group; },
Daniel@0 14691 getXY: function(item) {
Daniel@0 14692 var p = {x: this.x, y: this.y};
Daniel@0 14693 if (typeof item === 'string') {
Daniel@0 14694 item = this.name[item];
Daniel@0 14695 }
Daniel@0 14696 for (; item; item = item.mark && item.mark.group) {
Daniel@0 14697 p.x -= item.x || 0;
Daniel@0 14698 p.y -= item.y || 0;
Daniel@0 14699 }
Daniel@0 14700 return p;
Daniel@0 14701 },
Daniel@0 14702 getX: function(item) { return this.getXY(item).x; },
Daniel@0 14703 getY: function(item) { return this.getXY(item).y; }
Daniel@0 14704 };
Daniel@0 14705
Daniel@0 14706 function parseStreams(view) {
Daniel@0 14707 var model = view.model(),
Daniel@0 14708 spec = model.defs().signals,
Daniel@0 14709 registry = {handlers: {}, nodes: {}},
Daniel@0 14710 internal = dl.duplicate(registry), // Internal event processing
Daniel@0 14711 external = dl.duplicate(registry); // External event processing
Daniel@0 14712
Daniel@0 14713 (spec || []).forEach(function(sig) {
Daniel@0 14714 var signal = model.signal(sig.name);
Daniel@0 14715 if (sig.expr) return; // Cannot have an expr and stream definition.
Daniel@0 14716
Daniel@0 14717 (sig.streams || []).forEach(function(stream) {
Daniel@0 14718 var sel = selector.parse(stream.type),
Daniel@0 14719 exp = expr(stream.expr);
Daniel@0 14720 mergedStream(signal, sel, exp, stream);
Daniel@0 14721 });
Daniel@0 14722 });
Daniel@0 14723
Daniel@0 14724 // We register the event listeners all together so that if multiple
Daniel@0 14725 // signals are registered on the same event, they will receive the
Daniel@0 14726 // new value on the same pulse.
Daniel@0 14727 dl.keys(internal.handlers).forEach(function(type) {
Daniel@0 14728 view.on(type, function(evt, item) {
Daniel@0 14729 evt.preventDefault(); // stop text selection
Daniel@0 14730 extendEvent(evt, item);
Daniel@0 14731 fire(internal, type, (item && item.datum) || {}, evt);
Daniel@0 14732 });
Daniel@0 14733 });
Daniel@0 14734
Daniel@0 14735 // add external event listeners
Daniel@0 14736 dl.keys(external.handlers).forEach(function(type) {
Daniel@0 14737 if (typeof window === 'undefined') return; // No external support
Daniel@0 14738
Daniel@0 14739 var h = external.handlers[type],
Daniel@0 14740 t = type.split(':'), // --> no element pseudo-selectors
Daniel@0 14741 elt = (t[0] === 'window') ? [window] :
Daniel@0 14742 window.document.querySelectorAll(t[0]);
Daniel@0 14743
Daniel@0 14744 function handler(evt) {
Daniel@0 14745 extendEvent(evt);
Daniel@0 14746 fire(external, type, d3.select(this).datum(), evt);
Daniel@0 14747 }
Daniel@0 14748
Daniel@0 14749 for (var i=0; i<elt.length; ++i) {
Daniel@0 14750 elt[i].addEventListener(t[1], handler);
Daniel@0 14751 }
Daniel@0 14752
Daniel@0 14753 h.elements = elt;
Daniel@0 14754 h.listener = handler;
Daniel@0 14755 });
Daniel@0 14756
Daniel@0 14757 // remove external event listeners
Daniel@0 14758 external.detach = function() {
Daniel@0 14759 dl.keys(external.handlers).forEach(function(type) {
Daniel@0 14760 var h = external.handlers[type],
Daniel@0 14761 t = type.split(':'),
Daniel@0 14762 elt = h.elements || [];
Daniel@0 14763
Daniel@0 14764 for (var i=0; i<elt.length; ++i) {
Daniel@0 14765 elt[i].removeEventListener(t[1], h.listener);
Daniel@0 14766 }
Daniel@0 14767 });
Daniel@0 14768 };
Daniel@0 14769
Daniel@0 14770 // export detach method
Daniel@0 14771 return external.detach;
Daniel@0 14772
Daniel@0 14773 // -- helper functions -----
Daniel@0 14774
Daniel@0 14775 function extendEvent(evt, item) {
Daniel@0 14776 var mouse = d3.mouse((d3.event=evt, view.renderer().scene())),
Daniel@0 14777 pad = view.padding(),
Daniel@0 14778 names = {}, mark, group, i;
Daniel@0 14779
Daniel@0 14780 if (item) {
Daniel@0 14781 mark = item.mark;
Daniel@0 14782 group = mark.marktype === 'group' ? item : mark.group;
Daniel@0 14783 for (i=item; i!=null; i=i.mark.group) {
Daniel@0 14784 if (i.mark.def.name) {
Daniel@0 14785 names[i.mark.def.name] = i;
Daniel@0 14786 }
Daniel@0 14787 }
Daniel@0 14788 }
Daniel@0 14789 names.root = view.model().scene().items[0];
Daniel@0 14790
Daniel@0 14791 evt.vg = Object.create(vgEvent);
Daniel@0 14792 evt.vg.group = group;
Daniel@0 14793 evt.vg.item = item || {};
Daniel@0 14794 evt.vg.name = names;
Daniel@0 14795 evt.vg.x = mouse[0] - pad.left;
Daniel@0 14796 evt.vg.y = mouse[1] - pad.top;
Daniel@0 14797 }
Daniel@0 14798
Daniel@0 14799 function fire(registry, type, datum, evt) {
Daniel@0 14800 var handlers = registry.handlers[type],
Daniel@0 14801 node = registry.nodes[type],
Daniel@0 14802 cs = df.ChangeSet.create(null, true),
Daniel@0 14803 filtered = false,
Daniel@0 14804 val, i, n, h;
Daniel@0 14805
Daniel@0 14806 function invoke(f) {
Daniel@0 14807 return !f.fn(datum, evt, model.values(SIGNALS, f.globals));
Daniel@0 14808 }
Daniel@0 14809
Daniel@0 14810 for (i=0, n=handlers.length; i<n; ++i) {
Daniel@0 14811 h = handlers[i];
Daniel@0 14812 filtered = h.filters.some(invoke);
Daniel@0 14813 if (filtered) continue;
Daniel@0 14814
Daniel@0 14815 val = h.exp.fn(datum, evt, model.values(SIGNALS, h.exp.globals));
Daniel@0 14816 if (h.spec.scale) {
Daniel@0 14817 val = parseSignals.scale(model, h.spec, val, datum, evt);
Daniel@0 14818 }
Daniel@0 14819
Daniel@0 14820 if (val !== h.signal.value() || h.signal.verbose()) {
Daniel@0 14821 h.signal.value(val);
Daniel@0 14822 cs.signals[h.signal.name()] = 1;
Daniel@0 14823 }
Daniel@0 14824 }
Daniel@0 14825
Daniel@0 14826 model.propagate(cs, node);
Daniel@0 14827 }
Daniel@0 14828
Daniel@0 14829 function mergedStream(sig, selector, exp, spec) {
Daniel@0 14830 selector.forEach(function(s) {
Daniel@0 14831 if (s.event) domEvent(sig, s, exp, spec);
Daniel@0 14832 else if (s.signal) signal(sig, s, exp, spec);
Daniel@0 14833 else if (s.start) orderedStream(sig, s, exp, spec);
Daniel@0 14834 else if (s.stream) mergedStream(sig, s.stream, exp, spec);
Daniel@0 14835 });
Daniel@0 14836 }
Daniel@0 14837
Daniel@0 14838 function domEvent(sig, selector, exp, spec) {
Daniel@0 14839 var evt = selector.event,
Daniel@0 14840 name = selector.name,
Daniel@0 14841 mark = selector.mark,
Daniel@0 14842 target = selector.target,
Daniel@0 14843 filters = selector.filters || [],
Daniel@0 14844 registry = target ? external : internal,
Daniel@0 14845 type = target ? target+':'+evt : evt,
Daniel@0 14846 node = registry.nodes[type] || (registry.nodes[type] = new df.Node(model)),
Daniel@0 14847 handlers = registry.handlers[type] || (registry.handlers[type] = []);
Daniel@0 14848
Daniel@0 14849 if (name) {
Daniel@0 14850 filters.push('!!event.vg.name["' + name + '"]'); // Mimic event bubbling
Daniel@0 14851 } else if (mark) {
Daniel@0 14852 filters.push('event.vg.item.mark && event.vg.item.mark.marktype==='+dl.str(mark));
Daniel@0 14853 }
Daniel@0 14854
Daniel@0 14855 handlers.push({
Daniel@0 14856 signal: sig,
Daniel@0 14857 exp: exp,
Daniel@0 14858 spec: spec,
Daniel@0 14859 filters: filters.map(function(f) { return expr(f); })
Daniel@0 14860 });
Daniel@0 14861
Daniel@0 14862 node.addListener(sig);
Daniel@0 14863 }
Daniel@0 14864
Daniel@0 14865 function signal(sig, selector, exp, spec) {
Daniel@0 14866 var n = new df.Node(model);
Daniel@0 14867 n.evaluate = function(input) {
Daniel@0 14868 if (!input.signals[selector.signal]) return model.doNotPropagate;
Daniel@0 14869 var val = exp.fn(null, null, model.values(SIGNALS, exp.globals));
Daniel@0 14870 if (spec.scale) {
Daniel@0 14871 val = parseSignals.scale(model, spec, val);
Daniel@0 14872 }
Daniel@0 14873
Daniel@0 14874 if (val !== sig.value() || sig.verbose()) {
Daniel@0 14875 sig.value(val);
Daniel@0 14876 input.signals[sig.name()] = 1;
Daniel@0 14877 input.reflow = true;
Daniel@0 14878 }
Daniel@0 14879
Daniel@0 14880 return input;
Daniel@0 14881 };
Daniel@0 14882 n.dependency(df.Dependencies.SIGNALS, selector.signal);
Daniel@0 14883 n.addListener(sig);
Daniel@0 14884 model.signal(selector.signal).addListener(n);
Daniel@0 14885 }
Daniel@0 14886
Daniel@0 14887 function orderedStream(sig, selector, exp, spec) {
Daniel@0 14888 var name = sig.name(),
Daniel@0 14889 gk = name + GATEKEEPER,
Daniel@0 14890 trueFn = expr('true'),
Daniel@0 14891 falseFn = expr('false'),
Daniel@0 14892 middle = selector.middle,
Daniel@0 14893 filters = middle.filters || (middle.filters = []),
Daniel@0 14894 gatekeeper = model.signal(gk) || model.signal(gk, false);
Daniel@0 14895
Daniel@0 14896 // Register an anonymous signal to act as a gatekeeper. Its value is
Daniel@0 14897 // true or false depending on whether the start or end streams occur.
Daniel@0 14898 // The middle signal then simply filters for the gatekeeper's value.
Daniel@0 14899 mergedStream(gatekeeper, [selector.start], trueFn, {});
Daniel@0 14900 mergedStream(gatekeeper, [selector.end], falseFn, {});
Daniel@0 14901
Daniel@0 14902 filters.push(gatekeeper.name());
Daniel@0 14903 mergedStream(sig, [selector.middle], exp, spec);
Daniel@0 14904 }
Daniel@0 14905 }
Daniel@0 14906
Daniel@0 14907 module.exports = parseStreams;
Daniel@0 14908 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
Daniel@0 14909
Daniel@0 14910 },{"./events":93,"./expr":94,"./signals":103,"datalib":24,"vega-dataflow":39}],106:[function(require,module,exports){
Daniel@0 14911 var dl = require('datalib'),
Daniel@0 14912 transforms = require('../transforms/index');
Daniel@0 14913
Daniel@0 14914 function parseTransforms(model, def) {
Daniel@0 14915 var tx = new transforms[def.type](model);
Daniel@0 14916
Daniel@0 14917 // We want to rename output fields before setting any other properties,
Daniel@0 14918 // as subsequent properties may require output to be set (e.g. group by).
Daniel@0 14919 if(def.output) tx.output(def.output);
Daniel@0 14920
Daniel@0 14921 dl.keys(def).forEach(function(k) {
Daniel@0 14922 if(k === 'type' || k === 'output') return;
Daniel@0 14923 tx.param(k, def[k]);
Daniel@0 14924 });
Daniel@0 14925
Daniel@0 14926 return tx;
Daniel@0 14927 }
Daniel@0 14928
Daniel@0 14929 module.exports = parseTransforms;
Daniel@0 14930 },{"../transforms/index":139,"datalib":24}],107:[function(require,module,exports){
Daniel@0 14931 var dl = require('datalib'),
Daniel@0 14932 df = require('vega-dataflow'),
Daniel@0 14933 Node = df.Node, // jshint ignore:line
Daniel@0 14934 log = require('vega-logging'),
Daniel@0 14935 bound = require('vega-scenegraph').bound,
Daniel@0 14936 Encoder = require('./Encoder');
Daniel@0 14937
Daniel@0 14938 function Bounder(graph, mark) {
Daniel@0 14939 this._mark = mark;
Daniel@0 14940 return Node.prototype.init.call(this, graph)
Daniel@0 14941 .router(true)
Daniel@0 14942 .reflows(true)
Daniel@0 14943 .mutates(true);
Daniel@0 14944 }
Daniel@0 14945
Daniel@0 14946 var proto = (Bounder.prototype = new Node());
Daniel@0 14947
Daniel@0 14948 proto.evaluate = function(input) {
Daniel@0 14949 log.debug(input, ['bounds', this._mark.marktype]);
Daniel@0 14950
Daniel@0 14951 var type = this._mark.marktype,
Daniel@0 14952 isGrp = type === 'group',
Daniel@0 14953 items = this._mark.items,
Daniel@0 14954 hasLegends = dl.array(this._mark.def.legends).length > 0,
Daniel@0 14955 i, ilen, j, jlen, group, legend;
Daniel@0 14956
Daniel@0 14957 if (input.add.length || input.rem.length || !items.length ||
Daniel@0 14958 input.mod.length === items.length ||
Daniel@0 14959 type === 'area' || type === 'line') {
Daniel@0 14960 bound.mark(this._mark, null, isGrp && !hasLegends);
Daniel@0 14961 } else {
Daniel@0 14962 input.mod.forEach(function(item) { bound.item(item); });
Daniel@0 14963 }
Daniel@0 14964
Daniel@0 14965 if (isGrp && hasLegends) {
Daniel@0 14966 for (i=0, ilen=items.length; i<ilen; ++i) {
Daniel@0 14967 group = items[i];
Daniel@0 14968 group._legendPositions = null;
Daniel@0 14969 for (j=0, jlen=group.legendItems.length; j<jlen; ++j) {
Daniel@0 14970 legend = group.legendItems[j];
Daniel@0 14971 Encoder.update(this._graph, input.trans, 'vg_legendPosition', legend.items, input.dirty);
Daniel@0 14972 bound.mark(legend, null, false);
Daniel@0 14973 }
Daniel@0 14974 }
Daniel@0 14975
Daniel@0 14976 bound.mark(this._mark, null, true);
Daniel@0 14977 }
Daniel@0 14978
Daniel@0 14979 return df.ChangeSet.create(input, true);
Daniel@0 14980 };
Daniel@0 14981
Daniel@0 14982 module.exports = Bounder;
Daniel@0 14983 },{"./Encoder":109,"datalib":24,"vega-dataflow":39,"vega-logging":45,"vega-scenegraph":46}],108:[function(require,module,exports){
Daniel@0 14984 var dl = require('datalib'),
Daniel@0 14985 log = require('vega-logging'),
Daniel@0 14986 Item = require('vega-scenegraph').Item,
Daniel@0 14987 df = require('vega-dataflow'),
Daniel@0 14988 Node = df.Node, // jshint ignore:line
Daniel@0 14989 Deps = df.Dependencies,
Daniel@0 14990 Tuple = df.Tuple,
Daniel@0 14991 ChangeSet = df.ChangeSet,
Daniel@0 14992 Sentinel = {},
Daniel@0 14993 Encoder = require('./Encoder'),
Daniel@0 14994 Bounder = require('./Bounder'),
Daniel@0 14995 parseData = require('../parse/data');
Daniel@0 14996
Daniel@0 14997 function Builder() {
Daniel@0 14998 return arguments.length ? this.init.apply(this, arguments) : this;
Daniel@0 14999 }
Daniel@0 15000
Daniel@0 15001 var Status = Builder.STATUS = {
Daniel@0 15002 ENTER: 'enter',
Daniel@0 15003 UPDATE: 'update',
Daniel@0 15004 EXIT: 'exit'
Daniel@0 15005 };
Daniel@0 15006
Daniel@0 15007 var CONNECTED = 1, DISCONNECTED = 2;
Daniel@0 15008
Daniel@0 15009 var proto = (Builder.prototype = new Node());
Daniel@0 15010
Daniel@0 15011 proto.init = function(graph, def, mark, parent, parent_id, inheritFrom) {
Daniel@0 15012 Node.prototype.init.call(this, graph)
Daniel@0 15013 .router(true)
Daniel@0 15014 .collector(true);
Daniel@0 15015
Daniel@0 15016 this._def = def;
Daniel@0 15017 this._mark = mark;
Daniel@0 15018 this._from = (def.from ? def.from.data : null) || inheritFrom;
Daniel@0 15019 this._ds = dl.isString(this._from) ? graph.data(this._from) : null;
Daniel@0 15020 this._map = {};
Daniel@0 15021 this._status = null; // Connected or disconnected?
Daniel@0 15022
Daniel@0 15023 mark.def = def;
Daniel@0 15024 mark.marktype = def.type;
Daniel@0 15025 mark.interactive = (def.interactive !== false);
Daniel@0 15026 mark.items = [];
Daniel@0 15027 if (dl.isValid(def.name)) mark.name = def.name;
Daniel@0 15028
Daniel@0 15029 this._parent = parent;
Daniel@0 15030 this._parent_id = parent_id;
Daniel@0 15031
Daniel@0 15032 if (def.from && (def.from.mark || def.from.transform || def.from.modify)) {
Daniel@0 15033 inlineDs.call(this);
Daniel@0 15034 }
Daniel@0 15035
Daniel@0 15036 // Non-group mark builders are super nodes. Encoder and Bounder remain
Daniel@0 15037 // separate operators but are embedded and called by Builder.evaluate.
Daniel@0 15038 this._isSuper = (this._def.type !== 'group');
Daniel@0 15039 this._encoder = new Encoder(this._graph, this._mark, this);
Daniel@0 15040 this._bounder = new Bounder(this._graph, this._mark);
Daniel@0 15041 this._output = null; // Output changeset for reactive geom as Bounder reflows
Daniel@0 15042
Daniel@0 15043 if (this._ds) { this._encoder.dependency(Deps.DATA, this._from); }
Daniel@0 15044
Daniel@0 15045 // Since Builders are super nodes, copy over encoder dependencies
Daniel@0 15046 // (bounder has no registered dependencies).
Daniel@0 15047 this.dependency(Deps.DATA, this._encoder.dependency(Deps.DATA));
Daniel@0 15048 this.dependency(Deps.SCALES, this._encoder.dependency(Deps.SCALES));
Daniel@0 15049 this.dependency(Deps.SIGNALS, this._encoder.dependency(Deps.SIGNALS));
Daniel@0 15050
Daniel@0 15051 return this;
Daniel@0 15052 };
Daniel@0 15053
Daniel@0 15054 // Reactive geometry and mark-level transformations are handled here
Daniel@0 15055 // because they need their group's data-joined context.
Daniel@0 15056 function inlineDs() {
Daniel@0 15057 var from = this._def.from,
Daniel@0 15058 geom = from.mark,
Daniel@0 15059 src, name, spec, sibling, output, input;
Daniel@0 15060
Daniel@0 15061 if (geom) {
Daniel@0 15062 name = ['vg', this._parent_id, geom].join('_');
Daniel@0 15063 spec = {
Daniel@0 15064 name: name,
Daniel@0 15065 transform: from.transform,
Daniel@0 15066 modify: from.modify
Daniel@0 15067 };
Daniel@0 15068 } else {
Daniel@0 15069 src = this._graph.data(this._from);
Daniel@0 15070 name = ['vg', this._from, this._def.type, src.listeners(true).length].join('_');
Daniel@0 15071 spec = {
Daniel@0 15072 name: name,
Daniel@0 15073 source: this._from,
Daniel@0 15074 transform: from.transform,
Daniel@0 15075 modify: from.modify
Daniel@0 15076 };
Daniel@0 15077 }
Daniel@0 15078
Daniel@0 15079 this._from = name;
Daniel@0 15080 this._ds = parseData.datasource(this._graph, spec);
Daniel@0 15081 var node;
Daniel@0 15082
Daniel@0 15083 if (geom) {
Daniel@0 15084 sibling = this.sibling(geom);
Daniel@0 15085
Daniel@0 15086 // Bounder reflows, so we need an intermediary node to propagate
Daniel@0 15087 // the output constructed by the Builder.
Daniel@0 15088 node = new Node(this._graph).addListener(this._ds.listener());
Daniel@0 15089 node.evaluate = function() { return sibling._output; };
Daniel@0 15090
Daniel@0 15091 if (sibling._isSuper) {
Daniel@0 15092 sibling.addListener(node);
Daniel@0 15093 } else {
Daniel@0 15094 sibling._bounder.addListener(node);
Daniel@0 15095 }
Daniel@0 15096 } else {
Daniel@0 15097 // At this point, we have a new datasource but it is empty as
Daniel@0 15098 // the propagation cycle has already crossed the datasources.
Daniel@0 15099 // So, we repulse just this datasource. This should be safe
Daniel@0 15100 // as the ds isn't connected to the scenegraph yet.
Daniel@0 15101 output = this._ds.source().last();
Daniel@0 15102 input = ChangeSet.create(output);
Daniel@0 15103
Daniel@0 15104 input.add = output.add;
Daniel@0 15105 input.mod = output.mod;
Daniel@0 15106 input.rem = output.rem;
Daniel@0 15107 input.stamp = null;
Daniel@0 15108 this._graph.propagate(input, this._ds.listener(), output.stamp);
Daniel@0 15109 }
Daniel@0 15110 }
Daniel@0 15111
Daniel@0 15112 proto.ds = function() { return this._ds; };
Daniel@0 15113 proto.parent = function() { return this._parent; };
Daniel@0 15114 proto.encoder = function() { return this._encoder; };
Daniel@0 15115 proto.pipeline = function() { return [this]; };
Daniel@0 15116
Daniel@0 15117 proto.connect = function() {
Daniel@0 15118 var builder = this;
Daniel@0 15119
Daniel@0 15120 this._graph.connect(this.pipeline());
Daniel@0 15121 this._encoder._scales.forEach(function(s) {
Daniel@0 15122 if (!(s = builder._parent.scale(s))) return;
Daniel@0 15123 s.addListener(builder);
Daniel@0 15124 });
Daniel@0 15125
Daniel@0 15126 if (this._parent) {
Daniel@0 15127 if (this._isSuper) this.addListener(this._parent._collector);
Daniel@0 15128 else this._bounder.addListener(this._parent._collector);
Daniel@0 15129 }
Daniel@0 15130
Daniel@0 15131 return (this._status = CONNECTED, this);
Daniel@0 15132 };
Daniel@0 15133
Daniel@0 15134 proto.disconnect = function() {
Daniel@0 15135 var builder = this;
Daniel@0 15136 if (!this._listeners.length) return this;
Daniel@0 15137
Daniel@0 15138 function disconnectScales(scales) {
Daniel@0 15139 for(var i=0, len=scales.length, s; i<len; ++i) {
Daniel@0 15140 if (!(s = builder._parent.scale(scales[i]))) continue;
Daniel@0 15141 s.removeListener(builder);
Daniel@0 15142 }
Daniel@0 15143 }
Daniel@0 15144
Daniel@0 15145 Node.prototype.disconnect.call(this);
Daniel@0 15146 this._graph.disconnect(this.pipeline());
Daniel@0 15147 disconnectScales(this._encoder._scales);
Daniel@0 15148 disconnectScales(dl.keys(this._mark._scaleRefs));
Daniel@0 15149
Daniel@0 15150 return (this._status = DISCONNECTED, this);
Daniel@0 15151 };
Daniel@0 15152
Daniel@0 15153 proto.sibling = function(name) {
Daniel@0 15154 return this._parent.child(name, this._parent_id);
Daniel@0 15155 };
Daniel@0 15156
Daniel@0 15157 proto.evaluate = function(input) {
Daniel@0 15158 log.debug(input, ['building', (this._from || this._def.from), this._def.type]);
Daniel@0 15159
Daniel@0 15160 var self = this,
Daniel@0 15161 def = this._mark.def,
Daniel@0 15162 props = def.properties || {},
Daniel@0 15163 update = props.update || {},
Daniel@0 15164 output, fullUpdate, fcs, data, name;
Daniel@0 15165
Daniel@0 15166 if (this._ds) {
Daniel@0 15167 output = ChangeSet.create(input);
Daniel@0 15168
Daniel@0 15169 // We need to determine if any encoder dependencies have been updated.
Daniel@0 15170 // However, the encoder's data source will likely be updated, and shouldn't
Daniel@0 15171 // trigger all items to mod.
Daniel@0 15172 data = output.data[(name=this._ds.name())];
Daniel@0 15173 delete output.data[name];
Daniel@0 15174 fullUpdate = this._encoder.reevaluate(output);
Daniel@0 15175 output.data[name] = data;
Daniel@0 15176
Daniel@0 15177 // If a scale or signal in the update propset has been updated,
Daniel@0 15178 // send forward all items for reencoding if we do an early return.
Daniel@0 15179 if (fullUpdate) output.mod = this._mark.items.slice();
Daniel@0 15180
Daniel@0 15181 fcs = this._ds.last();
Daniel@0 15182 if (!fcs) throw Error('Builder evaluated before backing DataSource.');
Daniel@0 15183 if (fcs.stamp > this._stamp) {
Daniel@0 15184 output = join.call(this, fcs, this._ds.values(), true, fullUpdate);
Daniel@0 15185 }
Daniel@0 15186 } else {
Daniel@0 15187 data = dl.isFunction(this._def.from) ? this._def.from() : [Sentinel];
Daniel@0 15188 output = join.call(this, input, data);
Daniel@0 15189 }
Daniel@0 15190
Daniel@0 15191 // Stash output before Bounder for downstream reactive geometry.
Daniel@0 15192 this._output = output = this._graph.evaluate(output, this._encoder);
Daniel@0 15193
Daniel@0 15194 // Add any new scale references to the dependency list, and ensure
Daniel@0 15195 // they're connected.
Daniel@0 15196 if (update.nested && update.nested.length && this._status === CONNECTED) {
Daniel@0 15197 dl.keys(this._mark._scaleRefs).forEach(function(s) {
Daniel@0 15198 var scale = self._parent.scale(s);
Daniel@0 15199 if (!scale) return;
Daniel@0 15200
Daniel@0 15201 scale.addListener(self);
Daniel@0 15202 self.dependency(Deps.SCALES, s);
Daniel@0 15203 self._encoder.dependency(Deps.SCALES, s);
Daniel@0 15204 });
Daniel@0 15205 }
Daniel@0 15206
Daniel@0 15207 // Supernodes calculate bounds too, but only on items marked dirty.
Daniel@0 15208 if (this._isSuper) {
Daniel@0 15209 output.mod = output.mod.filter(function(x) { return x._dirty; });
Daniel@0 15210 output = this._graph.evaluate(output, this._bounder);
Daniel@0 15211 }
Daniel@0 15212
Daniel@0 15213 return output;
Daniel@0 15214 };
Daniel@0 15215
Daniel@0 15216 function newItem() {
Daniel@0 15217 var item = Tuple.ingest(new Item(this._mark));
Daniel@0 15218
Daniel@0 15219 // For the root node's item
Daniel@0 15220 if (this._def.width) Tuple.set(item, 'width', this._def.width);
Daniel@0 15221 if (this._def.height) Tuple.set(item, 'height', this._def.height);
Daniel@0 15222 return item;
Daniel@0 15223 }
Daniel@0 15224
Daniel@0 15225 function join(input, data, ds, fullUpdate) {
Daniel@0 15226 var output = ChangeSet.create(input),
Daniel@0 15227 keyf = keyFunction(this._def.key || (ds ? '_id' : null)),
Daniel@0 15228 prev = this._mark.items || [],
Daniel@0 15229 rem = ds ? input.rem : prev,
Daniel@0 15230 mod = Tuple.idMap((!ds || fullUpdate) ? data : input.mod),
Daniel@0 15231 next = [],
Daniel@0 15232 i, key, len, item, datum, enter, diff;
Daniel@0 15233
Daniel@0 15234 // Only mark rems as exiting. Due to keyf, there may be an add/mod
Daniel@0 15235 // tuple that replaces it.
Daniel@0 15236 for (i=0, len=rem.length; i<len; ++i) {
Daniel@0 15237 item = (rem[i] === prev[i]) ? prev[i] :
Daniel@0 15238 keyf ? this._map[keyf(rem[i])] : rem[i];
Daniel@0 15239 item.status = Status.EXIT;
Daniel@0 15240 }
Daniel@0 15241
Daniel@0 15242 for(i=0, len=data.length; i<len; ++i) {
Daniel@0 15243 datum = data[i];
Daniel@0 15244 item = keyf ? this._map[key = keyf(datum)] : prev[i];
Daniel@0 15245 enter = item ? false : (item = newItem.call(this), true);
Daniel@0 15246 item.status = enter ? Status.ENTER : Status.UPDATE;
Daniel@0 15247 diff = !enter && item.datum !== datum;
Daniel@0 15248 item.datum = datum;
Daniel@0 15249
Daniel@0 15250 if (keyf) {
Daniel@0 15251 Tuple.set(item, 'key', key);
Daniel@0 15252 this._map[key] = item;
Daniel@0 15253 }
Daniel@0 15254
Daniel@0 15255 if (enter) {
Daniel@0 15256 output.add.push(item);
Daniel@0 15257 } else if (diff || mod[datum._id]) {
Daniel@0 15258 output.mod.push(item);
Daniel@0 15259 }
Daniel@0 15260
Daniel@0 15261 next.push(item);
Daniel@0 15262 }
Daniel@0 15263
Daniel@0 15264 for (i=0, len=rem.length; i<len; ++i) {
Daniel@0 15265 item = (rem[i] === prev[i]) ? prev[i] :
Daniel@0 15266 keyf ? this._map[key = keyf(rem[i])] : rem[i];
Daniel@0 15267 if (item.status === Status.EXIT) {
Daniel@0 15268 item._dirty = true;
Daniel@0 15269 input.dirty.push(item);
Daniel@0 15270 next.push(item);
Daniel@0 15271 output.rem.push(item);
Daniel@0 15272 if (keyf) this._map[key] = null;
Daniel@0 15273 }
Daniel@0 15274 }
Daniel@0 15275
Daniel@0 15276 return (this._mark.items = next, output);
Daniel@0 15277 }
Daniel@0 15278
Daniel@0 15279 function keyFunction(key) {
Daniel@0 15280 if (key == null) return null;
Daniel@0 15281 var f = dl.array(key).map(dl.accessor);
Daniel@0 15282 return function(d) {
Daniel@0 15283 for (var s='', i=0, n=f.length; i<n; ++i) {
Daniel@0 15284 if (i>0) s += '|';
Daniel@0 15285 s += String(f[i](d));
Daniel@0 15286 }
Daniel@0 15287 return s;
Daniel@0 15288 };
Daniel@0 15289 }
Daniel@0 15290
Daniel@0 15291 module.exports = Builder;
Daniel@0 15292 },{"../parse/data":92,"./Bounder":107,"./Encoder":109,"datalib":24,"vega-dataflow":39,"vega-logging":45,"vega-scenegraph":46}],109:[function(require,module,exports){
Daniel@0 15293 var dl = require('datalib'),
Daniel@0 15294 log = require('vega-logging'),
Daniel@0 15295 df = require('vega-dataflow'),
Daniel@0 15296 Node = df.Node, // jshint ignore:line
Daniel@0 15297 Deps = df.Dependencies,
Daniel@0 15298 bound = require('vega-scenegraph').bound;
Daniel@0 15299
Daniel@0 15300 var EMPTY = {};
Daniel@0 15301
Daniel@0 15302 function Encoder(graph, mark, builder) {
Daniel@0 15303 var props = mark.def.properties || {},
Daniel@0 15304 enter = props.enter,
Daniel@0 15305 update = props.update,
Daniel@0 15306 exit = props.exit;
Daniel@0 15307
Daniel@0 15308 Node.prototype.init.call(this, graph);
Daniel@0 15309
Daniel@0 15310 this._mark = mark;
Daniel@0 15311 this._builder = builder;
Daniel@0 15312 var s = this._scales = [];
Daniel@0 15313
Daniel@0 15314 // Only scales used in the 'update' property set are set as
Daniel@0 15315 // encoder depedencies to have targeted reevaluations. However,
Daniel@0 15316 // we still want scales in 'enter' and 'exit' to be evaluated
Daniel@0 15317 // before the encoder.
Daniel@0 15318 if (enter) s.push.apply(s, enter.scales);
Daniel@0 15319
Daniel@0 15320 if (update) {
Daniel@0 15321 this.dependency(Deps.DATA, update.data);
Daniel@0 15322 this.dependency(Deps.SIGNALS, update.signals);
Daniel@0 15323 this.dependency(Deps.FIELDS, update.fields);
Daniel@0 15324 this.dependency(Deps.SCALES, update.scales);
Daniel@0 15325 s.push.apply(s, update.scales);
Daniel@0 15326 }
Daniel@0 15327
Daniel@0 15328 if (exit) s.push.apply(s, exit.scales);
Daniel@0 15329
Daniel@0 15330 return this.mutates(true);
Daniel@0 15331 }
Daniel@0 15332
Daniel@0 15333 var proto = (Encoder.prototype = new Node());
Daniel@0 15334
Daniel@0 15335 proto.evaluate = function(input) {
Daniel@0 15336 log.debug(input, ['encoding', this._mark.def.type]);
Daniel@0 15337 var graph = this._graph,
Daniel@0 15338 props = this._mark.def.properties || {},
Daniel@0 15339 items = this._mark.items,
Daniel@0 15340 enter = props.enter,
Daniel@0 15341 update = props.update,
Daniel@0 15342 exit = props.exit,
Daniel@0 15343 dirty = input.dirty,
Daniel@0 15344 preds = graph.predicates(),
Daniel@0 15345 req = input.request,
Daniel@0 15346 group = this._mark.group,
Daniel@0 15347 guide = group && (group.mark.axis || group.mark.legend),
Daniel@0 15348 db = EMPTY, sg = EMPTY, i, len, item, prop;
Daniel@0 15349
Daniel@0 15350 if (req && !guide) {
Daniel@0 15351 if ((prop = props[req]) && input.mod.length) {
Daniel@0 15352 db = prop.data ? graph.values(Deps.DATA, prop.data) : null;
Daniel@0 15353 sg = prop.signals ? graph.values(Deps.SIGNALS, prop.signals) : null;
Daniel@0 15354
Daniel@0 15355 for (i=0, len=input.mod.length; i<len; ++i) {
Daniel@0 15356 item = input.mod[i];
Daniel@0 15357 encode.call(this, prop, item, input.trans, db, sg, preds, dirty);
Daniel@0 15358 }
Daniel@0 15359 }
Daniel@0 15360
Daniel@0 15361 return input; // exit early if given request
Daniel@0 15362 }
Daniel@0 15363
Daniel@0 15364 db = values(Deps.DATA, graph, input, props);
Daniel@0 15365 sg = values(Deps.SIGNALS, graph, input, props);
Daniel@0 15366
Daniel@0 15367 // Items marked for removal are at the tail of items. Process them first.
Daniel@0 15368 for (i=0, len=input.rem.length; i<len; ++i) {
Daniel@0 15369 item = input.rem[i];
Daniel@0 15370 if (exit) encode.call(this, exit, item, input.trans, db, sg, preds, dirty);
Daniel@0 15371 if (input.trans && !exit) input.trans.interpolate(item, EMPTY);
Daniel@0 15372 else if (!input.trans) items.pop();
Daniel@0 15373 }
Daniel@0 15374
Daniel@0 15375 var update_status = require('./Builder').STATUS.UPDATE;
Daniel@0 15376 for (i=0, len=input.add.length; i<len; ++i) {
Daniel@0 15377 item = input.add[i];
Daniel@0 15378 if (enter) encode.call(this, enter, item, input.trans, db, sg, preds, dirty);
Daniel@0 15379 if (update) encode.call(this, update, item, input.trans, db, sg, preds, dirty);
Daniel@0 15380 item.status = update_status;
Daniel@0 15381 }
Daniel@0 15382
Daniel@0 15383 if (update) {
Daniel@0 15384 for (i=0, len=input.mod.length; i<len; ++i) {
Daniel@0 15385 item = input.mod[i];
Daniel@0 15386 encode.call(this, update, item, input.trans, db, sg, preds, dirty);
Daniel@0 15387 }
Daniel@0 15388 }
Daniel@0 15389
Daniel@0 15390 return input;
Daniel@0 15391 };
Daniel@0 15392
Daniel@0 15393 // Only marshal necessary data and signal values
Daniel@0 15394 function values(type, graph, input, props) {
Daniel@0 15395 var p, x, o, add = input.add.length;
Daniel@0 15396 if ((p=props.enter) && (x=p[type]).length && add) {
Daniel@0 15397 o = graph.values(type, x, (o=o||{}));
Daniel@0 15398 }
Daniel@0 15399 if ((p=props.exit) && (x=p[type]).length && input.rem.length) {
Daniel@0 15400 o = graph.values(type, x, (o=o||{}));
Daniel@0 15401 }
Daniel@0 15402 if ((p=props.update) && (x=p[type]).length && (add || input.mod.length)) {
Daniel@0 15403 o = graph.values(type, x, (o=o||{}));
Daniel@0 15404 }
Daniel@0 15405 return o || EMPTY;
Daniel@0 15406 }
Daniel@0 15407
Daniel@0 15408 function encode(prop, item, trans, db, sg, preds, dirty) {
Daniel@0 15409 var enc = prop.encode,
Daniel@0 15410 wasDirty = item._dirty,
Daniel@0 15411 isDirty = enc.call(enc, item, item.mark.group||item, trans, db, sg, preds);
Daniel@0 15412
Daniel@0 15413 item._dirty = isDirty || wasDirty;
Daniel@0 15414 if (isDirty && !wasDirty) dirty.push(item);
Daniel@0 15415 }
Daniel@0 15416
Daniel@0 15417 // If a specified property set called, or update property set
Daniel@0 15418 // uses nested fieldrefs, reevaluate all items.
Daniel@0 15419 proto.reevaluate = function(pulse) {
Daniel@0 15420 var def = this._mark.def,
Daniel@0 15421 props = def.properties || {},
Daniel@0 15422 reeval = dl.isFunction(def.from) || def.orient || pulse.request ||
Daniel@0 15423 Node.prototype.reevaluate.call(this, pulse);
Daniel@0 15424
Daniel@0 15425 return reeval || (props.update ? nestedRefs.call(this) : false);
Daniel@0 15426 };
Daniel@0 15427
Daniel@0 15428 // Test if any nested refs trigger a reflow of mark items.
Daniel@0 15429 function nestedRefs() {
Daniel@0 15430 var refs = this._mark.def.properties.update.nested,
Daniel@0 15431 parent = this._builder,
Daniel@0 15432 level = 0,
Daniel@0 15433 i = 0, len = refs.length,
Daniel@0 15434 ref, ds, stamp;
Daniel@0 15435
Daniel@0 15436 for (; i<len; ++i) {
Daniel@0 15437 ref = refs[i];
Daniel@0 15438
Daniel@0 15439 // Scale references are resolved via this._mark._scaleRefs which are
Daniel@0 15440 // added to dependency lists + connected in Builder.evaluate.
Daniel@0 15441 if (ref.scale) continue;
Daniel@0 15442
Daniel@0 15443 for (; level<ref.level; ++level) {
Daniel@0 15444 parent = parent.parent();
Daniel@0 15445 ds = parent.ds();
Daniel@0 15446 }
Daniel@0 15447
Daniel@0 15448 // Compare stamps to determine if a change in a group's properties
Daniel@0 15449 // or data should trigger a reeval. We cannot check anything fancier
Daniel@0 15450 // (e.g., pulse.fields) as the ref may use item.datum.
Daniel@0 15451 stamp = (ref.group ? parent.encoder() : ds.last())._stamp;
Daniel@0 15452 if (stamp > this._stamp) return true;
Daniel@0 15453 }
Daniel@0 15454
Daniel@0 15455 return false;
Daniel@0 15456 }
Daniel@0 15457
Daniel@0 15458 // Short-circuit encoder if user specifies items
Daniel@0 15459 Encoder.update = function(graph, trans, request, items, dirty) {
Daniel@0 15460 items = dl.array(items);
Daniel@0 15461 var preds = graph.predicates(),
Daniel@0 15462 db = graph.values(Deps.DATA),
Daniel@0 15463 sg = graph.values(Deps.SIGNALS),
Daniel@0 15464 i, len, item, props, prop;
Daniel@0 15465
Daniel@0 15466 for (i=0, len=items.length; i<len; ++i) {
Daniel@0 15467 item = items[i];
Daniel@0 15468 props = item.mark.def.properties;
Daniel@0 15469 prop = props && props[request];
Daniel@0 15470 if (prop) {
Daniel@0 15471 encode.call(null, prop, item, trans, db, sg, preds, dirty);
Daniel@0 15472 bound.item(item);
Daniel@0 15473 }
Daniel@0 15474 }
Daniel@0 15475
Daniel@0 15476 };
Daniel@0 15477
Daniel@0 15478 module.exports = Encoder;
Daniel@0 15479 },{"./Builder":108,"datalib":24,"vega-dataflow":39,"vega-logging":45,"vega-scenegraph":46}],110:[function(require,module,exports){
Daniel@0 15480 var dl = require('datalib'),
Daniel@0 15481 df = require('vega-dataflow'),
Daniel@0 15482 Node = df.Node, // jshint ignore:line
Daniel@0 15483 Deps = df.Dependencies,
Daniel@0 15484 Collector = df.Collector,
Daniel@0 15485 log = require('vega-logging'),
Daniel@0 15486 Builder = require('./Builder'),
Daniel@0 15487 Scale = require('./Scale'),
Daniel@0 15488 parseAxes = require('../parse/axes'),
Daniel@0 15489 parseLegends = require('../parse/legends');
Daniel@0 15490
Daniel@0 15491 function GroupBuilder() {
Daniel@0 15492 this._children = {};
Daniel@0 15493 this._scaler = null;
Daniel@0 15494 this._recursor = null;
Daniel@0 15495
Daniel@0 15496 this._scales = {};
Daniel@0 15497 this.scale = scale.bind(this);
Daniel@0 15498 return arguments.length ? this.init.apply(this, arguments) : this;
Daniel@0 15499 }
Daniel@0 15500
Daniel@0 15501 var Types = GroupBuilder.TYPES = {
Daniel@0 15502 GROUP: "group",
Daniel@0 15503 MARK: "mark",
Daniel@0 15504 AXIS: "axis",
Daniel@0 15505 LEGEND: "legend"
Daniel@0 15506 };
Daniel@0 15507
Daniel@0 15508 var proto = (GroupBuilder.prototype = new Builder());
Daniel@0 15509
Daniel@0 15510 proto.init = function(graph, def) {
Daniel@0 15511 var builder = this, name;
Daniel@0 15512
Daniel@0 15513 this._scaler = new Node(graph);
Daniel@0 15514
Daniel@0 15515 (def.scales||[]).forEach(function(s) {
Daniel@0 15516 s = builder.scale((name=s.name), new Scale(graph, s, builder));
Daniel@0 15517 builder.scale(name+":prev", s);
Daniel@0 15518 builder._scaler.addListener(s); // Scales should be computed after group is encoded
Daniel@0 15519 });
Daniel@0 15520
Daniel@0 15521 this._recursor = new Node(graph);
Daniel@0 15522 this._recursor.evaluate = recurse.bind(this);
Daniel@0 15523
Daniel@0 15524 var scales = (def.axes||[]).reduce(function(acc, x) {
Daniel@0 15525 return (acc[x.scale] = 1, acc);
Daniel@0 15526 }, {});
Daniel@0 15527
Daniel@0 15528 scales = (def.legends||[]).reduce(function(acc, x) {
Daniel@0 15529 return (acc[x.size || x.shape || x.fill || x.stroke], acc);
Daniel@0 15530 }, scales);
Daniel@0 15531
Daniel@0 15532 this._recursor.dependency(Deps.SCALES, dl.keys(scales));
Daniel@0 15533
Daniel@0 15534 // We only need a collector for up-propagation of bounds calculation,
Daniel@0 15535 // so only GroupBuilders, and not regular Builders, have collectors.
Daniel@0 15536 this._collector = new Collector(graph);
Daniel@0 15537
Daniel@0 15538 return Builder.prototype.init.apply(this, arguments);
Daniel@0 15539 };
Daniel@0 15540
Daniel@0 15541 proto.evaluate = function() {
Daniel@0 15542 var output = Builder.prototype.evaluate.apply(this, arguments),
Daniel@0 15543 builder = this;
Daniel@0 15544
Daniel@0 15545 output.add.forEach(function(group) { buildGroup.call(builder, output, group); });
Daniel@0 15546 return output;
Daniel@0 15547 };
Daniel@0 15548
Daniel@0 15549 proto.pipeline = function() {
Daniel@0 15550 return [this, this._scaler, this._recursor, this._collector, this._bounder];
Daniel@0 15551 };
Daniel@0 15552
Daniel@0 15553 proto.disconnect = function() {
Daniel@0 15554 var builder = this;
Daniel@0 15555 dl.keys(builder._children).forEach(function(group_id) {
Daniel@0 15556 builder._children[group_id].forEach(function(c) {
Daniel@0 15557 builder._recursor.removeListener(c.builder);
Daniel@0 15558 c.builder.disconnect();
Daniel@0 15559 });
Daniel@0 15560 });
Daniel@0 15561
Daniel@0 15562 builder._children = {};
Daniel@0 15563 return Builder.prototype.disconnect.call(this);
Daniel@0 15564 };
Daniel@0 15565
Daniel@0 15566 proto.child = function(name, group_id) {
Daniel@0 15567 var children = this._children[group_id],
Daniel@0 15568 i = 0, len = children.length,
Daniel@0 15569 child;
Daniel@0 15570
Daniel@0 15571 for (; i<len; ++i) {
Daniel@0 15572 child = children[i];
Daniel@0 15573 if (child.type == Types.MARK && child.builder._def.name == name) break;
Daniel@0 15574 }
Daniel@0 15575
Daniel@0 15576 return child.builder;
Daniel@0 15577 };
Daniel@0 15578
Daniel@0 15579 function recurse(input) {
Daniel@0 15580 var builder = this,
Daniel@0 15581 hasMarks = dl.array(this._def.marks).length > 0,
Daniel@0 15582 hasAxes = dl.array(this._def.axes).length > 0,
Daniel@0 15583 hasLegends = dl.array(this._def.legends).length > 0,
Daniel@0 15584 i, j, c, len, group, pipeline, def, inline = false;
Daniel@0 15585
Daniel@0 15586 for (i=0, len=input.add.length; i<len; ++i) {
Daniel@0 15587 group = input.add[i];
Daniel@0 15588 if (hasMarks) buildMarks.call(this, input, group);
Daniel@0 15589 if (hasAxes) buildAxes.call(this, input, group);
Daniel@0 15590 if (hasLegends) buildLegends.call(this, input, group);
Daniel@0 15591 }
Daniel@0 15592
Daniel@0 15593 // Wire up new children builders in reverse to minimize graph rewrites.
Daniel@0 15594 for (i=input.add.length-1; i>=0; --i) {
Daniel@0 15595 group = input.add[i];
Daniel@0 15596 for (j=this._children[group._id].length-1; j>=0; --j) {
Daniel@0 15597 c = this._children[group._id][j];
Daniel@0 15598 c.builder.connect();
Daniel@0 15599 pipeline = c.builder.pipeline();
Daniel@0 15600 def = c.builder._def;
Daniel@0 15601
Daniel@0 15602 // This new child needs to be built during this propagation cycle.
Daniel@0 15603 // We could add its builder as a listener off the _recursor node,
Daniel@0 15604 // but try to inline it if we can to minimize graph dispatches.
Daniel@0 15605 inline = (def.type !== Types.GROUP);
Daniel@0 15606 inline = inline && (this._graph.data(c.from) !== undefined);
Daniel@0 15607 inline = inline && (pipeline[pipeline.length-1].listeners().length === 1); // Reactive geom source
Daniel@0 15608 inline = inline && (def.from && !def.from.mark); // Reactive geom target
Daniel@0 15609 c.inline = inline;
Daniel@0 15610
Daniel@0 15611 if (inline) this._graph.evaluate(input, c.builder);
Daniel@0 15612 else this._recursor.addListener(c.builder);
Daniel@0 15613 }
Daniel@0 15614 }
Daniel@0 15615
Daniel@0 15616 function removeTemp(c) {
Daniel@0 15617 if (c.type == Types.MARK && !c.inline &&
Daniel@0 15618 builder._graph.data(c.from) !== undefined) {
Daniel@0 15619 builder._recursor.removeListener(c.builder);
Daniel@0 15620 }
Daniel@0 15621 }
Daniel@0 15622
Daniel@0 15623 function updateAxis(a) {
Daniel@0 15624 var scale = a.scale();
Daniel@0 15625 if (!input.scales[scale.scaleName]) return;
Daniel@0 15626 a.reset().def();
Daniel@0 15627 }
Daniel@0 15628
Daniel@0 15629 function updateLegend(l) {
Daniel@0 15630 var scale = l.size() || l.shape() || l.fill() || l.stroke();
Daniel@0 15631 if (!input.scales[scale.scaleName]) return;
Daniel@0 15632 l.reset().def();
Daniel@0 15633 }
Daniel@0 15634
Daniel@0 15635 for (i=0, len=input.mod.length; i<len; ++i) {
Daniel@0 15636 group = input.mod[i];
Daniel@0 15637
Daniel@0 15638 // Remove temporary connection for marks that draw from a source
Daniel@0 15639 if (hasMarks) builder._children[group._id].forEach(removeTemp);
Daniel@0 15640
Daniel@0 15641 // Update axis data defs
Daniel@0 15642 if (hasAxes) group.axes.forEach(updateAxis);
Daniel@0 15643
Daniel@0 15644 // Update legend data defs
Daniel@0 15645 if (hasLegends) group.legends.forEach(updateLegend);
Daniel@0 15646 }
Daniel@0 15647
Daniel@0 15648 function disconnectChildren(c) {
Daniel@0 15649 builder._recursor.removeListener(c.builder);
Daniel@0 15650 c.builder.disconnect();
Daniel@0 15651 }
Daniel@0 15652
Daniel@0 15653 for (i=0, len=input.rem.length; i<len; ++i) {
Daniel@0 15654 group = input.rem[i];
Daniel@0 15655 // For deleted groups, disconnect their children
Daniel@0 15656 builder._children[group._id].forEach(disconnectChildren);
Daniel@0 15657 delete builder._children[group._id];
Daniel@0 15658 }
Daniel@0 15659
Daniel@0 15660 return input;
Daniel@0 15661 }
Daniel@0 15662
Daniel@0 15663 function scale(name, x) {
Daniel@0 15664 var group = this, s = null;
Daniel@0 15665 if (arguments.length === 2) return (group._scales[name] = x, x);
Daniel@0 15666 while (s == null) {
Daniel@0 15667 s = group._scales[name];
Daniel@0 15668 group = group.mark ? group.mark.group : group._parent;
Daniel@0 15669 if (!group) break;
Daniel@0 15670 }
Daniel@0 15671 return s;
Daniel@0 15672 }
Daniel@0 15673
Daniel@0 15674 function buildGroup(input, group) {
Daniel@0 15675 log.debug(input, ["building group", group._id]);
Daniel@0 15676
Daniel@0 15677 group._scales = group._scales || {};
Daniel@0 15678 group.scale = scale.bind(group);
Daniel@0 15679
Daniel@0 15680 group.items = group.items || [];
Daniel@0 15681 this._children[group._id] = this._children[group._id] || [];
Daniel@0 15682
Daniel@0 15683 group.axes = group.axes || [];
Daniel@0 15684 group.axisItems = group.axisItems || [];
Daniel@0 15685
Daniel@0 15686 group.legends = group.legends || [];
Daniel@0 15687 group.legendItems = group.legendItems || [];
Daniel@0 15688 }
Daniel@0 15689
Daniel@0 15690 function buildMarks(input, group) {
Daniel@0 15691 log.debug(input, ["building children marks #"+group._id]);
Daniel@0 15692 var marks = this._def.marks,
Daniel@0 15693 mark, from, inherit, i, len, b;
Daniel@0 15694
Daniel@0 15695 for (i=0, len=marks.length; i<len; ++i) {
Daniel@0 15696 mark = marks[i];
Daniel@0 15697 from = mark.from || {};
Daniel@0 15698 inherit = group.datum._facetID;
Daniel@0 15699 group.items[i] = {group: group, _scaleRefs: {}};
Daniel@0 15700 b = (mark.type === Types.GROUP) ? new GroupBuilder() : new Builder();
Daniel@0 15701 b.init(this._graph, mark, group.items[i], this, group._id, inherit);
Daniel@0 15702 this._children[group._id].push({
Daniel@0 15703 builder: b,
Daniel@0 15704 from: from.data || (from.mark ? ("vg_" + group._id + "_" + from.mark) : inherit),
Daniel@0 15705 type: Types.MARK
Daniel@0 15706 });
Daniel@0 15707 }
Daniel@0 15708 }
Daniel@0 15709
Daniel@0 15710 function buildAxes(input, group) {
Daniel@0 15711 var axes = group.axes,
Daniel@0 15712 axisItems = group.axisItems,
Daniel@0 15713 builder = this;
Daniel@0 15714
Daniel@0 15715 parseAxes(this._graph, this._def.axes, axes, group);
Daniel@0 15716 axes.forEach(function(a, i) {
Daniel@0 15717 var scale = builder._def.axes[i].scale,
Daniel@0 15718 def = a.def(),
Daniel@0 15719 b = null;
Daniel@0 15720
Daniel@0 15721 axisItems[i] = {group: group, axis: true, layer: def.layer};
Daniel@0 15722 b = (def.type === Types.GROUP) ? new GroupBuilder() : new Builder();
Daniel@0 15723 b.init(builder._graph, def, axisItems[i], builder)
Daniel@0 15724 .dependency(Deps.SCALES, scale);
Daniel@0 15725 builder._children[group._id].push({ builder: b, type: Types.AXIS, scale: scale });
Daniel@0 15726 });
Daniel@0 15727 }
Daniel@0 15728
Daniel@0 15729 function buildLegends(input, group) {
Daniel@0 15730 var legends = group.legends,
Daniel@0 15731 legendItems = group.legendItems,
Daniel@0 15732 builder = this;
Daniel@0 15733
Daniel@0 15734 parseLegends(this._graph, this._def.legends, legends, group);
Daniel@0 15735 legends.forEach(function(l, i) {
Daniel@0 15736 var scale = l.size() || l.shape() || l.fill() || l.stroke(),
Daniel@0 15737 def = l.def(),
Daniel@0 15738 b = null;
Daniel@0 15739
Daniel@0 15740 legendItems[i] = {group: group, legend: true};
Daniel@0 15741 b = (def.type === Types.GROUP) ? new GroupBuilder() : new Builder();
Daniel@0 15742 b.init(builder._graph, def, legendItems[i], builder)
Daniel@0 15743 .dependency(Deps.SCALES, scale);
Daniel@0 15744 builder._children[group._id].push({ builder: b, type: Types.LEGEND, scale: scale });
Daniel@0 15745 });
Daniel@0 15746 }
Daniel@0 15747
Daniel@0 15748 module.exports = GroupBuilder;
Daniel@0 15749 },{"../parse/axes":90,"../parse/legends":96,"./Builder":108,"./Scale":111,"datalib":24,"vega-dataflow":39,"vega-logging":45}],111:[function(require,module,exports){
Daniel@0 15750 (function (global){
Daniel@0 15751 var d3 = (typeof window !== "undefined" ? window['d3'] : typeof global !== "undefined" ? global['d3'] : null),
Daniel@0 15752 dl = require('datalib'),
Daniel@0 15753 df = require('vega-dataflow'),
Daniel@0 15754 log = require('vega-logging'),
Daniel@0 15755 Node = df.Node, // jshint ignore:line
Daniel@0 15756 Deps = df.Dependencies,
Daniel@0 15757 Aggregate = require('../transforms/Aggregate');
Daniel@0 15758
Daniel@0 15759 var Properties = {
Daniel@0 15760 width: 1,
Daniel@0 15761 height: 1
Daniel@0 15762 };
Daniel@0 15763
Daniel@0 15764 var Types = {
Daniel@0 15765 LINEAR: 'linear',
Daniel@0 15766 ORDINAL: 'ordinal',
Daniel@0 15767 LOG: 'log',
Daniel@0 15768 POWER: 'pow',
Daniel@0 15769 SQRT: 'sqrt',
Daniel@0 15770 TIME: 'time',
Daniel@0 15771 TIME_UTC: 'utc',
Daniel@0 15772 QUANTILE: 'quantile',
Daniel@0 15773 QUANTIZE: 'quantize',
Daniel@0 15774 THRESHOLD: 'threshold'
Daniel@0 15775 };
Daniel@0 15776
Daniel@0 15777 var DataRef = {
Daniel@0 15778 DOMAIN: 'domain',
Daniel@0 15779 RANGE: 'range',
Daniel@0 15780
Daniel@0 15781 COUNT: 'count',
Daniel@0 15782 GROUPBY: 'groupby',
Daniel@0 15783 MIN: 'min',
Daniel@0 15784 MAX: 'max',
Daniel@0 15785 VALUE: 'value',
Daniel@0 15786
Daniel@0 15787 ASC: 'asc',
Daniel@0 15788 DESC: 'desc'
Daniel@0 15789 };
Daniel@0 15790
Daniel@0 15791 function Scale(graph, def, parent) {
Daniel@0 15792 this._def = def;
Daniel@0 15793 this._parent = parent;
Daniel@0 15794 this._updated = false;
Daniel@0 15795 return Node.prototype.init.call(this, graph).reflows(true);
Daniel@0 15796 }
Daniel@0 15797
Daniel@0 15798 var proto = (Scale.prototype = new Node());
Daniel@0 15799
Daniel@0 15800 proto.evaluate = function(input) {
Daniel@0 15801 var self = this,
Daniel@0 15802 fn = function(group) { scale.call(self, group); };
Daniel@0 15803
Daniel@0 15804 this._updated = false;
Daniel@0 15805 input.add.forEach(fn);
Daniel@0 15806 input.mod.forEach(fn);
Daniel@0 15807
Daniel@0 15808 // Scales are at the end of an encoding pipeline, so they should forward a
Daniel@0 15809 // reflow pulse. Thus, if multiple scales update in the parent group, we don't
Daniel@0 15810 // reevaluate child marks multiple times.
Daniel@0 15811 if (this._updated) {
Daniel@0 15812 input.scales[this._def.name] = 1;
Daniel@0 15813 log.debug(input, ["scale", this._def.name]);
Daniel@0 15814 }
Daniel@0 15815 return df.ChangeSet.create(input, true);
Daniel@0 15816 };
Daniel@0 15817
Daniel@0 15818 // All of a scale's dependencies are registered during propagation as we parse
Daniel@0 15819 // dataRefs. So a scale must be responsible for connecting itself to dependents.
Daniel@0 15820 proto.dependency = function(type, deps) {
Daniel@0 15821 if (arguments.length == 2) {
Daniel@0 15822 var method = (type === Deps.DATA ? 'data' : 'signal');
Daniel@0 15823 deps = dl.array(deps);
Daniel@0 15824 for (var i=0, len=deps.length; i<len; ++i) {
Daniel@0 15825 this._graph[method](deps[i]).addListener(this._parent);
Daniel@0 15826 }
Daniel@0 15827 }
Daniel@0 15828
Daniel@0 15829 return Node.prototype.dependency.call(this, type, deps);
Daniel@0 15830 };
Daniel@0 15831
Daniel@0 15832 function scale(group) {
Daniel@0 15833 var name = this._def.name,
Daniel@0 15834 prev = name + ':prev',
Daniel@0 15835 s = instance.call(this, group.scale(name)),
Daniel@0 15836 m = s.type===Types.ORDINAL ? ordinal : quantitative,
Daniel@0 15837 rng = range.call(this, group);
Daniel@0 15838
Daniel@0 15839 m.call(this, s, rng, group);
Daniel@0 15840
Daniel@0 15841 group.scale(name, s);
Daniel@0 15842 group.scale(prev, group.scale(prev) || s);
Daniel@0 15843
Daniel@0 15844 return s;
Daniel@0 15845 }
Daniel@0 15846
Daniel@0 15847 function instance(scale) {
Daniel@0 15848 var config = this._graph.config(),
Daniel@0 15849 type = this._def.type || Types.LINEAR;
Daniel@0 15850 if (!scale || type !== scale.type) {
Daniel@0 15851 var ctor = config.scale[type] || d3.scale[type];
Daniel@0 15852 if (!ctor) throw Error('Unrecognized scale type: ' + type);
Daniel@0 15853 (scale = ctor()).type = scale.type || type;
Daniel@0 15854 scale.scaleName = this._def.name;
Daniel@0 15855 scale._prev = {};
Daniel@0 15856 }
Daniel@0 15857 return scale;
Daniel@0 15858 }
Daniel@0 15859
Daniel@0 15860 function ordinal(scale, rng, group) {
Daniel@0 15861 var def = this._def,
Daniel@0 15862 prev = scale._prev,
Daniel@0 15863 dataDrivenRange = false,
Daniel@0 15864 pad = signal.call(this, def.padding) || 0,
Daniel@0 15865 outer = def.outerPadding == null ? pad : signal.call(this, def.outerPadding),
Daniel@0 15866 points = def.points && signal.call(this, def.points),
Daniel@0 15867 round = signal.call(this, def.round) || def.round == null,
Daniel@0 15868 domain, str;
Daniel@0 15869
Daniel@0 15870 // range pre-processing for data-driven ranges
Daniel@0 15871 if (dl.isObject(def.range) && !dl.isArray(def.range)) {
Daniel@0 15872 dataDrivenRange = true;
Daniel@0 15873 rng = dataRef.call(this, DataRef.RANGE, def.range, scale, group);
Daniel@0 15874 }
Daniel@0 15875
Daniel@0 15876 // domain
Daniel@0 15877 domain = dataRef.call(this, DataRef.DOMAIN, def.domain, scale, group);
Daniel@0 15878 if (domain && !dl.equal(prev.domain, domain)) {
Daniel@0 15879 scale.domain(domain);
Daniel@0 15880 prev.domain = domain;
Daniel@0 15881 this._updated = true;
Daniel@0 15882 }
Daniel@0 15883
Daniel@0 15884 // range
Daniel@0 15885 if (dl.equal(prev.range, rng)) return;
Daniel@0 15886
Daniel@0 15887 // width-defined range
Daniel@0 15888 if (def.bandWidth) {
Daniel@0 15889 var bw = signal.call(this, def.bandWidth),
Daniel@0 15890 len = domain.length,
Daniel@0 15891 space = def.points ? (pad*bw) : (pad*bw*(len-1) + 2*outer),
Daniel@0 15892 start;
Daniel@0 15893 if (rng[0] > rng[1]) {
Daniel@0 15894 start = rng[1] || 0;
Daniel@0 15895 rng = [start + (bw * len + space), start];
Daniel@0 15896 } else {
Daniel@0 15897 start = rng[0] || 0;
Daniel@0 15898 rng = [start, start + (bw * len + space)];
Daniel@0 15899 }
Daniel@0 15900 }
Daniel@0 15901
Daniel@0 15902 str = typeof rng[0] === 'string';
Daniel@0 15903 if (str || rng.length > 2 || rng.length===1 || dataDrivenRange) {
Daniel@0 15904 scale.range(rng); // color or shape values
Daniel@0 15905 } else if (points && round) {
Daniel@0 15906 scale.rangeRoundPoints(rng, pad);
Daniel@0 15907 } else if (points) {
Daniel@0 15908 scale.rangePoints(rng, pad);
Daniel@0 15909 } else if (round) {
Daniel@0 15910 scale.rangeRoundBands(rng, pad, outer);
Daniel@0 15911 } else {
Daniel@0 15912 scale.rangeBands(rng, pad, outer);
Daniel@0 15913 }
Daniel@0 15914
Daniel@0 15915 if (!scale.invert) {
Daniel@0 15916 scale.invert = function(x, y) {
Daniel@0 15917 if (arguments.length === 1) {
Daniel@0 15918 return scale.domain()[d3.bisect(scale.range(), x) - 1];
Daniel@0 15919 } else if (arguments.length === 2) { // Invert extents
Daniel@0 15920 if (!dl.isNumber(x) || !dl.isNumber(y)) {
Daniel@0 15921 throw Error('Extents to ordinal invert are not numbers ('+x+', '+y+').');
Daniel@0 15922 }
Daniel@0 15923
Daniel@0 15924 var points = [],
Daniel@0 15925 rng = scale.range(),
Daniel@0 15926 i = 0, len = rng.length, r;
Daniel@0 15927
Daniel@0 15928 for(; i<len; ++i) {
Daniel@0 15929 r = rng[i];
Daniel@0 15930 if (x < y ? x <= r && r <= y : y <= r && r <= x) {
Daniel@0 15931 points.push(r);
Daniel@0 15932 }
Daniel@0 15933 }
Daniel@0 15934
Daniel@0 15935 return points.map(function(p) { return scale.invert(p); });
Daniel@0 15936 }
Daniel@0 15937 };
Daniel@0 15938 }
Daniel@0 15939
Daniel@0 15940 prev.range = rng;
Daniel@0 15941 this._updated = true;
Daniel@0 15942 }
Daniel@0 15943
Daniel@0 15944 function quantitative(scale, rng, group) {
Daniel@0 15945 var def = this._def,
Daniel@0 15946 prev = scale._prev,
Daniel@0 15947 round = signal.call(this, def.round),
Daniel@0 15948 exponent = signal.call(this, def.exponent),
Daniel@0 15949 clamp = signal.call(this, def.clamp),
Daniel@0 15950 nice = signal.call(this, def.nice),
Daniel@0 15951 domain, interval;
Daniel@0 15952
Daniel@0 15953 // domain
Daniel@0 15954 domain = (def.type === Types.QUANTILE) ?
Daniel@0 15955 dataRef.call(this, DataRef.DOMAIN, def.domain, scale, group) :
Daniel@0 15956 domainMinMax.call(this, scale, group);
Daniel@0 15957 if (domain && !dl.equal(prev.domain, domain)) {
Daniel@0 15958 scale.domain(domain);
Daniel@0 15959 prev.domain = domain;
Daniel@0 15960 this._updated = true;
Daniel@0 15961 }
Daniel@0 15962
Daniel@0 15963 // range
Daniel@0 15964 // vertical scales should flip by default, so use XOR here
Daniel@0 15965 if (signal.call(this, def.range) === 'height') rng = rng.reverse();
Daniel@0 15966 if (dl.equal(prev.range, rng)) return;
Daniel@0 15967 scale[round && scale.rangeRound ? 'rangeRound' : 'range'](rng);
Daniel@0 15968 prev.range = rng;
Daniel@0 15969 this._updated = true;
Daniel@0 15970
Daniel@0 15971 // TODO: Support signals for these properties. Until then, only eval
Daniel@0 15972 // them once.
Daniel@0 15973 if (this._stamp > 0) return;
Daniel@0 15974 if (exponent && def.type===Types.POWER) scale.exponent(exponent);
Daniel@0 15975 if (clamp) scale.clamp(true);
Daniel@0 15976 if (nice) {
Daniel@0 15977 if (def.type === Types.TIME) {
Daniel@0 15978 interval = d3.time[nice];
Daniel@0 15979 if (!interval) log.error('Unrecognized interval: ' + interval);
Daniel@0 15980 scale.nice(interval);
Daniel@0 15981 } else {
Daniel@0 15982 scale.nice();
Daniel@0 15983 }
Daniel@0 15984 }
Daniel@0 15985 }
Daniel@0 15986
Daniel@0 15987 function isUniques(scale) {
Daniel@0 15988 return scale.type === Types.ORDINAL || scale.type === Types.QUANTILE;
Daniel@0 15989 }
Daniel@0 15990
Daniel@0 15991 function getRefs(def) {
Daniel@0 15992 return def.fields || dl.array(def);
Daniel@0 15993 }
Daniel@0 15994
Daniel@0 15995 function inherits(refs) {
Daniel@0 15996 return refs.some(function(r) {
Daniel@0 15997 if (!r.data) return true;
Daniel@0 15998 return r.data && dl.array(r.field).some(function(f) {
Daniel@0 15999 return f.parent;
Daniel@0 16000 });
Daniel@0 16001 });
Daniel@0 16002 }
Daniel@0 16003
Daniel@0 16004 function getFields(ref, group) {
Daniel@0 16005 return dl.array(ref.field).map(function(f) {
Daniel@0 16006 return f.parent ?
Daniel@0 16007 dl.accessor(f.parent)(group.datum) :
Daniel@0 16008 f; // String or {'signal'}
Daniel@0 16009 });
Daniel@0 16010 }
Daniel@0 16011
Daniel@0 16012 // Scale datarefs can be computed over multiple schema types.
Daniel@0 16013 // This function determines the type of aggregator created, and
Daniel@0 16014 // what data is sent to it: values, tuples, or multi-tuples that must
Daniel@0 16015 // be standardized into a consistent schema.
Daniel@0 16016 function aggrType(def, scale) {
Daniel@0 16017 var refs = getRefs(def);
Daniel@0 16018
Daniel@0 16019 // If we're operating over only a single domain, send full tuples
Daniel@0 16020 // through for efficiency (fewer accessor creations/calls)
Daniel@0 16021 if (refs.length == 1 && dl.array(refs[0].field).length == 1) {
Daniel@0 16022 return Aggregate.TYPES.TUPLE;
Daniel@0 16023 }
Daniel@0 16024
Daniel@0 16025 // With quantitative scales, we only care about min/max.
Daniel@0 16026 if (!isUniques(scale)) return Aggregate.TYPES.VALUE;
Daniel@0 16027
Daniel@0 16028 // If we don't sort, then we can send values directly to aggrs as well
Daniel@0 16029 if (!dl.isObject(def.sort)) return Aggregate.TYPES.VALUE;
Daniel@0 16030
Daniel@0 16031 return Aggregate.TYPES.MULTI;
Daniel@0 16032 }
Daniel@0 16033
Daniel@0 16034 function getCache(which, def, scale, group) {
Daniel@0 16035 var refs = getRefs(def),
Daniel@0 16036 inherit = inherits(refs),
Daniel@0 16037 atype = aggrType(def, scale),
Daniel@0 16038 uniques = isUniques(scale),
Daniel@0 16039 sort = def.sort,
Daniel@0 16040 ck = '_'+which,
Daniel@0 16041 fields = getFields(refs[0], group);
Daniel@0 16042
Daniel@0 16043 if (scale[ck] || this[ck]) return scale[ck] || this[ck];
Daniel@0 16044
Daniel@0 16045 var cache = new Aggregate(this._graph).type(atype),
Daniel@0 16046 groupby, summarize;
Daniel@0 16047
Daniel@0 16048 // If a scale's dataref doesn't inherit data from the group, we can
Daniel@0 16049 // store the dataref aggregator at the Scale (dataflow node) level.
Daniel@0 16050 if (inherit) {
Daniel@0 16051 scale[ck] = cache;
Daniel@0 16052 } else {
Daniel@0 16053 this[ck] = cache;
Daniel@0 16054 }
Daniel@0 16055
Daniel@0 16056 if (uniques) {
Daniel@0 16057 if (atype === Aggregate.TYPES.VALUE) {
Daniel@0 16058 groupby = [{ name: DataRef.GROUPBY, get: dl.identity }];
Daniel@0 16059 summarize = {'*': DataRef.COUNT};
Daniel@0 16060 } else if (atype === Aggregate.TYPES.TUPLE) {
Daniel@0 16061 groupby = [{ name: DataRef.GROUPBY, get: dl.$(fields[0]) }];
Daniel@0 16062 summarize = dl.isObject(sort) ? [{
Daniel@0 16063 field: DataRef.VALUE,
Daniel@0 16064 get: dl.$(sort.field),
Daniel@0 16065 ops: [sort.op]
Daniel@0 16066 }] : {'*': DataRef.COUNT};
Daniel@0 16067 } else { // atype === Aggregate.TYPES.MULTI
Daniel@0 16068 groupby = DataRef.GROUPBY;
Daniel@0 16069 summarize = [{ field: DataRef.VALUE, ops: [sort.op] }];
Daniel@0 16070 }
Daniel@0 16071 } else {
Daniel@0 16072 groupby = [];
Daniel@0 16073 summarize = [{
Daniel@0 16074 field: DataRef.VALUE,
Daniel@0 16075 get: (atype == Aggregate.TYPES.TUPLE) ? dl.$(fields[0]) : dl.identity,
Daniel@0 16076 ops: [DataRef.MIN, DataRef.MAX],
Daniel@0 16077 as: [DataRef.MIN, DataRef.MAX]
Daniel@0 16078 }];
Daniel@0 16079 }
Daniel@0 16080
Daniel@0 16081 cache.param('groupby', groupby)
Daniel@0 16082 .param('summarize', summarize);
Daniel@0 16083
Daniel@0 16084 return (cache._lastUpdate = -1, cache);
Daniel@0 16085 }
Daniel@0 16086
Daniel@0 16087 function dataRef(which, def, scale, group) {
Daniel@0 16088 if (def == null) { return []; }
Daniel@0 16089 if (dl.isArray(def)) return def.map(signal.bind(this));
Daniel@0 16090
Daniel@0 16091 var self = this, graph = this._graph,
Daniel@0 16092 refs = getRefs(def),
Daniel@0 16093 inherit = inherits(refs),
Daniel@0 16094 atype = aggrType(def, scale),
Daniel@0 16095 cache = getCache.apply(this, arguments),
Daniel@0 16096 sort = def.sort,
Daniel@0 16097 uniques = isUniques(scale),
Daniel@0 16098 i, rlen, j, flen, ref, fields, field, data, from, so, cmp;
Daniel@0 16099
Daniel@0 16100 function addDep(s) {
Daniel@0 16101 self.dependency(Deps.SIGNALS, s);
Daniel@0 16102 }
Daniel@0 16103
Daniel@0 16104 if (inherit || (!inherit && cache._lastUpdate < this._stamp)) {
Daniel@0 16105 for (i=0, rlen=refs.length; i<rlen; ++i) {
Daniel@0 16106 ref = refs[i];
Daniel@0 16107 from = ref.data || group.datum._facetID;
Daniel@0 16108 data = graph.data(from).last();
Daniel@0 16109
Daniel@0 16110 if (data.stamp <= this._stamp) continue;
Daniel@0 16111
Daniel@0 16112 fields = getFields(ref, group);
Daniel@0 16113 for (j=0, flen=fields.length; j<flen; ++j) {
Daniel@0 16114 field = fields[j];
Daniel@0 16115
Daniel@0 16116 if (atype === Aggregate.TYPES.VALUE) {
Daniel@0 16117 cache.accessors(null, field);
Daniel@0 16118 } else if (atype === Aggregate.TYPES.MULTI) {
Daniel@0 16119 cache.accessors(field, ref.sort || sort.field);
Daniel@0 16120 } // Else (Tuple-case) is handled by the aggregator accessors by default
Daniel@0 16121
Daniel@0 16122 cache.evaluate(data);
Daniel@0 16123 }
Daniel@0 16124
Daniel@0 16125 this.dependency(Deps.DATA, from);
Daniel@0 16126 cache.dependency(Deps.SIGNALS).forEach(addDep);
Daniel@0 16127 }
Daniel@0 16128
Daniel@0 16129 cache._lastUpdate = this._stamp;
Daniel@0 16130
Daniel@0 16131 data = cache.aggr().result();
Daniel@0 16132 if (uniques) {
Daniel@0 16133 if (dl.isObject(sort)) {
Daniel@0 16134 cmp = (so = sort.order) && so.signal ? graph.signalRef(so.signal) : so;
Daniel@0 16135 cmp = (cmp == DataRef.DESC ? '-' : '+') + sort.op + '_' + DataRef.VALUE;
Daniel@0 16136 cmp = dl.comparator(cmp);
Daniel@0 16137 } else if (sort === true) {
Daniel@0 16138 cmp = dl.comparator(DataRef.GROUPBY);
Daniel@0 16139 }
Daniel@0 16140
Daniel@0 16141 if (cmp) data = data.sort(cmp);
Daniel@0 16142 cache._values = data.map(function(d) { return d[DataRef.GROUPBY]; });
Daniel@0 16143 } else {
Daniel@0 16144 data = data[0];
Daniel@0 16145 cache._values = !dl.isValid(data) ? [] : [data[DataRef.MIN], data[DataRef.MAX]];
Daniel@0 16146 }
Daniel@0 16147 }
Daniel@0 16148
Daniel@0 16149 return cache._values;
Daniel@0 16150 }
Daniel@0 16151
Daniel@0 16152 function signal(v) {
Daniel@0 16153 if (!v || !v.signal) return v;
Daniel@0 16154 var s = v.signal, ref;
Daniel@0 16155 this.dependency(Deps.SIGNALS, (ref = dl.field(s))[0]);
Daniel@0 16156 return this._graph.signalRef(ref);
Daniel@0 16157 }
Daniel@0 16158
Daniel@0 16159 function domainMinMax(scale, group) {
Daniel@0 16160 var def = this._def,
Daniel@0 16161 domain = [null, null], s, z;
Daniel@0 16162
Daniel@0 16163 if (def.domain !== undefined) {
Daniel@0 16164 domain = (!dl.isObject(def.domain)) ? domain :
Daniel@0 16165 dataRef.call(this, DataRef.DOMAIN, def.domain, scale, group);
Daniel@0 16166 }
Daniel@0 16167
Daniel@0 16168 z = domain.length - 1;
Daniel@0 16169 if (def.domainMin !== undefined) {
Daniel@0 16170 if (dl.isObject(def.domainMin)) {
Daniel@0 16171 if (def.domainMin.signal) {
Daniel@0 16172 domain[0] = dl.isValid(s=signal.call(this, def.domainMin)) ? s : domain[0];
Daniel@0 16173 } else {
Daniel@0 16174 domain[0] = dataRef.call(this, DataRef.DOMAIN+DataRef.MIN, def.domainMin, scale, group)[0];
Daniel@0 16175 }
Daniel@0 16176 } else {
Daniel@0 16177 domain[0] = def.domainMin;
Daniel@0 16178 }
Daniel@0 16179 }
Daniel@0 16180 if (def.domainMax !== undefined) {
Daniel@0 16181 if (dl.isObject(def.domainMax)) {
Daniel@0 16182 if (def.domainMax.signal) {
Daniel@0 16183 domain[z] = dl.isValid(s=signal.call(this, def.domainMax)) ? s : domain[z];
Daniel@0 16184 } else {
Daniel@0 16185 domain[z] = dataRef.call(this, DataRef.DOMAIN+DataRef.MAX, def.domainMax, scale, group)[1];
Daniel@0 16186 }
Daniel@0 16187 } else {
Daniel@0 16188 domain[z] = def.domainMax;
Daniel@0 16189 }
Daniel@0 16190 }
Daniel@0 16191 if (def.type !== Types.LOG && def.type !== Types.TIME && (def.zero || def.zero===undefined)) {
Daniel@0 16192 domain[0] = Math.min(0, domain[0]);
Daniel@0 16193 domain[z] = Math.max(0, domain[z]);
Daniel@0 16194 }
Daniel@0 16195 return domain;
Daniel@0 16196 }
Daniel@0 16197
Daniel@0 16198 function range(group) {
Daniel@0 16199 var def = this._def,
Daniel@0 16200 config = this._graph.config(),
Daniel@0 16201 rangeVal = signal.call(this, def.range),
Daniel@0 16202 rng = [null, null];
Daniel@0 16203
Daniel@0 16204 if (rangeVal !== undefined) {
Daniel@0 16205 if (typeof rangeVal === 'string') {
Daniel@0 16206 if (Properties[rangeVal]) {
Daniel@0 16207 rng = [0, group[rangeVal]];
Daniel@0 16208 } else if (config.range[rangeVal]) {
Daniel@0 16209 rng = config.range[rangeVal];
Daniel@0 16210 } else {
Daniel@0 16211 log.error('Unrecogized range: ' + rangeVal);
Daniel@0 16212 return rng;
Daniel@0 16213 }
Daniel@0 16214 } else if (dl.isArray(rangeVal)) {
Daniel@0 16215 rng = dl.duplicate(rangeVal).map(signal.bind(this));
Daniel@0 16216 } else if (dl.isObject(rangeVal)) {
Daniel@0 16217 return null; // early exit
Daniel@0 16218 } else {
Daniel@0 16219 rng = [0, rangeVal];
Daniel@0 16220 }
Daniel@0 16221 }
Daniel@0 16222 if (def.rangeMin !== undefined) {
Daniel@0 16223 rng[0] = def.rangeMin.signal ?
Daniel@0 16224 signal.call(this, def.rangeMin) :
Daniel@0 16225 def.rangeMin;
Daniel@0 16226 }
Daniel@0 16227 if (def.rangeMax !== undefined) {
Daniel@0 16228 rng[rng.length-1] = def.rangeMax.signal ?
Daniel@0 16229 signal.call(this, def.rangeMax) :
Daniel@0 16230 def.rangeMax;
Daniel@0 16231 }
Daniel@0 16232
Daniel@0 16233 if (def.reverse !== undefined) {
Daniel@0 16234 var rev = signal.call(this, def.reverse);
Daniel@0 16235 if (dl.isObject(rev)) {
Daniel@0 16236 rev = dl.accessor(rev.field)(group.datum);
Daniel@0 16237 }
Daniel@0 16238 if (rev) rng = rng.reverse();
Daniel@0 16239 }
Daniel@0 16240
Daniel@0 16241 return rng;
Daniel@0 16242 }
Daniel@0 16243
Daniel@0 16244 module.exports = Scale;
Daniel@0 16245 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
Daniel@0 16246
Daniel@0 16247 },{"../transforms/Aggregate":116,"datalib":24,"vega-dataflow":39,"vega-logging":45}],112:[function(require,module,exports){
Daniel@0 16248 (function (global){
Daniel@0 16249 var d3 = (typeof window !== "undefined" ? window['d3'] : typeof global !== "undefined" ? global['d3'] : null),
Daniel@0 16250 bound = require('vega-scenegraph').bound,
Daniel@0 16251 Tuple = require('vega-dataflow').Tuple,
Daniel@0 16252 Status = require('./Builder').STATUS;
Daniel@0 16253
Daniel@0 16254 function Transition(duration, ease) {
Daniel@0 16255 this.duration = duration || 500;
Daniel@0 16256 this.ease = ease && d3.ease(ease) || d3.ease('cubic-in-out');
Daniel@0 16257 this.updates = {next: null};
Daniel@0 16258 }
Daniel@0 16259
Daniel@0 16260 var prototype = Transition.prototype;
Daniel@0 16261
Daniel@0 16262 var skip = {
Daniel@0 16263 'text': 1,
Daniel@0 16264 'url': 1
Daniel@0 16265 };
Daniel@0 16266
Daniel@0 16267 prototype.interpolate = function(item, values) {
Daniel@0 16268 var key, curr, next, interp, list = null;
Daniel@0 16269
Daniel@0 16270 for (key in values) {
Daniel@0 16271 curr = item[key];
Daniel@0 16272 next = values[key];
Daniel@0 16273 if (curr !== next) {
Daniel@0 16274 if (skip[key] || curr === undefined) {
Daniel@0 16275 // skip interpolation for specific keys or undefined start values
Daniel@0 16276 Tuple.set(item, key, next);
Daniel@0 16277 } else if (typeof curr === 'number' && !isFinite(curr)) {
Daniel@0 16278 // for NaN or infinite numeric values, skip to final value
Daniel@0 16279 Tuple.set(item, key, next);
Daniel@0 16280 } else {
Daniel@0 16281 // otherwise lookup interpolator
Daniel@0 16282 interp = d3.interpolate(curr, next);
Daniel@0 16283 interp.property = key;
Daniel@0 16284 (list || (list=[])).push(interp);
Daniel@0 16285 }
Daniel@0 16286 }
Daniel@0 16287 }
Daniel@0 16288
Daniel@0 16289 if (list === null && item.status === Status.EXIT) {
Daniel@0 16290 list = []; // ensure exiting items are included
Daniel@0 16291 }
Daniel@0 16292
Daniel@0 16293 if (list != null) {
Daniel@0 16294 list.item = item;
Daniel@0 16295 list.ease = item.mark.ease || this.ease;
Daniel@0 16296 list.next = this.updates.next;
Daniel@0 16297 this.updates.next = list;
Daniel@0 16298 }
Daniel@0 16299 return this;
Daniel@0 16300 };
Daniel@0 16301
Daniel@0 16302 prototype.start = function(callback) {
Daniel@0 16303 var t = this, prev = t.updates, curr = prev.next;
Daniel@0 16304 for (; curr!=null; prev=curr, curr=prev.next) {
Daniel@0 16305 if (curr.item.status === Status.EXIT) {
Daniel@0 16306 // Only mark item as exited when it is removed.
Daniel@0 16307 curr.item.status = Status.UPDATE;
Daniel@0 16308 curr.remove = true;
Daniel@0 16309 }
Daniel@0 16310 }
Daniel@0 16311 t.callback = callback;
Daniel@0 16312 d3.timer(function(elapsed) { return step.call(t, elapsed); });
Daniel@0 16313 };
Daniel@0 16314
Daniel@0 16315 function step(elapsed) {
Daniel@0 16316 var list = this.updates, prev = list, curr = prev.next,
Daniel@0 16317 duration = this.duration,
Daniel@0 16318 item, delay, f, e, i, n, stop = true;
Daniel@0 16319
Daniel@0 16320 for (; curr!=null; prev=curr, curr=prev.next) {
Daniel@0 16321 item = curr.item;
Daniel@0 16322 delay = item.delay || 0;
Daniel@0 16323
Daniel@0 16324 f = (elapsed - delay) / duration;
Daniel@0 16325 if (f < 0) { stop = false; continue; }
Daniel@0 16326 if (f > 1) f = 1;
Daniel@0 16327 e = curr.ease(f);
Daniel@0 16328
Daniel@0 16329 for (i=0, n=curr.length; i<n; ++i) {
Daniel@0 16330 item[curr[i].property] = curr[i](e);
Daniel@0 16331 }
Daniel@0 16332 item.touch();
Daniel@0 16333 bound.item(item);
Daniel@0 16334
Daniel@0 16335 if (f === 1) {
Daniel@0 16336 if (curr.remove) {
Daniel@0 16337 item.status = Status.EXIT;
Daniel@0 16338 item.remove();
Daniel@0 16339 }
Daniel@0 16340 prev.next = curr.next;
Daniel@0 16341 curr = prev;
Daniel@0 16342 } else {
Daniel@0 16343 stop = false;
Daniel@0 16344 }
Daniel@0 16345 }
Daniel@0 16346
Daniel@0 16347 this.callback();
Daniel@0 16348 return stop;
Daniel@0 16349 }
Daniel@0 16350
Daniel@0 16351 module.exports = Transition;
Daniel@0 16352 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
Daniel@0 16353
Daniel@0 16354 },{"./Builder":108,"vega-dataflow":39,"vega-scenegraph":46}],113:[function(require,module,exports){
Daniel@0 16355 var dl = require('datalib'),
Daniel@0 16356 Tuple = require('vega-dataflow').Tuple,
Daniel@0 16357 parseMark = require('../parse/mark');
Daniel@0 16358
Daniel@0 16359 var TIME = 'time',
Daniel@0 16360 UTC = 'utc',
Daniel@0 16361 STRING = 'string',
Daniel@0 16362 ORDINAL = 'ordinal',
Daniel@0 16363 NUMBER = 'number';
Daniel@0 16364
Daniel@0 16365 function axs(model) {
Daniel@0 16366 var scale,
Daniel@0 16367 config = model.config(),
Daniel@0 16368 orient = config.axis.orient,
Daniel@0 16369 offset = 0,
Daniel@0 16370 titleOffset = config.axis.titleOffset,
Daniel@0 16371 axisDef = {},
Daniel@0 16372 layer = 'front',
Daniel@0 16373 grid = false,
Daniel@0 16374 title = null,
Daniel@0 16375 tickMajorSize = config.axis.tickSize,
Daniel@0 16376 tickMinorSize = config.axis.tickSize,
Daniel@0 16377 tickEndSize = config.axis.tickSize,
Daniel@0 16378 tickPadding = config.axis.padding,
Daniel@0 16379 tickValues = null,
Daniel@0 16380 tickFormatString = null,
Daniel@0 16381 tickFormatType = null,
Daniel@0 16382 tickSubdivide = 0,
Daniel@0 16383 tickCount = config.axis.ticks,
Daniel@0 16384 gridLineStyle = {},
Daniel@0 16385 tickLabelStyle = {},
Daniel@0 16386 majorTickStyle = {},
Daniel@0 16387 minorTickStyle = {},
Daniel@0 16388 titleStyle = {},
Daniel@0 16389 domainStyle = {},
Daniel@0 16390 m = { // Axis marks as references for updates
Daniel@0 16391 gridLines: {},
Daniel@0 16392 majorTicks: {},
Daniel@0 16393 minorTicks: {},
Daniel@0 16394 tickLabels: {},
Daniel@0 16395 domain: {},
Daniel@0 16396 title: {}
Daniel@0 16397 };
Daniel@0 16398
Daniel@0 16399 var axis = {};
Daniel@0 16400
Daniel@0 16401 function reset() {
Daniel@0 16402 axisDef.type = null;
Daniel@0 16403 }
Daniel@0 16404
Daniel@0 16405 function ingest(d) {
Daniel@0 16406 return {data: d};
Daniel@0 16407 }
Daniel@0 16408
Daniel@0 16409 function getTickFormat() {
Daniel@0 16410 var formatType = tickFormatType || inferFormatType();
Daniel@0 16411 return getFormatter(formatType, tickFormatString);
Daniel@0 16412 }
Daniel@0 16413
Daniel@0 16414 function inferFormatType() {
Daniel@0 16415 switch (scale.type) {
Daniel@0 16416 case TIME: return TIME;
Daniel@0 16417 case UTC: return UTC;
Daniel@0 16418 case ORDINAL: return STRING;
Daniel@0 16419 default: return NUMBER;
Daniel@0 16420 }
Daniel@0 16421 }
Daniel@0 16422
Daniel@0 16423 // Adapted from d3 log scale
Daniel@0 16424 // TODO customize? replace with range-size-aware filtering?
Daniel@0 16425 function logFilter(domain, count, f) {
Daniel@0 16426 if (count == null) return f;
Daniel@0 16427 var base = scale.base(),
Daniel@0 16428 k = Math.min(base, scale.ticks().length / count),
Daniel@0 16429 v = domain[0] > 0 ? (e = 1e-12, Math.ceil) : (e = -1e-12, Math.floor),
Daniel@0 16430 e;
Daniel@0 16431 function log(x) {
Daniel@0 16432 return (domain[0] < 0 ?
Daniel@0 16433 -Math.log(x > 0 ? 0 : -x) :
Daniel@0 16434 Math.log(x < 0 ? 0 : x)) / Math.log(base);
Daniel@0 16435 }
Daniel@0 16436 function pow(x) {
Daniel@0 16437 return domain[0] < 0 ? -Math.pow(base, -x) : Math.pow(base, x);
Daniel@0 16438 }
Daniel@0 16439 return function(d) {
Daniel@0 16440 return pow(v(log(d) + e)) / d >= k ? f(d) : '';
Daniel@0 16441 };
Daniel@0 16442 }
Daniel@0 16443
Daniel@0 16444 function getFormatter(formatType, str) {
Daniel@0 16445 var fmt = dl.format,
Daniel@0 16446 log = scale.type === 'log',
Daniel@0 16447 domain, f;
Daniel@0 16448
Daniel@0 16449 switch (formatType) {
Daniel@0 16450 case NUMBER:
Daniel@0 16451 domain = scale.domain();
Daniel@0 16452 f = fmt.auto.number(domain, tickCount, str || (log ? '.1r' : null));
Daniel@0 16453 return log ? logFilter(domain, tickCount, f) : f;
Daniel@0 16454 case TIME: return (str ? fmt : fmt.auto).time(str);
Daniel@0 16455 case UTC: return (str ? fmt : fmt.auto).utc(str);
Daniel@0 16456 default: return String;
Daniel@0 16457 }
Daniel@0 16458 }
Daniel@0 16459
Daniel@0 16460 function getTicks(format) {
Daniel@0 16461 var major = tickValues || (scale.ticks ? scale.ticks(tickCount) : scale.domain()),
Daniel@0 16462 minor = axisSubdivide(scale, major, tickSubdivide).map(ingest);
Daniel@0 16463 major = major.map(function(d) { return (d = ingest(d), d.label = format(d.data), d); });
Daniel@0 16464 return [major, minor];
Daniel@0 16465 }
Daniel@0 16466
Daniel@0 16467 axis.def = function() {
Daniel@0 16468 if (!axisDef.type) axis_def(scale);
Daniel@0 16469
Daniel@0 16470 var ticks = getTicks(getTickFormat());
Daniel@0 16471 var tdata = title ? [title].map(ingest) : [];
Daniel@0 16472
Daniel@0 16473 axisDef.marks[0].from = function() { return grid ? ticks[0] : []; };
Daniel@0 16474 axisDef.marks[1].from = function() { return ticks[0]; };
Daniel@0 16475 axisDef.marks[2].from = function() { return ticks[1]; };
Daniel@0 16476 axisDef.marks[3].from = axisDef.marks[1].from;
Daniel@0 16477 axisDef.marks[4].from = function() { return [1]; };
Daniel@0 16478 axisDef.marks[5].from = function() { return tdata; };
Daniel@0 16479 axisDef.offset = offset;
Daniel@0 16480 axisDef.orient = orient;
Daniel@0 16481 axisDef.layer = layer;
Daniel@0 16482
Daniel@0 16483 return axisDef;
Daniel@0 16484 };
Daniel@0 16485
Daniel@0 16486 function axis_def(scale) {
Daniel@0 16487 // setup scale mapping
Daniel@0 16488 var newScale, oldScale, range;
Daniel@0 16489 if (scale.type === ORDINAL) {
Daniel@0 16490 newScale = {scale: scale.scaleName, offset: 0.5 + scale.rangeBand()/2};
Daniel@0 16491 oldScale = newScale;
Daniel@0 16492 } else {
Daniel@0 16493 newScale = {scale: scale.scaleName, offset: 0.5};
Daniel@0 16494 oldScale = {scale: scale.scaleName+':prev', offset: 0.5};
Daniel@0 16495 }
Daniel@0 16496 range = axisScaleRange(scale);
Daniel@0 16497
Daniel@0 16498 // setup axis marks
Daniel@0 16499 dl.extend(m.gridLines, axisTicks(config));
Daniel@0 16500 dl.extend(m.majorTicks, axisTicks(config));
Daniel@0 16501 dl.extend(m.minorTicks, axisTicks(config));
Daniel@0 16502 dl.extend(m.tickLabels, axisTickLabels(config));
Daniel@0 16503 dl.extend(m.domain, axisDomain(config));
Daniel@0 16504 dl.extend(m.title, axisTitle(config));
Daniel@0 16505 m.gridLines.properties.enter.stroke = {value: config.axis.gridColor};
Daniel@0 16506 m.gridLines.properties.enter.strokeOpacity = {value: config.axis.gridOpacity};
Daniel@0 16507
Daniel@0 16508 // extend axis marks based on axis orientation
Daniel@0 16509 axisTicksExtend(orient, m.gridLines, oldScale, newScale, Infinity);
Daniel@0 16510 axisTicksExtend(orient, m.majorTicks, oldScale, newScale, tickMajorSize);
Daniel@0 16511 axisTicksExtend(orient, m.minorTicks, oldScale, newScale, tickMinorSize);
Daniel@0 16512 axisLabelExtend(orient, m.tickLabels, oldScale, newScale, tickMajorSize, tickPadding);
Daniel@0 16513
Daniel@0 16514 axisDomainExtend(orient, m.domain, range, tickEndSize);
Daniel@0 16515 axisTitleExtend(orient, m.title, range, titleOffset); // TODO get offset
Daniel@0 16516
Daniel@0 16517 // add / override custom style properties
Daniel@0 16518 dl.extend(m.gridLines.properties.update, gridLineStyle);
Daniel@0 16519 dl.extend(m.majorTicks.properties.update, majorTickStyle);
Daniel@0 16520 dl.extend(m.minorTicks.properties.update, minorTickStyle);
Daniel@0 16521 dl.extend(m.tickLabels.properties.update, tickLabelStyle);
Daniel@0 16522 dl.extend(m.domain.properties.update, domainStyle);
Daniel@0 16523 dl.extend(m.title.properties.update, titleStyle);
Daniel@0 16524
Daniel@0 16525 var marks = [m.gridLines, m.majorTicks, m.minorTicks, m.tickLabels, m.domain, m.title];
Daniel@0 16526 dl.extend(axisDef, {
Daniel@0 16527 type: 'group',
Daniel@0 16528 interactive: false,
Daniel@0 16529 properties: {
Daniel@0 16530 enter: {
Daniel@0 16531 encode: axisUpdate,
Daniel@0 16532 scales: [scale.scaleName],
Daniel@0 16533 signals: [], data: []
Daniel@0 16534 },
Daniel@0 16535 update: {
Daniel@0 16536 encode: axisUpdate,
Daniel@0 16537 scales: [scale.scaleName],
Daniel@0 16538 signals: [], data: []
Daniel@0 16539 }
Daniel@0 16540 }
Daniel@0 16541 });
Daniel@0 16542
Daniel@0 16543 axisDef.marks = marks.map(function(m) { return parseMark(model, m); });
Daniel@0 16544 }
Daniel@0 16545
Daniel@0 16546 axis.scale = function(x) {
Daniel@0 16547 if (!arguments.length) return scale;
Daniel@0 16548 if (scale !== x) { scale = x; reset(); }
Daniel@0 16549 return axis;
Daniel@0 16550 };
Daniel@0 16551
Daniel@0 16552 axis.orient = function(x) {
Daniel@0 16553 if (!arguments.length) return orient;
Daniel@0 16554 if (orient !== x) {
Daniel@0 16555 orient = x in axisOrients ? x + '' : config.axis.orient;
Daniel@0 16556 reset();
Daniel@0 16557 }
Daniel@0 16558 return axis;
Daniel@0 16559 };
Daniel@0 16560
Daniel@0 16561 axis.title = function(x) {
Daniel@0 16562 if (!arguments.length) return title;
Daniel@0 16563 if (title !== x) { title = x; reset(); }
Daniel@0 16564 return axis;
Daniel@0 16565 };
Daniel@0 16566
Daniel@0 16567 axis.tickCount = function(x) {
Daniel@0 16568 if (!arguments.length) return tickCount;
Daniel@0 16569 tickCount = x;
Daniel@0 16570 return axis;
Daniel@0 16571 };
Daniel@0 16572
Daniel@0 16573 axis.tickValues = function(x) {
Daniel@0 16574 if (!arguments.length) return tickValues;
Daniel@0 16575 tickValues = x;
Daniel@0 16576 return axis;
Daniel@0 16577 };
Daniel@0 16578
Daniel@0 16579 axis.tickFormat = function(x) {
Daniel@0 16580 if (!arguments.length) return tickFormatString;
Daniel@0 16581 if (tickFormatString !== x) {
Daniel@0 16582 tickFormatString = x;
Daniel@0 16583 reset();
Daniel@0 16584 }
Daniel@0 16585 return axis;
Daniel@0 16586 };
Daniel@0 16587
Daniel@0 16588 axis.tickFormatType = function(x) {
Daniel@0 16589 if (!arguments.length) return tickFormatType;
Daniel@0 16590 if (tickFormatType !== x) {
Daniel@0 16591 tickFormatType = x;
Daniel@0 16592 reset();
Daniel@0 16593 }
Daniel@0 16594 return axis;
Daniel@0 16595 };
Daniel@0 16596
Daniel@0 16597 axis.tickSize = function(x, y) {
Daniel@0 16598 if (!arguments.length) return tickMajorSize;
Daniel@0 16599 var n = arguments.length - 1,
Daniel@0 16600 major = +x,
Daniel@0 16601 minor = n > 1 ? +y : tickMajorSize,
Daniel@0 16602 end = n > 0 ? +arguments[n] : tickMajorSize;
Daniel@0 16603
Daniel@0 16604 if (tickMajorSize !== major ||
Daniel@0 16605 tickMinorSize !== minor ||
Daniel@0 16606 tickEndSize !== end) {
Daniel@0 16607 reset();
Daniel@0 16608 }
Daniel@0 16609
Daniel@0 16610 tickMajorSize = major;
Daniel@0 16611 tickMinorSize = minor;
Daniel@0 16612 tickEndSize = end;
Daniel@0 16613 return axis;
Daniel@0 16614 };
Daniel@0 16615
Daniel@0 16616 axis.tickSubdivide = function(x) {
Daniel@0 16617 if (!arguments.length) return tickSubdivide;
Daniel@0 16618 tickSubdivide = +x;
Daniel@0 16619 return axis;
Daniel@0 16620 };
Daniel@0 16621
Daniel@0 16622 axis.offset = function(x) {
Daniel@0 16623 if (!arguments.length) return offset;
Daniel@0 16624 offset = dl.isObject(x) ? x : +x;
Daniel@0 16625 return axis;
Daniel@0 16626 };
Daniel@0 16627
Daniel@0 16628 axis.tickPadding = function(x) {
Daniel@0 16629 if (!arguments.length) return tickPadding;
Daniel@0 16630 if (tickPadding !== +x) { tickPadding = +x; reset(); }
Daniel@0 16631 return axis;
Daniel@0 16632 };
Daniel@0 16633
Daniel@0 16634 axis.titleOffset = function(x) {
Daniel@0 16635 if (!arguments.length) return titleOffset;
Daniel@0 16636 if (titleOffset !== +x) { titleOffset = +x; reset(); }
Daniel@0 16637 return axis;
Daniel@0 16638 };
Daniel@0 16639
Daniel@0 16640 axis.layer = function(x) {
Daniel@0 16641 if (!arguments.length) return layer;
Daniel@0 16642 if (layer !== x) { layer = x; reset(); }
Daniel@0 16643 return axis;
Daniel@0 16644 };
Daniel@0 16645
Daniel@0 16646 axis.grid = function(x) {
Daniel@0 16647 if (!arguments.length) return grid;
Daniel@0 16648 if (grid !== x) { grid = x; reset(); }
Daniel@0 16649 return axis;
Daniel@0 16650 };
Daniel@0 16651
Daniel@0 16652 axis.gridLineProperties = function(x) {
Daniel@0 16653 if (!arguments.length) return gridLineStyle;
Daniel@0 16654 if (gridLineStyle !== x) { gridLineStyle = x; }
Daniel@0 16655 return axis;
Daniel@0 16656 };
Daniel@0 16657
Daniel@0 16658 axis.majorTickProperties = function(x) {
Daniel@0 16659 if (!arguments.length) return majorTickStyle;
Daniel@0 16660 if (majorTickStyle !== x) { majorTickStyle = x; }
Daniel@0 16661 return axis;
Daniel@0 16662 };
Daniel@0 16663
Daniel@0 16664 axis.minorTickProperties = function(x) {
Daniel@0 16665 if (!arguments.length) return minorTickStyle;
Daniel@0 16666 if (minorTickStyle !== x) { minorTickStyle = x; }
Daniel@0 16667 return axis;
Daniel@0 16668 };
Daniel@0 16669
Daniel@0 16670 axis.tickLabelProperties = function(x) {
Daniel@0 16671 if (!arguments.length) return tickLabelStyle;
Daniel@0 16672 if (tickLabelStyle !== x) { tickLabelStyle = x; }
Daniel@0 16673 return axis;
Daniel@0 16674 };
Daniel@0 16675
Daniel@0 16676 axis.titleProperties = function(x) {
Daniel@0 16677 if (!arguments.length) return titleStyle;
Daniel@0 16678 if (titleStyle !== x) { titleStyle = x; }
Daniel@0 16679 return axis;
Daniel@0 16680 };
Daniel@0 16681
Daniel@0 16682 axis.domainProperties = function(x) {
Daniel@0 16683 if (!arguments.length) return domainStyle;
Daniel@0 16684 if (domainStyle !== x) { domainStyle = x; }
Daniel@0 16685 return axis;
Daniel@0 16686 };
Daniel@0 16687
Daniel@0 16688 axis.reset = function() {
Daniel@0 16689 reset();
Daniel@0 16690 return axis;
Daniel@0 16691 };
Daniel@0 16692
Daniel@0 16693 return axis;
Daniel@0 16694 }
Daniel@0 16695
Daniel@0 16696 var axisOrients = {top: 1, right: 1, bottom: 1, left: 1};
Daniel@0 16697
Daniel@0 16698 function axisSubdivide(scale, ticks, m) {
Daniel@0 16699 var subticks = [];
Daniel@0 16700 if (m && ticks.length > 1) {
Daniel@0 16701 var extent = axisScaleExtent(scale.domain()),
Daniel@0 16702 i = -1,
Daniel@0 16703 n = ticks.length,
Daniel@0 16704 d = (ticks[1] - ticks[0]) / ++m,
Daniel@0 16705 j,
Daniel@0 16706 v;
Daniel@0 16707 while (++i < n) {
Daniel@0 16708 for (j = m; --j > 0;) {
Daniel@0 16709 if ((v = +ticks[i] - j * d) >= extent[0]) {
Daniel@0 16710 subticks.push(v);
Daniel@0 16711 }
Daniel@0 16712 }
Daniel@0 16713 }
Daniel@0 16714 for (--i, j = 0; ++j < m && (v = +ticks[i] + j * d) < extent[1];) {
Daniel@0 16715 subticks.push(v);
Daniel@0 16716 }
Daniel@0 16717 }
Daniel@0 16718 return subticks;
Daniel@0 16719 }
Daniel@0 16720
Daniel@0 16721 function axisScaleExtent(domain) {
Daniel@0 16722 var start = domain[0], stop = domain[domain.length - 1];
Daniel@0 16723 return start < stop ? [start, stop] : [stop, start];
Daniel@0 16724 }
Daniel@0 16725
Daniel@0 16726 function axisScaleRange(scale) {
Daniel@0 16727 return scale.rangeExtent ?
Daniel@0 16728 scale.rangeExtent() :
Daniel@0 16729 axisScaleExtent(scale.range());
Daniel@0 16730 }
Daniel@0 16731
Daniel@0 16732 var axisAlign = {
Daniel@0 16733 bottom: 'center',
Daniel@0 16734 top: 'center',
Daniel@0 16735 left: 'right',
Daniel@0 16736 right: 'left'
Daniel@0 16737 };
Daniel@0 16738
Daniel@0 16739 var axisBaseline = {
Daniel@0 16740 bottom: 'top',
Daniel@0 16741 top: 'bottom',
Daniel@0 16742 left: 'middle',
Daniel@0 16743 right: 'middle'
Daniel@0 16744 };
Daniel@0 16745
Daniel@0 16746 function axisLabelExtend(orient, labels, oldScale, newScale, size, pad) {
Daniel@0 16747 size = Math.max(size, 0) + pad;
Daniel@0 16748 if (orient === 'left' || orient === 'top') {
Daniel@0 16749 size *= -1;
Daniel@0 16750 }
Daniel@0 16751 if (orient === 'top' || orient === 'bottom') {
Daniel@0 16752 dl.extend(labels.properties.enter, {
Daniel@0 16753 x: oldScale,
Daniel@0 16754 y: {value: size},
Daniel@0 16755 });
Daniel@0 16756 dl.extend(labels.properties.update, {
Daniel@0 16757 x: newScale,
Daniel@0 16758 y: {value: size},
Daniel@0 16759 align: {value: 'center'},
Daniel@0 16760 baseline: {value: axisBaseline[orient]}
Daniel@0 16761 });
Daniel@0 16762 } else {
Daniel@0 16763 dl.extend(labels.properties.enter, {
Daniel@0 16764 x: {value: size},
Daniel@0 16765 y: oldScale,
Daniel@0 16766 });
Daniel@0 16767 dl.extend(labels.properties.update, {
Daniel@0 16768 x: {value: size},
Daniel@0 16769 y: newScale,
Daniel@0 16770 align: {value: axisAlign[orient]},
Daniel@0 16771 baseline: {value: 'middle'}
Daniel@0 16772 });
Daniel@0 16773 }
Daniel@0 16774 }
Daniel@0 16775
Daniel@0 16776 function axisTicksExtend(orient, ticks, oldScale, newScale, size) {
Daniel@0 16777 var sign = (orient === 'left' || orient === 'top') ? -1 : 1;
Daniel@0 16778 if (size === Infinity) {
Daniel@0 16779 size = (orient === 'top' || orient === 'bottom') ?
Daniel@0 16780 {field: {group: 'height', level: 2}, mult: -sign} :
Daniel@0 16781 {field: {group: 'width', level: 2}, mult: -sign};
Daniel@0 16782 } else {
Daniel@0 16783 size = {value: sign * size};
Daniel@0 16784 }
Daniel@0 16785 if (orient === 'top' || orient === 'bottom') {
Daniel@0 16786 dl.extend(ticks.properties.enter, {
Daniel@0 16787 x: oldScale,
Daniel@0 16788 y: {value: 0},
Daniel@0 16789 y2: size
Daniel@0 16790 });
Daniel@0 16791 dl.extend(ticks.properties.update, {
Daniel@0 16792 x: newScale,
Daniel@0 16793 y: {value: 0},
Daniel@0 16794 y2: size
Daniel@0 16795 });
Daniel@0 16796 dl.extend(ticks.properties.exit, {
Daniel@0 16797 x: newScale,
Daniel@0 16798 });
Daniel@0 16799 } else {
Daniel@0 16800 dl.extend(ticks.properties.enter, {
Daniel@0 16801 x: {value: 0},
Daniel@0 16802 x2: size,
Daniel@0 16803 y: oldScale
Daniel@0 16804 });
Daniel@0 16805 dl.extend(ticks.properties.update, {
Daniel@0 16806 x: {value: 0},
Daniel@0 16807 x2: size,
Daniel@0 16808 y: newScale
Daniel@0 16809 });
Daniel@0 16810 dl.extend(ticks.properties.exit, {
Daniel@0 16811 y: newScale,
Daniel@0 16812 });
Daniel@0 16813 }
Daniel@0 16814 }
Daniel@0 16815
Daniel@0 16816 function axisTitleExtend(orient, title, range, offset) {
Daniel@0 16817 var mid = ~~((range[0] + range[1]) / 2),
Daniel@0 16818 sign = (orient === 'top' || orient === 'left') ? -1 : 1;
Daniel@0 16819
Daniel@0 16820 if (orient === 'bottom' || orient === 'top') {
Daniel@0 16821 dl.extend(title.properties.update, {
Daniel@0 16822 x: {value: mid},
Daniel@0 16823 y: {value: sign*offset},
Daniel@0 16824 angle: {value: 0}
Daniel@0 16825 });
Daniel@0 16826 } else {
Daniel@0 16827 dl.extend(title.properties.update, {
Daniel@0 16828 x: {value: sign*offset},
Daniel@0 16829 y: {value: mid},
Daniel@0 16830 angle: {value: orient === 'left' ? -90 : 90}
Daniel@0 16831 });
Daniel@0 16832 }
Daniel@0 16833 }
Daniel@0 16834
Daniel@0 16835 function axisDomainExtend(orient, domain, range, size) {
Daniel@0 16836 var path;
Daniel@0 16837 if (orient === 'top' || orient === 'left') {
Daniel@0 16838 size = -1 * size;
Daniel@0 16839 }
Daniel@0 16840 if (orient === 'bottom' || orient === 'top') {
Daniel@0 16841 path = 'M' + range[0] + ',' + size + 'V0H' + range[1] + 'V' + size;
Daniel@0 16842 } else {
Daniel@0 16843 path = 'M' + size + ',' + range[0] + 'H0V' + range[1] + 'H' + size;
Daniel@0 16844 }
Daniel@0 16845 domain.properties.update.path = {value: path};
Daniel@0 16846 }
Daniel@0 16847
Daniel@0 16848 function axisUpdate(item, group, trans) {
Daniel@0 16849 var o = trans ? {} : item,
Daniel@0 16850 offset = item.mark.def.offset,
Daniel@0 16851 orient = item.mark.def.orient,
Daniel@0 16852 width = group.width,
Daniel@0 16853 height = group.height; // TODO fallback to global w,h?
Daniel@0 16854
Daniel@0 16855 if (dl.isArray(offset)) {
Daniel@0 16856 var ofx = offset[0],
Daniel@0 16857 ofy = offset[1];
Daniel@0 16858
Daniel@0 16859 switch (orient) {
Daniel@0 16860 case 'left': { Tuple.set(o, 'x', -ofx); Tuple.set(o, 'y', ofy); break; }
Daniel@0 16861 case 'right': { Tuple.set(o, 'x', width + ofx); Tuple.set(o, 'y', ofy); break; }
Daniel@0 16862 case 'bottom': { Tuple.set(o, 'x', ofx); Tuple.set(o, 'y', height + ofy); break; }
Daniel@0 16863 case 'top': { Tuple.set(o, 'x', ofx); Tuple.set(o, 'y', -ofy); break; }
Daniel@0 16864 default: { Tuple.set(o, 'x', ofx); Tuple.set(o, 'y', ofy); }
Daniel@0 16865 }
Daniel@0 16866 } else {
Daniel@0 16867 if (dl.isObject(offset)) {
Daniel@0 16868 offset = -group.scale(offset.scale)(offset.value);
Daniel@0 16869 }
Daniel@0 16870
Daniel@0 16871 switch (orient) {
Daniel@0 16872 case 'left': { Tuple.set(o, 'x', -offset); Tuple.set(o, 'y', 0); break; }
Daniel@0 16873 case 'right': { Tuple.set(o, 'x', width + offset); Tuple.set(o, 'y', 0); break; }
Daniel@0 16874 case 'bottom': { Tuple.set(o, 'x', 0); Tuple.set(o, 'y', height + offset); break; }
Daniel@0 16875 case 'top': { Tuple.set(o, 'x', 0); Tuple.set(o, 'y', -offset); break; }
Daniel@0 16876 default: { Tuple.set(o, 'x', 0); Tuple.set(o, 'y', 0); }
Daniel@0 16877 }
Daniel@0 16878 }
Daniel@0 16879
Daniel@0 16880 if (trans) trans.interpolate(item, o);
Daniel@0 16881 return true;
Daniel@0 16882 }
Daniel@0 16883
Daniel@0 16884 function axisTicks(config) {
Daniel@0 16885 return {
Daniel@0 16886 type: 'rule',
Daniel@0 16887 interactive: false,
Daniel@0 16888 key: 'data',
Daniel@0 16889 properties: {
Daniel@0 16890 enter: {
Daniel@0 16891 stroke: {value: config.axis.tickColor},
Daniel@0 16892 strokeWidth: {value: config.axis.tickWidth},
Daniel@0 16893 opacity: {value: 1e-6}
Daniel@0 16894 },
Daniel@0 16895 exit: { opacity: {value: 1e-6} },
Daniel@0 16896 update: { opacity: {value: 1} }
Daniel@0 16897 }
Daniel@0 16898 };
Daniel@0 16899 }
Daniel@0 16900
Daniel@0 16901 function axisTickLabels(config) {
Daniel@0 16902 return {
Daniel@0 16903 type: 'text',
Daniel@0 16904 interactive: true,
Daniel@0 16905 key: 'data',
Daniel@0 16906 properties: {
Daniel@0 16907 enter: {
Daniel@0 16908 fill: {value: config.axis.tickLabelColor},
Daniel@0 16909 font: {value: config.axis.tickLabelFont},
Daniel@0 16910 fontSize: {value: config.axis.tickLabelFontSize},
Daniel@0 16911 opacity: {value: 1e-6},
Daniel@0 16912 text: {field: 'label'}
Daniel@0 16913 },
Daniel@0 16914 exit: { opacity: {value: 1e-6} },
Daniel@0 16915 update: { opacity: {value: 1} }
Daniel@0 16916 }
Daniel@0 16917 };
Daniel@0 16918 }
Daniel@0 16919
Daniel@0 16920 function axisTitle(config) {
Daniel@0 16921 return {
Daniel@0 16922 type: 'text',
Daniel@0 16923 interactive: true,
Daniel@0 16924 properties: {
Daniel@0 16925 enter: {
Daniel@0 16926 font: {value: config.axis.titleFont},
Daniel@0 16927 fontSize: {value: config.axis.titleFontSize},
Daniel@0 16928 fontWeight: {value: config.axis.titleFontWeight},
Daniel@0 16929 fill: {value: config.axis.titleColor},
Daniel@0 16930 align: {value: 'center'},
Daniel@0 16931 baseline: {value: 'middle'},
Daniel@0 16932 text: {field: 'data'}
Daniel@0 16933 },
Daniel@0 16934 update: {}
Daniel@0 16935 }
Daniel@0 16936 };
Daniel@0 16937 }
Daniel@0 16938
Daniel@0 16939 function axisDomain(config) {
Daniel@0 16940 return {
Daniel@0 16941 type: 'path',
Daniel@0 16942 interactive: false,
Daniel@0 16943 properties: {
Daniel@0 16944 enter: {
Daniel@0 16945 x: {value: 0.5},
Daniel@0 16946 y: {value: 0.5},
Daniel@0 16947 stroke: {value: config.axis.axisColor},
Daniel@0 16948 strokeWidth: {value: config.axis.axisWidth}
Daniel@0 16949 },
Daniel@0 16950 update: {}
Daniel@0 16951 }
Daniel@0 16952 };
Daniel@0 16953 }
Daniel@0 16954
Daniel@0 16955 module.exports = axs;
Daniel@0 16956 },{"../parse/mark":97,"datalib":24,"vega-dataflow":39}],114:[function(require,module,exports){
Daniel@0 16957 (function (global){
Daniel@0 16958 var d3 = (typeof window !== "undefined" ? window['d3'] : typeof global !== "undefined" ? global['d3'] : null),
Daniel@0 16959 dl = require('datalib'),
Daniel@0 16960 Gradient = require('vega-scenegraph').Gradient,
Daniel@0 16961 parseProperties = require('../parse/properties'),
Daniel@0 16962 parseMark = require('../parse/mark');
Daniel@0 16963
Daniel@0 16964 function lgnd(model) {
Daniel@0 16965 var size = null,
Daniel@0 16966 shape = null,
Daniel@0 16967 fill = null,
Daniel@0 16968 stroke = null,
Daniel@0 16969 spacing = null,
Daniel@0 16970 values = null,
Daniel@0 16971 format = null,
Daniel@0 16972 formatString = null,
Daniel@0 16973 config = model.config(),
Daniel@0 16974 title,
Daniel@0 16975 orient = 'right',
Daniel@0 16976 offset = config.legend.offset,
Daniel@0 16977 padding = config.legend.padding,
Daniel@0 16978 tickArguments = [5],
Daniel@0 16979 legendStyle = {},
Daniel@0 16980 symbolStyle = {},
Daniel@0 16981 gradientStyle = {},
Daniel@0 16982 titleStyle = {},
Daniel@0 16983 labelStyle = {},
Daniel@0 16984 m = { // Legend marks as references for updates
Daniel@0 16985 titles: {},
Daniel@0 16986 symbols: {},
Daniel@0 16987 labels: {},
Daniel@0 16988 gradient: {}
Daniel@0 16989 };
Daniel@0 16990
Daniel@0 16991 var legend = {},
Daniel@0 16992 legendDef = {};
Daniel@0 16993
Daniel@0 16994 function reset() { legendDef.type = null; }
Daniel@0 16995 function ingest(d, i) { return {data: d, index: i}; }
Daniel@0 16996
Daniel@0 16997 legend.def = function() {
Daniel@0 16998 var scale = size || shape || fill || stroke;
Daniel@0 16999
Daniel@0 17000 format = !formatString ? null : ((scale.type === 'time') ?
Daniel@0 17001 dl.format.time(formatString) : dl.format.number(formatString));
Daniel@0 17002
Daniel@0 17003 if (!legendDef.type) {
Daniel@0 17004 legendDef = (scale===fill || scale===stroke) && !discrete(scale.type) ?
Daniel@0 17005 quantDef(scale) : ordinalDef(scale);
Daniel@0 17006 }
Daniel@0 17007 legendDef.orient = orient;
Daniel@0 17008 legendDef.offset = offset;
Daniel@0 17009 legendDef.padding = padding;
Daniel@0 17010 return legendDef;
Daniel@0 17011 };
Daniel@0 17012
Daniel@0 17013 function discrete(type) {
Daniel@0 17014 return type==='ordinal' || type==='quantize' ||
Daniel@0 17015 type==='quantile' || type==='threshold';
Daniel@0 17016 }
Daniel@0 17017
Daniel@0 17018 function ordinalDef(scale) {
Daniel@0 17019 var def = o_legend_def(size, shape, fill, stroke);
Daniel@0 17020
Daniel@0 17021 // generate data
Daniel@0 17022 var data = (values == null ?
Daniel@0 17023 (scale.ticks ? scale.ticks.apply(scale, tickArguments) : scale.domain()) :
Daniel@0 17024 values).map(ingest);
Daniel@0 17025 var fmt = format==null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : String) : format;
Daniel@0 17026
Daniel@0 17027 // determine spacing between legend entries
Daniel@0 17028 var fs, range, offset, pad=5, domain = d3.range(data.length);
Daniel@0 17029 if (size) {
Daniel@0 17030 range = data.map(function(x) { return Math.sqrt(size(x.data)); });
Daniel@0 17031 offset = d3.max(range);
Daniel@0 17032 range = range.reduce(function(a,b,i,z) {
Daniel@0 17033 if (i > 0) a[i] = a[i-1] + z[i-1]/2 + pad;
Daniel@0 17034 return (a[i] += b/2, a); }, [0]).map(Math.round);
Daniel@0 17035 } else {
Daniel@0 17036 offset = Math.round(Math.sqrt(config.legend.symbolSize));
Daniel@0 17037 range = spacing ||
Daniel@0 17038 (fs = labelStyle.fontSize) && (fs.value + pad) ||
Daniel@0 17039 (config.legend.labelFontSize + pad);
Daniel@0 17040 range = domain.map(function(d,i) {
Daniel@0 17041 return Math.round(offset/2 + i*range);
Daniel@0 17042 });
Daniel@0 17043 }
Daniel@0 17044
Daniel@0 17045 // account for padding and title size
Daniel@0 17046 var sz = padding, ts;
Daniel@0 17047 if (title) {
Daniel@0 17048 ts = titleStyle.fontSize;
Daniel@0 17049 sz += 5 + ((ts && ts.value) || config.legend.titleFontSize);
Daniel@0 17050 }
Daniel@0 17051 for (var i=0, n=range.length; i<n; ++i) range[i] += sz;
Daniel@0 17052
Daniel@0 17053 // build scale for label layout
Daniel@0 17054 var scaleSpec = {
Daniel@0 17055 name: 'legend',
Daniel@0 17056 type: 'ordinal',
Daniel@0 17057 points: true,
Daniel@0 17058 domain: domain,
Daniel@0 17059 range: range
Daniel@0 17060 };
Daniel@0 17061
Daniel@0 17062 // update legend def
Daniel@0 17063 var tdata = (title ? [title] : []).map(ingest);
Daniel@0 17064 data.forEach(function(d) {
Daniel@0 17065 d.label = fmt(d.data);
Daniel@0 17066 d.offset = offset;
Daniel@0 17067 });
Daniel@0 17068 def.scales = [ scaleSpec ];
Daniel@0 17069 def.marks[0].from = function() { return tdata; };
Daniel@0 17070 def.marks[1].from = function() { return data; };
Daniel@0 17071 def.marks[2].from = def.marks[1].from;
Daniel@0 17072
Daniel@0 17073 return def;
Daniel@0 17074 }
Daniel@0 17075
Daniel@0 17076 function o_legend_def(size, shape, fill, stroke) {
Daniel@0 17077 // setup legend marks
Daniel@0 17078 var titles = dl.extend(m.titles, vg_legendTitle(config)),
Daniel@0 17079 symbols = dl.extend(m.symbols, vg_legendSymbols(config)),
Daniel@0 17080 labels = dl.extend(m.labels, vg_vLegendLabels(config));
Daniel@0 17081
Daniel@0 17082 // extend legend marks
Daniel@0 17083 vg_legendSymbolExtend(symbols, size, shape, fill, stroke);
Daniel@0 17084
Daniel@0 17085 // add / override custom style properties
Daniel@0 17086 dl.extend(titles.properties.update, titleStyle);
Daniel@0 17087 dl.extend(symbols.properties.update, symbolStyle);
Daniel@0 17088 dl.extend(labels.properties.update, labelStyle);
Daniel@0 17089
Daniel@0 17090 // padding from legend border
Daniel@0 17091 titles.properties.enter.x.value += padding;
Daniel@0 17092 titles.properties.enter.y.value += padding;
Daniel@0 17093 labels.properties.enter.x.offset += padding + 1;
Daniel@0 17094 symbols.properties.enter.x.offset = padding + 1;
Daniel@0 17095 labels.properties.update.x.offset += padding + 1;
Daniel@0 17096 symbols.properties.update.x.offset = padding + 1;
Daniel@0 17097
Daniel@0 17098 dl.extend(legendDef, {
Daniel@0 17099 type: 'group',
Daniel@0 17100 interactive: false,
Daniel@0 17101 properties: {
Daniel@0 17102 enter: parseProperties(model, 'group', legendStyle),
Daniel@0 17103 vg_legendPosition: {
Daniel@0 17104 encode: vg_legendPosition,
Daniel@0 17105 signals: [], scales:[], data: [], fields: []
Daniel@0 17106 }
Daniel@0 17107 }
Daniel@0 17108 });
Daniel@0 17109
Daniel@0 17110 legendDef.marks = [titles, symbols, labels].map(function(m) { return parseMark(model, m); });
Daniel@0 17111 return legendDef;
Daniel@0 17112 }
Daniel@0 17113
Daniel@0 17114 function quantDef(scale) {
Daniel@0 17115 var def = q_legend_def(scale),
Daniel@0 17116 dom = scale.domain(),
Daniel@0 17117 data = (values == null ?
Daniel@0 17118 (scale.ticks ? scale.ticks.apply(scale, tickArguments) : scale.domain()) :
Daniel@0 17119 values).map(ingest),
Daniel@0 17120 width = (gradientStyle.width && gradientStyle.width.value) || config.legend.gradientWidth,
Daniel@0 17121 fmt = format==null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : String) : format;
Daniel@0 17122
Daniel@0 17123 // build scale for label layout
Daniel@0 17124 var layoutSpec = {
Daniel@0 17125 name: 'legend',
Daniel@0 17126 type: scale.type,
Daniel@0 17127 round: true,
Daniel@0 17128 zero: false,
Daniel@0 17129 domain: [dom[0], dom[dom.length-1]],
Daniel@0 17130 range: [padding, width+padding]
Daniel@0 17131 };
Daniel@0 17132 if (scale.type==='pow') layoutSpec.exponent = scale.exponent();
Daniel@0 17133
Daniel@0 17134 // update legend def
Daniel@0 17135 var tdata = (title ? [title] : []).map(ingest);
Daniel@0 17136 data.forEach(function(d,i) {
Daniel@0 17137 d.label = fmt(d.data);
Daniel@0 17138 d.align = i==(data.length-1) ? 'right' : i===0 ? 'left' : 'center';
Daniel@0 17139 });
Daniel@0 17140 def.scales = [ layoutSpec ];
Daniel@0 17141 def.marks[0].from = function() { return tdata; };
Daniel@0 17142 def.marks[1].from = function() { return [1]; };
Daniel@0 17143 def.marks[2].from = function() { return data; };
Daniel@0 17144 return def;
Daniel@0 17145 }
Daniel@0 17146
Daniel@0 17147 function q_legend_def(scale) {
Daniel@0 17148 // setup legend marks
Daniel@0 17149 var titles = dl.extend(m.titles, vg_legendTitle(config)),
Daniel@0 17150 gradient = dl.extend(m.gradient, vg_legendGradient(config)),
Daniel@0 17151 labels = dl.extend(m.labels, vg_hLegendLabels(config)),
Daniel@0 17152 grad = new Gradient();
Daniel@0 17153
Daniel@0 17154 // setup color gradient
Daniel@0 17155 var dom = scale.domain(),
Daniel@0 17156 min = dom[0],
Daniel@0 17157 max = dom[dom.length-1],
Daniel@0 17158 f = scale.copy().domain([min, max]).range([0,1]);
Daniel@0 17159
Daniel@0 17160 var stops = (scale.type !== 'linear' && scale.ticks) ?
Daniel@0 17161 scale.ticks.call(scale, 15) : dom;
Daniel@0 17162 if (min !== stops[0]) stops.unshift(min);
Daniel@0 17163 if (max !== stops[stops.length-1]) stops.push(max);
Daniel@0 17164
Daniel@0 17165 for (var i=0, n=stops.length; i<n; ++i) {
Daniel@0 17166 grad.stop(f(stops[i]), scale(stops[i]));
Daniel@0 17167 }
Daniel@0 17168 gradient.properties.enter.fill = {value: grad};
Daniel@0 17169
Daniel@0 17170 // add / override custom style properties
Daniel@0 17171 dl.extend(titles.properties.update, titleStyle);
Daniel@0 17172 dl.extend(gradient.properties.update, gradientStyle);
Daniel@0 17173 dl.extend(labels.properties.update, labelStyle);
Daniel@0 17174
Daniel@0 17175 // account for gradient size
Daniel@0 17176 var gp = gradient.properties, gh = gradientStyle.height,
Daniel@0 17177 hh = (gh && gh.value) || gp.enter.height.value;
Daniel@0 17178 labels.properties.enter.y.value = hh;
Daniel@0 17179 labels.properties.update.y.value = hh;
Daniel@0 17180
Daniel@0 17181 // account for title size as needed
Daniel@0 17182 if (title) {
Daniel@0 17183 var tp = titles.properties, fs = titleStyle.fontSize,
Daniel@0 17184 sz = 4 + ((fs && fs.value) || tp.enter.fontSize.value);
Daniel@0 17185 gradient.properties.enter.y.value += sz;
Daniel@0 17186 labels.properties.enter.y.value += sz;
Daniel@0 17187 gradient.properties.update.y.value += sz;
Daniel@0 17188 labels.properties.update.y.value += sz;
Daniel@0 17189 }
Daniel@0 17190
Daniel@0 17191 // padding from legend border
Daniel@0 17192 titles.properties.enter.x.value += padding;
Daniel@0 17193 titles.properties.enter.y.value += padding;
Daniel@0 17194 gradient.properties.enter.x.value += padding;
Daniel@0 17195 gradient.properties.enter.y.value += padding;
Daniel@0 17196 labels.properties.enter.y.value += padding;
Daniel@0 17197 gradient.properties.update.x.value += padding;
Daniel@0 17198 gradient.properties.update.y.value += padding;
Daniel@0 17199 labels.properties.update.y.value += padding;
Daniel@0 17200
Daniel@0 17201 dl.extend(legendDef, {
Daniel@0 17202 type: 'group',
Daniel@0 17203 interactive: false,
Daniel@0 17204 properties: {
Daniel@0 17205 enter: parseProperties(model, 'group', legendStyle),
Daniel@0 17206 vg_legendPosition: {
Daniel@0 17207 encode: vg_legendPosition,
Daniel@0 17208 signals: [], scales: [], data: [], fields: []
Daniel@0 17209 }
Daniel@0 17210 }
Daniel@0 17211 });
Daniel@0 17212
Daniel@0 17213 legendDef.marks = [titles, gradient, labels].map(function(m) { return parseMark(model, m); });
Daniel@0 17214 return legendDef;
Daniel@0 17215 }
Daniel@0 17216
Daniel@0 17217 legend.size = function(x) {
Daniel@0 17218 if (!arguments.length) return size;
Daniel@0 17219 if (size !== x) { size = x; reset(); }
Daniel@0 17220 return legend;
Daniel@0 17221 };
Daniel@0 17222
Daniel@0 17223 legend.shape = function(x) {
Daniel@0 17224 if (!arguments.length) return shape;
Daniel@0 17225 if (shape !== x) { shape = x; reset(); }
Daniel@0 17226 return legend;
Daniel@0 17227 };
Daniel@0 17228
Daniel@0 17229 legend.fill = function(x) {
Daniel@0 17230 if (!arguments.length) return fill;
Daniel@0 17231 if (fill !== x) { fill = x; reset(); }
Daniel@0 17232 return legend;
Daniel@0 17233 };
Daniel@0 17234
Daniel@0 17235 legend.stroke = function(x) {
Daniel@0 17236 if (!arguments.length) return stroke;
Daniel@0 17237 if (stroke !== x) { stroke = x; reset(); }
Daniel@0 17238 return legend;
Daniel@0 17239 };
Daniel@0 17240
Daniel@0 17241 legend.title = function(x) {
Daniel@0 17242 if (!arguments.length) return title;
Daniel@0 17243 if (title !== x) { title = x; reset(); }
Daniel@0 17244 return legend;
Daniel@0 17245 };
Daniel@0 17246
Daniel@0 17247 legend.format = function(x) {
Daniel@0 17248 if (!arguments.length) return formatString;
Daniel@0 17249 if (formatString !== x) {
Daniel@0 17250 formatString = x;
Daniel@0 17251 reset();
Daniel@0 17252 }
Daniel@0 17253 return legend;
Daniel@0 17254 };
Daniel@0 17255
Daniel@0 17256 legend.spacing = function(x) {
Daniel@0 17257 if (!arguments.length) return spacing;
Daniel@0 17258 if (spacing !== +x) { spacing = +x; reset(); }
Daniel@0 17259 return legend;
Daniel@0 17260 };
Daniel@0 17261
Daniel@0 17262 legend.orient = function(x) {
Daniel@0 17263 if (!arguments.length) return orient;
Daniel@0 17264 orient = x in vg_legendOrients ? x + '' : config.legend.orient;
Daniel@0 17265 return legend;
Daniel@0 17266 };
Daniel@0 17267
Daniel@0 17268 legend.offset = function(x) {
Daniel@0 17269 if (!arguments.length) return offset;
Daniel@0 17270 offset = +x;
Daniel@0 17271 return legend;
Daniel@0 17272 };
Daniel@0 17273
Daniel@0 17274 legend.values = function(x) {
Daniel@0 17275 if (!arguments.length) return values;
Daniel@0 17276 values = x;
Daniel@0 17277 return legend;
Daniel@0 17278 };
Daniel@0 17279
Daniel@0 17280 legend.legendProperties = function(x) {
Daniel@0 17281 if (!arguments.length) return legendStyle;
Daniel@0 17282 legendStyle = x;
Daniel@0 17283 return legend;
Daniel@0 17284 };
Daniel@0 17285
Daniel@0 17286 legend.symbolProperties = function(x) {
Daniel@0 17287 if (!arguments.length) return symbolStyle;
Daniel@0 17288 symbolStyle = x;
Daniel@0 17289 return legend;
Daniel@0 17290 };
Daniel@0 17291
Daniel@0 17292 legend.gradientProperties = function(x) {
Daniel@0 17293 if (!arguments.length) return gradientStyle;
Daniel@0 17294 gradientStyle = x;
Daniel@0 17295 return legend;
Daniel@0 17296 };
Daniel@0 17297
Daniel@0 17298 legend.labelProperties = function(x) {
Daniel@0 17299 if (!arguments.length) return labelStyle;
Daniel@0 17300 labelStyle = x;
Daniel@0 17301 return legend;
Daniel@0 17302 };
Daniel@0 17303
Daniel@0 17304 legend.titleProperties = function(x) {
Daniel@0 17305 if (!arguments.length) return titleStyle;
Daniel@0 17306 titleStyle = x;
Daniel@0 17307 return legend;
Daniel@0 17308 };
Daniel@0 17309
Daniel@0 17310 legend.reset = function() {
Daniel@0 17311 reset();
Daniel@0 17312 return legend;
Daniel@0 17313 };
Daniel@0 17314
Daniel@0 17315 return legend;
Daniel@0 17316 }
Daniel@0 17317
Daniel@0 17318 var vg_legendOrients = {right: 1, left: 1};
Daniel@0 17319
Daniel@0 17320 function vg_legendPosition(item, group, trans, db, signals, predicates) {
Daniel@0 17321 var o = trans ? {} : item, gx,
Daniel@0 17322 offset = item.mark.def.offset,
Daniel@0 17323 orient = item.mark.def.orient,
Daniel@0 17324 pad = item.mark.def.padding * 2,
Daniel@0 17325 lw = ~~item.bounds.width() + (item.width ? 0 : pad),
Daniel@0 17326 lh = ~~item.bounds.height() + (item.height ? 0 : pad),
Daniel@0 17327 pos = group._legendPositions ||
Daniel@0 17328 (group._legendPositions = {right: 0.5, left: 0.5});
Daniel@0 17329
Daniel@0 17330 o.x = 0.5;
Daniel@0 17331 o.width = lw;
Daniel@0 17332 o.y = pos[orient];
Daniel@0 17333 pos[orient] += (o.height = lh);
Daniel@0 17334
Daniel@0 17335 // HACK: use to estimate group bounds during animated transition
Daniel@0 17336 if (!trans && group.bounds) {
Daniel@0 17337 group.bounds.delta = group.bounds.x2 - group.width;
Daniel@0 17338 }
Daniel@0 17339
Daniel@0 17340 switch (orient) {
Daniel@0 17341 case 'left': {
Daniel@0 17342 gx = group.bounds ? group.bounds.x1 : 0;
Daniel@0 17343 o.x += gx - offset - lw;
Daniel@0 17344 break;
Daniel@0 17345 }
Daniel@0 17346 case 'right': {
Daniel@0 17347 gx = group.width + (group.bounds && trans ? group.bounds.delta : 0);
Daniel@0 17348 o.x += gx + offset;
Daniel@0 17349 break;
Daniel@0 17350 }
Daniel@0 17351 }
Daniel@0 17352
Daniel@0 17353 if (trans) trans.interpolate(item, o);
Daniel@0 17354 var enc = item.mark.def.properties.enter.encode;
Daniel@0 17355 enc.call(enc, item, group, trans, db, signals, predicates);
Daniel@0 17356 return true;
Daniel@0 17357 }
Daniel@0 17358
Daniel@0 17359 function vg_legendSymbolExtend(mark, size, shape, fill, stroke) {
Daniel@0 17360 var e = mark.properties.enter,
Daniel@0 17361 u = mark.properties.update;
Daniel@0 17362 if (size) e.size = u.size = {scale: size.scaleName, field: 'data'};
Daniel@0 17363 if (shape) e.shape = u.shape = {scale: shape.scaleName, field: 'data'};
Daniel@0 17364 if (fill) e.fill = u.fill = {scale: fill.scaleName, field: 'data'};
Daniel@0 17365 if (stroke) e.stroke = u.stroke = {scale: stroke.scaleName, field: 'data'};
Daniel@0 17366 }
Daniel@0 17367
Daniel@0 17368 function vg_legendTitle(config) {
Daniel@0 17369 var cfg = config.legend;
Daniel@0 17370 return {
Daniel@0 17371 type: 'text',
Daniel@0 17372 interactive: false,
Daniel@0 17373 key: 'data',
Daniel@0 17374 properties: {
Daniel@0 17375 enter: {
Daniel@0 17376 x: {value: 0},
Daniel@0 17377 y: {value: 0},
Daniel@0 17378 fill: {value: cfg.titleColor},
Daniel@0 17379 font: {value: cfg.titleFont},
Daniel@0 17380 fontSize: {value: cfg.titleFontSize},
Daniel@0 17381 fontWeight: {value: cfg.titleFontWeight},
Daniel@0 17382 baseline: {value: 'top'},
Daniel@0 17383 text: {field: 'data'},
Daniel@0 17384 opacity: {value: 1e-6}
Daniel@0 17385 },
Daniel@0 17386 exit: { opacity: {value: 1e-6} },
Daniel@0 17387 update: { opacity: {value: 1} }
Daniel@0 17388 }
Daniel@0 17389 };
Daniel@0 17390 }
Daniel@0 17391
Daniel@0 17392 function vg_legendSymbols(config) {
Daniel@0 17393 var cfg = config.legend;
Daniel@0 17394 return {
Daniel@0 17395 type: 'symbol',
Daniel@0 17396 interactive: false,
Daniel@0 17397 key: 'data',
Daniel@0 17398 properties: {
Daniel@0 17399 enter: {
Daniel@0 17400 x: {field: 'offset', mult: 0.5},
Daniel@0 17401 y: {scale: 'legend', field: 'index'},
Daniel@0 17402 shape: {value: cfg.symbolShape},
Daniel@0 17403 size: {value: cfg.symbolSize},
Daniel@0 17404 stroke: {value: cfg.symbolColor},
Daniel@0 17405 strokeWidth: {value: cfg.symbolStrokeWidth},
Daniel@0 17406 opacity: {value: 1e-6}
Daniel@0 17407 },
Daniel@0 17408 exit: { opacity: {value: 1e-6} },
Daniel@0 17409 update: {
Daniel@0 17410 x: {field: 'offset', mult: 0.5},
Daniel@0 17411 y: {scale: 'legend', field: 'index'},
Daniel@0 17412 opacity: {value: 1}
Daniel@0 17413 }
Daniel@0 17414 }
Daniel@0 17415 };
Daniel@0 17416 }
Daniel@0 17417
Daniel@0 17418 function vg_vLegendLabels(config) {
Daniel@0 17419 var cfg = config.legend;
Daniel@0 17420 return {
Daniel@0 17421 type: 'text',
Daniel@0 17422 interactive: false,
Daniel@0 17423 key: 'data',
Daniel@0 17424 properties: {
Daniel@0 17425 enter: {
Daniel@0 17426 x: {field: 'offset', offset: 5},
Daniel@0 17427 y: {scale: 'legend', field: 'index'},
Daniel@0 17428 fill: {value: cfg.labelColor},
Daniel@0 17429 font: {value: cfg.labelFont},
Daniel@0 17430 fontSize: {value: cfg.labelFontSize},
Daniel@0 17431 align: {value: cfg.labelAlign},
Daniel@0 17432 baseline: {value: cfg.labelBaseline},
Daniel@0 17433 text: {field: 'label'},
Daniel@0 17434 opacity: {value: 1e-6}
Daniel@0 17435 },
Daniel@0 17436 exit: { opacity: {value: 1e-6} },
Daniel@0 17437 update: {
Daniel@0 17438 opacity: {value: 1},
Daniel@0 17439 x: {field: 'offset', offset: 5},
Daniel@0 17440 y: {scale: 'legend', field: 'index'},
Daniel@0 17441 }
Daniel@0 17442 }
Daniel@0 17443 };
Daniel@0 17444 }
Daniel@0 17445
Daniel@0 17446 function vg_legendGradient(config) {
Daniel@0 17447 var cfg = config.legend;
Daniel@0 17448 return {
Daniel@0 17449 type: 'rect',
Daniel@0 17450 interactive: false,
Daniel@0 17451 properties: {
Daniel@0 17452 enter: {
Daniel@0 17453 x: {value: 0},
Daniel@0 17454 y: {value: 0},
Daniel@0 17455 width: {value: cfg.gradientWidth},
Daniel@0 17456 height: {value: cfg.gradientHeight},
Daniel@0 17457 stroke: {value: cfg.gradientStrokeColor},
Daniel@0 17458 strokeWidth: {value: cfg.gradientStrokeWidth},
Daniel@0 17459 opacity: {value: 1e-6}
Daniel@0 17460 },
Daniel@0 17461 exit: { opacity: {value: 1e-6} },
Daniel@0 17462 update: {
Daniel@0 17463 x: {value: 0},
Daniel@0 17464 y: {value: 0},
Daniel@0 17465 opacity: {value: 1}
Daniel@0 17466 }
Daniel@0 17467 }
Daniel@0 17468 };
Daniel@0 17469 }
Daniel@0 17470
Daniel@0 17471 function vg_hLegendLabels(config) {
Daniel@0 17472 var cfg = config.legend;
Daniel@0 17473 return {
Daniel@0 17474 type: 'text',
Daniel@0 17475 interactive: false,
Daniel@0 17476 key: 'data',
Daniel@0 17477 properties: {
Daniel@0 17478 enter: {
Daniel@0 17479 x: {scale: 'legend', field: 'data'},
Daniel@0 17480 y: {value: 20},
Daniel@0 17481 dy: {value: 2},
Daniel@0 17482 fill: {value: cfg.labelColor},
Daniel@0 17483 font: {value: cfg.labelFont},
Daniel@0 17484 fontSize: {value: cfg.labelFontSize},
Daniel@0 17485 align: {field: 'align'},
Daniel@0 17486 baseline: {value: 'top'},
Daniel@0 17487 text: {field: 'label'},
Daniel@0 17488 opacity: {value: 1e-6}
Daniel@0 17489 },
Daniel@0 17490 exit: { opacity: {value: 1e-6} },
Daniel@0 17491 update: {
Daniel@0 17492 x: {scale: 'legend', field: 'data'},
Daniel@0 17493 y: {value: 20},
Daniel@0 17494 opacity: {value: 1}
Daniel@0 17495 }
Daniel@0 17496 }
Daniel@0 17497 };
Daniel@0 17498 }
Daniel@0 17499
Daniel@0 17500 module.exports = lgnd;
Daniel@0 17501 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
Daniel@0 17502
Daniel@0 17503 },{"../parse/mark":97,"../parse/properties":102,"datalib":24,"vega-scenegraph":46}],115:[function(require,module,exports){
Daniel@0 17504 module.exports = function visit(node, func) {
Daniel@0 17505 var i, n, s, m, items;
Daniel@0 17506 if (func(node)) return true;
Daniel@0 17507
Daniel@0 17508 var sets = ['items', 'axisItems', 'legendItems'];
Daniel@0 17509 for (s=0, m=sets.length; s<m; ++s) {
Daniel@0 17510 if ((items = node[sets[s]])) {
Daniel@0 17511 for (i=0, n=items.length; i<n; ++i) {
Daniel@0 17512 if (visit(items[i], func)) return true;
Daniel@0 17513 }
Daniel@0 17514 }
Daniel@0 17515 }
Daniel@0 17516 };
Daniel@0 17517 },{}],116:[function(require,module,exports){
Daniel@0 17518 var dl = require('datalib'),
Daniel@0 17519 df = require('vega-dataflow'),
Daniel@0 17520 log = require('vega-logging'),
Daniel@0 17521 ChangeSet = df.ChangeSet,
Daniel@0 17522 Tuple = df.Tuple,
Daniel@0 17523 Deps = df.Dependencies,
Daniel@0 17524 Transform = require('./Transform'),
Daniel@0 17525 Facetor = require('./Facetor');
Daniel@0 17526
Daniel@0 17527 function Aggregate(graph) {
Daniel@0 17528 Transform.prototype.init.call(this, graph);
Daniel@0 17529
Daniel@0 17530 Transform.addParameters(this, {
Daniel@0 17531 groupby: {type: 'array<field>'},
Daniel@0 17532 summarize: {
Daniel@0 17533 type: 'custom',
Daniel@0 17534 set: function(summarize) {
Daniel@0 17535 var signalDeps = {},
Daniel@0 17536 tx = this._transform,
Daniel@0 17537 i, len, f, fields, name, ops;
Daniel@0 17538
Daniel@0 17539 if (!dl.isArray(fields = summarize)) { // Object syntax from dl
Daniel@0 17540 fields = [];
Daniel@0 17541 for (name in summarize) {
Daniel@0 17542 ops = dl.array(summarize[name]);
Daniel@0 17543 fields.push({field: name, ops: ops});
Daniel@0 17544 }
Daniel@0 17545 }
Daniel@0 17546
Daniel@0 17547 function sg(x) { if (x.signal) signalDeps[x.signal] = 1; }
Daniel@0 17548
Daniel@0 17549 for (i=0, len=fields.length; i<len; ++i) {
Daniel@0 17550 f = fields[i];
Daniel@0 17551 if (f.field.signal) { signalDeps[f.field.signal] = 1; }
Daniel@0 17552 dl.array(f.ops).forEach(sg);
Daniel@0 17553 dl.array(f.as).forEach(sg);
Daniel@0 17554 }
Daniel@0 17555
Daniel@0 17556 tx._fields = fields;
Daniel@0 17557 tx._aggr = null;
Daniel@0 17558 tx.dependency(Deps.SIGNALS, dl.keys(signalDeps));
Daniel@0 17559 return tx;
Daniel@0 17560 }
Daniel@0 17561 }
Daniel@0 17562 });
Daniel@0 17563
Daniel@0 17564 this._aggr = null; // dl.Aggregator
Daniel@0 17565 this._input = null; // Used by Facetor._on_keep.
Daniel@0 17566 this._args = null; // To cull re-computation.
Daniel@0 17567 this._fields = [];
Daniel@0 17568 this._out = [];
Daniel@0 17569
Daniel@0 17570 this._type = TYPES.TUPLE;
Daniel@0 17571 this._acc = {groupby: dl.true, value: dl.true};
Daniel@0 17572
Daniel@0 17573 return this.router(true).produces(true);
Daniel@0 17574 }
Daniel@0 17575
Daniel@0 17576 var prototype = (Aggregate.prototype = Object.create(Transform.prototype));
Daniel@0 17577 prototype.constructor = Aggregate;
Daniel@0 17578
Daniel@0 17579 var TYPES = Aggregate.TYPES = {
Daniel@0 17580 VALUE: 1,
Daniel@0 17581 TUPLE: 2,
Daniel@0 17582 MULTI: 3
Daniel@0 17583 };
Daniel@0 17584
Daniel@0 17585 Aggregate.VALID_OPS = [
Daniel@0 17586 'values', 'count', 'valid', 'missing', 'distinct',
Daniel@0 17587 'sum', 'mean', 'average', 'variance', 'variancep', 'stdev',
Daniel@0 17588 'stdevp', 'median', 'q1', 'q3', 'modeskew', 'min', 'max',
Daniel@0 17589 'argmin', 'argmax'
Daniel@0 17590 ];
Daniel@0 17591
Daniel@0 17592 prototype.type = function(type) {
Daniel@0 17593 return (this._type = type, this);
Daniel@0 17594 };
Daniel@0 17595
Daniel@0 17596 prototype.accessors = function(groupby, value) {
Daniel@0 17597 var acc = this._acc;
Daniel@0 17598 acc.groupby = dl.$(groupby) || dl.true;
Daniel@0 17599 acc.value = dl.$(value) || dl.true;
Daniel@0 17600 };
Daniel@0 17601
Daniel@0 17602 prototype.aggr = function() {
Daniel@0 17603 if (this._aggr) return this._aggr;
Daniel@0 17604
Daniel@0 17605 var g = this._graph,
Daniel@0 17606 hasGetter = false,
Daniel@0 17607 args = [],
Daniel@0 17608 groupby = this.param('groupby').field,
Daniel@0 17609 value = function(x) { return x.signal ? g.signalRef(x.signal) : x; };
Daniel@0 17610
Daniel@0 17611 // Prepare summarize fields.
Daniel@0 17612 var fields = this._fields.map(function(f) {
Daniel@0 17613 var field = {
Daniel@0 17614 name: value(f.field),
Daniel@0 17615 as: dl.array(f.as),
Daniel@0 17616 ops: dl.array(value(f.ops)).map(value),
Daniel@0 17617 get: f.get
Daniel@0 17618 };
Daniel@0 17619 hasGetter = hasGetter || field.get != null;
Daniel@0 17620 args.push(field.name);
Daniel@0 17621 return field;
Daniel@0 17622 });
Daniel@0 17623
Daniel@0 17624 // If there is an arbitrary getter, all bets are off.
Daniel@0 17625 // Otherwise, we can check argument fields to cull re-computation.
Daniel@0 17626 groupby.forEach(function(g) {
Daniel@0 17627 if (g.get) hasGetter = true;
Daniel@0 17628 args.push(g.name || g);
Daniel@0 17629 });
Daniel@0 17630 this._args = hasGetter || !fields.length ? null : args;
Daniel@0 17631
Daniel@0 17632 if (!fields.length) fields = {'*': 'values'};
Daniel@0 17633
Daniel@0 17634 // Instatiate our aggregator instance.
Daniel@0 17635 // Facetor is a special subclass that can facet into data pipelines.
Daniel@0 17636 var aggr = this._aggr = new Facetor()
Daniel@0 17637 .groupby(groupby)
Daniel@0 17638 .stream(true)
Daniel@0 17639 .summarize(fields);
Daniel@0 17640
Daniel@0 17641 // Collect output fields sets by this aggregate.
Daniel@0 17642 this._out = getFields(aggr);
Daniel@0 17643
Daniel@0 17644 // If we are processing tuples, key them by '_id'.
Daniel@0 17645 if (this._type !== TYPES.VALUE) { aggr.key('_id'); }
Daniel@0 17646
Daniel@0 17647 return aggr;
Daniel@0 17648 };
Daniel@0 17649
Daniel@0 17650 function getFields(aggr) {
Daniel@0 17651 // Collect the output fields set by this aggregate.
Daniel@0 17652 var f = [], i, n, j, m, dims, vals, meas;
Daniel@0 17653
Daniel@0 17654 dims = aggr._dims;
Daniel@0 17655 for (i=0, n=dims.length; i<n; ++i) {
Daniel@0 17656 f.push(dims[i].name);
Daniel@0 17657 }
Daniel@0 17658
Daniel@0 17659 vals = aggr._aggr;
Daniel@0 17660 for (i=0, n=vals.length; i<n; ++i) {
Daniel@0 17661 meas = vals[i].measures.fields;
Daniel@0 17662 for (j=0, m=meas.length; j<m; ++j) {
Daniel@0 17663 f.push(meas[j]);
Daniel@0 17664 }
Daniel@0 17665 }
Daniel@0 17666
Daniel@0 17667 return f;
Daniel@0 17668 }
Daniel@0 17669
Daniel@0 17670 prototype.transform = function(input, reset) {
Daniel@0 17671 log.debug(input, ['aggregate']);
Daniel@0 17672 this._input = input; // Used by Facetor._on_keep.
Daniel@0 17673
Daniel@0 17674 var output = ChangeSet.create(input),
Daniel@0 17675 aggr = this.aggr(),
Daniel@0 17676 out = this._out,
Daniel@0 17677 args = this._args,
Daniel@0 17678 reeval = true,
Daniel@0 17679 p = Tuple.prev,
Daniel@0 17680 add, rem, mod, i;
Daniel@0 17681
Daniel@0 17682 // Upon reset, retract prior tuples and re-initialize.
Daniel@0 17683 if (reset) {
Daniel@0 17684 output.rem.push.apply(output.rem, aggr.result());
Daniel@0 17685 aggr.clear();
Daniel@0 17686 this._aggr = null;
Daniel@0 17687 aggr = this.aggr();
Daniel@0 17688 }
Daniel@0 17689
Daniel@0 17690 // Get update methods according to input type.
Daniel@0 17691 if (this._type === TYPES.TUPLE) {
Daniel@0 17692 add = function(x) { aggr._add(x); Tuple.prev_init(x); };
Daniel@0 17693 rem = function(x) { aggr._rem(p(x)); };
Daniel@0 17694 mod = function(x) { aggr._mod(x, p(x)); };
Daniel@0 17695 } else {
Daniel@0 17696 var gby = this._acc.groupby,
Daniel@0 17697 val = this._acc.value,
Daniel@0 17698 get = this._type === TYPES.VALUE ? val : function(x) {
Daniel@0 17699 return { _id: x._id, groupby: gby(x), value: val(x) };
Daniel@0 17700 };
Daniel@0 17701 add = function(x) { aggr._add(get(x)); Tuple.prev_init(x); };
Daniel@0 17702 rem = function(x) { aggr._rem(get(p(x))); };
Daniel@0 17703 mod = function(x) { aggr._mod(get(x), get(p(x))); };
Daniel@0 17704 }
Daniel@0 17705
Daniel@0 17706 input.add.forEach(add);
Daniel@0 17707 if (reset) {
Daniel@0 17708 // A signal change triggered reflow. Add everything.
Daniel@0 17709 // No need for rem, we cleared the aggregator.
Daniel@0 17710 input.mod.forEach(add);
Daniel@0 17711 } else {
Daniel@0 17712 input.rem.forEach(rem);
Daniel@0 17713
Daniel@0 17714 // If possible, check argument fields to see if we need to re-process mods.
Daniel@0 17715 if (args) for (i=0, reeval=false; i<args.length; ++i) {
Daniel@0 17716 if (input.fields[args[i]]) { reeval = true; break; }
Daniel@0 17717 }
Daniel@0 17718 if (reeval) input.mod.forEach(mod);
Daniel@0 17719 }
Daniel@0 17720
Daniel@0 17721 // Indicate output fields and return aggregate tuples.
Daniel@0 17722 for (i=0; i<out.length; ++i) {
Daniel@0 17723 output.fields[out[i]] = 1;
Daniel@0 17724 }
Daniel@0 17725 return aggr.changes(output);
Daniel@0 17726 };
Daniel@0 17727
Daniel@0 17728 module.exports = Aggregate;
Daniel@0 17729 },{"./Facetor":122,"./Transform":135,"datalib":24,"vega-dataflow":39,"vega-logging":45}],117:[function(require,module,exports){
Daniel@0 17730 var Base = require('./Transform').prototype;
Daniel@0 17731
Daniel@0 17732 function BatchTransform() {
Daniel@0 17733 // Nearest appropriate collector.
Daniel@0 17734 // Set by the dataflow Graph during connection.
Daniel@0 17735 this._collector = null;
Daniel@0 17736 }
Daniel@0 17737
Daniel@0 17738 var prototype = (BatchTransform.prototype = Object.create(Base));
Daniel@0 17739 prototype.constructor = BatchTransform;
Daniel@0 17740
Daniel@0 17741 prototype.init = function(graph) {
Daniel@0 17742 Base.init.call(this, graph);
Daniel@0 17743 return this.batch(true);
Daniel@0 17744 };
Daniel@0 17745
Daniel@0 17746 prototype.transform = function(input) {
Daniel@0 17747 return this.batchTransform(input, this._collector.data());
Daniel@0 17748 };
Daniel@0 17749
Daniel@0 17750 prototype.batchTransform = function(/* input, data */) {
Daniel@0 17751 };
Daniel@0 17752
Daniel@0 17753 module.exports = BatchTransform;
Daniel@0 17754 },{"./Transform":135}],118:[function(require,module,exports){
Daniel@0 17755 var bins = require('datalib').bins,
Daniel@0 17756 Tuple = require('vega-dataflow').Tuple,
Daniel@0 17757 log = require('vega-logging'),
Daniel@0 17758 Transform = require('./Transform');
Daniel@0 17759
Daniel@0 17760 function Bin(graph) {
Daniel@0 17761 Transform.prototype.init.call(this, graph);
Daniel@0 17762 Transform.addParameters(this, {
Daniel@0 17763 field: {type: 'field'},
Daniel@0 17764 min: {type: 'value'},
Daniel@0 17765 max: {type: 'value'},
Daniel@0 17766 base: {type: 'value', default: 10},
Daniel@0 17767 maxbins: {type: 'value', default: 20},
Daniel@0 17768 step: {type: 'value'},
Daniel@0 17769 steps: {type: 'value'},
Daniel@0 17770 minstep: {type: 'value'},
Daniel@0 17771 div: {type: 'array<value>', default: [5, 2]}
Daniel@0 17772 });
Daniel@0 17773
Daniel@0 17774 this._output = {bin: 'bin'};
Daniel@0 17775 return this.mutates(true);
Daniel@0 17776 }
Daniel@0 17777
Daniel@0 17778 var prototype = (Bin.prototype = Object.create(Transform.prototype));
Daniel@0 17779 prototype.constructor = Bin;
Daniel@0 17780
Daniel@0 17781 prototype.transform = function(input) {
Daniel@0 17782 log.debug(input, ['binning']);
Daniel@0 17783
Daniel@0 17784 var output = this._output.bin,
Daniel@0 17785 step = this.param('step'),
Daniel@0 17786 steps = this.param('steps'),
Daniel@0 17787 minstep = this.param('minstep'),
Daniel@0 17788 get = this.param('field').accessor,
Daniel@0 17789 opt = {
Daniel@0 17790 min: this.param('min'),
Daniel@0 17791 max: this.param('max'),
Daniel@0 17792 base: this.param('base'),
Daniel@0 17793 maxbins: this.param('maxbins'),
Daniel@0 17794 div: this.param('div')
Daniel@0 17795 };
Daniel@0 17796
Daniel@0 17797 if (step) opt.step = step;
Daniel@0 17798 if (steps) opt.steps = steps;
Daniel@0 17799 if (minstep) opt.minstep = minstep;
Daniel@0 17800 var b = bins(opt);
Daniel@0 17801
Daniel@0 17802 function update(d) {
Daniel@0 17803 var v = get(d);
Daniel@0 17804 v = v == null ? null
Daniel@0 17805 : b.start + b.step * ~~((v - b.start) / b.step);
Daniel@0 17806 Tuple.set(d, output, v);
Daniel@0 17807 }
Daniel@0 17808 input.add.forEach(update);
Daniel@0 17809 input.mod.forEach(update);
Daniel@0 17810 input.rem.forEach(update);
Daniel@0 17811
Daniel@0 17812 input.fields[output] = 1;
Daniel@0 17813 return input;
Daniel@0 17814 };
Daniel@0 17815
Daniel@0 17816 module.exports = Bin;
Daniel@0 17817 },{"./Transform":135,"datalib":24,"vega-dataflow":39,"vega-logging":45}],119:[function(require,module,exports){
Daniel@0 17818 var df = require('vega-dataflow'),
Daniel@0 17819 Tuple = df.Tuple,
Daniel@0 17820 log = require('vega-logging'),
Daniel@0 17821 Transform = require('./Transform');
Daniel@0 17822
Daniel@0 17823 function CountPattern(graph) {
Daniel@0 17824 Transform.prototype.init.call(this, graph);
Daniel@0 17825 Transform.addParameters(this, {
Daniel@0 17826 field: {type: 'field', default: 'data'},
Daniel@0 17827 pattern: {type: 'value', default: '[\\w\']+'},
Daniel@0 17828 case: {type: 'value', default: 'lower'},
Daniel@0 17829 stopwords: {type: 'value', default: ''}
Daniel@0 17830 });
Daniel@0 17831
Daniel@0 17832 this._output = {text: 'text', count: 'count'};
Daniel@0 17833
Daniel@0 17834 return this.router(true).produces(true);
Daniel@0 17835 }
Daniel@0 17836
Daniel@0 17837 var prototype = (CountPattern.prototype = Object.create(Transform.prototype));
Daniel@0 17838 prototype.constructor = CountPattern;
Daniel@0 17839
Daniel@0 17840 prototype.transform = function(input, reset) {
Daniel@0 17841 log.debug(input, ['countpattern']);
Daniel@0 17842
Daniel@0 17843 var get = this.param('field').accessor,
Daniel@0 17844 pattern = this.param('pattern'),
Daniel@0 17845 stop = this.param('stopwords'),
Daniel@0 17846 rem = false;
Daniel@0 17847
Daniel@0 17848 // update parameters
Daniel@0 17849 if (this._stop !== stop) {
Daniel@0 17850 this._stop = stop;
Daniel@0 17851 this._stop_re = new RegExp('^' + stop + '$', 'i');
Daniel@0 17852 reset = true;
Daniel@0 17853 }
Daniel@0 17854
Daniel@0 17855 if (this._pattern !== pattern) {
Daniel@0 17856 this._pattern = pattern;
Daniel@0 17857 this._match = new RegExp(this._pattern, 'g');
Daniel@0 17858 reset = true;
Daniel@0 17859 }
Daniel@0 17860
Daniel@0 17861 if (reset) this._counts = {};
Daniel@0 17862
Daniel@0 17863 function curr(t) { return (Tuple.prev_init(t), get(t)); }
Daniel@0 17864 function prev(t) { return get(Tuple.prev(t)); }
Daniel@0 17865
Daniel@0 17866 this._add(input.add, curr);
Daniel@0 17867 if (!reset) this._rem(input.rem, prev);
Daniel@0 17868 if (reset || (rem = input.fields[get.field])) {
Daniel@0 17869 if (rem) this._rem(input.mod, prev);
Daniel@0 17870 this._add(input.mod, curr);
Daniel@0 17871 }
Daniel@0 17872
Daniel@0 17873 // generate output tuples
Daniel@0 17874 return this._changeset(input);
Daniel@0 17875 };
Daniel@0 17876
Daniel@0 17877 prototype._changeset = function(input) {
Daniel@0 17878 var counts = this._counts,
Daniel@0 17879 tuples = this._tuples || (this._tuples = {}),
Daniel@0 17880 change = df.ChangeSet.create(input),
Daniel@0 17881 out = this._output, w, t, c;
Daniel@0 17882
Daniel@0 17883 for (w in counts) {
Daniel@0 17884 t = tuples[w];
Daniel@0 17885 c = counts[w] || 0;
Daniel@0 17886 if (!t && c) {
Daniel@0 17887 tuples[w] = (t = Tuple.ingest({}));
Daniel@0 17888 t[out.text] = w;
Daniel@0 17889 t[out.count] = c;
Daniel@0 17890 change.add.push(t);
Daniel@0 17891 } else if (c === 0) {
Daniel@0 17892 if (t) change.rem.push(t);
Daniel@0 17893 delete counts[w];
Daniel@0 17894 delete tuples[w];
Daniel@0 17895 } else if (t[out.count] !== c) {
Daniel@0 17896 Tuple.set(t, out.count, c);
Daniel@0 17897 change.mod.push(t);
Daniel@0 17898 }
Daniel@0 17899 }
Daniel@0 17900 return change;
Daniel@0 17901 };
Daniel@0 17902
Daniel@0 17903 prototype._tokenize = function(text) {
Daniel@0 17904 switch (this.param('case')) {
Daniel@0 17905 case 'upper': text = text.toUpperCase(); break;
Daniel@0 17906 case 'lower': text = text.toLowerCase(); break;
Daniel@0 17907 }
Daniel@0 17908 return text.match(this._match);
Daniel@0 17909 };
Daniel@0 17910
Daniel@0 17911 prototype._add = function(tuples, get) {
Daniel@0 17912 var counts = this._counts,
Daniel@0 17913 stop = this._stop_re,
Daniel@0 17914 tok, i, j, t;
Daniel@0 17915
Daniel@0 17916 for (j=0; j<tuples.length; ++j) {
Daniel@0 17917 tok = this._tokenize(get(tuples[j]));
Daniel@0 17918 for (i=0; i<tok.length; ++i) {
Daniel@0 17919 if (!stop.test(t=tok[i])) {
Daniel@0 17920 counts[t] = 1 + (counts[t] || 0);
Daniel@0 17921 }
Daniel@0 17922 }
Daniel@0 17923 }
Daniel@0 17924 };
Daniel@0 17925
Daniel@0 17926 prototype._rem = function(tuples, get) {
Daniel@0 17927 var counts = this._counts,
Daniel@0 17928 stop = this._stop_re,
Daniel@0 17929 tok, i, j, t;
Daniel@0 17930
Daniel@0 17931 for (j=0; j<tuples.length; ++j) {
Daniel@0 17932 tok = this._tokenize(get(tuples[j]));
Daniel@0 17933 for (i=0; i<tok.length; ++i) {
Daniel@0 17934 if (!stop.test(t=tok[i])) {
Daniel@0 17935 counts[t] -= 1;
Daniel@0 17936 }
Daniel@0 17937 }
Daniel@0 17938 }
Daniel@0 17939 };
Daniel@0 17940
Daniel@0 17941 module.exports = CountPattern;
Daniel@0 17942 },{"./Transform":135,"vega-dataflow":39,"vega-logging":45}],120:[function(require,module,exports){
Daniel@0 17943 var df = require('vega-dataflow'),
Daniel@0 17944 ChangeSet = df.ChangeSet,
Daniel@0 17945 Tuple = df.Tuple,
Daniel@0 17946 SIGNALS = df.Dependencies.SIGNALS,
Daniel@0 17947 log = require('vega-logging'),
Daniel@0 17948 Transform = require('./Transform'),
Daniel@0 17949 BatchTransform = require('./BatchTransform');
Daniel@0 17950
Daniel@0 17951 function Cross(graph) {
Daniel@0 17952 BatchTransform.prototype.init.call(this, graph);
Daniel@0 17953 Transform.addParameters(this, {
Daniel@0 17954 with: {type: 'data'},
Daniel@0 17955 diagonal: {type: 'value', default: 'true'},
Daniel@0 17956 filter: {type: 'expr'}
Daniel@0 17957 });
Daniel@0 17958
Daniel@0 17959 this._output = {'left': 'a', 'right': 'b'};
Daniel@0 17960 this._lastRem = null; // Most recent stamp that rem occured.
Daniel@0 17961 this._lastWith = null; // Last time we crossed w/withds.
Daniel@0 17962 this._ids = {};
Daniel@0 17963 this._cache = {};
Daniel@0 17964
Daniel@0 17965 return this.router(true).produces(true);
Daniel@0 17966 }
Daniel@0 17967
Daniel@0 17968 var prototype = (Cross.prototype = Object.create(BatchTransform.prototype));
Daniel@0 17969 prototype.constructor = Cross;
Daniel@0 17970
Daniel@0 17971 // Each cached incoming tuple also has a stamp to track if we need to do
Daniel@0 17972 // lazy filtering of removed tuples.
Daniel@0 17973 function cache(x, t) {
Daniel@0 17974 var c = this._cache[x._id] = this._cache[x._id] || {c: [], s: this._stamp};
Daniel@0 17975 c.c.push(t);
Daniel@0 17976 }
Daniel@0 17977
Daniel@0 17978 function add(output, left, data, diag, test, x) {
Daniel@0 17979 var i = 0, len = data.length, t = {}, y, id;
Daniel@0 17980
Daniel@0 17981 for (; i<len; ++i) {
Daniel@0 17982 y = data[i];
Daniel@0 17983 id = left ? x._id+'_'+y._id : y._id+'_'+x._id;
Daniel@0 17984 if (this._ids[id]) continue;
Daniel@0 17985 if (x._id == y._id && !diag) continue;
Daniel@0 17986
Daniel@0 17987 t[this._output.left] = left ? x : y;
Daniel@0 17988 t[this._output.right] = left ? y : x;
Daniel@0 17989
Daniel@0 17990 // Only ingest a tuple if we keep it around.
Daniel@0 17991 if (!test || test(t)) {
Daniel@0 17992 output.add.push(t=Tuple.ingest(t));
Daniel@0 17993 cache.call(this, x, t);
Daniel@0 17994 cache.call(this, y, t);
Daniel@0 17995 this._ids[id] = 1;
Daniel@0 17996 t = {};
Daniel@0 17997 }
Daniel@0 17998 }
Daniel@0 17999 }
Daniel@0 18000
Daniel@0 18001 function mod(output, left, x) {
Daniel@0 18002 var cross = this,
Daniel@0 18003 c = this._cache[x._id];
Daniel@0 18004
Daniel@0 18005 if (this._lastRem > c.s) { // Removed tuples haven't been filtered yet
Daniel@0 18006 c.c = c.c.filter(function(y) {
Daniel@0 18007 var t = y[cross._output[left ? 'right' : 'left']];
Daniel@0 18008 return cross._cache[t._id] !== null;
Daniel@0 18009 });
Daniel@0 18010 c.s = this._lastRem;
Daniel@0 18011 }
Daniel@0 18012
Daniel@0 18013 output.mod.push.apply(output.mod, c.c);
Daniel@0 18014 }
Daniel@0 18015
Daniel@0 18016 function rem(output, x) {
Daniel@0 18017 output.rem.push.apply(output.rem, this._cache[x._id].c);
Daniel@0 18018 this._cache[x._id] = null;
Daniel@0 18019 this._lastRem = this._stamp;
Daniel@0 18020 }
Daniel@0 18021
Daniel@0 18022 function upFields(input, output) {
Daniel@0 18023 if (input.add.length || input.rem.length) {
Daniel@0 18024 output.fields[this._output.left] = 1;
Daniel@0 18025 output.fields[this._output.right] = 1;
Daniel@0 18026 }
Daniel@0 18027 }
Daniel@0 18028
Daniel@0 18029 prototype.batchTransform = function(input, data) {
Daniel@0 18030 log.debug(input, ['crossing']);
Daniel@0 18031
Daniel@0 18032 var w = this.param('with'),
Daniel@0 18033 f = this.param('filter'),
Daniel@0 18034 diag = this.param('diagonal'),
Daniel@0 18035 graph = this._graph,
Daniel@0 18036 signals = graph.values(SIGNALS, this.dependency(SIGNALS)),
Daniel@0 18037 test = f ? function(x) {return f(x, null, signals); } : null,
Daniel@0 18038 selfCross = (!w.name),
Daniel@0 18039 woutput = selfCross ? input : w.source.last(),
Daniel@0 18040 wdata = selfCross ? data : w.source.values(),
Daniel@0 18041 output = ChangeSet.create(input),
Daniel@0 18042 r = rem.bind(this, output);
Daniel@0 18043
Daniel@0 18044 input.rem.forEach(r);
Daniel@0 18045 input.add.forEach(add.bind(this, output, true, wdata, diag, test));
Daniel@0 18046
Daniel@0 18047 if (!selfCross && woutput.stamp > this._lastWith) {
Daniel@0 18048 woutput.rem.forEach(r);
Daniel@0 18049 woutput.add.forEach(add.bind(this, output, false, data, diag, test));
Daniel@0 18050 woutput.mod.forEach(mod.bind(this, output, false));
Daniel@0 18051 upFields.call(this, woutput, output);
Daniel@0 18052 this._lastWith = woutput.stamp;
Daniel@0 18053 }
Daniel@0 18054
Daniel@0 18055 // Mods need to come after all removals have been run.
Daniel@0 18056 input.mod.forEach(mod.bind(this, output, true));
Daniel@0 18057 upFields.call(this, input, output);
Daniel@0 18058
Daniel@0 18059 return output;
Daniel@0 18060 };
Daniel@0 18061
Daniel@0 18062 module.exports = Cross;
Daniel@0 18063 },{"./BatchTransform":117,"./Transform":135,"vega-dataflow":39,"vega-logging":45}],121:[function(require,module,exports){
Daniel@0 18064 var Transform = require('./Transform'),
Daniel@0 18065 Aggregate = require('./Aggregate');
Daniel@0 18066
Daniel@0 18067 function Facet(graph) {
Daniel@0 18068 Transform.addParameters(this, {
Daniel@0 18069 transform: {
Daniel@0 18070 type: "custom",
Daniel@0 18071 set: function(pipeline) {
Daniel@0 18072 return (this._transform._pipeline = pipeline, this._transform);
Daniel@0 18073 },
Daniel@0 18074 get: function() {
Daniel@0 18075 var parse = require('../parse/transforms'),
Daniel@0 18076 facet = this._transform;
Daniel@0 18077 return facet._pipeline.map(function(t) {
Daniel@0 18078 return parse(facet._graph, t);
Daniel@0 18079 });
Daniel@0 18080 }
Daniel@0 18081 }
Daniel@0 18082 });
Daniel@0 18083
Daniel@0 18084 this._pipeline = [];
Daniel@0 18085 return Aggregate.call(this, graph);
Daniel@0 18086 }
Daniel@0 18087
Daniel@0 18088 var prototype = (Facet.prototype = Object.create(Aggregate.prototype));
Daniel@0 18089 prototype.constructor = Facet;
Daniel@0 18090
Daniel@0 18091 prototype.aggr = function() {
Daniel@0 18092 return Aggregate.prototype.aggr.call(this).facet(this);
Daniel@0 18093 };
Daniel@0 18094
Daniel@0 18095 module.exports = Facet;
Daniel@0 18096 },{"../parse/transforms":106,"./Aggregate":116,"./Transform":135}],122:[function(require,module,exports){
Daniel@0 18097 var dl = require('datalib'),
Daniel@0 18098 Aggregator = dl.Aggregator,
Daniel@0 18099 Base = Aggregator.prototype,
Daniel@0 18100 df = require('vega-dataflow'),
Daniel@0 18101 Tuple = df.Tuple,
Daniel@0 18102 log = require('vega-logging'),
Daniel@0 18103 facetID = 0;
Daniel@0 18104
Daniel@0 18105 function Facetor() {
Daniel@0 18106 Aggregator.call(this);
Daniel@0 18107 this._facet = null;
Daniel@0 18108 this._facetID = ++facetID;
Daniel@0 18109 }
Daniel@0 18110
Daniel@0 18111 var prototype = (Facetor.prototype = Object.create(Base));
Daniel@0 18112 prototype.constructor = Facetor;
Daniel@0 18113
Daniel@0 18114 prototype.facet = function(f) {
Daniel@0 18115 return arguments.length ? (this._facet = f, this) : this._facet;
Daniel@0 18116 };
Daniel@0 18117
Daniel@0 18118 prototype._ingest = function(t) {
Daniel@0 18119 return Tuple.ingest(t, null);
Daniel@0 18120 };
Daniel@0 18121
Daniel@0 18122 prototype._assign = Tuple.set;
Daniel@0 18123
Daniel@0 18124 function disconnect_cell(facet) {
Daniel@0 18125 log.debug({}, ['disconnecting cell', this.tuple._id]);
Daniel@0 18126 var pipeline = this.ds.pipeline();
Daniel@0 18127 facet.removeListener(pipeline[0]);
Daniel@0 18128 facet._graph.removeListener(pipeline[0]);
Daniel@0 18129 facet._graph.disconnect(pipeline);
Daniel@0 18130 }
Daniel@0 18131
Daniel@0 18132 prototype._newcell = function(x, key) {
Daniel@0 18133 var cell = Base._newcell.call(this, x, key),
Daniel@0 18134 facet = this._facet;
Daniel@0 18135
Daniel@0 18136 if (facet) {
Daniel@0 18137 var graph = facet._graph,
Daniel@0 18138 tuple = cell.tuple,
Daniel@0 18139 pipeline = facet.param('transform');
Daniel@0 18140 cell.ds = graph.data(tuple._facetID, pipeline, tuple);
Daniel@0 18141 cell.disconnect = disconnect_cell;
Daniel@0 18142 facet.addListener(pipeline[0]);
Daniel@0 18143 }
Daniel@0 18144
Daniel@0 18145 return cell;
Daniel@0 18146 };
Daniel@0 18147
Daniel@0 18148 prototype._newtuple = function(x, key) {
Daniel@0 18149 var t = Base._newtuple.call(this, x);
Daniel@0 18150 if (this._facet) {
Daniel@0 18151 Tuple.set(t, 'key', key);
Daniel@0 18152 Tuple.set(t, '_facetID', this._facetID + '_' + key);
Daniel@0 18153 }
Daniel@0 18154 return t;
Daniel@0 18155 };
Daniel@0 18156
Daniel@0 18157 prototype.clear = function() {
Daniel@0 18158 if (this._facet) {
Daniel@0 18159 for (var k in this._cells) {
Daniel@0 18160 this._cells[k].disconnect(this._facet);
Daniel@0 18161 }
Daniel@0 18162 }
Daniel@0 18163 return Base.clear.call(this);
Daniel@0 18164 };
Daniel@0 18165
Daniel@0 18166 prototype._on_add = function(x, cell) {
Daniel@0 18167 if (this._facet) cell.ds._input.add.push(x);
Daniel@0 18168 };
Daniel@0 18169
Daniel@0 18170 prototype._on_rem = function(x, cell) {
Daniel@0 18171 if (this._facet) cell.ds._input.rem.push(x);
Daniel@0 18172 };
Daniel@0 18173
Daniel@0 18174 prototype._on_mod = function(x, prev, cell0, cell1) {
Daniel@0 18175 if (this._facet) { // Propagate tuples
Daniel@0 18176 if (cell0 === cell1) {
Daniel@0 18177 cell0.ds._input.mod.push(x);
Daniel@0 18178 } else {
Daniel@0 18179 cell0.ds._input.rem.push(x);
Daniel@0 18180 cell1.ds._input.add.push(x);
Daniel@0 18181 }
Daniel@0 18182 }
Daniel@0 18183 };
Daniel@0 18184
Daniel@0 18185 prototype._on_drop = function(cell) {
Daniel@0 18186 if (this._facet) cell.disconnect(this._facet);
Daniel@0 18187 };
Daniel@0 18188
Daniel@0 18189 prototype._on_keep = function(cell) {
Daniel@0 18190 // propagate sort, signals, fields, etc.
Daniel@0 18191 if (this._facet) df.ChangeSet.copy(this._input, cell.ds._input);
Daniel@0 18192 };
Daniel@0 18193
Daniel@0 18194 module.exports = Facetor;
Daniel@0 18195 },{"datalib":24,"vega-dataflow":39,"vega-logging":45}],123:[function(require,module,exports){
Daniel@0 18196 var df = require('vega-dataflow'),
Daniel@0 18197 SIGNALS = df.Dependencies.SIGNALS,
Daniel@0 18198 log = require('vega-logging'),
Daniel@0 18199 Transform = require('./Transform');
Daniel@0 18200
Daniel@0 18201 function Filter(graph) {
Daniel@0 18202 Transform.prototype.init.call(this, graph);
Daniel@0 18203 Transform.addParameters(this, {test: {type: 'expr'}});
Daniel@0 18204
Daniel@0 18205 this._skip = {};
Daniel@0 18206 return this.router(true);
Daniel@0 18207 }
Daniel@0 18208
Daniel@0 18209 var prototype = (Filter.prototype = Object.create(Transform.prototype));
Daniel@0 18210 prototype.constructor = Filter;
Daniel@0 18211
Daniel@0 18212 prototype.transform = function(input) {
Daniel@0 18213 log.debug(input, ['filtering']);
Daniel@0 18214
Daniel@0 18215 var output = df.ChangeSet.create(input),
Daniel@0 18216 graph = this._graph,
Daniel@0 18217 skip = this._skip,
Daniel@0 18218 test = this.param('test'),
Daniel@0 18219 signals = graph.values(SIGNALS, this.dependency(SIGNALS));
Daniel@0 18220
Daniel@0 18221 input.rem.forEach(function(x) {
Daniel@0 18222 if (skip[x._id] !== 1) output.rem.push(x);
Daniel@0 18223 else skip[x._id] = 0;
Daniel@0 18224 });
Daniel@0 18225
Daniel@0 18226 input.add.forEach(function(x) {
Daniel@0 18227 if (test(x, null, signals)) output.add.push(x);
Daniel@0 18228 else skip[x._id] = 1;
Daniel@0 18229 });
Daniel@0 18230
Daniel@0 18231 input.mod.forEach(function(x) {
Daniel@0 18232 var b = test(x, null, signals),
Daniel@0 18233 s = (skip[x._id] === 1);
Daniel@0 18234 if (b && s) {
Daniel@0 18235 skip[x._id] = 0;
Daniel@0 18236 output.add.push(x);
Daniel@0 18237 } else if (b && !s) {
Daniel@0 18238 output.mod.push(x);
Daniel@0 18239 } else if (!b && s) {
Daniel@0 18240 // do nothing, keep skip true
Daniel@0 18241 } else { // !b && !s
Daniel@0 18242 output.rem.push(x);
Daniel@0 18243 skip[x._id] = 1;
Daniel@0 18244 }
Daniel@0 18245 });
Daniel@0 18246
Daniel@0 18247 return output;
Daniel@0 18248 };
Daniel@0 18249
Daniel@0 18250 module.exports = Filter;
Daniel@0 18251 },{"./Transform":135,"vega-dataflow":39,"vega-logging":45}],124:[function(require,module,exports){
Daniel@0 18252 var df = require('vega-dataflow'),
Daniel@0 18253 Tuple = df.Tuple,
Daniel@0 18254 log = require('vega-logging'),
Daniel@0 18255 Transform = require('./Transform');
Daniel@0 18256
Daniel@0 18257 function Fold(graph) {
Daniel@0 18258 Transform.prototype.init.call(this, graph);
Daniel@0 18259 Transform.addParameters(this, {
Daniel@0 18260 fields: {type: 'array<field>'}
Daniel@0 18261 });
Daniel@0 18262
Daniel@0 18263 this._output = {key: 'key', value: 'value'};
Daniel@0 18264 this._cache = {};
Daniel@0 18265
Daniel@0 18266 return this.router(true).produces(true);
Daniel@0 18267 }
Daniel@0 18268
Daniel@0 18269 var prototype = (Fold.prototype = Object.create(Transform.prototype));
Daniel@0 18270 prototype.constructor = Fold;
Daniel@0 18271
Daniel@0 18272 prototype._reset = function(input, output) {
Daniel@0 18273 for (var id in this._cache) {
Daniel@0 18274 output.rem.push.apply(output.rem, this._cache[id]);
Daniel@0 18275 }
Daniel@0 18276 this._cache = {};
Daniel@0 18277 };
Daniel@0 18278
Daniel@0 18279 prototype._tuple = function(x, i, len) {
Daniel@0 18280 var list = this._cache[x._id] || (this._cache[x._id] = Array(len));
Daniel@0 18281 return list[i] ? Tuple.rederive(x, list[i]) : (list[i] = Tuple.derive(x));
Daniel@0 18282 };
Daniel@0 18283
Daniel@0 18284 prototype._fn = function(data, on, out) {
Daniel@0 18285 var i, j, n, m, d, t;
Daniel@0 18286 for (i=0, n=data.length; i<n; ++i) {
Daniel@0 18287 d = data[i];
Daniel@0 18288 for (j=0, m=on.field.length; j<m; ++j) {
Daniel@0 18289 t = this._tuple(d, j, m);
Daniel@0 18290 Tuple.set(t, this._output.key, on.field[j]);
Daniel@0 18291 Tuple.set(t, this._output.value, on.accessor[j](d));
Daniel@0 18292 out.push(t);
Daniel@0 18293 }
Daniel@0 18294 }
Daniel@0 18295 };
Daniel@0 18296
Daniel@0 18297 prototype.transform = function(input, reset) {
Daniel@0 18298 log.debug(input, ['folding']);
Daniel@0 18299
Daniel@0 18300 var fold = this,
Daniel@0 18301 on = this.param('fields'),
Daniel@0 18302 output = df.ChangeSet.create(input);
Daniel@0 18303
Daniel@0 18304 if (reset) this._reset(input, output);
Daniel@0 18305
Daniel@0 18306 this._fn(input.add, on, output.add);
Daniel@0 18307 this._fn(input.mod, on, reset ? output.add : output.mod);
Daniel@0 18308 input.rem.forEach(function(x) {
Daniel@0 18309 output.rem.push.apply(output.rem, fold._cache[x._id]);
Daniel@0 18310 fold._cache[x._id] = null;
Daniel@0 18311 });
Daniel@0 18312
Daniel@0 18313 // If we're only propagating values, don't mark key/value as updated.
Daniel@0 18314 if (input.add.length || input.rem.length ||
Daniel@0 18315 on.field.some(function(f) { return !!input.fields[f]; })) {
Daniel@0 18316 output.fields[this._output.key] = 1;
Daniel@0 18317 output.fields[this._output.value] = 1;
Daniel@0 18318 }
Daniel@0 18319 return output;
Daniel@0 18320 };
Daniel@0 18321
Daniel@0 18322 module.exports = Fold;
Daniel@0 18323 },{"./Transform":135,"vega-dataflow":39,"vega-logging":45}],125:[function(require,module,exports){
Daniel@0 18324 (function (global){
Daniel@0 18325 var d3 = (typeof window !== "undefined" ? window['d3'] : typeof global !== "undefined" ? global['d3'] : null),
Daniel@0 18326 df = require('vega-dataflow'),
Daniel@0 18327 Tuple = df.Tuple,
Daniel@0 18328 ChangeSet = df.ChangeSet,
Daniel@0 18329 log = require('vega-logging'),
Daniel@0 18330 Transform = require('./Transform');
Daniel@0 18331
Daniel@0 18332 function Force(graph) {
Daniel@0 18333 Transform.prototype.init.call(this, graph);
Daniel@0 18334
Daniel@0 18335 this._prev = null;
Daniel@0 18336 this._interactive = false;
Daniel@0 18337 this._setup = true;
Daniel@0 18338 this._nodes = [];
Daniel@0 18339 this._links = [];
Daniel@0 18340 this._layout = d3.layout.force();
Daniel@0 18341
Daniel@0 18342 Transform.addParameters(this, {
Daniel@0 18343 size: {type: 'array<value>', default: [500, 500]},
Daniel@0 18344 bound: {type: 'value', default: true},
Daniel@0 18345 links: {type: 'data'},
Daniel@0 18346
Daniel@0 18347 // TODO: for now force these to be value params only (pun-intended)
Daniel@0 18348 // Can update to include fields after Parameter refactoring.
Daniel@0 18349 linkStrength: {type: 'value', default: 1},
Daniel@0 18350 linkDistance: {type: 'value', default: 20},
Daniel@0 18351 charge: {type: 'value', default: -30},
Daniel@0 18352
Daniel@0 18353 chargeDistance: {type: 'value', default: Infinity},
Daniel@0 18354 friction: {type: 'value', default: 0.9},
Daniel@0 18355 theta: {type: 'value', default: 0.8},
Daniel@0 18356 gravity: {type: 'value', default: 0.1},
Daniel@0 18357 alpha: {type: 'value', default: 0.1},
Daniel@0 18358 iterations: {type: 'value', default: 500},
Daniel@0 18359
Daniel@0 18360 interactive: {type: 'value', default: this._interactive},
Daniel@0 18361 active: {type: 'value', default: this._prev},
Daniel@0 18362 fixed: {type: 'data'}
Daniel@0 18363 });
Daniel@0 18364
Daniel@0 18365 this._output = {
Daniel@0 18366 'x': 'layout_x',
Daniel@0 18367 'y': 'layout_y'
Daniel@0 18368 };
Daniel@0 18369
Daniel@0 18370 return this.mutates(true);
Daniel@0 18371 }
Daniel@0 18372
Daniel@0 18373 var prototype = (Force.prototype = Object.create(Transform.prototype));
Daniel@0 18374 prototype.constructor = Force;
Daniel@0 18375
Daniel@0 18376 prototype.transform = function(nodeInput, reset) {
Daniel@0 18377 log.debug(nodeInput, ['force']);
Daniel@0 18378 reset = reset - (nodeInput.signals.active ? 1 : 0);
Daniel@0 18379
Daniel@0 18380 // get variables
Daniel@0 18381 var interactive = this.param('interactive'),
Daniel@0 18382 linkSource = this.param('links').source,
Daniel@0 18383 linkInput = linkSource.last(),
Daniel@0 18384 active = this.param('active'),
Daniel@0 18385 output = this._output,
Daniel@0 18386 layout = this._layout,
Daniel@0 18387 nodes = this._nodes,
Daniel@0 18388 links = this._links;
Daniel@0 18389
Daniel@0 18390 // configure nodes, links and layout
Daniel@0 18391 if (linkInput.stamp < nodeInput.stamp) linkInput = null;
Daniel@0 18392 this.configure(nodeInput, linkInput, interactive, reset);
Daniel@0 18393
Daniel@0 18394 // run batch layout
Daniel@0 18395 if (!interactive) {
Daniel@0 18396 var iterations = this.param('iterations');
Daniel@0 18397 for (var i=0; i<iterations; ++i) layout.tick();
Daniel@0 18398 layout.stop();
Daniel@0 18399 }
Daniel@0 18400
Daniel@0 18401 // update node positions
Daniel@0 18402 this.update(active);
Daniel@0 18403
Daniel@0 18404 // re-up alpha on parameter change
Daniel@0 18405 if (reset || active !== this._prev && active && active.update) {
Daniel@0 18406 layout.alpha(this.param('alpha')); // re-start layout
Daniel@0 18407 }
Daniel@0 18408
Daniel@0 18409 // update active node status,
Daniel@0 18410 if (active !== this._prev) {
Daniel@0 18411 this._prev = active;
Daniel@0 18412 }
Daniel@0 18413
Daniel@0 18414 // process removed nodes or edges
Daniel@0 18415 if (nodeInput.rem.length) {
Daniel@0 18416 layout.nodes(this._nodes = Tuple.idFilter(nodes, nodeInput.rem));
Daniel@0 18417 }
Daniel@0 18418 if (linkInput && linkInput.rem.length) {
Daniel@0 18419 layout.links(this._links = Tuple.idFilter(links, linkInput.rem));
Daniel@0 18420 }
Daniel@0 18421
Daniel@0 18422 // return changeset
Daniel@0 18423 nodeInput.fields[output.x] = 1;
Daniel@0 18424 nodeInput.fields[output.y] = 1;
Daniel@0 18425 return nodeInput;
Daniel@0 18426 };
Daniel@0 18427
Daniel@0 18428 prototype.configure = function(nodeInput, linkInput, interactive, reset) {
Daniel@0 18429 // check if we need to run configuration
Daniel@0 18430 var layout = this._layout,
Daniel@0 18431 update = this._setup || nodeInput.add.length ||
Daniel@0 18432 linkInput && linkInput.add.length ||
Daniel@0 18433 interactive !== this._interactive ||
Daniel@0 18434 this.param('charge') !== layout.charge() ||
Daniel@0 18435 this.param('linkStrength') !== layout.linkStrength() ||
Daniel@0 18436 this.param('linkDistance') !== layout.linkDistance();
Daniel@0 18437
Daniel@0 18438 if (update || reset) {
Daniel@0 18439 // a parameter changed, so update tick-only parameters
Daniel@0 18440 layout
Daniel@0 18441 .size(this.param('size'))
Daniel@0 18442 .chargeDistance(this.param('chargeDistance'))
Daniel@0 18443 .theta(this.param('theta'))
Daniel@0 18444 .gravity(this.param('gravity'))
Daniel@0 18445 .friction(this.param('friction'));
Daniel@0 18446 }
Daniel@0 18447
Daniel@0 18448 if (!update) return; // if no more updates needed, return now
Daniel@0 18449
Daniel@0 18450 this._setup = false;
Daniel@0 18451 this._interactive = interactive;
Daniel@0 18452
Daniel@0 18453 var force = this,
Daniel@0 18454 graph = this._graph,
Daniel@0 18455 nodes = this._nodes,
Daniel@0 18456 links = this._links, a, i;
Daniel@0 18457
Daniel@0 18458 // process added nodes
Daniel@0 18459 for (a=nodeInput.add, i=0; i<a.length; ++i) {
Daniel@0 18460 nodes.push({tuple: a[i]});
Daniel@0 18461 }
Daniel@0 18462
Daniel@0 18463 // process added edges
Daniel@0 18464 if (linkInput) for (a=linkInput.add, i=0; i<a.length; ++i) {
Daniel@0 18465 // TODO add configurable source/target accessors
Daniel@0 18466 // TODO support lookup by node id
Daniel@0 18467 // TODO process 'mod' of edge source or target?
Daniel@0 18468 links.push({
Daniel@0 18469 tuple: a[i],
Daniel@0 18470 source: nodes[a[i].source],
Daniel@0 18471 target: nodes[a[i].target]
Daniel@0 18472 });
Daniel@0 18473 }
Daniel@0 18474
Daniel@0 18475 // setup handler for force layout tick events
Daniel@0 18476 var tickHandler = !interactive ? null : function() {
Daniel@0 18477 // re-schedule the transform, force reflow
Daniel@0 18478 graph.propagate(ChangeSet.create(null, true), force);
Daniel@0 18479 };
Daniel@0 18480
Daniel@0 18481 // configure the rest of the layout
Daniel@0 18482 layout
Daniel@0 18483 .linkStrength(this.param('linkStrength'))
Daniel@0 18484 .linkDistance(this.param('linkDistance'))
Daniel@0 18485 .charge(this.param('charge'))
Daniel@0 18486 .nodes(nodes)
Daniel@0 18487 .links(links)
Daniel@0 18488 .on('tick', tickHandler)
Daniel@0 18489 .start().alpha(this.param('alpha'));
Daniel@0 18490 };
Daniel@0 18491
Daniel@0 18492 prototype.update = function(active) {
Daniel@0 18493 var output = this._output,
Daniel@0 18494 bound = this.param('bound'),
Daniel@0 18495 fixed = this.param('fixed'),
Daniel@0 18496 size = this.param('size'),
Daniel@0 18497 nodes = this._nodes,
Daniel@0 18498 lut = {}, id, i, n, t, x, y;
Daniel@0 18499
Daniel@0 18500 if (fixed && fixed.source) {
Daniel@0 18501 // TODO: could cache and update as needed?
Daniel@0 18502 fixed = fixed.source.values();
Daniel@0 18503 for (i=0, n=fixed.length; i<n; ++i) {
Daniel@0 18504 lut[fixed[i].id] = 1;
Daniel@0 18505 }
Daniel@0 18506 }
Daniel@0 18507
Daniel@0 18508 for (i=0; i<nodes.length; ++i) {
Daniel@0 18509 n = nodes[i];
Daniel@0 18510 t = n.tuple;
Daniel@0 18511 id = t._id;
Daniel@0 18512
Daniel@0 18513 if (active && active.id === id) {
Daniel@0 18514 n.fixed = 1;
Daniel@0 18515 if (active.update) {
Daniel@0 18516 n.x = n.px = active.x;
Daniel@0 18517 n.y = n.py = active.y;
Daniel@0 18518 }
Daniel@0 18519 } else {
Daniel@0 18520 n.fixed = lut[id] || 0;
Daniel@0 18521 }
Daniel@0 18522
Daniel@0 18523 x = bound ? Math.max(0, Math.min(n.x, size[0])) : n.x;
Daniel@0 18524 y = bound ? Math.max(0, Math.min(n.y, size[1])) : n.y;
Daniel@0 18525 Tuple.set(t, output.x, x);
Daniel@0 18526 Tuple.set(t, output.y, y);
Daniel@0 18527 }
Daniel@0 18528 };
Daniel@0 18529
Daniel@0 18530 module.exports = Force;
Daniel@0 18531 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
Daniel@0 18532
Daniel@0 18533 },{"./Transform":135,"vega-dataflow":39,"vega-logging":45}],126:[function(require,module,exports){
Daniel@0 18534 var df = require('vega-dataflow'),
Daniel@0 18535 Tuple = df.Tuple,
Daniel@0 18536 SIGNALS = df.Dependencies.SIGNALS,
Daniel@0 18537 log = require('vega-logging'),
Daniel@0 18538 Transform = require('./Transform');
Daniel@0 18539
Daniel@0 18540 function Formula(graph) {
Daniel@0 18541 Transform.prototype.init.call(this, graph);
Daniel@0 18542 Transform.addParameters(this, {
Daniel@0 18543 field: {type: 'value'},
Daniel@0 18544 expr: {type: 'expr'}
Daniel@0 18545 });
Daniel@0 18546
Daniel@0 18547 return this.mutates(true);
Daniel@0 18548 }
Daniel@0 18549
Daniel@0 18550 var prototype = (Formula.prototype = Object.create(Transform.prototype));
Daniel@0 18551 prototype.constructor = Formula;
Daniel@0 18552
Daniel@0 18553 prototype.transform = function(input) {
Daniel@0 18554 log.debug(input, ['formulating']);
Daniel@0 18555
Daniel@0 18556 var g = this._graph,
Daniel@0 18557 field = this.param('field'),
Daniel@0 18558 expr = this.param('expr'),
Daniel@0 18559 signals = g.values(SIGNALS, this.dependency(SIGNALS));
Daniel@0 18560
Daniel@0 18561 function set(x) {
Daniel@0 18562 Tuple.set(x, field, expr(x, null, signals));
Daniel@0 18563 }
Daniel@0 18564
Daniel@0 18565 input.add.forEach(set);
Daniel@0 18566
Daniel@0 18567 if (this.reevaluate(input)) {
Daniel@0 18568 input.mod.forEach(set);
Daniel@0 18569 }
Daniel@0 18570
Daniel@0 18571 input.fields[field] = 1;
Daniel@0 18572 return input;
Daniel@0 18573 };
Daniel@0 18574
Daniel@0 18575 module.exports = Formula;
Daniel@0 18576 },{"./Transform":135,"vega-dataflow":39,"vega-logging":45}],127:[function(require,module,exports){
Daniel@0 18577 (function (global){
Daniel@0 18578 var d3 = (typeof window !== "undefined" ? window['d3'] : typeof global !== "undefined" ? global['d3'] : null),
Daniel@0 18579 dl = require('datalib'),
Daniel@0 18580 Tuple = require('vega-dataflow').Tuple,
Daniel@0 18581 log = require('vega-logging'),
Daniel@0 18582 Transform = require('./Transform');
Daniel@0 18583
Daniel@0 18584 function Geo(graph) {
Daniel@0 18585 Transform.prototype.init.call(this, graph);
Daniel@0 18586 Transform.addParameters(this, Geo.Parameters);
Daniel@0 18587 Transform.addParameters(this, {
Daniel@0 18588 lon: {type: 'field'},
Daniel@0 18589 lat: {type: 'field'}
Daniel@0 18590 });
Daniel@0 18591
Daniel@0 18592 this._output = {
Daniel@0 18593 'x': 'layout_x',
Daniel@0 18594 'y': 'layout_y'
Daniel@0 18595 };
Daniel@0 18596 return this.mutates(true);
Daniel@0 18597 }
Daniel@0 18598
Daniel@0 18599 Geo.Parameters = {
Daniel@0 18600 projection: {type: 'value', default: 'mercator'},
Daniel@0 18601 center: {type: 'array<value>'},
Daniel@0 18602 translate: {type: 'array<value>'},
Daniel@0 18603 rotate: {type: 'array<value>'},
Daniel@0 18604 scale: {type: 'value'},
Daniel@0 18605 precision: {type: 'value'},
Daniel@0 18606 clipAngle: {type: 'value'},
Daniel@0 18607 clipExtent: {type: 'value'}
Daniel@0 18608 };
Daniel@0 18609
Daniel@0 18610 Geo.d3Projection = function() {
Daniel@0 18611 var p = this.param('projection'),
Daniel@0 18612 param = Geo.Parameters,
Daniel@0 18613 proj, name, value;
Daniel@0 18614
Daniel@0 18615 if (p !== this._mode) {
Daniel@0 18616 this._mode = p;
Daniel@0 18617 this._projection = d3.geo[p]();
Daniel@0 18618 }
Daniel@0 18619 proj = this._projection;
Daniel@0 18620
Daniel@0 18621 for (name in param) {
Daniel@0 18622 if (name === 'projection' || !proj[name]) continue;
Daniel@0 18623 value = this.param(name);
Daniel@0 18624 if (value === undefined || (dl.isArray(value) && value.length === 0)) {
Daniel@0 18625 continue;
Daniel@0 18626 }
Daniel@0 18627 if (value !== proj[name]()) {
Daniel@0 18628 proj[name](value);
Daniel@0 18629 }
Daniel@0 18630 }
Daniel@0 18631
Daniel@0 18632 return proj;
Daniel@0 18633 };
Daniel@0 18634
Daniel@0 18635 var prototype = (Geo.prototype = Object.create(Transform.prototype));
Daniel@0 18636 prototype.constructor = Geo;
Daniel@0 18637
Daniel@0 18638 prototype.transform = function(input) {
Daniel@0 18639 log.debug(input, ['geo']);
Daniel@0 18640
Daniel@0 18641 var output = this._output,
Daniel@0 18642 lon = this.param('lon').accessor,
Daniel@0 18643 lat = this.param('lat').accessor,
Daniel@0 18644 proj = Geo.d3Projection.call(this);
Daniel@0 18645
Daniel@0 18646 function set(t) {
Daniel@0 18647 var ll = [lon(t), lat(t)];
Daniel@0 18648 var xy = proj(ll) || [null, null];
Daniel@0 18649 Tuple.set(t, output.x, xy[0]);
Daniel@0 18650 Tuple.set(t, output.y, xy[1]);
Daniel@0 18651 }
Daniel@0 18652
Daniel@0 18653 input.add.forEach(set);
Daniel@0 18654 if (this.reevaluate(input)) {
Daniel@0 18655 input.mod.forEach(set);
Daniel@0 18656 input.rem.forEach(set);
Daniel@0 18657 }
Daniel@0 18658
Daniel@0 18659 input.fields[output.x] = 1;
Daniel@0 18660 input.fields[output.y] = 1;
Daniel@0 18661 return input;
Daniel@0 18662 };
Daniel@0 18663
Daniel@0 18664 module.exports = Geo;
Daniel@0 18665 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
Daniel@0 18666
Daniel@0 18667 },{"./Transform":135,"datalib":24,"vega-dataflow":39,"vega-logging":45}],128:[function(require,module,exports){
Daniel@0 18668 (function (global){
Daniel@0 18669 var d3 = (typeof window !== "undefined" ? window['d3'] : typeof global !== "undefined" ? global['d3'] : null),
Daniel@0 18670 dl = require('datalib'),
Daniel@0 18671 Tuple = require('vega-dataflow').Tuple,
Daniel@0 18672 log = require('vega-logging'),
Daniel@0 18673 Geo = require('./Geo'),
Daniel@0 18674 Transform = require('./Transform');
Daniel@0 18675
Daniel@0 18676 function GeoPath(graph) {
Daniel@0 18677 Transform.prototype.init.call(this, graph);
Daniel@0 18678 Transform.addParameters(this, Geo.Parameters);
Daniel@0 18679 Transform.addParameters(this, {
Daniel@0 18680 field: {type: 'field', default: null},
Daniel@0 18681 });
Daniel@0 18682
Daniel@0 18683 this._output = {
Daniel@0 18684 'path': 'layout_path'
Daniel@0 18685 };
Daniel@0 18686 return this.mutates(true);
Daniel@0 18687 }
Daniel@0 18688
Daniel@0 18689 var prototype = (GeoPath.prototype = Object.create(Transform.prototype));
Daniel@0 18690 prototype.constructor = GeoPath;
Daniel@0 18691
Daniel@0 18692 prototype.transform = function(input) {
Daniel@0 18693 log.debug(input, ['geopath']);
Daniel@0 18694
Daniel@0 18695 var output = this._output,
Daniel@0 18696 geojson = this.param('field').accessor || dl.identity,
Daniel@0 18697 proj = Geo.d3Projection.call(this),
Daniel@0 18698 path = d3.geo.path().projection(proj);
Daniel@0 18699
Daniel@0 18700 function set(t) {
Daniel@0 18701 Tuple.set(t, output.path, path(geojson(t)));
Daniel@0 18702 }
Daniel@0 18703
Daniel@0 18704 input.add.forEach(set);
Daniel@0 18705 if (this.reevaluate(input)) {
Daniel@0 18706 input.mod.forEach(set);
Daniel@0 18707 input.rem.forEach(set);
Daniel@0 18708 }
Daniel@0 18709
Daniel@0 18710 input.fields[output.path] = 1;
Daniel@0 18711 return input;
Daniel@0 18712 };
Daniel@0 18713
Daniel@0 18714 module.exports = GeoPath;
Daniel@0 18715 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
Daniel@0 18716
Daniel@0 18717 },{"./Geo":127,"./Transform":135,"datalib":24,"vega-dataflow":39,"vega-logging":45}],129:[function(require,module,exports){
Daniel@0 18718 var Tuple = require('vega-dataflow').Tuple,
Daniel@0 18719 log = require('vega-logging'),
Daniel@0 18720 Transform = require('./Transform');
Daniel@0 18721
Daniel@0 18722 function LinkPath(graph) {
Daniel@0 18723 Transform.prototype.init.call(this, graph);
Daniel@0 18724 Transform.addParameters(this, {
Daniel@0 18725 sourceX: {type: 'field', default: '_source.layout_x'},
Daniel@0 18726 sourceY: {type: 'field', default: '_source.layout_y'},
Daniel@0 18727 targetX: {type: 'field', default: '_target.layout_x'},
Daniel@0 18728 targetY: {type: 'field', default: '_target.layout_y'},
Daniel@0 18729 tension: {type: 'value', default: 0.2},
Daniel@0 18730 shape: {type: 'value', default: 'line'}
Daniel@0 18731 });
Daniel@0 18732
Daniel@0 18733 this._output = {'path': 'layout_path'};
Daniel@0 18734 return this.mutates(true);
Daniel@0 18735 }
Daniel@0 18736
Daniel@0 18737 var prototype = (LinkPath.prototype = Object.create(Transform.prototype));
Daniel@0 18738 prototype.constructor = LinkPath;
Daniel@0 18739
Daniel@0 18740 function line(sx, sy, tx, ty) {
Daniel@0 18741 return 'M' + sx + ',' + sy +
Daniel@0 18742 'L' + tx + ',' + ty;
Daniel@0 18743 }
Daniel@0 18744
Daniel@0 18745 function curve(sx, sy, tx, ty, tension) {
Daniel@0 18746 var dx = tx - sx,
Daniel@0 18747 dy = ty - sy,
Daniel@0 18748 ix = tension * (dx + dy),
Daniel@0 18749 iy = tension * (dy - dx);
Daniel@0 18750 return 'M' + sx + ',' + sy +
Daniel@0 18751 'C' + (sx+ix) + ',' + (sy+iy) +
Daniel@0 18752 ' ' + (tx+iy) + ',' + (ty-ix) +
Daniel@0 18753 ' ' + tx + ',' + ty;
Daniel@0 18754 }
Daniel@0 18755
Daniel@0 18756 function diagonalX(sx, sy, tx, ty) {
Daniel@0 18757 var m = (sx + tx) / 2;
Daniel@0 18758 return 'M' + sx + ',' + sy +
Daniel@0 18759 'C' + m + ',' + sy +
Daniel@0 18760 ' ' + m + ',' + ty +
Daniel@0 18761 ' ' + tx + ',' + ty;
Daniel@0 18762 }
Daniel@0 18763
Daniel@0 18764 function diagonalY(sx, sy, tx, ty) {
Daniel@0 18765 var m = (sy + ty) / 2;
Daniel@0 18766 return 'M' + sx + ',' + sy +
Daniel@0 18767 'C' + sx + ',' + m +
Daniel@0 18768 ' ' + tx + ',' + m +
Daniel@0 18769 ' ' + tx + ',' + ty;
Daniel@0 18770 }
Daniel@0 18771
Daniel@0 18772 var shapes = {
Daniel@0 18773 line: line,
Daniel@0 18774 curve: curve,
Daniel@0 18775 diagonal: diagonalX,
Daniel@0 18776 diagonalX: diagonalX,
Daniel@0 18777 diagonalY: diagonalY
Daniel@0 18778 };
Daniel@0 18779
Daniel@0 18780 prototype.transform = function(input) {
Daniel@0 18781 log.debug(input, ['linkpath']);
Daniel@0 18782
Daniel@0 18783 var output = this._output,
Daniel@0 18784 shape = shapes[this.param('shape')] || shapes.line,
Daniel@0 18785 sourceX = this.param('sourceX').accessor,
Daniel@0 18786 sourceY = this.param('sourceY').accessor,
Daniel@0 18787 targetX = this.param('targetX').accessor,
Daniel@0 18788 targetY = this.param('targetY').accessor,
Daniel@0 18789 tension = this.param('tension');
Daniel@0 18790
Daniel@0 18791 function set(t) {
Daniel@0 18792 var path = shape(sourceX(t), sourceY(t), targetX(t), targetY(t), tension);
Daniel@0 18793 Tuple.set(t, output.path, path);
Daniel@0 18794 }
Daniel@0 18795
Daniel@0 18796 input.add.forEach(set);
Daniel@0 18797 if (this.reevaluate(input)) {
Daniel@0 18798 input.mod.forEach(set);
Daniel@0 18799 input.rem.forEach(set);
Daniel@0 18800 }
Daniel@0 18801
Daniel@0 18802 input.fields[output.path] = 1;
Daniel@0 18803 return input;
Daniel@0 18804 };
Daniel@0 18805
Daniel@0 18806 module.exports = LinkPath;
Daniel@0 18807 },{"./Transform":135,"vega-dataflow":39,"vega-logging":45}],130:[function(require,module,exports){
Daniel@0 18808 var Tuple = require('vega-dataflow').Tuple,
Daniel@0 18809 log = require('vega-logging'),
Daniel@0 18810 Transform = require('./Transform');
Daniel@0 18811
Daniel@0 18812 function Lookup(graph) {
Daniel@0 18813 Transform.prototype.init.call(this, graph);
Daniel@0 18814 Transform.addParameters(this, {
Daniel@0 18815 on: {type: 'data'},
Daniel@0 18816 onKey: {type: 'field', default: null},
Daniel@0 18817 as: {type: 'array<value>'},
Daniel@0 18818 keys: {type: 'array<field>', default: ['data']},
Daniel@0 18819 default: {type: 'value'}
Daniel@0 18820 });
Daniel@0 18821
Daniel@0 18822 return this.mutates(true);
Daniel@0 18823 }
Daniel@0 18824
Daniel@0 18825 var prototype = (Lookup.prototype = Object.create(Transform.prototype));
Daniel@0 18826 prototype.constructor = Lookup;
Daniel@0 18827
Daniel@0 18828 prototype.transform = function(input, reset) {
Daniel@0 18829 log.debug(input, ['lookup']);
Daniel@0 18830
Daniel@0 18831 var on = this.param('on'),
Daniel@0 18832 onLast = on.source.last(),
Daniel@0 18833 onData = on.source.values(),
Daniel@0 18834 onKey = this.param('onKey'),
Daniel@0 18835 onF = onKey.field,
Daniel@0 18836 keys = this.param('keys'),
Daniel@0 18837 get = keys.accessor,
Daniel@0 18838 as = this.param('as'),
Daniel@0 18839 defaultValue = this.param('default'),
Daniel@0 18840 lut = this._lut,
Daniel@0 18841 i, v;
Daniel@0 18842
Daniel@0 18843 // build lookup table on init, withKey modified, or tuple add/rem
Daniel@0 18844 if (lut == null || this._on !== onF || onF && onLast.fields[onF] ||
Daniel@0 18845 onLast.add.length || onLast.rem.length)
Daniel@0 18846 {
Daniel@0 18847 if (onF) { // build hash from withKey field
Daniel@0 18848 onKey = onKey.accessor;
Daniel@0 18849 for (lut={}, i=0; i<onData.length; ++i) {
Daniel@0 18850 lut[onKey(v = onData[i])] = v;
Daniel@0 18851 }
Daniel@0 18852 } else { // otherwise, use index-based lookup
Daniel@0 18853 lut = onData;
Daniel@0 18854 }
Daniel@0 18855 this._lut = lut;
Daniel@0 18856 this._on = onF;
Daniel@0 18857 reset = true;
Daniel@0 18858 }
Daniel@0 18859
Daniel@0 18860 function set(t) {
Daniel@0 18861 for (var i=0; i<get.length; ++i) {
Daniel@0 18862 var v = lut[get[i](t)] || defaultValue;
Daniel@0 18863 Tuple.set(t, as[i], v);
Daniel@0 18864 }
Daniel@0 18865 }
Daniel@0 18866
Daniel@0 18867 input.add.forEach(set);
Daniel@0 18868 var run = keys.field.some(function(f) { return input.fields[f]; });
Daniel@0 18869 if (run || reset) {
Daniel@0 18870 input.mod.forEach(set);
Daniel@0 18871 input.rem.forEach(set);
Daniel@0 18872 }
Daniel@0 18873
Daniel@0 18874 as.forEach(function(k) { input.fields[k] = 1; });
Daniel@0 18875 return input;
Daniel@0 18876 };
Daniel@0 18877
Daniel@0 18878 module.exports = Lookup;
Daniel@0 18879 },{"./Transform":135,"vega-dataflow":39,"vega-logging":45}],131:[function(require,module,exports){
Daniel@0 18880 var dl = require('datalib'),
Daniel@0 18881 Deps = require('vega-dataflow').Dependencies,
Daniel@0 18882 expr = require('../parse/expr');
Daniel@0 18883
Daniel@0 18884 var arrayType = /array/i,
Daniel@0 18885 dataType = /data/i,
Daniel@0 18886 fieldType = /field/i,
Daniel@0 18887 exprType = /expr/i,
Daniel@0 18888 valType = /value/i;
Daniel@0 18889
Daniel@0 18890 function Parameter(name, type, transform) {
Daniel@0 18891 this._name = name;
Daniel@0 18892 this._type = type;
Daniel@0 18893 this._transform = transform;
Daniel@0 18894
Daniel@0 18895 // If parameter is defined w/signals, it must be resolved
Daniel@0 18896 // on every pulse.
Daniel@0 18897 this._value = [];
Daniel@0 18898 this._accessors = [];
Daniel@0 18899 this._resolution = false;
Daniel@0 18900 this._signals = {};
Daniel@0 18901 }
Daniel@0 18902
Daniel@0 18903 var prototype = Parameter.prototype;
Daniel@0 18904
Daniel@0 18905 function get() {
Daniel@0 18906 var isArray = arrayType.test(this._type),
Daniel@0 18907 isData = dataType.test(this._type),
Daniel@0 18908 isField = fieldType.test(this._type);
Daniel@0 18909
Daniel@0 18910 var val = isArray ? this._value : this._value[0],
Daniel@0 18911 acc = isArray ? this._accessors : this._accessors[0];
Daniel@0 18912
Daniel@0 18913 if (!dl.isValid(acc) && valType.test(this._type)) {
Daniel@0 18914 return val;
Daniel@0 18915 } else {
Daniel@0 18916 return isData ? { name: val, source: acc } :
Daniel@0 18917 isField ? { field: val, accessor: acc } : val;
Daniel@0 18918 }
Daniel@0 18919 }
Daniel@0 18920
Daniel@0 18921 prototype.get = function() {
Daniel@0 18922 var graph = this._transform._graph,
Daniel@0 18923 isData = dataType.test(this._type),
Daniel@0 18924 isField = fieldType.test(this._type),
Daniel@0 18925 s, idx, val;
Daniel@0 18926
Daniel@0 18927 // If we don't require resolution, return the value immediately.
Daniel@0 18928 if (!this._resolution) return get.call(this);
Daniel@0 18929
Daniel@0 18930 if (isData) {
Daniel@0 18931 this._accessors = this._value.map(function(v) { return graph.data(v); });
Daniel@0 18932 return get.call(this); // TODO: support signal as dataTypes
Daniel@0 18933 }
Daniel@0 18934
Daniel@0 18935 for (s in this._signals) {
Daniel@0 18936 idx = this._signals[s];
Daniel@0 18937 val = graph.signalRef(s);
Daniel@0 18938
Daniel@0 18939 if (isField) {
Daniel@0 18940 this._accessors[idx] = this._value[idx] != val ?
Daniel@0 18941 dl.accessor(val) : this._accessors[idx];
Daniel@0 18942 }
Daniel@0 18943
Daniel@0 18944 this._value[idx] = val;
Daniel@0 18945 }
Daniel@0 18946
Daniel@0 18947 return get.call(this);
Daniel@0 18948 };
Daniel@0 18949
Daniel@0 18950 prototype.set = function(value) {
Daniel@0 18951 var p = this,
Daniel@0 18952 isExpr = exprType.test(this._type),
Daniel@0 18953 isData = dataType.test(this._type),
Daniel@0 18954 isField = fieldType.test(this._type);
Daniel@0 18955
Daniel@0 18956 this._value = dl.array(value).map(function(v, i) {
Daniel@0 18957 if (dl.isString(v)) {
Daniel@0 18958 if (isExpr) {
Daniel@0 18959 var e = expr(v);
Daniel@0 18960 p._transform.dependency(Deps.FIELDS, e.fields);
Daniel@0 18961 p._transform.dependency(Deps.SIGNALS, e.globals);
Daniel@0 18962 return e.fn;
Daniel@0 18963 } else if (isField) { // Backwards compatibility
Daniel@0 18964 p._accessors[i] = dl.accessor(v);
Daniel@0 18965 p._transform.dependency(Deps.FIELDS, dl.field(v));
Daniel@0 18966 } else if (isData) {
Daniel@0 18967 p._resolution = true;
Daniel@0 18968 p._transform.dependency(Deps.DATA, v);
Daniel@0 18969 }
Daniel@0 18970 return v;
Daniel@0 18971 } else if (v.value !== undefined) {
Daniel@0 18972 return v.value;
Daniel@0 18973 } else if (v.field !== undefined) {
Daniel@0 18974 p._accessors[i] = dl.accessor(v.field);
Daniel@0 18975 p._transform.dependency(Deps.FIELDS, dl.field(v.field));
Daniel@0 18976 return v.field;
Daniel@0 18977 } else if (v.signal !== undefined) {
Daniel@0 18978 p._resolution = true;
Daniel@0 18979 p._signals[v.signal] = i;
Daniel@0 18980 p._transform.dependency(Deps.SIGNALS, v.signal);
Daniel@0 18981 return v.signal;
Daniel@0 18982 }
Daniel@0 18983
Daniel@0 18984 return v;
Daniel@0 18985 });
Daniel@0 18986
Daniel@0 18987 return p._transform;
Daniel@0 18988 };
Daniel@0 18989
Daniel@0 18990 module.exports = Parameter;
Daniel@0 18991 },{"../parse/expr":94,"datalib":24,"vega-dataflow":39}],132:[function(require,module,exports){
Daniel@0 18992 var dl = require('datalib'),
Daniel@0 18993 Tuple = require('vega-dataflow').Tuple,
Daniel@0 18994 log = require('vega-logging'),
Daniel@0 18995 Transform = require('./Transform'),
Daniel@0 18996 BatchTransform = require('./BatchTransform');
Daniel@0 18997
Daniel@0 18998 function Pie(graph) {
Daniel@0 18999 BatchTransform.prototype.init.call(this, graph);
Daniel@0 19000 Transform.addParameters(this, {
Daniel@0 19001 field: {type: 'field', default: null},
Daniel@0 19002 startAngle: {type: 'value', default: 0},
Daniel@0 19003 endAngle: {type: 'value', default: 2 * Math.PI},
Daniel@0 19004 sort: {type: 'value', default: false}
Daniel@0 19005 });
Daniel@0 19006
Daniel@0 19007 this._output = {
Daniel@0 19008 'start': 'layout_start',
Daniel@0 19009 'end': 'layout_end',
Daniel@0 19010 'mid': 'layout_mid'
Daniel@0 19011 };
Daniel@0 19012
Daniel@0 19013 return this.mutates(true);
Daniel@0 19014 }
Daniel@0 19015
Daniel@0 19016 var prototype = (Pie.prototype = Object.create(BatchTransform.prototype));
Daniel@0 19017 prototype.constructor = Pie;
Daniel@0 19018
Daniel@0 19019 function ones() { return 1; }
Daniel@0 19020
Daniel@0 19021 prototype.batchTransform = function(input, data) {
Daniel@0 19022 log.debug(input, ['pie']);
Daniel@0 19023
Daniel@0 19024 var output = this._output,
Daniel@0 19025 field = this.param('field').accessor || ones,
Daniel@0 19026 start = this.param('startAngle'),
Daniel@0 19027 stop = this.param('endAngle'),
Daniel@0 19028 sort = this.param('sort');
Daniel@0 19029
Daniel@0 19030 var values = data.map(field),
Daniel@0 19031 a = start,
Daniel@0 19032 k = (stop - start) / dl.sum(values),
Daniel@0 19033 index = dl.range(data.length),
Daniel@0 19034 i, t, v;
Daniel@0 19035
Daniel@0 19036 if (sort) {
Daniel@0 19037 index.sort(function(a, b) {
Daniel@0 19038 return values[a] - values[b];
Daniel@0 19039 });
Daniel@0 19040 }
Daniel@0 19041
Daniel@0 19042 for (i=0; i<index.length; ++i) {
Daniel@0 19043 t = data[index[i]];
Daniel@0 19044 v = values[index[i]];
Daniel@0 19045 Tuple.set(t, output.start, a);
Daniel@0 19046 Tuple.set(t, output.mid, (a + 0.5 * v * k));
Daniel@0 19047 Tuple.set(t, output.end, (a += v * k));
Daniel@0 19048 }
Daniel@0 19049
Daniel@0 19050 input.fields[output.start] = 1;
Daniel@0 19051 input.fields[output.end] = 1;
Daniel@0 19052 input.fields[output.mid] = 1;
Daniel@0 19053 return input;
Daniel@0 19054 };
Daniel@0 19055
Daniel@0 19056 module.exports = Pie;
Daniel@0 19057 },{"./BatchTransform":117,"./Transform":135,"datalib":24,"vega-dataflow":39,"vega-logging":45}],133:[function(require,module,exports){
Daniel@0 19058 var dl = require('datalib'),
Daniel@0 19059 log = require('vega-logging'),
Daniel@0 19060 Transform = require('./Transform');
Daniel@0 19061
Daniel@0 19062 function Sort(graph) {
Daniel@0 19063 Transform.prototype.init.call(this, graph);
Daniel@0 19064 Transform.addParameters(this, {by: {type: 'array<field>'} });
Daniel@0 19065 this.router(true);
Daniel@0 19066 }
Daniel@0 19067
Daniel@0 19068 var prototype = (Sort.prototype = Object.create(Transform.prototype));
Daniel@0 19069 prototype.constructor = Sort;
Daniel@0 19070
Daniel@0 19071 prototype.transform = function(input) {
Daniel@0 19072 log.debug(input, ['sorting']);
Daniel@0 19073
Daniel@0 19074 if (input.add.length || input.mod.length || input.rem.length) {
Daniel@0 19075 input.sort = dl.comparator(this.param('by').field);
Daniel@0 19076 }
Daniel@0 19077 return input;
Daniel@0 19078 };
Daniel@0 19079
Daniel@0 19080 module.exports = Sort;
Daniel@0 19081 },{"./Transform":135,"datalib":24,"vega-logging":45}],134:[function(require,module,exports){
Daniel@0 19082 var dl = require('datalib'),
Daniel@0 19083 Tuple = require('vega-dataflow').Tuple,
Daniel@0 19084 log = require('vega-logging'),
Daniel@0 19085 Transform = require('./Transform'),
Daniel@0 19086 BatchTransform = require('./BatchTransform');
Daniel@0 19087
Daniel@0 19088 function Stack(graph) {
Daniel@0 19089 BatchTransform.prototype.init.call(this, graph);
Daniel@0 19090 Transform.addParameters(this, {
Daniel@0 19091 groupby: {type: 'array<field>'},
Daniel@0 19092 sortby: {type: 'array<field>'},
Daniel@0 19093 field: {type: 'field'},
Daniel@0 19094 offset: {type: 'value', default: 'zero'}
Daniel@0 19095 });
Daniel@0 19096
Daniel@0 19097 this._output = {
Daniel@0 19098 'start': 'layout_start',
Daniel@0 19099 'end': 'layout_end',
Daniel@0 19100 'mid': 'layout_mid'
Daniel@0 19101 };
Daniel@0 19102 return this.mutates(true);
Daniel@0 19103 }
Daniel@0 19104
Daniel@0 19105 var prototype = (Stack.prototype = Object.create(BatchTransform.prototype));
Daniel@0 19106 prototype.constructor = Stack;
Daniel@0 19107
Daniel@0 19108 prototype.batchTransform = function(input, data) {
Daniel@0 19109 log.debug(input, ['stacking']);
Daniel@0 19110
Daniel@0 19111 var groupby = this.param('groupby').accessor,
Daniel@0 19112 sortby = dl.comparator(this.param('sortby').field),
Daniel@0 19113 field = this.param('field').accessor,
Daniel@0 19114 offset = this.param('offset'),
Daniel@0 19115 output = this._output;
Daniel@0 19116
Daniel@0 19117 // partition, sum, and sort the stack groups
Daniel@0 19118 var groups = partition(data, groupby, sortby, field);
Daniel@0 19119
Daniel@0 19120 // compute stack layouts per group
Daniel@0 19121 for (var i=0, max=groups.max; i<groups.length; ++i) {
Daniel@0 19122 var group = groups[i],
Daniel@0 19123 sum = group.sum,
Daniel@0 19124 off = offset==='center' ? (max - sum)/2 : 0,
Daniel@0 19125 scale = offset==='normalize' ? (1/sum) : 1,
Daniel@0 19126 j, x, a, b = off, v = 0;
Daniel@0 19127
Daniel@0 19128 // set stack coordinates for each datum in group
Daniel@0 19129 for (j=0; j<group.length; ++j) {
Daniel@0 19130 x = group[j];
Daniel@0 19131 a = b; // use previous value for start point
Daniel@0 19132 v += field(x);
Daniel@0 19133 b = scale * v + off; // compute end point
Daniel@0 19134 Tuple.set(x, output.start, a);
Daniel@0 19135 Tuple.set(x, output.end, b);
Daniel@0 19136 Tuple.set(x, output.mid, 0.5 * (a + b));
Daniel@0 19137 }
Daniel@0 19138 }
Daniel@0 19139
Daniel@0 19140 input.fields[output.start] = 1;
Daniel@0 19141 input.fields[output.end] = 1;
Daniel@0 19142 input.fields[output.mid] = 1;
Daniel@0 19143 return input;
Daniel@0 19144 };
Daniel@0 19145
Daniel@0 19146 function partition(data, groupby, sortby, field) {
Daniel@0 19147 var groups = [],
Daniel@0 19148 get = function(f) { return f(x); },
Daniel@0 19149 map, i, x, k, g, s, max;
Daniel@0 19150
Daniel@0 19151 // partition data points into stack groups
Daniel@0 19152 if (groupby == null) {
Daniel@0 19153 groups.push(data.slice());
Daniel@0 19154 } else {
Daniel@0 19155 for (map={}, i=0; i<data.length; ++i) {
Daniel@0 19156 x = data[i];
Daniel@0 19157 k = groupby.map(get);
Daniel@0 19158 g = map[k] || (groups.push(map[k] = []), map[k]);
Daniel@0 19159 g.push(x);
Daniel@0 19160 }
Daniel@0 19161 }
Daniel@0 19162
Daniel@0 19163 // compute sums of groups, sort groups as needed
Daniel@0 19164 for (k=0, max=0; k<groups.length; ++k) {
Daniel@0 19165 g = groups[k];
Daniel@0 19166 for (i=0, s=0; i<g.length; ++i) {
Daniel@0 19167 s += field(g[i]);
Daniel@0 19168 }
Daniel@0 19169 g.sum = s;
Daniel@0 19170 if (s > max) max = s;
Daniel@0 19171 if (sortby != null) g.sort(sortby);
Daniel@0 19172 }
Daniel@0 19173 groups.max = max;
Daniel@0 19174
Daniel@0 19175 return groups;
Daniel@0 19176 }
Daniel@0 19177
Daniel@0 19178 module.exports = Stack;
Daniel@0 19179 },{"./BatchTransform":117,"./Transform":135,"datalib":24,"vega-dataflow":39,"vega-logging":45}],135:[function(require,module,exports){
Daniel@0 19180 var df = require('vega-dataflow'),
Daniel@0 19181 Base = df.Node.prototype, // jshint ignore:line
Daniel@0 19182 Deps = df.Dependencies,
Daniel@0 19183 Parameter = require('./Parameter');
Daniel@0 19184
Daniel@0 19185 function Transform(graph) {
Daniel@0 19186 if (graph) Base.init.call(this, graph);
Daniel@0 19187 }
Daniel@0 19188
Daniel@0 19189 Transform.addParameters = function(proto, params) {
Daniel@0 19190 proto._parameters = proto._parameters || {};
Daniel@0 19191 for (var name in params) {
Daniel@0 19192 var p = params[name],
Daniel@0 19193 param = new Parameter(name, p.type, proto);
Daniel@0 19194
Daniel@0 19195 proto._parameters[name] = param;
Daniel@0 19196
Daniel@0 19197 if (p.type === 'custom') {
Daniel@0 19198 if (p.set) param.set = p.set.bind(param);
Daniel@0 19199 if (p.get) param.get = p.get.bind(param);
Daniel@0 19200 }
Daniel@0 19201
Daniel@0 19202 if (p.hasOwnProperty('default')) param.set(p.default);
Daniel@0 19203 }
Daniel@0 19204 };
Daniel@0 19205
Daniel@0 19206 var prototype = (Transform.prototype = Object.create(Base));
Daniel@0 19207 prototype.constructor = Transform;
Daniel@0 19208
Daniel@0 19209 prototype.param = function(name, value) {
Daniel@0 19210 var param = this._parameters[name];
Daniel@0 19211 return (param === undefined) ? this :
Daniel@0 19212 (arguments.length === 1) ? param.get() : param.set(value);
Daniel@0 19213 };
Daniel@0 19214
Daniel@0 19215 // Perform transformation. Subclasses should override.
Daniel@0 19216 prototype.transform = function(input/*, reset */) {
Daniel@0 19217 return input;
Daniel@0 19218 };
Daniel@0 19219
Daniel@0 19220 prototype.evaluate = function(input) {
Daniel@0 19221 // Many transforms store caches that must be invalidated if
Daniel@0 19222 // a signal value has changed.
Daniel@0 19223 var reset = this._stamp < input.stamp &&
Daniel@0 19224 this.dependency(Deps.SIGNALS).reduce(function(c, s) {
Daniel@0 19225 return c += input.signals[s] ? 1 : 0;
Daniel@0 19226 }, 0);
Daniel@0 19227 return this.transform(input, reset);
Daniel@0 19228 };
Daniel@0 19229
Daniel@0 19230 prototype.output = function(map) {
Daniel@0 19231 for (var key in this._output) {
Daniel@0 19232 if (map[key] !== undefined) {
Daniel@0 19233 this._output[key] = map[key];
Daniel@0 19234 }
Daniel@0 19235 }
Daniel@0 19236 return this;
Daniel@0 19237 };
Daniel@0 19238
Daniel@0 19239 module.exports = Transform;
Daniel@0 19240 },{"./Parameter":131,"vega-dataflow":39}],136:[function(require,module,exports){
Daniel@0 19241 (function (global){
Daniel@0 19242 var d3 = (typeof window !== "undefined" ? window['d3'] : typeof global !== "undefined" ? global['d3'] : null),
Daniel@0 19243 dl = require('datalib'),
Daniel@0 19244 Tuple = require('vega-dataflow').Tuple,
Daniel@0 19245 log = require('vega-logging'),
Daniel@0 19246 Transform = require('./Transform'),
Daniel@0 19247 BatchTransform = require('./BatchTransform');
Daniel@0 19248
Daniel@0 19249 var defaultRatio = 0.5 * (1 + Math.sqrt(5));
Daniel@0 19250
Daniel@0 19251 function Treemap(graph) {
Daniel@0 19252 BatchTransform.prototype.init.call(this, graph);
Daniel@0 19253 Transform.addParameters(this, {
Daniel@0 19254 // hierarchy parameters
Daniel@0 19255 sort: {type: 'array<field>', default: ['-value']},
Daniel@0 19256 children: {type: 'field', default: 'children'},
Daniel@0 19257 field: {type: 'field', default: 'value'},
Daniel@0 19258 // treemap parameters
Daniel@0 19259 size: {type: 'array<value>', default: [500, 500]},
Daniel@0 19260 round: {type: 'value', default: true},
Daniel@0 19261 sticky: {type: 'value', default: false},
Daniel@0 19262 ratio: {type: 'value', default: defaultRatio},
Daniel@0 19263 padding: {type: 'value', default: null},
Daniel@0 19264 mode: {type: 'value', default: 'squarify'}
Daniel@0 19265 });
Daniel@0 19266
Daniel@0 19267 this._layout = d3.layout.treemap();
Daniel@0 19268
Daniel@0 19269 this._output = {
Daniel@0 19270 'x': 'layout_x',
Daniel@0 19271 'y': 'layout_y',
Daniel@0 19272 'width': 'layout_width',
Daniel@0 19273 'height': 'layout_height',
Daniel@0 19274 'depth': 'layout_depth',
Daniel@0 19275 };
Daniel@0 19276 return this.mutates(true);
Daniel@0 19277 }
Daniel@0 19278
Daniel@0 19279 var prototype = (Treemap.prototype = Object.create(BatchTransform.prototype));
Daniel@0 19280 prototype.constructor = Treemap;
Daniel@0 19281
Daniel@0 19282 prototype.batchTransform = function(input, data) {
Daniel@0 19283 log.debug(input, ['treemap']);
Daniel@0 19284
Daniel@0 19285 // get variables
Daniel@0 19286 var layout = this._layout,
Daniel@0 19287 output = this._output;
Daniel@0 19288
Daniel@0 19289 // configure layout
Daniel@0 19290 layout
Daniel@0 19291 .sort(dl.comparator(this.param('sort').field))
Daniel@0 19292 .children(this.param('children').accessor)
Daniel@0 19293 .value(this.param('field').accessor)
Daniel@0 19294 .size(this.param('size'))
Daniel@0 19295 .round(this.param('round'))
Daniel@0 19296 .sticky(this.param('sticky'))
Daniel@0 19297 .ratio(this.param('ratio'))
Daniel@0 19298 .padding(this.param('padding'))
Daniel@0 19299 .mode(this.param('mode'))
Daniel@0 19300 .nodes(data[0]);
Daniel@0 19301
Daniel@0 19302 // copy layout values to nodes
Daniel@0 19303 data.forEach(function(n) {
Daniel@0 19304 Tuple.set(n, output.x, n.x);
Daniel@0 19305 Tuple.set(n, output.y, n.y);
Daniel@0 19306 Tuple.set(n, output.width, n.dx);
Daniel@0 19307 Tuple.set(n, output.height, n.dy);
Daniel@0 19308 Tuple.set(n, output.depth, n.depth);
Daniel@0 19309 });
Daniel@0 19310
Daniel@0 19311 // return changeset
Daniel@0 19312 input.fields[output.x] = 1;
Daniel@0 19313 input.fields[output.y] = 1;
Daniel@0 19314 input.fields[output.width] = 1;
Daniel@0 19315 input.fields[output.height] = 1;
Daniel@0 19316 return input;
Daniel@0 19317 };
Daniel@0 19318
Daniel@0 19319 module.exports = Treemap;
Daniel@0 19320 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
Daniel@0 19321
Daniel@0 19322 },{"./BatchTransform":117,"./Transform":135,"datalib":24,"vega-dataflow":39,"vega-logging":45}],137:[function(require,module,exports){
Daniel@0 19323 (function (global){
Daniel@0 19324 var d3 = (typeof window !== "undefined" ? window['d3'] : typeof global !== "undefined" ? global['d3'] : null),
Daniel@0 19325 Tuple = require('vega-dataflow/src/Tuple'),
Daniel@0 19326 log = require('vega-logging'),
Daniel@0 19327 Transform = require('./Transform'),
Daniel@0 19328 BatchTransform = require('./BatchTransform');
Daniel@0 19329
Daniel@0 19330 function Voronoi(graph) {
Daniel@0 19331 BatchTransform.prototype.init.call(this, graph);
Daniel@0 19332 Transform.addParameters(this, {
Daniel@0 19333 clipExtent: {type: 'array<value>', default: [[-1e5,-1e5],[1e5,1e5]]},
Daniel@0 19334 x: {type: 'field', default: 'layout_x'},
Daniel@0 19335 y: {type: 'field', default: 'layout_y'}
Daniel@0 19336 });
Daniel@0 19337
Daniel@0 19338 this._layout = d3.geom.voronoi();
Daniel@0 19339 this._output = {'path': 'layout_path'};
Daniel@0 19340
Daniel@0 19341 return this.mutates(true);
Daniel@0 19342 }
Daniel@0 19343
Daniel@0 19344 var prototype = (Voronoi.prototype = Object.create(BatchTransform.prototype));
Daniel@0 19345 prototype.constructor = Voronoi;
Daniel@0 19346
Daniel@0 19347 prototype.batchTransform = function(input, data) {
Daniel@0 19348 log.debug(input, ['voronoi']);
Daniel@0 19349
Daniel@0 19350 // get variables
Daniel@0 19351 var pathname = this._output.path;
Daniel@0 19352
Daniel@0 19353 // configure layout
Daniel@0 19354 var polygons = this._layout
Daniel@0 19355 .clipExtent(this.param('clipExtent'))
Daniel@0 19356 .x(this.param('x').accessor)
Daniel@0 19357 .y(this.param('y').accessor)
Daniel@0 19358 (data);
Daniel@0 19359
Daniel@0 19360 // build and assign path strings
Daniel@0 19361 for (var i=0; i<data.length; ++i) {
Daniel@0 19362 Tuple.set(data[i], pathname, 'M' + polygons[i].join('L') + 'Z');
Daniel@0 19363 }
Daniel@0 19364
Daniel@0 19365 // return changeset
Daniel@0 19366 input.fields[pathname] = 1;
Daniel@0 19367 return input;
Daniel@0 19368 };
Daniel@0 19369
Daniel@0 19370 module.exports = Voronoi;
Daniel@0 19371 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
Daniel@0 19372
Daniel@0 19373 },{"./BatchTransform":117,"./Transform":135,"vega-dataflow/src/Tuple":38,"vega-logging":45}],138:[function(require,module,exports){
Daniel@0 19374 (function (global){
Daniel@0 19375 var dl = require('datalib'),
Daniel@0 19376 d3 = (typeof window !== "undefined" ? window['d3'] : typeof global !== "undefined" ? global['d3'] : null),
Daniel@0 19377 d3_cloud = (typeof window !== "undefined" ? window['d3']['layout']['cloud'] : typeof global !== "undefined" ? global['d3']['layout']['cloud'] : null),
Daniel@0 19378 Tuple = require('vega-dataflow/src/Tuple'),
Daniel@0 19379 log = require('vega-logging'),
Daniel@0 19380 Transform = require('./Transform'),
Daniel@0 19381 BatchTransform = require('./BatchTransform');
Daniel@0 19382
Daniel@0 19383 function Wordcloud(graph) {
Daniel@0 19384 BatchTransform.prototype.init.call(this, graph);
Daniel@0 19385 Transform.addParameters(this, {
Daniel@0 19386 size: {type: 'array<value>', default: [900, 500]},
Daniel@0 19387 text: {type: 'field', default: 'data'},
Daniel@0 19388 rotate: {type: 'field|value', default: 0},
Daniel@0 19389 font: {type: 'field|value', default: {value: 'sans-serif'}},
Daniel@0 19390 fontSize: {type: 'field|value', default: 14},
Daniel@0 19391 fontStyle: {type: 'field|value', default: {value: 'normal'}},
Daniel@0 19392 fontWeight: {type: 'field|value', default: {value: 'normal'}},
Daniel@0 19393 fontScale: {type: 'array<value>', default: [10, 50]},
Daniel@0 19394 padding: {type: 'value', default: 1},
Daniel@0 19395 spiral: {type: 'value', default: 'archimedean'}
Daniel@0 19396 });
Daniel@0 19397
Daniel@0 19398 this._layout = d3_cloud();
Daniel@0 19399
Daniel@0 19400 this._output = {
Daniel@0 19401 'x': 'layout_x',
Daniel@0 19402 'y': 'layout_y',
Daniel@0 19403 'font': 'layout_font',
Daniel@0 19404 'fontSize': 'layout_fontSize',
Daniel@0 19405 'fontStyle': 'layout_fontStyle',
Daniel@0 19406 'fontWeight': 'layout_fontWeight',
Daniel@0 19407 'rotate': 'layout_rotate',
Daniel@0 19408 };
Daniel@0 19409
Daniel@0 19410 return this.mutates(true);
Daniel@0 19411 }
Daniel@0 19412
Daniel@0 19413 var prototype = (Wordcloud.prototype = Object.create(BatchTransform.prototype));
Daniel@0 19414 prototype.constructor = Wordcloud;
Daniel@0 19415
Daniel@0 19416 function get(p) {
Daniel@0 19417 return (p && p.accessor) || p;
Daniel@0 19418 }
Daniel@0 19419
Daniel@0 19420 function wrap(tuple) {
Daniel@0 19421 var x = Object.create(tuple);
Daniel@0 19422 x._tuple = tuple;
Daniel@0 19423 return x;
Daniel@0 19424 }
Daniel@0 19425
Daniel@0 19426 prototype.batchTransform = function(input, data) {
Daniel@0 19427 log.debug(input, ['wordcloud']);
Daniel@0 19428
Daniel@0 19429 // get variables
Daniel@0 19430 var layout = this._layout,
Daniel@0 19431 output = this._output,
Daniel@0 19432 fontSize = this.param('fontSize'),
Daniel@0 19433 range = fontSize.accessor && this.param('fontScale'),
Daniel@0 19434 size, scale;
Daniel@0 19435 fontSize = fontSize.accessor || d3.functor(fontSize);
Daniel@0 19436
Daniel@0 19437 // create font size scaling function as needed
Daniel@0 19438 if (range.length) {
Daniel@0 19439 scale = d3.scale.sqrt()
Daniel@0 19440 .domain(dl.extent(data, size=fontSize))
Daniel@0 19441 .range(range);
Daniel@0 19442 fontSize = function(x) { return scale(size(x)); };
Daniel@0 19443 }
Daniel@0 19444
Daniel@0 19445 // configure layout
Daniel@0 19446 layout
Daniel@0 19447 .size(this.param('size'))
Daniel@0 19448 .text(get(this.param('text')))
Daniel@0 19449 .padding(this.param('padding'))
Daniel@0 19450 .spiral(this.param('spiral'))
Daniel@0 19451 .rotate(get(this.param('rotate')))
Daniel@0 19452 .font(get(this.param('font')))
Daniel@0 19453 .fontStyle(get(this.param('fontStyle')))
Daniel@0 19454 .fontWeight(get(this.param('fontWeight')))
Daniel@0 19455 .fontSize(fontSize)
Daniel@0 19456 .words(data.map(wrap)) // wrap to avoid tuple writes
Daniel@0 19457 .on('end', function(words) {
Daniel@0 19458 var size = layout.size(),
Daniel@0 19459 dx = size[0] >> 1,
Daniel@0 19460 dy = size[1] >> 1,
Daniel@0 19461 w, t, i, len;
Daniel@0 19462
Daniel@0 19463 for (i=0, len=words.length; i<len; ++i) {
Daniel@0 19464 w = words[i];
Daniel@0 19465 t = w._tuple;
Daniel@0 19466 Tuple.set(t, output.x, w.x + dx);
Daniel@0 19467 Tuple.set(t, output.y, w.y + dy);
Daniel@0 19468 Tuple.set(t, output.font, w.font);
Daniel@0 19469 Tuple.set(t, output.fontSize, w.size);
Daniel@0 19470 Tuple.set(t, output.fontStyle, w.style);
Daniel@0 19471 Tuple.set(t, output.fontWeight, w.weight);
Daniel@0 19472 Tuple.set(t, output.rotate, w.rotate);
Daniel@0 19473 }
Daniel@0 19474 })
Daniel@0 19475 .start();
Daniel@0 19476
Daniel@0 19477 // return changeset
Daniel@0 19478 for (var key in output) input.fields[output[key]] = 1;
Daniel@0 19479 return input;
Daniel@0 19480 };
Daniel@0 19481
Daniel@0 19482 module.exports = Wordcloud;
Daniel@0 19483 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
Daniel@0 19484
Daniel@0 19485 },{"./BatchTransform":117,"./Transform":135,"datalib":24,"vega-dataflow/src/Tuple":38,"vega-logging":45}],139:[function(require,module,exports){
Daniel@0 19486 module.exports = {
Daniel@0 19487 aggregate: require('./Aggregate'),
Daniel@0 19488 bin: require('./Bin'),
Daniel@0 19489 cross: require('./Cross'),
Daniel@0 19490 countpattern: require('./CountPattern'),
Daniel@0 19491 linkpath: require('./LinkPath'),
Daniel@0 19492 facet: require('./Facet'),
Daniel@0 19493 filter: require('./Filter'),
Daniel@0 19494 fold: require('./Fold'),
Daniel@0 19495 force: require('./Force'),
Daniel@0 19496 formula: require('./Formula'),
Daniel@0 19497 geo: require('./Geo'),
Daniel@0 19498 geopath: require('./GeoPath'),
Daniel@0 19499 lookup: require('./Lookup'),
Daniel@0 19500 pie: require('./Pie'),
Daniel@0 19501 sort: require('./Sort'),
Daniel@0 19502 stack: require('./Stack'),
Daniel@0 19503 treemap: require('./Treemap'),
Daniel@0 19504 voronoi: require('./Voronoi'),
Daniel@0 19505 wordcloud: require('./Wordcloud')
Daniel@0 19506 };
Daniel@0 19507 },{"./Aggregate":116,"./Bin":118,"./CountPattern":119,"./Cross":120,"./Facet":121,"./Filter":123,"./Fold":124,"./Force":125,"./Formula":126,"./Geo":127,"./GeoPath":128,"./LinkPath":129,"./Lookup":130,"./Pie":132,"./Sort":133,"./Stack":134,"./Treemap":136,"./Voronoi":137,"./Wordcloud":138}]},{},[1])(1)
Daniel@0 19508 });
Daniel@0 19509 //# sourceMappingURL=vega.js.map