Skip to content

Instantly share code, notes, and snippets.

@ztsai
Created August 4, 2015 23:54
Show Gist options
  • Select an option

  • Save ztsai/485f60baca2758df69e9 to your computer and use it in GitHub Desktop.

Select an option

Save ztsai/485f60baca2758df69e9 to your computer and use it in GitHub Desktop.
/*!
Plottable 1.5.0 (https://github.com/palantir/plottable)
Copyright 2014-2015 Palantir Technologies
Licensed under MIT (https://github.com/palantir/plottable/blob/master/LICENSE)
*/
(function(root, factory) {
if(typeof exports === 'object') {
module.exports = factory(require, exports, module);
}
else if(typeof define === 'function' && define.amd) {
define(['require', 'exports', 'module'], factory);
}
else {
var req = function(id) {return root[id];},
exp = root,
mod = {exports: exp};
root['Plottable'] = factory(req, exp, mod);
}
}(this, function(require, exports, module) {
///<reference path="../reference.ts" />
var Plottable;
(function (Plottable) {
var Utils;
(function (Utils) {
var Math;
(function (Math) {
var nativeMath = window.Math;
/**
* Checks if x is between a and b.
*
* @param {number} x The value to test if in range
* @param {number} a The beginning of the (inclusive) range
* @param {number} b The ending of the (inclusive) range
* @return {boolean} Whether x is in [a, b]
*/
function inRange(x, a, b) {
return (nativeMath.min(a, b) <= x && x <= nativeMath.max(a, b));
}
Math.inRange = inRange;
/**
* Clamps x to the range [min, max].
*
* @param {number} x The value to be clamped.
* @param {number} min The minimum value.
* @param {number} max The maximum value.
* @return {number} A clamped value in the range [min, max].
*/
function clamp(x, min, max) {
return nativeMath.min(nativeMath.max(min, x), max);
}
Math.clamp = clamp;
function max(array, firstArg, secondArg) {
var accessor = typeof (firstArg) === "function" ? firstArg : null;
var defaultValue = accessor == null ? firstArg : secondArg;
/* tslint:disable:ban */
var maxValue = accessor == null ? d3.max(array) : d3.max(array, accessor);
/* tslint:enable:ban */
return maxValue !== undefined ? maxValue : defaultValue;
}
Math.max = max;
function min(array, firstArg, secondArg) {
var accessor = typeof (firstArg) === "function" ? firstArg : null;
var defaultValue = accessor == null ? firstArg : secondArg;
/* tslint:disable:ban */
var minValue = accessor == null ? d3.min(array) : d3.min(array, accessor);
/* tslint:enable:ban */
return minValue !== undefined ? minValue : defaultValue;
}
Math.min = min;
/**
* Returns true **only** if x is NaN
*/
function isNaN(n) {
return n !== n;
}
Math.isNaN = isNaN;
/**
* Returns true if the argument is a number, which is not NaN
* Numbers represented as strings do not pass this function
*/
function isValidNumber(n) {
return typeof n === "number" && !Plottable.Utils.Math.isNaN(n) && isFinite(n);
}
Math.isValidNumber = isValidNumber;
/**
* Generates an array of consecutive, strictly increasing numbers
* in the range [start, stop) separeted by step
*/
function range(start, stop, step) {
if (step === void 0) { step = 1; }
if (step === 0) {
throw new Error("step cannot be 0");
}
var length = nativeMath.max(nativeMath.ceil((stop - start) / step), 0);
var range = [];
for (var i = 0; i < length; ++i) {
range[i] = start + step * i;
}
return range;
}
Math.range = range;
/**
* Returns the square of the distance between two points
*
* @param {Point} p1
* @param {Point} p2
* @return {number} dist(p1, p2)^2
*/
function distanceSquared(p1, p2) {
return nativeMath.pow(p2.y - p1.y, 2) + nativeMath.pow(p2.x - p1.x, 2);
}
Math.distanceSquared = distanceSquared;
})(Math = Utils.Math || (Utils.Math = {}));
})(Utils = Plottable.Utils || (Plottable.Utils = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var Plottable;
(function (Plottable) {
var Utils;
(function (Utils) {
/**
* Shim for ES6 map.
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
*/
var Map = (function () {
function Map() {
if (typeof window.Map === "function") {
this._es6Map = new window.Map();
}
else {
this._keyValuePairs = [];
}
}
Map.prototype.set = function (key, value) {
if (Utils.Math.isNaN(key)) {
throw new Error("NaN may not be used as a key to the Map");
}
if (this._es6Map != null) {
this._es6Map.set(key, value);
return this;
}
for (var i = 0; i < this._keyValuePairs.length; i++) {
if (this._keyValuePairs[i].key === key) {
this._keyValuePairs[i].value = value;
return this;
}
}
this._keyValuePairs.push({ key: key, value: value });
return this;
};
Map.prototype.get = function (key) {
if (this._es6Map != null) {
return this._es6Map.get(key);
}
for (var i = 0; i < this._keyValuePairs.length; i++) {
if (this._keyValuePairs[i].key === key) {
return this._keyValuePairs[i].value;
}
}
return undefined;
};
Map.prototype.has = function (key) {
if (this._es6Map != null) {
return this._es6Map.has(key);
}
for (var i = 0; i < this._keyValuePairs.length; i++) {
if (this._keyValuePairs[i].key === key) {
return true;
}
}
return false;
};
Map.prototype.forEach = function (callbackFn, thisArg) {
var _this = this;
if (this._es6Map != null) {
var callbackWrapper = function (value, key) { return callbackFn.call(thisArg, value, key, _this); };
this._es6Map.forEach(callbackWrapper, thisArg);
return;
}
this._keyValuePairs.forEach(function (keyValuePair) {
callbackFn.call(thisArg, keyValuePair.value, keyValuePair.key, _this);
});
};
Map.prototype.delete = function (key) {
if (this._es6Map != null) {
return this._es6Map.delete(key);
}
for (var i = 0; i < this._keyValuePairs.length; i++) {
if (this._keyValuePairs[i].key === key) {
this._keyValuePairs.splice(i, 1);
return true;
}
}
return false;
};
return Map;
})();
Utils.Map = Map;
})(Utils = Plottable.Utils || (Plottable.Utils = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var Plottable;
(function (Plottable) {
var Utils;
(function (Utils) {
/**
* Shim for ES6 set.
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
*/
var Set = (function () {
function Set() {
if (typeof window.Set === "function") {
this._es6Set = new window.Set();
}
else {
this._values = [];
}
this.size = 0;
}
Set.prototype.add = function (value) {
if (this._es6Set != null) {
this._es6Set.add(value);
this.size = this._es6Set.size;
return this;
}
if (!this.has(value)) {
this._values.push(value);
this.size = this._values.length;
}
return this;
};
Set.prototype.delete = function (value) {
if (this._es6Set != null) {
var deleted = this._es6Set.delete(value);
this.size = this._es6Set.size;
return deleted;
}
var index = this._values.indexOf(value);
if (index !== -1) {
this._values.splice(index, 1);
this.size = this._values.length;
return true;
}
return false;
};
Set.prototype.has = function (value) {
if (this._es6Set != null) {
return this._es6Set.has(value);
}
return this._values.indexOf(value) !== -1;
};
Set.prototype.forEach = function (callback, thisArg) {
var _this = this;
if (this._es6Set != null) {
var callbackWrapper = function (value, value2) { return callback.call(thisArg, value, value2, _this); };
this._es6Set.forEach(callbackWrapper, thisArg);
return;
}
this._values.forEach(function (value) {
callback.call(thisArg, value, value, _this);
});
};
return Set;
})();
Utils.Set = Set;
})(Utils = Plottable.Utils || (Plottable.Utils = {}));
})(Plottable || (Plottable = {}));
var Plottable;
(function (Plottable) {
var Utils;
(function (Utils) {
var DOM;
(function (DOM) {
var nativeMath = window.Math;
/**
* Gets the bounding box of an element.
* @param {d3.Selection} element
* @returns {SVGRed} The bounding box.
*/
function elementBBox(element) {
var bbox;
// HACKHACK: Firefox won't correctly measure nodes with style "display: none" or their descendents (FF Bug 612118).
try {
bbox = element.node().getBBox();
}
catch (err) {
bbox = { x: 0, y: 0, width: 0, height: 0 };
}
return bbox;
}
DOM.elementBBox = elementBBox;
/**
* Screen refresh rate which is assumed to be 60fps
*/
DOM.SCREEN_REFRESH_RATE_MILLISECONDS = 1000 / 60;
/**
* Polyfill for `window.requestAnimationFrame`.
* If the function exists, then we use the function directly.
* Otherwise, we set a timeout on `SCREEN_REFRESH_RATE_MILLISECONDS` and then perform the function.
*
* @param {() => void} callback The callback to call in the next animation frame
*/
function requestAnimationFramePolyfill(callback) {
if (window.requestAnimationFrame != null) {
window.requestAnimationFrame(callback);
}
else {
setTimeout(callback, DOM.SCREEN_REFRESH_RATE_MILLISECONDS);
}
}
DOM.requestAnimationFramePolyfill = requestAnimationFramePolyfill;
/**
* Calculates the width of the element.
* The width includes the padding and the border on the element's left and right sides.
*
* @param {Element} element The element to query
* @returns {number} The width of the element.
*/
function elementWidth(element) {
var style = window.getComputedStyle(element);
return _parseStyleValue(style, "width")
+ _parseStyleValue(style, "padding-left")
+ _parseStyleValue(style, "padding-right")
+ _parseStyleValue(style, "border-left-width")
+ _parseStyleValue(style, "border-right-width");
}
DOM.elementWidth = elementWidth;
/**
* Calculates the height of the element.
* The height includes the padding the and the border on the element's top and bottom sides.
*
* @param {Element} element The element to query
* @returns {number} The height of the element
*/
function elementHeight(element) {
var style = window.getComputedStyle(element);
return _parseStyleValue(style, "height")
+ _parseStyleValue(style, "padding-top")
+ _parseStyleValue(style, "padding-bottom")
+ _parseStyleValue(style, "border-top-width")
+ _parseStyleValue(style, "border-bottom-width");
}
DOM.elementHeight = elementHeight;
function translate(selection, x, y) {
var transformMatrix = d3.transform(selection.attr("transform"));
if (x == null) {
return transformMatrix.translate;
}
y = (y == null) ? 0 : y;
transformMatrix.translate[0] = x;
transformMatrix.translate[1] = y;
selection.attr("transform", transformMatrix.toString());
return selection;
}
DOM.translate = translate;
/**
* Checks if the first ClientRect overlaps the second.
*
* @param {ClientRect} clientRectA The first ClientRect
* @param {ClientRect} clientRectB The second ClientRect
* @returns {boolean} If the ClientRects overlap each other.
*/
function clientRectsOverlap(clientRectA, clientRectB) {
if (clientRectA.right < clientRectB.left) {
return false;
}
if (clientRectA.left > clientRectB.right) {
return false;
}
if (clientRectA.bottom < clientRectB.top) {
return false;
}
if (clientRectA.top > clientRectB.bottom) {
return false;
}
return true;
}
DOM.clientRectsOverlap = clientRectsOverlap;
/**
* Returns true if and only if innerClientRect is inside outerClientRect.
*
* @param {ClientRect} innerClientRect The first ClientRect
* @param {ClientRect} outerClientRect The second ClientRect
* @returns {boolean} If and only if the innerClientRect is inside outerClientRect.
*/
function clientRectInside(innerClientRect, outerClientRect) {
return (nativeMath.floor(outerClientRect.left) <= nativeMath.ceil(innerClientRect.left) &&
nativeMath.floor(outerClientRect.top) <= nativeMath.ceil(innerClientRect.top) &&
nativeMath.floor(innerClientRect.right) <= nativeMath.ceil(outerClientRect.right) &&
nativeMath.floor(innerClientRect.bottom) <= nativeMath.ceil(outerClientRect.bottom));
}
DOM.clientRectInside = clientRectInside;
/**
* Retrieves the bounding svg of the input element
*
* @param {SVGElement} element The element to query
* @returns {SVGElement} The bounding svg
*/
function boundingSVG(element) {
var ownerSVG = element.ownerSVGElement;
if (ownerSVG != null) {
return ownerSVG;
}
if (element.nodeName.toLowerCase() === "svg") {
return element;
}
return null; // not in the DOM
}
DOM.boundingSVG = boundingSVG;
var _latestClipPathId = 0;
/**
* Generates a ClipPath ID that is unique for this instance of Plottable
*/
function generateUniqueClipPathId() {
return "plottableClipPath" + ++_latestClipPathId;
}
DOM.generateUniqueClipPathId = generateUniqueClipPathId;
/**
* Returns true if the supplied coordinates or Ranges intersect or are contained by bbox.
*
* @param {number | Range} xValOrRange The x coordinate or Range to test
* @param {number | Range} yValOrRange The y coordinate or Range to test
* @param {SVGRect} bbox The bbox
* @param {number} tolerance Amount by which to expand bbox, in each dimension, before
* testing intersection
*
* @returns {boolean} True if the supplied coordinates or Ranges intersect or are
* contained by bbox, false otherwise.
*/
function intersectsBBox(xValOrRange, yValOrRange, bbox, tolerance) {
if (tolerance === void 0) { tolerance = 0.5; }
var xRange = _parseRange(xValOrRange);
var yRange = _parseRange(yValOrRange);
// SVGRects are positioned with sub-pixel accuracy (the default unit
// for the x, y, height & width attributes), but user selections (e.g. via
// mouse events) usually have pixel accuracy. A tolerance of half-a-pixel
// seems appropriate.
return bbox.x + bbox.width >= xRange.min - tolerance &&
bbox.x <= xRange.max + tolerance &&
bbox.y + bbox.height >= yRange.min - tolerance &&
bbox.y <= yRange.max + tolerance;
}
DOM.intersectsBBox = intersectsBBox;
/**
* Create a Range from a number or an object with "min" and "max" defined.
*
* @param {any} input The object to parse
*
* @returns {Range} The generated Range
*/
function _parseRange(input) {
if (typeof (input) === "number") {
var value = input;
return { min: value, max: value };
}
var range = input;
if (range instanceof Object && "min" in range && "max" in range) {
return range;
}
throw new Error("input '" + input + "' can't be parsed as an Range");
}
function _parseStyleValue(style, property) {
var value = style.getPropertyValue(property);
var parsedValue = parseFloat(value);
return parsedValue || 0;
}
})(DOM = Utils.DOM || (Utils.DOM = {}));
})(Utils = Plottable.Utils || (Plottable.Utils = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var Plottable;
(function (Plottable) {
var Utils;
(function (Utils) {
var Color;
(function (Color) {
var nativeMath = window.Math;
/**
* Return contrast ratio between two colors
* Based on implementation from chroma.js by Gregor Aisch (gka) (licensed under BSD)
* chroma.js may be found here: https://github.com/gka/chroma.js
* License may be found here: https://github.com/gka/chroma.js/blob/master/LICENSE
* see http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef
*/
function contrast(a, b) {
var l1 = luminance(a) + 0.05;
var l2 = luminance(b) + 0.05;
return l1 > l2 ? l1 / l2 : l2 / l1;
}
Color.contrast = contrast;
/**
* Returns a brighter copy of this color. Each channel is multiplied by 0.7 ^ -factor.
* Channel values are capped at the maximum value of 255, and the minimum value of 30.
*/
function lightenColor(color, factor) {
var hsl = d3.hsl(color).brighter(factor);
return hsl.rgb().toString();
}
Color.lightenColor = lightenColor;
/**
* Gets the Hex Code of the color resulting by applying the className CSS class to the
* colorTester selection. Returns null if the tester is transparent.
*
* @param {d3.Selection<void>} colorTester The d3 selection to apply the CSS class to
* @param {string} className The name of the class to be applied
* @return {string} The hex code of the computed color
*/
function colorTest(colorTester, className) {
colorTester.classed(className, true);
// Use regex to get the text inside the rgb parentheses
var colorStyle = colorTester.style("background-color");
if (colorStyle === "transparent") {
return null;
}
var rgb = /\((.+)\)/.exec(colorStyle)[1]
.split(",")
.map(function (colorValue) {
var colorNumber = +colorValue;
var hexValue = colorNumber.toString(16);
return colorNumber < 16 ? "0" + hexValue : hexValue;
});
if (rgb.length === 4 && rgb[3] === "00") {
return null;
}
var hexCode = "#" + rgb.join("");
colorTester.classed(className, false);
return hexCode;
}
Color.colorTest = colorTest;
/**
* Return relative luminance (defined here: http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef)
* Based on implementation from chroma.js by Gregor Aisch (gka) (licensed under BSD)
* chroma.js may be found here: https://github.com/gka/chroma.js
* License may be found here: https://github.com/gka/chroma.js/blob/master/LICENSE
*/
function luminance(color) {
var rgb = d3.rgb(color);
var lum = function (x) {
x = x / 255;
return x <= 0.03928 ? x / 12.92 : nativeMath.pow((x + 0.055) / 1.055, 2.4);
};
var r = lum(rgb.r);
var g = lum(rgb.g);
var b = lum(rgb.b);
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}
})(Color = Utils.Color || (Utils.Color = {}));
})(Utils = Plottable.Utils || (Plottable.Utils = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var Plottable;
(function (Plottable) {
var Utils;
(function (Utils) {
var Array;
(function (Array) {
var nativeArray = window.Array;
/**
* Takes two arrays of numbers and adds them together
*
* @param {number[]} aList The first array of numbers
* @param {number[]} bList The second array of numbers
* @return {number[]} An array of numbers where x[i] = aList[i] + bList[i]
*/
function add(aList, bList) {
if (aList.length !== bList.length) {
throw new Error("attempted to add arrays of unequal length");
}
return aList.map(function (_, i) { return aList[i] + bList[i]; });
}
Array.add = add;
/**
* Take an array of values, and return the unique values.
* Will work iff ∀ a, b, a.toString() == b.toString() => a == b; will break on Object inputs
*
* @param {T[]} values The values to find uniqueness for
* @return {T[]} The unique values
*/
function uniq(arr) {
var seen = d3.set();
var result = [];
arr.forEach(function (x) {
if (!seen.has(String(x))) {
seen.add(String(x));
result.push(x);
}
});
return result;
}
Array.uniq = uniq;
/**
* @param {T[][]} a The 2D array that will have its elements joined together.
* @return {T[]} Every array in a, concatenated together in the order they appear.
*/
function flatten(a) {
return nativeArray.prototype.concat.apply([], a);
}
Array.flatten = flatten;
/**
* Creates an array of length `count`, filled with value or (if value is a function), value()
*
* @param {T | ((index?: number) => T)} value The value to fill the array with or a value generator (called with index as arg)
* @param {number} count The length of the array to generate
* @return {any[]}
*/
function createFilledArray(value, count) {
var out = [];
for (var i = 0; i < count; i++) {
out[i] = typeof (value) === "function" ? value(i) : value;
}
return out;
}
Array.createFilledArray = createFilledArray;
})(Array = Utils.Array || (Utils.Array = {}));
})(Utils = Plottable.Utils || (Plottable.Utils = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Utils;
(function (Utils) {
/**
* A set of callbacks which can be all invoked at once.
* Each callback exists at most once in the set (based on reference equality).
* All callbacks should have the same signature.
*/
var CallbackSet = (function (_super) {
__extends(CallbackSet, _super);
function CallbackSet() {
_super.apply(this, arguments);
}
CallbackSet.prototype.callCallbacks = function () {
var _this = this;
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i - 0] = arguments[_i];
}
this.forEach(function (callback) {
callback.apply(_this, args);
});
return this;
};
return CallbackSet;
})(Utils.Set);
Utils.CallbackSet = CallbackSet;
})(Utils = Plottable.Utils || (Plottable.Utils = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var Plottable;
(function (Plottable) {
var Utils;
(function (Utils) {
var Stacking;
(function (Stacking) {
var nativeMath = window.Math;
/**
* Computes the StackingResult (value and offset) for each data point in each Dataset.
*
* @param {Dataset[]} datasets The Datasets to be stacked on top of each other in the order of stacking
* @param {Accessor<any>} keyAccessor Accessor for the key of the data
* @param {Accessor<number>} valueAccessor Accessor for the value of the data
* @return {StackingResult} value and offset for each datapoint in each Dataset
*/
function stack(datasets, keyAccessor, valueAccessor) {
var positiveOffsets = d3.map();
var negativeOffsets = d3.map();
var datasetToKeyToStackedDatum = new Utils.Map();
datasets.forEach(function (dataset) {
var keyToStackedDatum = new Utils.Map();
dataset.data().forEach(function (datum, index) {
var key = normalizeKey(keyAccessor(datum, index, dataset));
var value = +valueAccessor(datum, index, dataset);
var offset;
var offsetMap = (value >= 0) ? positiveOffsets : negativeOffsets;
if (offsetMap.has(key)) {
offset = offsetMap.get(key);
offsetMap.set(key, offset + value);
}
else {
offset = 0;
offsetMap.set(key, value);
}
keyToStackedDatum.set(key, {
value: value,
offset: offset
});
});
datasetToKeyToStackedDatum.set(dataset, keyToStackedDatum);
});
return datasetToKeyToStackedDatum;
}
Stacking.stack = stack;
/**
* Computes the total extent over all data points in all Datasets, taking stacking into consideration.
*
* @param {StackingResult} stackingResult The value and offset information for each datapoint in each dataset
* @oaram {Accessor<any>} keyAccessor Accessor for the key of the data existent in the stackingResult
* @param {Accessor<boolean>} filter A filter for data to be considered when computing the total extent
* @return {[number, number]} The total extent
*/
function stackedExtent(stackingResult, keyAccessor, filter) {
var extents = [];
stackingResult.forEach(function (stackedDatumMap, dataset) {
dataset.data().forEach(function (datum, index) {
if (filter != null && !filter(datum, index, dataset)) {
return;
}
var stackedDatum = stackedDatumMap.get(normalizeKey(keyAccessor(datum, index, dataset)));
extents.push(stackedDatum.value + stackedDatum.offset);
});
});
var maxStackExtent = Utils.Math.max(extents, 0);
var minStackExtent = Utils.Math.min(extents, 0);
return [nativeMath.min(minStackExtent, 0), nativeMath.max(0, maxStackExtent)];
}
Stacking.stackedExtent = stackedExtent;
/**
* Normalizes a key used for stacking
*
* @param {any} key The key to be normalized
* @return {string} The stringified key
*/
function normalizeKey(key) {
return String(key);
}
Stacking.normalizeKey = normalizeKey;
})(Stacking = Utils.Stacking || (Utils.Stacking = {}));
})(Utils = Plottable.Utils || (Plottable.Utils = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var Plottable;
(function (Plottable) {
var Utils;
(function (Utils) {
var Window;
(function (Window) {
/**
* Print a warning message to the console, if it is available.
*
* @param {string} The warnings to print
*/
function warn(warning) {
if (!Plottable.Configs.SHOW_WARNINGS) {
return;
}
/* tslint:disable:no-console */
if (window.console != null) {
if (window.console.warn != null) {
console.warn(warning);
}
else if (window.console.log != null) {
console.log(warning);
}
}
/* tslint:enable:no-console */
}
Window.warn = warn;
/**
* Is like setTimeout, but activates synchronously if time=0
* We special case 0 because of an observed issue where calling setTimeout causes visible flickering.
* We believe this is because when requestAnimationFrame calls into the paint function, as soon as that function finishes
* evaluating, the results are painted to the screen. As a result, if we want something to occur immediately but call setTimeout
* with time=0, then it is pushed to the call stack and rendered in the next frame, so the component that was rendered via
* setTimeout appears out-of-sync with the rest of the plot.
*/
function setTimeout(f, time) {
var args = [];
for (var _i = 2; _i < arguments.length; _i++) {
args[_i - 2] = arguments[_i];
}
if (time === 0) {
f(args);
return -1;
}
else {
return window.setTimeout(f, time, args);
}
}
Window.setTimeout = setTimeout;
/**
* Sends a deprecation warning to the console. The warning includes the name of the deprecated method,
* version number of the deprecation, and an optional message.
*
* To be used in the first line of a deprecated method.
*
* @param {string} callingMethod The name of the method being deprecated
* @param {string} version The version when the tagged method became obsolete
* @param {string?} message Optional message to be shown with the warning
*/
function deprecated(callingMethod, version, message) {
if (message === void 0) { message = ""; }
Utils.Window.warn("Method " + callingMethod + " has been deprecated in version " + version +
". Please refer to the release notes. " + message);
}
Window.deprecated = deprecated;
})(Window = Utils.Window || (Utils.Window = {}));
})(Utils = Plottable.Utils || (Plottable.Utils = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var Plottable;
(function (Plottable) {
var Utils;
(function (Utils) {
var ClientToSVGTranslator = (function () {
function ClientToSVGTranslator(svg) {
this._svg = svg;
this._measureRect = document.createElementNS(svg.namespaceURI, "rect");
this._measureRect.setAttribute("class", "measure-rect");
this._measureRect.setAttribute("style", "opacity: 0; visibility: hidden;");
this._measureRect.setAttribute("width", "1");
this._measureRect.setAttribute("height", "1");
this._svg.appendChild(this._measureRect);
}
/**
* Returns the ClientToSVGTranslator for the <svg> containing elem.
* If one already exists on that <svg>, it will be returned; otherwise, a new one will be created.
*/
ClientToSVGTranslator.getTranslator = function (elem) {
var svg = Utils.DOM.boundingSVG(elem);
var translator = svg[ClientToSVGTranslator._TRANSLATOR_KEY];
if (translator == null) {
translator = new ClientToSVGTranslator(svg);
svg[ClientToSVGTranslator._TRANSLATOR_KEY] = translator;
}
return translator;
};
/**
* Computes the position relative to the <svg> in svg-coordinate-space.
*/
ClientToSVGTranslator.prototype.computePosition = function (clientX, clientY) {
// get the origin
this._measureRect.setAttribute("x", "0");
this._measureRect.setAttribute("y", "0");
var mrBCR = this._measureRect.getBoundingClientRect();
var origin = { x: mrBCR.left, y: mrBCR.top };
// calculate the scale
var sampleDistance = 100;
this._measureRect.setAttribute("x", String(sampleDistance));
this._measureRect.setAttribute("y", String(sampleDistance));
mrBCR = this._measureRect.getBoundingClientRect();
var testPoint = { x: mrBCR.left, y: mrBCR.top };
// invalid measurements -- SVG might not be in the DOM
if (origin.x === testPoint.x || origin.y === testPoint.y) {
return null;
}
var scaleX = (testPoint.x - origin.x) / sampleDistance;
var scaleY = (testPoint.y - origin.y) / sampleDistance;
// get the true cursor position
this._measureRect.setAttribute("x", String((clientX - origin.x) / scaleX));
this._measureRect.setAttribute("y", String((clientY - origin.y) / scaleY));
mrBCR = this._measureRect.getBoundingClientRect();
var trueCursorPosition = { x: mrBCR.left, y: mrBCR.top };
var scaledPosition = {
x: (trueCursorPosition.x - origin.x) / scaleX,
y: (trueCursorPosition.y - origin.y) / scaleY
};
return scaledPosition;
};
/**
* Checks whether event happened inside <svg> element.
*/
ClientToSVGTranslator.prototype.insideSVG = function (e) {
return Utils.DOM.boundingSVG(e.target) === this._svg;
};
ClientToSVGTranslator._TRANSLATOR_KEY = "__Plottable_ClientToSVGTranslator";
return ClientToSVGTranslator;
})();
Utils.ClientToSVGTranslator = ClientToSVGTranslator;
})(Utils = Plottable.Utils || (Plottable.Utils = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var Plottable;
(function (Plottable) {
var Configs;
(function (Configs) {
/**
* Specifies if Plottable should show warnings.
*/
Configs.SHOW_WARNINGS = true;
})(Configs = Plottable.Configs || (Plottable.Configs = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var Plottable;
(function (Plottable) {
Plottable.version = "1.5.0";
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var Plottable;
(function (Plottable) {
var Dataset = (function () {
/**
* A Dataset contains an array of data and some metadata.
* Changes to the data or metadata will cause anything subscribed to the Dataset to update.
*
* @constructor
* @param {any[]} [data=[]] The data for this Dataset.
* @param {any} [metadata={}] An object containing additional information.
*/
function Dataset(data, metadata) {
if (data === void 0) { data = []; }
if (metadata === void 0) { metadata = {}; }
this._data = data;
this._metadata = metadata;
this._callbacks = new Plottable.Utils.CallbackSet();
}
/**
* Adds a callback to be called when the Dataset updates.
*
* @param {DatasetCallback} callback.
* @returns {Dataset} The calling Dataset.
*/
Dataset.prototype.onUpdate = function (callback) {
this._callbacks.add(callback);
return this;
};
/**
* Removes a callback that would be called when the Dataset updates.
*
* @param {DatasetCallback} callback
* @returns {Dataset} The calling Dataset.
*/
Dataset.prototype.offUpdate = function (callback) {
this._callbacks.delete(callback);
return this;
};
Dataset.prototype.data = function (data) {
if (data == null) {
return this._data;
}
else {
this._data = data;
this._callbacks.callCallbacks(this);
return this;
}
};
Dataset.prototype.metadata = function (metadata) {
if (metadata == null) {
return this._metadata;
}
else {
this._metadata = metadata;
this._callbacks.callCallbacks(this);
return this;
}
};
return Dataset;
})();
Plottable.Dataset = Dataset;
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var Plottable;
(function (Plottable) {
var RenderPolicies;
(function (RenderPolicies) {
/**
* Renders Components immediately after they are enqueued.
* Useful for debugging, horrible for performance.
*/
var Immediate = (function () {
function Immediate() {
}
Immediate.prototype.render = function () {
Plottable.RenderController.flush();
};
return Immediate;
})();
RenderPolicies.Immediate = Immediate;
/**
* The default way to render, which only tries to render every frame
* (usually, 1/60th of a second).
*/
var AnimationFrame = (function () {
function AnimationFrame() {
}
AnimationFrame.prototype.render = function () {
Plottable.Utils.DOM.requestAnimationFramePolyfill(Plottable.RenderController.flush);
};
return AnimationFrame;
})();
RenderPolicies.AnimationFrame = AnimationFrame;
/**
* Renders with `setTimeout()`.
* Generally an inferior way to render compared to `requestAnimationFrame`,
* but useful for browsers that don't suppoort `requestAnimationFrame`.
*/
var Timeout = (function () {
function Timeout() {
this._timeoutMsec = Plottable.Utils.DOM.SCREEN_REFRESH_RATE_MILLISECONDS;
}
Timeout.prototype.render = function () {
setTimeout(Plottable.RenderController.flush, this._timeoutMsec);
};
return Timeout;
})();
RenderPolicies.Timeout = Timeout;
})(RenderPolicies = Plottable.RenderPolicies || (Plottable.RenderPolicies = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var Plottable;
(function (Plottable) {
/**
* The RenderController is responsible for enqueueing and synchronizing
* layout and render calls for Components.
*
* Layout and render calls occur inside an animation callback
* (window.requestAnimationFrame if available).
*
* RenderController.flush() immediately lays out and renders all Components currently enqueued.
*
* To always have immediate rendering (useful for debugging), call
* ```typescript
* Plottable.RenderController.setRenderPolicy(
* new Plottable.RenderPolicies.Immediate()
* );
* ```
*/
var RenderController;
(function (RenderController) {
var _componentsNeedingRender = new Plottable.Utils.Set();
var _componentsNeedingComputeLayout = new Plottable.Utils.Set();
var _animationRequested = false;
var _isCurrentlyFlushing = false;
var Policy;
(function (Policy) {
Policy.IMMEDIATE = "immediate";
Policy.ANIMATION_FRAME = "animationframe";
Policy.TIMEOUT = "timeout";
})(Policy = RenderController.Policy || (RenderController.Policy = {}));
var _renderPolicy = new Plottable.RenderPolicies.AnimationFrame();
function renderPolicy(renderPolicy) {
if (renderPolicy == null) {
return _renderPolicy;
}
switch (renderPolicy.toLowerCase()) {
case Policy.IMMEDIATE:
_renderPolicy = new Plottable.RenderPolicies.Immediate();
break;
case Policy.ANIMATION_FRAME:
_renderPolicy = new Plottable.RenderPolicies.AnimationFrame();
break;
case Policy.TIMEOUT:
_renderPolicy = new Plottable.RenderPolicies.Timeout();
break;
default:
Plottable.Utils.Window.warn("Unrecognized renderPolicy: " + renderPolicy);
}
}
RenderController.renderPolicy = renderPolicy;
/**
* Enqueues the Component for rendering.
*
* @param {Component} component
*/
function registerToRender(component) {
if (_isCurrentlyFlushing) {
Plottable.Utils.Window.warn("Registered to render while other components are flushing: request may be ignored");
}
_componentsNeedingRender.add(component);
requestRender();
}
RenderController.registerToRender = registerToRender;
/**
* Enqueues the Component for layout and rendering.
*
* @param {Component} component
*/
function registerToComputeLayout(component) {
_componentsNeedingComputeLayout.add(component);
_componentsNeedingRender.add(component);
requestRender();
}
RenderController.registerToComputeLayout = registerToComputeLayout;
function requestRender() {
// Only run or enqueue flush on first request.
if (!_animationRequested) {
_animationRequested = true;
_renderPolicy.render();
}
}
/**
* Renders all Components waiting to be rendered immediately
* instead of waiting until the next frame.
*
* Useful to call when debugging.
*/
function flush() {
if (_animationRequested) {
// Layout
_componentsNeedingComputeLayout.forEach(function (component) { return component.computeLayout(); });
// Top level render; Containers will put their children in the toRender queue
_componentsNeedingRender.forEach(function (component) { return component.render(); });
_isCurrentlyFlushing = true;
var failed = new Plottable.Utils.Set();
_componentsNeedingRender.forEach(function (component) {
try {
component.renderImmediately();
}
catch (err) {
// throw error with timeout to avoid interrupting further renders
window.setTimeout(function () { throw err; }, 0);
failed.add(component);
}
});
_componentsNeedingComputeLayout = new Plottable.Utils.Set();
_componentsNeedingRender = failed;
_animationRequested = false;
_isCurrentlyFlushing = false;
}
}
RenderController.flush = flush;
})(RenderController = Plottable.RenderController || (Plottable.RenderController = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var Plottable;
(function (Plottable) {
/**
* This field is deprecated and will be removed in v2.0.0.
*
* The number of milliseconds between midnight one day and the next is
* not a fixed quantity.
*
* Use date.setDate(date.getDate() + number_of_days) instead.
*
*/
Plottable.MILLISECONDS_IN_ONE_DAY = 24 * 60 * 60 * 1000;
var Formatters;
(function (Formatters) {
/**
* Creates a formatter for currency values.
*
* @param {number} [precision] The number of decimal places to show (default 2).
* @param {string} [symbol] The currency symbol to use (default "$").
* @param {boolean} [prefix] Whether to prepend or append the currency symbol (default true).
* @param {boolean} [onlyShowUnchanged] Whether to return a value if value changes after formatting (default true).
*
* @returns {Formatter} A formatter for currency values.
*/
function currency(precision, symbol, prefix) {
if (precision === void 0) { precision = 2; }
if (symbol === void 0) { symbol = "$"; }
if (prefix === void 0) { prefix = true; }
var fixedFormatter = Formatters.fixed(precision);
return function (d) {
var formattedValue = fixedFormatter(Math.abs(d));
if (formattedValue !== "") {
if (prefix) {
formattedValue = symbol + formattedValue;
}
else {
formattedValue += symbol;
}
if (d < 0) {
formattedValue = "-" + formattedValue;
}
}
return formattedValue;
};
}
Formatters.currency = currency;
/**
* Creates a formatter that displays exactly [precision] decimal places.
*
* @param {number} [precision] The number of decimal places to show (default 3).
* @param {boolean} [onlyShowUnchanged] Whether to return a value if value changes after formatting (default true).
*
* @returns {Formatter} A formatter that displays exactly [precision] decimal places.
*/
function fixed(precision) {
if (precision === void 0) { precision = 3; }
verifyPrecision(precision);
return function (d) { return d.toFixed(precision); };
}
Formatters.fixed = fixed;
/**
* Creates a formatter that formats numbers to show no more than
* [precision] decimal places. All other values are stringified.
*
* @param {number} [precision] The number of decimal places to show (default 3).
* @param {boolean} [onlyShowUnchanged] Whether to return a value if value changes after formatting (default true).
*
* @returns {Formatter} A formatter for general values.
*/
function general(precision) {
if (precision === void 0) { precision = 3; }
verifyPrecision(precision);
return function (d) {
if (typeof d === "number") {
var multiplier = Math.pow(10, precision);
return String(Math.round(d * multiplier) / multiplier);
}
else {
return String(d);
}
};
}
Formatters.general = general;
/**
* Creates a formatter that stringifies its input.
*
* @returns {Formatter} A formatter that stringifies its input.
*/
function identity() {
return function (d) { return String(d); };
}
Formatters.identity = identity;
/**
* Creates a formatter for percentage values.
* Multiplies the input by 100 and appends "%".
*
* @param {number} [precision] The number of decimal places to show (default 0).
* @param {boolean} [onlyShowUnchanged] Whether to return a value if value changes after formatting (default true).
*
* @returns {Formatter} A formatter for percentage values.
*/
function percentage(precision) {
if (precision === void 0) { precision = 0; }
var fixedFormatter = Formatters.fixed(precision);
return function (d) {
var valToFormat = d * 100;
// Account for float imprecision
var valString = d.toString();
var integerPowerTen = Math.pow(10, valString.length - (valString.indexOf(".") + 1));
valToFormat = parseInt((valToFormat * integerPowerTen).toString(), 10) / integerPowerTen;
return fixedFormatter(valToFormat) + "%";
};
}
Formatters.percentage = percentage;
/**
* Creates a formatter for values that displays [precision] significant figures
* and puts SI notation.
*
* @param {number} [precision] The number of significant figures to show (default 3).
*
* @returns {Formatter} A formatter for SI values.
*/
function siSuffix(precision) {
if (precision === void 0) { precision = 3; }
verifyPrecision(precision);
return function (d) { return d3.format("." + precision + "s")(d); };
}
Formatters.siSuffix = siSuffix;
/**
* Creates a formatter for values that displays abbreviated values
* and uses standard short scale suffixes
* - K - thousands - 10 ^ 3
* - M - millions - 10 ^ 6
* - B - billions - 10 ^ 9
* - T - trillions - 10 ^ 12
* - Q - quadrillions - 10 ^ 15
*
* Numbers with a magnitude outside of (10 ^ (-precision), 10 ^ 15) are shown using
* scientific notation to avoid creating extremely long decimal strings.
*
* @param {number} [precision] the number of decimal places to show (default 3)
* @returns {Formatter} A formatter with short scale formatting
*/
function shortScale(precision) {
if (precision === void 0) { precision = 3; }
verifyPrecision(precision);
precision = Math.floor(precision);
var suffixes = "KMBTQ";
var exponentFormatter = d3.format("." + precision + "e");
var fixedFormatter = d3.format("." + precision + "f");
var max = Math.pow(10, (3 * (suffixes.length + 1)));
var min = Math.pow(10, -precision);
return function (num) {
var absNum = Math.abs(num);
if ((absNum < min || absNum >= max) && absNum !== 0) {
return exponentFormatter(num);
}
var idx = -1;
while (absNum >= Math.pow(1000, idx + 2) && idx < (suffixes.length - 1)) {
idx++;
}
var output = "";
if (idx === -1) {
output = fixedFormatter(num);
}
else {
output = fixedFormatter(num / Math.pow(1000, idx + 1)) + suffixes[idx];
}
// catch rounding by the underlying d3 formatter
if ((num > 0 && output.substr(0, 4) === "1000") || (num < 0 && output.substr(0, 5) === "-1000")) {
if (idx < suffixes.length - 1) {
idx++;
output = fixedFormatter(num / Math.pow(1000, idx + 1)) + suffixes[idx];
}
else {
output = exponentFormatter(num);
}
}
return output;
};
}
Formatters.shortScale = shortScale;
/**
* Creates a multi time formatter that displays dates.
*
* @returns {Formatter} A formatter for time/date values.
*/
function multiTime() {
var numFormats = 8;
// these defaults were taken from d3
// https://github.com/mbostock/d3/wiki/Time-Formatting#format_multi
var timeFormat = {};
timeFormat[0] = {
format: ".%L",
filter: function (d) { return d.getMilliseconds() !== 0; }
};
timeFormat[1] = {
format: ":%S",
filter: function (d) { return d.getSeconds() !== 0; }
};
timeFormat[2] = {
format: "%I:%M",
filter: function (d) { return d.getMinutes() !== 0; }
};
timeFormat[3] = {
format: "%I %p",
filter: function (d) { return d.getHours() !== 0; }
};
timeFormat[4] = {
format: "%a %d",
filter: function (d) { return d.getDay() !== 0 && d.getDate() !== 1; }
};
timeFormat[5] = {
format: "%b %d",
filter: function (d) { return d.getDate() !== 1; }
};
timeFormat[6] = {
format: "%b",
filter: function (d) { return d.getMonth() !== 0; }
};
timeFormat[7] = {
format: "%Y",
filter: function () { return true; }
};
return function (d) {
for (var i = 0; i < numFormats; i++) {
if (timeFormat[i].filter(d)) {
return d3.time.format(timeFormat[i].format)(d);
}
}
};
}
Formatters.multiTime = multiTime;
/**
* Creates a time formatter that displays time/date using given specifier.
*
* List of directives can be found on: https://github.com/mbostock/d3/wiki/Time-Formatting#format
*
* @param {string} [specifier] The specifier for the formatter.
*
* @returns {Formatter} A formatter for time/date values.
*/
function time(specifier) {
return d3.time.format(specifier);
}
Formatters.time = time;
/**
* Creates a formatter for relative dates.
*
* @param {number} baseValue The start date (as epoch time) used in computing relative dates (default 0)
* @param {number} increment The unit used in calculating relative date values (default MILLISECONDS_IN_ONE_DAY)
* @param {string} label The label to append to the formatted string (default "")
*
* @returns {Formatter} A formatter for time/date values.
*/
function relativeDate(baseValue, increment, label) {
if (baseValue === void 0) { baseValue = 0; }
if (increment === void 0) { increment = Plottable.MILLISECONDS_IN_ONE_DAY; }
if (label === void 0) { label = ""; }
Plottable.Utils.Window.deprecated("relativeDate()", "1.3", "Not safe for use with time zones.");
return function (d) {
var relativeDate = Math.round((d.valueOf() - baseValue) / increment);
return relativeDate.toString() + label;
};
}
Formatters.relativeDate = relativeDate;
function verifyPrecision(precision) {
if (precision < 0 || precision > 20) {
throw new RangeError("Formatter precision must be between 0 and 20");
}
}
})(Formatters = Plottable.Formatters || (Plottable.Formatters = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var Plottable;
(function (Plottable) {
var SymbolFactories;
(function (SymbolFactories) {
function circle() {
return function (symbolSize) { return d3.svg.symbol().type("circle").size(Math.PI * Math.pow(symbolSize / 2, 2))(null); };
}
SymbolFactories.circle = circle;
function square() {
return function (symbolSize) { return d3.svg.symbol().type("square").size(Math.pow(symbolSize, 2))(null); };
}
SymbolFactories.square = square;
function cross() {
return function (symbolSize) { return d3.svg.symbol().type("cross").size((5 / 9) * Math.pow(symbolSize, 2))(null); };
}
SymbolFactories.cross = cross;
function diamond() {
return function (symbolSize) { return d3.svg.symbol().type("diamond").size(Math.tan(Math.PI / 6) * Math.pow(symbolSize, 2) / 2)(null); };
}
SymbolFactories.diamond = diamond;
function triangleUp() {
return function (symbolSize) { return d3.svg.symbol().type("triangle-up").size(Math.sqrt(3) * Math.pow(symbolSize / 2, 2))(null); };
}
SymbolFactories.triangleUp = triangleUp;
function triangleDown() {
return function (symbolSize) { return d3.svg.symbol().type("triangle-down").size(Math.sqrt(3) * Math.pow(symbolSize / 2, 2))(null); };
}
SymbolFactories.triangleDown = triangleDown;
})(SymbolFactories = Plottable.SymbolFactories || (Plottable.SymbolFactories = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var Plottable;
(function (Plottable) {
var Scale = (function () {
/**
* A Scale is a function (in the mathematical sense) that maps values from a domain to a range.
*
* @constructor
*/
function Scale() {
this._autoDomainAutomatically = true;
this._domainModificationInProgress = false;
this._callbacks = new Plottable.Utils.CallbackSet();
this._includedValuesProviders = new Plottable.Utils.Set();
}
/**
* Given an array of potential domain values, computes the extent of those values.
*
* @param {D[]} values
* @returns {D[]} The extent of the input values.
*/
Scale.prototype.extentOfValues = function (values) {
return []; // this should be overwritten
};
Scale.prototype._getAllIncludedValues = function () {
var _this = this;
var providerArray = [];
this._includedValuesProviders.forEach(function (provider) {
var extents = provider(_this);
providerArray = providerArray.concat(extents);
});
return providerArray;
};
Scale.prototype._getExtent = function () {
return []; // this should be overwritten
};
/**
* Adds a callback to be called when the Scale updates.
*
* @param {ScaleCallback} callback.
* @returns {Scale} The calling Scale.
*/
Scale.prototype.onUpdate = function (callback) {
this._callbacks.add(callback);
return this;
};
/**
* Removes a callback that would be called when the Scale updates.
*
* @param {ScaleCallback} callback.
* @returns {Scale} The calling Scale.
*/
Scale.prototype.offUpdate = function (callback) {
this._callbacks.delete(callback);
return this;
};
Scale.prototype._dispatchUpdate = function () {
this._callbacks.callCallbacks(this);
};
/**
* Sets the Scale's domain so that it spans the Extents of all its ExtentsProviders.
*
* @returns {Scale} The calling Scale.
*/
Scale.prototype.autoDomain = function () {
this._autoDomainAutomatically = true;
this._setDomain(this._getExtent());
return this;
};
Scale.prototype._autoDomainIfAutomaticMode = function () {
if (this._autoDomainAutomatically) {
this.autoDomain();
}
};
/**
* Computes the range value corresponding to a given domain value.
*
* @param {D} value
* @returns {R} The range value corresponding to the supplied domain value.
*/
Scale.prototype.scale = function (value) {
throw new Error("Subclasses should override scale");
};
Scale.prototype.domain = function (values) {
if (values == null) {
return this._getDomain();
}
else {
this._autoDomainAutomatically = false;
this._setDomain(values);
return this;
}
};
Scale.prototype._getDomain = function () {
throw new Error("Subclasses should override _getDomain");
};
Scale.prototype._setDomain = function (values) {
if (!this._domainModificationInProgress) {
this._domainModificationInProgress = true;
this._setBackingScaleDomain(values);
this._dispatchUpdate();
this._domainModificationInProgress = false;
}
};
Scale.prototype._setBackingScaleDomain = function (values) {
throw new Error("Subclasses should override _setBackingDomain");
};
Scale.prototype.range = function (values) {
if (values == null) {
return this._getRange();
}
else {
this._setRange(values);
return this;
}
};
Scale.prototype._getRange = function () {
throw new Error("Subclasses should override _getRange");
};
Scale.prototype._setRange = function (values) {
throw new Error("Subclasses should override _setRange");
};
/**
* Adds an IncludedValuesProvider to the Scale.
*
* @param {Scales.IncludedValuesProvider} provider
* @returns {Scale} The calling Scale.
*/
Scale.prototype.addIncludedValuesProvider = function (provider) {
this._includedValuesProviders.add(provider);
this._autoDomainIfAutomaticMode();
return this;
};
/**
* Removes the IncludedValuesProvider from the Scale.
*
* @param {Scales.IncludedValuesProvider} provider
* @returns {Scale} The calling Scale.
*/
Scale.prototype.removeIncludedValuesProvider = function (provider) {
this._includedValuesProviders.delete(provider);
this._autoDomainIfAutomaticMode();
return this;
};
return Scale;
})();
Plottable.Scale = Scale;
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var QuantitativeScale = (function (_super) {
__extends(QuantitativeScale, _super);
/**
* A QuantitativeScale is a Scale that maps number-like values to numbers.
* It is invertible and continuous.
*
* @constructor
*/
function QuantitativeScale() {
_super.call(this);
this._tickGenerator = function (scale) { return scale.defaultTicks(); };
this._padProportion = 0.05;
this._paddingExceptionsProviders = new Plottable.Utils.Set();
}
QuantitativeScale.prototype.autoDomain = function () {
this._domainMin = null;
this._domainMax = null;
_super.prototype.autoDomain.call(this);
return this;
};
QuantitativeScale.prototype._autoDomainIfAutomaticMode = function () {
if (this._domainMin != null && this._domainMax != null) {
this._setDomain([this._domainMin, this._domainMax]);
return;
}
var computedExtent = this._getExtent();
if (this._domainMin != null) {
var maxValue = computedExtent[1];
if (this._domainMin >= maxValue) {
maxValue = this._expandSingleValueDomain([this._domainMin, this._domainMin])[1];
}
this._setDomain([this._domainMin, maxValue]);
return;
}
if (this._domainMax != null) {
var minValue = computedExtent[0];
if (this._domainMax <= minValue) {
minValue = this._expandSingleValueDomain([this._domainMax, this._domainMax])[0];
}
this._setDomain([minValue, this._domainMax]);
return;
}
_super.prototype._autoDomainIfAutomaticMode.call(this);
};
QuantitativeScale.prototype._getExtent = function () {
var includedValues = this._getAllIncludedValues();
var extent = this._defaultExtent();
if (includedValues.length !== 0) {
var combinedExtent = [
Plottable.Utils.Math.min(includedValues, extent[0]),
Plottable.Utils.Math.max(includedValues, extent[1])
];
extent = this._padDomain(combinedExtent);
}
if (this._domainMin != null) {
extent[0] = this._domainMin;
}
if (this._domainMax != null) {
extent[1] = this._domainMax;
}
return extent;
};
/**
* Adds a padding exception provider.
* If one end of the domain is set to an excepted value as a result of autoDomain()-ing,
* that end of the domain will not be padded.
*
* @param {Scales.PaddingExceptionProvider<D>} provider The provider function.
* @returns {QuantitativeScale} The calling QuantitativeScale.
*/
QuantitativeScale.prototype.addPaddingExceptionsProvider = function (provider) {
this._paddingExceptionsProviders.add(provider);
this._autoDomainIfAutomaticMode();
return this;
};
/**
* Removes the padding exception provider.
*
* @param {Scales.PaddingExceptionProvider<D>} provider The provider function.
* @returns {QuantitativeScale} The calling QuantitativeScale.
*/
QuantitativeScale.prototype.removePaddingExceptionsProvider = function (provider) {
this._paddingExceptionsProviders.delete(provider);
this._autoDomainIfAutomaticMode();
return this;
};
QuantitativeScale.prototype.padProportion = function (padProportion) {
if (padProportion == null) {
return this._padProportion;
}
if (padProportion < 0) {
throw new Error("padProportion must be non-negative");
}
this._padProportion = padProportion;
this._autoDomainIfAutomaticMode();
return this;
};
QuantitativeScale.prototype._padDomain = function (domain) {
var _this = this;
if (domain[0].valueOf() === domain[1].valueOf()) {
return this._expandSingleValueDomain(domain);
}
if (this._padProportion === 0) {
return domain;
}
var p = this._padProportion / 2;
var min = domain[0];
var max = domain[1];
var minExistsInExceptions = false;
var maxExistsInExceptions = false;
this._paddingExceptionsProviders.forEach(function (provider) {
var values = provider(_this);
values.forEach(function (value) {
if (value.valueOf() === min.valueOf()) {
minExistsInExceptions = true;
}
if (value.valueOf() === max.valueOf()) {
maxExistsInExceptions = true;
}
});
});
var newMin = minExistsInExceptions ? min : this.invert(this.scale(min) - (this.scale(max) - this.scale(min)) * p);
var newMax = maxExistsInExceptions ? max : this.invert(this.scale(max) + (this.scale(max) - this.scale(min)) * p);
return this._niceDomain([newMin, newMax]);
};
QuantitativeScale.prototype._expandSingleValueDomain = function (singleValueDomain) {
return singleValueDomain;
};
/**
* Computes the domain value corresponding to a supplied range value.
*
* @param {number} value: A value from the Scale's range.
* @returns {D} The domain value corresponding to the supplied range value.
*/
QuantitativeScale.prototype.invert = function (value) {
throw new Error("Subclasses should override invert");
};
QuantitativeScale.prototype.domain = function (values) {
if (values != null) {
this._domainMin = values[0];
this._domainMax = values[1];
}
return _super.prototype.domain.call(this, values);
};
QuantitativeScale.prototype.domainMin = function (domainMin) {
if (domainMin == null) {
return this.domain()[0];
}
this._domainMin = domainMin;
this._autoDomainIfAutomaticMode();
return this;
};
QuantitativeScale.prototype.domainMax = function (domainMax) {
if (domainMax == null) {
return this.domain()[1];
}
this._domainMax = domainMax;
this._autoDomainIfAutomaticMode();
return this;
};
QuantitativeScale.prototype.extentOfValues = function (values) {
// HACKHACK: TS1.4 doesn't consider numbers to be Number-like (valueOf() returning number), so D can't be typed correctly
var extent = d3.extent(values.filter(function (value) { return Plottable.Utils.Math.isValidNumber(+value); }));
if (extent[0] == null || extent[1] == null) {
return [];
}
else {
return extent;
}
};
QuantitativeScale.prototype._setDomain = function (values) {
var isNaNOrInfinity = function (x) { return Plottable.Utils.Math.isNaN(x) || x === Infinity || x === -Infinity; };
if (isNaNOrInfinity(values[0]) || isNaNOrInfinity(values[1])) {
Plottable.Utils.Window.warn("Warning: QuantitativeScales cannot take NaN or Infinity as a domain value. Ignoring.");
return;
}
_super.prototype._setDomain.call(this, values);
};
/**
* Gets the array of tick values generated by the default algorithm.
*/
QuantitativeScale.prototype.defaultTicks = function () {
throw new Error("Subclasses should override _getDefaultTicks");
};
/**
* Gets an array of tick values spanning the domain.
*
* @returns {D[]}
*/
QuantitativeScale.prototype.ticks = function () {
return this._tickGenerator(this);
};
/**
* Given a domain, expands its domain onto "nice" values, e.g. whole
* numbers.
*/
QuantitativeScale.prototype._niceDomain = function (domain, count) {
throw new Error("Subclasses should override _niceDomain");
};
QuantitativeScale.prototype._defaultExtent = function () {
throw new Error("Subclasses should override _defaultExtent");
};
QuantitativeScale.prototype.tickGenerator = function (generator) {
if (generator == null) {
return this._tickGenerator;
}
else {
this._tickGenerator = generator;
return this;
}
};
QuantitativeScale._DEFAULT_NUM_TICKS = 10;
return QuantitativeScale;
})(Plottable.Scale);
Plottable.QuantitativeScale = QuantitativeScale;
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Scales;
(function (Scales) {
var Linear = (function (_super) {
__extends(Linear, _super);
/**
* @constructor
*/
function Linear() {
_super.call(this);
this._d3Scale = d3.scale.linear();
}
Linear.prototype._defaultExtent = function () {
return [0, 1];
};
Linear.prototype._expandSingleValueDomain = function (singleValueDomain) {
if (singleValueDomain[0] === singleValueDomain[1]) {
return [singleValueDomain[0] - 1, singleValueDomain[1] + 1];
}
return singleValueDomain;
};
Linear.prototype.scale = function (value) {
return this._d3Scale(value);
};
Linear.prototype._getDomain = function () {
return this._d3Scale.domain();
};
Linear.prototype._setBackingScaleDomain = function (values) {
this._d3Scale.domain(values);
};
Linear.prototype._getRange = function () {
return this._d3Scale.range();
};
Linear.prototype._setRange = function (values) {
this._d3Scale.range(values);
};
Linear.prototype.invert = function (value) {
return this._d3Scale.invert(value);
};
Linear.prototype.defaultTicks = function () {
return this._d3Scale.ticks(Scales.Linear._DEFAULT_NUM_TICKS);
};
Linear.prototype._niceDomain = function (domain, count) {
return this._d3Scale.copy().domain(domain).nice(count).domain();
};
return Linear;
})(Plottable.QuantitativeScale);
Scales.Linear = Linear;
})(Scales = Plottable.Scales || (Plottable.Scales = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Scales;
(function (Scales) {
var ModifiedLog = (function (_super) {
__extends(ModifiedLog, _super);
/**
* A ModifiedLog Scale acts as a regular log scale for large numbers.
* As it approaches 0, it gradually becomes linear.
* Consequently, a ModifiedLog Scale can process 0 and negative numbers.
*
* @constructor
* @param {number} [base=10]
* The base of the log. Must be > 1.
*
* For x <= base, scale(x) = log(x).
*
* For 0 < x < base, scale(x) will become more and more
* linear as it approaches 0.
*
* At x == 0, scale(x) == 0.
*
* For negative values, scale(-x) = -scale(x).
*/
function ModifiedLog(base) {
if (base === void 0) { base = 10; }
_super.call(this);
this._d3Scale = d3.scale.linear();
this._base = base;
this._pivot = this._base;
this._setDomain(this._defaultExtent());
if (base <= 1) {
throw new Error("ModifiedLogScale: The base must be > 1");
}
}
/**
* Returns an adjusted log10 value for graphing purposes. The first
* adjustment is that negative values are changed to positive during
* the calculations, and then the answer is negated at the end. The
* second is that, for values less than 10, an increasingly large
* (0 to 1) scaling factor is added such that at 0 the value is
* adjusted to 1, resulting in a returned result of 0.
*/
ModifiedLog.prototype._adjustedLog = function (x) {
var negationFactor = x < 0 ? -1 : 1;
x *= negationFactor;
if (x < this._pivot) {
x += (this._pivot - x) / this._pivot;
}
x = Math.log(x) / Math.log(this._base);
x *= negationFactor;
return x;
};
ModifiedLog.prototype._invertedAdjustedLog = function (x) {
var negationFactor = x < 0 ? -1 : 1;
x *= negationFactor;
x = Math.pow(this._base, x);
if (x < this._pivot) {
x = (this._pivot * (x - 1)) / (this._pivot - 1);
}
x *= negationFactor;
return x;
};
ModifiedLog.prototype.scale = function (x) {
return this._d3Scale(this._adjustedLog(x));
};
ModifiedLog.prototype.invert = function (x) {
return this._invertedAdjustedLog(this._d3Scale.invert(x));
};
ModifiedLog.prototype._getDomain = function () {
return this._untransformedDomain;
};
ModifiedLog.prototype._setDomain = function (values) {
this._untransformedDomain = values;
var transformedDomain = [this._adjustedLog(values[0]), this._adjustedLog(values[1])];
_super.prototype._setDomain.call(this, transformedDomain);
};
ModifiedLog.prototype._setBackingScaleDomain = function (values) {
this._d3Scale.domain(values);
};
ModifiedLog.prototype.ticks = function () {
// Say your domain is [-100, 100] and your pivot is 10.
// then we're going to draw negative log ticks from -100 to -10,
// linear ticks from -10 to 10, and positive log ticks from 10 to 100.
var middle = function (x, y, z) { return [x, y, z].sort(function (a, b) { return a - b; })[1]; };
var min = Plottable.Utils.Math.min(this._untransformedDomain, 0);
var max = Plottable.Utils.Math.max(this._untransformedDomain, 0);
var negativeLower = min;
var negativeUpper = middle(min, max, -this._pivot);
var positiveLower = middle(min, max, this._pivot);
var positiveUpper = max;
var negativeLogTicks = this._logTicks(-negativeUpper, -negativeLower).map(function (x) { return -x; }).reverse();
var positiveLogTicks = this._logTicks(positiveLower, positiveUpper);
var linearMin = Math.max(min, -this._pivot);
var linearMax = Math.min(max, this._pivot);
var linearTicks = d3.scale.linear().domain([linearMin, linearMax]).ticks(this._howManyTicks(linearMin, linearMax));
var ticks = negativeLogTicks.concat(linearTicks).concat(positiveLogTicks);
// If you only have 1 tick, you can't tell how big the scale is.
if (ticks.length <= 1) {
ticks = d3.scale.linear().domain([min, max]).ticks(Scales.ModifiedLog._DEFAULT_NUM_TICKS);
}
return ticks;
};
/**
* Return an appropriate number of ticks from lower to upper.
*
* This will first try to fit as many powers of this.base as it can from
* lower to upper.
*
* If it still has ticks after that, it will generate ticks in "clusters",
* e.g. [20, 30, ... 90, 100] would be a cluster, [200, 300, ... 900, 1000]
* would be another cluster.
*
* This function will generate clusters as large as it can while not
* drastically exceeding its number of ticks.
*/
ModifiedLog.prototype._logTicks = function (lower, upper) {
var _this = this;
var nTicks = this._howManyTicks(lower, upper);
if (nTicks === 0) {
return [];
}
var startLogged = Math.floor(Math.log(lower) / Math.log(this._base));
var endLogged = Math.ceil(Math.log(upper) / Math.log(this._base));
var bases = d3.range(endLogged, startLogged, -Math.ceil((endLogged - startLogged) / nTicks));
var multiples = d3.range(this._base, 1, -(this._base - 1)).map(Math.floor);
var uniqMultiples = Plottable.Utils.Array.uniq(multiples);
var clusters = bases.map(function (b) { return uniqMultiples.map(function (x) { return Math.pow(_this._base, b - 1) * x; }); });
var flattened = Plottable.Utils.Array.flatten(clusters);
var filtered = flattened.filter(function (x) { return lower <= x && x <= upper; });
var sorted = filtered.sort(function (x, y) { return x - y; });
return sorted;
};
/**
* How many ticks does the range [lower, upper] deserve?
*
* e.g. if your domain was [10, 1000] and I asked _howManyTicks(10, 100),
* I would get 1/2 of the ticks. The range 10, 100 takes up 1/2 of the
* distance when plotted.
*/
ModifiedLog.prototype._howManyTicks = function (lower, upper) {
var adjustedMin = this._adjustedLog(Plottable.Utils.Math.min(this._untransformedDomain, 0));
var adjustedMax = this._adjustedLog(Plottable.Utils.Math.max(this._untransformedDomain, 0));
var adjustedLower = this._adjustedLog(lower);
var adjustedUpper = this._adjustedLog(upper);
var proportion = (adjustedUpper - adjustedLower) / (adjustedMax - adjustedMin);
var ticks = Math.ceil(proportion * Scales.ModifiedLog._DEFAULT_NUM_TICKS);
return ticks;
};
ModifiedLog.prototype._niceDomain = function (domain, count) {
return domain;
};
ModifiedLog.prototype._defaultExtent = function () {
return [0, this._base];
};
ModifiedLog.prototype._expandSingleValueDomain = function (singleValueDomain) {
if (singleValueDomain[0] === singleValueDomain[1]) {
var singleValue = singleValueDomain[0];
if (singleValue > 0) {
return [singleValue / this._base, singleValue * this._base];
}
else if (singleValue === 0) {
return [-this._base, this._base];
}
else {
return [singleValue * this._base, singleValue / this._base];
}
}
return singleValueDomain;
};
ModifiedLog.prototype._getRange = function () {
return this._d3Scale.range();
};
ModifiedLog.prototype._setRange = function (values) {
this._d3Scale.range(values);
};
ModifiedLog.prototype.defaultTicks = function () {
return this._d3Scale.ticks(Scales.ModifiedLog._DEFAULT_NUM_TICKS);
};
return ModifiedLog;
})(Plottable.QuantitativeScale);
Scales.ModifiedLog = ModifiedLog;
})(Scales = Plottable.Scales || (Plottable.Scales = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Scales;
(function (Scales) {
var Category = (function (_super) {
__extends(Category, _super);
/**
* A Category Scale maps strings to numbers.
*
* @constructor
*/
function Category() {
_super.call(this);
this._range = [0, 1];
this._d3Scale = d3.scale.ordinal();
var d3InnerPadding = 0.3;
this._innerPadding = Category._convertToPlottableInnerPadding(d3InnerPadding);
this._outerPadding = Category._convertToPlottableOuterPadding(0.5, d3InnerPadding);
}
Category.prototype.extentOfValues = function (values) {
return Plottable.Utils.Array.uniq(values);
};
Category.prototype._getExtent = function () {
return Plottable.Utils.Array.uniq(this._getAllIncludedValues());
};
Category.prototype.domain = function (values) {
return _super.prototype.domain.call(this, values);
};
Category.prototype._setDomain = function (values) {
_super.prototype._setDomain.call(this, values);
this.range(this.range()); // update range
};
Category.prototype.range = function (values) {
if (values == null) {
return this._range;
}
else {
this._range = values;
var d3InnerPadding = 1 - 1 / (1 + this.innerPadding());
var d3OuterPadding = this.outerPadding() / (1 + this.innerPadding());
this._d3Scale.rangeBands(values, d3InnerPadding, d3OuterPadding);
return this;
}
};
Category._convertToPlottableInnerPadding = function (d3InnerPadding) {
return 1 / (1 - d3InnerPadding) - 1;
};
Category._convertToPlottableOuterPadding = function (d3OuterPadding, d3InnerPadding) {
return d3OuterPadding / (1 - d3InnerPadding);
};
/**
* Returns the width of the range band.
*
* @returns {number} The range band width
*/
Category.prototype.rangeBand = function () {
return this._d3Scale.rangeBand();
};
/**
* Returns the step width of the scale.
*
* The step width is the pixel distance between adjacent values in the domain.
*
* @returns {number}
*/
Category.prototype.stepWidth = function () {
return this.rangeBand() * (1 + this.innerPadding());
};
Category.prototype.innerPadding = function (innerPadding) {
if (innerPadding == null) {
return this._innerPadding;
}
this._innerPadding = innerPadding;
this.range(this.range());
this._dispatchUpdate();
return this;
};
Category.prototype.outerPadding = function (outerPadding) {
if (outerPadding == null) {
return this._outerPadding;
}
this._outerPadding = outerPadding;
this.range(this.range());
this._dispatchUpdate();
return this;
};
Category.prototype.scale = function (value) {
// scale it to the middle
return this._d3Scale(value) + this.rangeBand() / 2;
};
Category.prototype._getDomain = function () {
return this._d3Scale.domain();
};
Category.prototype._setBackingScaleDomain = function (values) {
this._d3Scale.domain(values);
};
Category.prototype._getRange = function () {
return this._d3Scale.range();
};
Category.prototype._setRange = function (values) {
this._d3Scale.range(values);
};
return Category;
})(Plottable.Scale);
Scales.Category = Category;
})(Scales = Plottable.Scales || (Plottable.Scales = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Scales;
(function (Scales) {
var Color = (function (_super) {
__extends(Color, _super);
/**
* A Color Scale maps string values to color hex values expressed as a string.
*
* @constructor
* @param {string} [scaleType] One of "Category10"/"Category20"/"Category20b"/"Category20c".
* (see https://github.com/mbostock/d3/wiki/Ordinal-Scales#categorical-colors)
* If not supplied, reads the colors defined using CSS -- see plottable.css.
*/
function Color(scaleType) {
_super.call(this);
var scale;
switch (scaleType) {
case null:
case undefined:
if (Color._plottableColorCache == null) {
Color._plottableColorCache = Color._getPlottableColors();
}
scale = d3.scale.ordinal().range(Color._plottableColorCache);
break;
case "Category10":
case "category10":
case "10":
scale = d3.scale.category10();
break;
case "Category20":
case "category20":
case "20":
scale = d3.scale.category20();
break;
case "Category20b":
case "category20b":
case "20b":
scale = d3.scale.category20b();
break;
case "Category20c":
case "category20c":
case "20c":
scale = d3.scale.category20c();
break;
default:
throw new Error("Unsupported ColorScale type");
}
this._d3Scale = scale;
}
Color.prototype.extentOfValues = function (values) {
return Plottable.Utils.Array.uniq(values);
};
// Duplicated from OrdinalScale._getExtent - should be removed in #388
Color.prototype._getExtent = function () {
return Plottable.Utils.Array.uniq(this._getAllIncludedValues());
};
Color.invalidateColorCache = function () {
Color._plottableColorCache = null;
};
Color._getPlottableColors = function () {
var plottableDefaultColors = [];
var colorTester = d3.select("body").append("plottable-color-tester");
var defaultColorHex = Plottable.Utils.Color.colorTest(colorTester, "");
var i = 0;
var colorHex;
while ((colorHex = Plottable.Utils.Color.colorTest(colorTester, "plottable-colors-" + i)) !== null &&
i < this._MAXIMUM_COLORS_FROM_CSS) {
if (colorHex === defaultColorHex && colorHex === plottableDefaultColors[plottableDefaultColors.length - 1]) {
break;
}
plottableDefaultColors.push(colorHex);
i++;
}
colorTester.remove();
return plottableDefaultColors;
};
/**
* Returns the color-string corresponding to a given string.
* If there are not enough colors in the range(), a lightened version of an existing color will be used.
*
* @param {string} value
* @returns {string}
*/
Color.prototype.scale = function (value) {
var color = this._d3Scale(value);
var index = this.domain().indexOf(value);
var numLooped = Math.floor(index / this.range().length);
var modifyFactor = Math.log(numLooped * Color._LOOP_LIGHTEN_FACTOR + 1);
return Plottable.Utils.Color.lightenColor(color, modifyFactor);
};
Color.prototype._getDomain = function () {
return this._d3Scale.domain();
};
Color.prototype._setBackingScaleDomain = function (values) {
this._d3Scale.domain(values);
};
Color.prototype._getRange = function () {
return this._d3Scale.range();
};
Color.prototype._setRange = function (values) {
this._d3Scale.range(values);
};
Color._LOOP_LIGHTEN_FACTOR = 1.6;
// The maximum number of colors we are getting from CSS stylesheets
Color._MAXIMUM_COLORS_FROM_CSS = 256;
return Color;
})(Plottable.Scale);
Scales.Color = Color;
})(Scales = Plottable.Scales || (Plottable.Scales = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Scales;
(function (Scales) {
var Time = (function (_super) {
__extends(Time, _super);
/**
* A Time Scale maps Date objects to numbers.
*
* @constructor
*/
function Time() {
_super.call(this);
this._d3Scale = d3.time.scale();
}
/**
* Returns an array of ticks values separated by the specified interval.
*
* @param {string} interval A string specifying the interval unit.
* @param {number?} [step] The number of multiples of the interval between consecutive ticks.
* @return {Date[]}
*/
Time.prototype.tickInterval = function (interval, step) {
// temporarily creats a time scale from our linear scale into a time scale so we can get access to its api
var tempScale = d3.time.scale();
var d3Interval = Time.timeIntervalToD3Time(interval);
tempScale.domain(this.domain());
tempScale.range(this.range());
return tempScale.ticks(d3Interval, step);
};
Time.prototype._setDomain = function (values) {
if (values[1] < values[0]) {
throw new Error("Scale.Time domain values must be in chronological order");
}
return _super.prototype._setDomain.call(this, values);
};
Time.prototype._defaultExtent = function () {
var now = new Date();
var endTimeValue = now.valueOf();
now.setDate(now.getDate() - 1);
var startTimeValue = now.valueOf();
return [new Date(startTimeValue), new Date(endTimeValue)];
};
Time.prototype._expandSingleValueDomain = function (singleValueDomain) {
var startTime = singleValueDomain[0].getTime();
var endTime = singleValueDomain[1].getTime();
if (startTime === endTime) {
var startDate = new Date(startTime);
startDate.setDate(startDate.getDate() - 1);
var endDate = new Date(endTime);
endDate.setDate(endDate.getDate() + 1);
return [startDate, endDate];
}
return singleValueDomain;
};
Time.prototype.scale = function (value) {
return this._d3Scale(value);
};
Time.prototype._getDomain = function () {
return this._d3Scale.domain();
};
Time.prototype._setBackingScaleDomain = function (values) {
this._d3Scale.domain(values);
};
Time.prototype._getRange = function () {
return this._d3Scale.range();
};
Time.prototype._setRange = function (values) {
this._d3Scale.range(values);
};
Time.prototype.invert = function (value) {
return this._d3Scale.invert(value);
};
Time.prototype.defaultTicks = function () {
return this._d3Scale.ticks(Scales.Time._DEFAULT_NUM_TICKS);
};
Time.prototype._niceDomain = function (domain) {
return this._d3Scale.copy().domain(domain).nice().domain();
};
/**
* Transforms the Plottable TimeInterval string into a d3 time interval equivalent.
* If the provided TimeInterval is incorrect, the default is d3.time.year
*/
Time.timeIntervalToD3Time = function (timeInterval) {
switch (timeInterval) {
case Plottable.TimeInterval.second:
return d3.time.second;
case Plottable.TimeInterval.minute:
return d3.time.minute;
case Plottable.TimeInterval.hour:
return d3.time.hour;
case Plottable.TimeInterval.day:
return d3.time.day;
case Plottable.TimeInterval.week:
return d3.time.week;
case Plottable.TimeInterval.month:
return d3.time.month;
case Plottable.TimeInterval.year:
return d3.time.year;
default:
throw Error("TimeInterval specified does not exist: " + timeInterval);
}
};
return Time;
})(Plottable.QuantitativeScale);
Scales.Time = Time;
})(Scales = Plottable.Scales || (Plottable.Scales = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Scales;
(function (Scales) {
var InterpolatedColor = (function (_super) {
__extends(InterpolatedColor, _super);
/**
* An InterpolatedColor Scale maps numbers to color hex values, expressed as strings.
*
* @param {string} [scaleType="linear"] One of "linear"/"log"/"sqrt"/"pow".
*/
function InterpolatedColor(scaleType) {
if (scaleType === void 0) { scaleType = "linear"; }
_super.call(this);
switch (scaleType) {
case "linear":
this._colorScale = d3.scale.linear();
break;
case "log":
this._colorScale = d3.scale.log();
break;
case "sqrt":
this._colorScale = d3.scale.sqrt();
break;
case "pow":
this._colorScale = d3.scale.pow();
break;
}
if (this._colorScale == null) {
throw new Error("unknown QuantitativeScale scale type " + scaleType);
}
this.range(InterpolatedColor.REDS);
}
InterpolatedColor.prototype.extentOfValues = function (values) {
var extent = d3.extent(values);
if (extent[0] == null || extent[1] == null) {
return [];
}
else {
return extent;
}
};
/**
* Generates the converted QuantitativeScale.
*/
InterpolatedColor.prototype._d3InterpolatedScale = function () {
return this._colorScale.range([0, 1]).interpolate(this._interpolateColors());
};
/**
* Generates the d3 interpolator for colors.
*/
InterpolatedColor.prototype._interpolateColors = function () {
var colors = this._colorRange;
if (colors.length < 2) {
throw new Error("Color scale arrays must have at least two elements.");
}
;
return function (a, b) {
return function (t) {
// Clamp t parameter to [0,1]
t = Math.max(0, Math.min(1, t));
// Determine indices for colors
var tScaled = t * (colors.length - 1);
var i0 = Math.floor(tScaled);
var i1 = Math.ceil(tScaled);
var frac = (tScaled - i0);
// Interpolate in the L*a*b color space
return d3.interpolateLab(colors[i0], colors[i1])(frac);
};
};
};
InterpolatedColor.prototype._resetScale = function () {
this._d3Scale = this._d3InterpolatedScale();
this._autoDomainIfAutomaticMode();
this._dispatchUpdate();
};
InterpolatedColor.prototype.autoDomain = function () {
// InterpolatedColorScales do not pad
var includedValues = this._getAllIncludedValues();
if (includedValues.length > 0) {
this._setDomain([Plottable.Utils.Math.min(includedValues, 0), Plottable.Utils.Math.max(includedValues, 0)]);
}
return this;
};
InterpolatedColor.prototype.scale = function (value) {
return this._d3Scale(value);
};
InterpolatedColor.prototype._getDomain = function () {
return this._d3Scale.domain();
};
InterpolatedColor.prototype._setBackingScaleDomain = function (values) {
this._d3Scale.domain(values);
};
InterpolatedColor.prototype._getRange = function () {
return this._colorRange;
};
InterpolatedColor.prototype._setRange = function (range) {
this._colorRange = range;
this._resetScale();
};
InterpolatedColor.REDS = [
"#FFFFFF",
"#FFF6E1",
"#FEF4C0",
"#FED976",
"#FEB24C",
"#FD8D3C",
"#FC4E2A",
"#E31A1C",
"#B10026" // red
];
InterpolatedColor.BLUES = [
"#FFFFFF",
"#CCFFFF",
"#A5FFFD",
"#85F7FB",
"#6ED3EF",
"#55A7E0",
"#417FD0",
"#2545D3",
"#0B02E1" // blue
];
InterpolatedColor.POSNEG = [
"#0B02E1",
"#2545D3",
"#417FD0",
"#55A7E0",
"#6ED3EF",
"#85F7FB",
"#A5FFFD",
"#CCFFFF",
"#FFFFFF",
"#FFF6E1",
"#FEF4C0",
"#FED976",
"#FEB24C",
"#FD8D3C",
"#FC4E2A",
"#E31A1C",
"#B10026" // red
];
return InterpolatedColor;
})(Plottable.Scale);
Scales.InterpolatedColor = InterpolatedColor;
})(Scales = Plottable.Scales || (Plottable.Scales = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var Plottable;
(function (Plottable) {
var Scales;
(function (Scales) {
var TickGenerators;
(function (TickGenerators) {
/**
* Creates a TickGenerator using the specified interval.
*
* Generates ticks at multiples of the interval while also including the domain boundaries.
*
* @param {number} interval
* @returns {TickGenerator}
*/
function intervalTickGenerator(interval) {
if (interval <= 0) {
throw new Error("interval must be positive number");
}
return function (s) {
var domain = s.domain();
var low = Math.min(domain[0], domain[1]);
var high = Math.max(domain[0], domain[1]);
var firstTick = Math.ceil(low / interval) * interval;
var numTicks = Math.floor((high - firstTick) / interval) + 1;
var lowTicks = low % interval === 0 ? [] : [low];
var middleTicks = Plottable.Utils.Math.range(0, numTicks).map(function (t) { return firstTick + t * interval; });
var highTicks = high % interval === 0 ? [] : [high];
return lowTicks.concat(middleTicks).concat(highTicks);
};
}
TickGenerators.intervalTickGenerator = intervalTickGenerator;
/**
* Creates a TickGenerator returns only integer tick values.
*
* @returns {TickGenerator}
*/
function integerTickGenerator() {
return function (s) {
var defaultTicks = s.defaultTicks();
return defaultTicks.filter(function (tick, i) { return (tick % 1 === 0) || (i === 0) || (i === defaultTicks.length - 1); });
};
}
TickGenerators.integerTickGenerator = integerTickGenerator;
})(TickGenerators = Scales.TickGenerators || (Scales.TickGenerators = {}));
})(Scales = Plottable.Scales || (Plottable.Scales = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var Plottable;
(function (Plottable) {
var Drawer = (function () {
/**
* A Drawer draws svg elements based on the input Dataset.
*
* @constructor
* @param {Dataset} dataset The dataset associated with this Drawer
*/
function Drawer(dataset) {
this._cachedSelectionValid = false;
this._dataset = dataset;
}
Drawer.prototype.renderArea = function (area) {
if (area == null) {
return this._renderArea;
}
this._renderArea = area;
this._cachedSelectionValid = false;
return this;
};
/**
* Removes the Drawer and its renderArea
*/
Drawer.prototype.remove = function () {
if (this.renderArea() != null) {
this.renderArea().remove();
}
};
/**
* Binds data to selection
*
* @param{any[]} data The data to be drawn
*/
Drawer.prototype._bindSelectionData = function (data) {
var dataElements = this.selection().data(data);
dataElements.enter().append(this._svgElementName);
dataElements.exit().remove();
this._applyDefaultAttributes(dataElements);
};
Drawer.prototype._applyDefaultAttributes = function (selection) {
if (this._className != null) {
selection.classed(this._className, true);
}
};
/**
* Draws data using one step
*
* @param{AppliedDrawStep} step The step, how data should be drawn.
*/
Drawer.prototype._drawStep = function (step) {
var selection = this.selection();
var colorAttributes = ["fill", "stroke"];
colorAttributes.forEach(function (colorAttribute) {
if (step.attrToAppliedProjector[colorAttribute] != null) {
selection.attr(colorAttribute, step.attrToAppliedProjector[colorAttribute]);
}
});
step.animator.animate(selection, step.attrToAppliedProjector);
if (this._className != null) {
this.selection().classed(this._className, true);
}
};
Drawer.prototype._appliedProjectors = function (attrToProjector) {
var _this = this;
var modifiedAttrToProjector = {};
Object.keys(attrToProjector).forEach(function (attr) {
modifiedAttrToProjector[attr] =
function (datum, index) { return attrToProjector[attr](datum, index, _this._dataset); };
});
return modifiedAttrToProjector;
};
/**
* Calculates the total time it takes to use the input drawSteps to draw the input data
*
* @param {any[]} data The data that would have been drawn
* @param {Drawers.DrawStep[]} drawSteps The DrawSteps to use
* @returns {number} The total time it takes to draw
*/
Drawer.prototype.totalDrawTime = function (data, drawSteps) {
var delay = 0;
drawSteps.forEach(function (drawStep, i) {
delay += drawStep.animator.totalTime(data.length);
});
return delay;
};
/**
* Draws the data into the renderArea using the spefic steps and metadata
*
* @param{any[]} data The data to be drawn
* @param{DrawStep[]} drawSteps The list of steps, which needs to be drawn
*/
Drawer.prototype.draw = function (data, drawSteps) {
var _this = this;
var appliedDrawSteps = drawSteps.map(function (dr) {
var attrToAppliedProjector = _this._appliedProjectors(dr.attrToProjector);
return {
attrToAppliedProjector: attrToAppliedProjector,
animator: dr.animator
};
});
this._bindSelectionData(data);
this._cachedSelectionValid = false;
var delay = 0;
appliedDrawSteps.forEach(function (drawStep, i) {
Plottable.Utils.Window.setTimeout(function () { return _this._drawStep(drawStep); }, delay);
delay += drawStep.animator.totalTime(data.length);
});
return this;
};
Drawer.prototype.selection = function () {
if (!this._cachedSelectionValid) {
this._cachedSelection = this.renderArea().selectAll(this.selector());
this._cachedSelectionValid = true;
}
return this._cachedSelection;
};
/**
* Returns the CSS selector for this Drawer's visual elements.
*/
Drawer.prototype.selector = function () {
return this._svgElementName;
};
/**
* Returns the D3 selection corresponding to the datum with the specified index.
*/
Drawer.prototype.selectionForIndex = function (index) {
return d3.select(this.selection()[0][index]);
};
return Drawer;
})();
Plottable.Drawer = Drawer;
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Drawers;
(function (Drawers) {
var Line = (function (_super) {
__extends(Line, _super);
function Line(dataset) {
_super.call(this, dataset);
this._className = "line";
this._svgElementName = "path";
}
Line.prototype._applyDefaultAttributes = function (selection) {
_super.prototype._applyDefaultAttributes.call(this, selection);
selection.style("fill", "none");
};
Line.prototype.selectionForIndex = function (index) {
return d3.select(this.selection()[0][0]);
};
return Line;
})(Plottable.Drawer);
Drawers.Line = Line;
})(Drawers = Plottable.Drawers || (Plottable.Drawers = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Drawers;
(function (Drawers) {
var Area = (function (_super) {
__extends(Area, _super);
function Area(dataset) {
_super.call(this, dataset);
this._className = "area";
this._svgElementName = "path";
}
Area.prototype._applyDefaultAttributes = function (selection) {
_super.prototype._applyDefaultAttributes.call(this, selection);
selection.style("stroke", "none");
};
Area.prototype.selectionForIndex = function (index) {
return d3.select(this.selection()[0][0]);
};
return Area;
})(Plottable.Drawer);
Drawers.Area = Area;
})(Drawers = Plottable.Drawers || (Plottable.Drawers = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Drawers;
(function (Drawers) {
var Rectangle = (function (_super) {
__extends(Rectangle, _super);
function Rectangle(dataset) {
_super.call(this, dataset);
this._svgElementName = "rect";
}
return Rectangle;
})(Plottable.Drawer);
Drawers.Rectangle = Rectangle;
})(Drawers = Plottable.Drawers || (Plottable.Drawers = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Drawers;
(function (Drawers) {
var Arc = (function (_super) {
__extends(Arc, _super);
function Arc(dataset) {
_super.call(this, dataset);
this._className = "arc";
this._svgElementName = "path";
}
return Arc;
})(Plottable.Drawer);
Drawers.Arc = Arc;
})(Drawers = Plottable.Drawers || (Plottable.Drawers = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Drawers;
(function (Drawers) {
var Symbol = (function (_super) {
__extends(Symbol, _super);
function Symbol(dataset) {
_super.call(this, dataset);
this._svgElementName = "path";
this._className = "symbol";
}
return Symbol;
})(Plottable.Drawer);
Drawers.Symbol = Symbol;
})(Drawers = Plottable.Drawers || (Plottable.Drawers = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Drawers;
(function (Drawers) {
var Segment = (function (_super) {
__extends(Segment, _super);
function Segment(dataset) {
_super.call(this, dataset);
this._svgElementName = "line";
}
return Segment;
})(Plottable.Drawer);
Drawers.Segment = Segment;
})(Drawers = Plottable.Drawers || (Plottable.Drawers = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var Plottable;
(function (Plottable) {
var Components;
(function (Components) {
var Alignment = (function () {
function Alignment() {
}
Alignment.TOP = "top";
Alignment.BOTTOM = "bottom";
Alignment.LEFT = "left";
Alignment.RIGHT = "right";
Alignment.CENTER = "center";
return Alignment;
})();
Components.Alignment = Alignment;
})(Components = Plottable.Components || (Plottable.Components = {}));
var Component = (function () {
function Component() {
this._clipPathEnabled = false;
this._origin = { x: 0, y: 0 }; // Origin of the coordinate space for the Component.
this._xAlignment = "left";
this._yAlignment = "top";
this._isSetup = false;
this._isAnchored = false;
this._boxes = [];
this._isTopLevelComponent = false;
this._cssClasses = new Plottable.Utils.Set();
this._destroyed = false;
this._onAnchorCallbacks = new Plottable.Utils.CallbackSet();
this._onDetachCallbacks = new Plottable.Utils.CallbackSet();
this._cssClasses.add("component");
}
/**
* Attaches the Component as a child of a given d3 Selection.
*
* @param {d3.Selection} selection.
* @returns {Component} The calling Component.
*/
Component.prototype.anchor = function (selection) {
if (this._destroyed) {
throw new Error("Can't reuse destroy()-ed Components!");
}
if (selection.node().nodeName.toLowerCase() === "svg") {
// svg node gets the "plottable" CSS class
this._rootSVG = selection;
this._rootSVG.classed("plottable", true);
// visible overflow for firefox https://stackoverflow.com/questions/5926986/why-does-firefox-appear-to-truncate-embedded-svgs
this._rootSVG.style("overflow", "visible");
this._isTopLevelComponent = true;
}
if (this._element != null) {
// reattach existing element
selection.node().appendChild(this._element.node());
}
else {
this._element = selection.append("g");
this._setup();
}
this._isAnchored = true;
this._onAnchorCallbacks.callCallbacks(this);
return this;
};
/**
* Adds a callback to be called on anchoring the Component to the DOM.
* If the Component is already anchored, the callback is called immediately.
*
* @param {ComponentCallback} callback
* @return {Component}
*/
Component.prototype.onAnchor = function (callback) {
if (this._isAnchored) {
callback(this);
}
this._onAnchorCallbacks.add(callback);
return this;
};
/**
* Removes a callback that would be called on anchoring the Component to the DOM.
* The callback is identified by reference equality.
*
* @param {ComponentCallback} callback
* @return {Component}
*/
Component.prototype.offAnchor = function (callback) {
this._onAnchorCallbacks.delete(callback);
return this;
};
/**
* Creates additional elements as necessary for the Component to function.
* Called during anchor() if the Component's element has not been created yet.
* Override in subclasses to provide additional functionality.
*/
Component.prototype._setup = function () {
var _this = this;
if (this._isSetup) {
return;
}
this._cssClasses.forEach(function (cssClass) {
_this._element.classed(cssClass, true);
});
this._cssClasses = new Plottable.Utils.Set();
this._backgroundContainer = this._element.append("g").classed("background-container", true);
this._addBox("background-fill", this._backgroundContainer);
this._content = this._element.append("g").classed("content", true);
this._foregroundContainer = this._element.append("g").classed("foreground-container", true);
this._boxContainer = this._element.append("g").classed("box-container", true);
if (this._clipPathEnabled) {
this._generateClipPath();
}
;
this._boundingBox = this._addBox("bounding-box");
this._isSetup = true;
};
/**
* Given available space in pixels, returns the minimum width and height this Component will need.
*
* @param {number} availableWidth
* @param {number} availableHeight
* @returns {SpaceRequest}
*/
Component.prototype.requestedSpace = function (availableWidth, availableHeight) {
return {
minWidth: 0,
minHeight: 0
};
};
/**
* Computes and sets the size, position, and alignment of the Component from the specified values.
* If no parameters are supplied and the Component is a root node,
* they are inferred from the size of the Component's element.
*
* @param {Point} [origin] Origin of the space offered to the Component.
* @param {number} [availableWidth] Available width in pixels.
* @param {number} [availableHeight] Available height in pixels.
* @returns {Component} The calling Component.
*/
Component.prototype.computeLayout = function (origin, availableWidth, availableHeight) {
var _this = this;
if (origin == null || availableWidth == null || availableHeight == null) {
if (this._element == null) {
throw new Error("anchor() must be called before computeLayout()");
}
else if (this._isTopLevelComponent) {
// we are the root node, retrieve height/width from root SVG
origin = { x: 0, y: 0 };
// Set width/height to 100% if not specified, to allow accurate size calculation
// see http://www.w3.org/TR/CSS21/visudet.html#block-replaced-width
// and http://www.w3.org/TR/CSS21/visudet.html#inline-replaced-height
if (this._rootSVG.attr("width") == null) {
this._rootSVG.attr("width", "100%");
}
if (this._rootSVG.attr("height") == null) {
this._rootSVG.attr("height", "100%");
}
var elem = this._rootSVG.node();
availableWidth = Plottable.Utils.DOM.elementWidth(elem);
availableHeight = Plottable.Utils.DOM.elementHeight(elem);
}
else {
throw new Error("null arguments cannot be passed to computeLayout() on a non-root node");
}
}
var size = this._sizeFromOffer(availableWidth, availableHeight);
this._width = size.width;
this._height = size.height;
var xAlignProportion = Component._xAlignToProportion[this._xAlignment];
var yAlignProportion = Component._yAlignToProportion[this._yAlignment];
this._origin = {
x: origin.x + (availableWidth - this.width()) * xAlignProportion,
y: origin.y + (availableHeight - this.height()) * yAlignProportion
};
this._element.attr("transform", "translate(" + this._origin.x + "," + this._origin.y + ")");
this._boxes.forEach(function (b) { return b.attr("width", _this.width()).attr("height", _this.height()); });
return this;
};
Component.prototype._sizeFromOffer = function (availableWidth, availableHeight) {
var requestedSpace = this.requestedSpace(availableWidth, availableHeight);
return {
width: this.fixedWidth() ? Math.min(availableWidth, requestedSpace.minWidth) : availableWidth,
height: this.fixedHeight() ? Math.min(availableHeight, requestedSpace.minHeight) : availableHeight
};
};
/**
* Queues the Component for rendering.
*
* @returns {Component} The calling Component.
*/
Component.prototype.render = function () {
if (this._isAnchored && this._isSetup && this.width() >= 0 && this.height() >= 0) {
Plottable.RenderController.registerToRender(this);
}
return this;
};
Component.prototype._scheduleComputeLayout = function () {
if (this._isAnchored && this._isSetup) {
Plottable.RenderController.registerToComputeLayout(this);
}
};
/**
* Renders the Component without waiting for the next frame.
*/
Component.prototype.renderImmediately = function () {
return this;
};
/**
* Causes the Component to re-layout and render.
*
* This function should be called when a CSS change has occured that could
* influence the layout of the Component, such as changing the font size.
*
* @returns {Component} The calling Component.
*/
Component.prototype.redraw = function () {
if (this._isAnchored && this._isSetup) {
if (this._isTopLevelComponent) {
this._scheduleComputeLayout();
}
else {
this.parent().redraw();
}
}
return this;
};
/**
* Renders the Component to a given <svg>.
*
* @param {String|d3.Selection} element A selector-string for the <svg>, or a d3 selection containing an <svg>.
* @returns {Component} The calling Component.
*/
Component.prototype.renderTo = function (element) {
this.detach();
if (element != null) {
var selection;
if (typeof (element) === "string") {
selection = d3.select(element);
}
else {
selection = element;
}
if (!selection.node() || selection.node().nodeName.toLowerCase() !== "svg") {
throw new Error("Plottable requires a valid SVG to renderTo");
}
this.anchor(selection);
}
if (this._element == null) {
throw new Error("If a Component has never been rendered before, then renderTo must be given a node to render to, " +
"or a d3.Selection, or a selector string");
}
this.computeLayout();
this.render();
// flush so that consumers can immediately attach to stuff we create in the DOM
Plottable.RenderController.flush();
return this;
};
Component.prototype.xAlignment = function (xAlignment) {
if (xAlignment == null) {
return this._xAlignment;
}
xAlignment = xAlignment.toLowerCase();
if (Component._xAlignToProportion[xAlignment] == null) {
throw new Error("Unsupported alignment: " + xAlignment);
}
this._xAlignment = xAlignment;
this.redraw();
return this;
};
Component.prototype.yAlignment = function (yAlignment) {
if (yAlignment == null) {
return this._yAlignment;
}
yAlignment = yAlignment.toLowerCase();
if (Component._yAlignToProportion[yAlignment] == null) {
throw new Error("Unsupported alignment: " + yAlignment);
}
this._yAlignment = yAlignment;
this.redraw();
return this;
};
Component.prototype._addBox = function (className, parentElement) {
if (this._element == null) {
throw new Error("Adding boxes before anchoring is currently disallowed");
}
parentElement = parentElement == null ? this._boxContainer : parentElement;
var box = parentElement.append("rect");
if (className != null) {
box.classed(className, true);
}
this._boxes.push(box);
if (this.width() != null && this.height() != null) {
box.attr("width", this.width()).attr("height", this.height());
}
return box;
};
Component.prototype._generateClipPath = function () {
// The clip path will prevent content from overflowing its Component space.
// HACKHACK: IE <=9 does not respect the HTML base element in SVG.
// They don't need the current URL in the clip path reference.
var prefix = /MSIE [5-9]/.test(navigator.userAgent) ? "" : document.location.href;
prefix = prefix.split("#")[0]; // To fix cases where an anchor tag was used
var clipPathId = Plottable.Utils.DOM.generateUniqueClipPathId();
this._element.attr("clip-path", "url(\"" + prefix + "#" + clipPathId + "\")");
var clipPathParent = this._boxContainer.append("clipPath")
.attr("id", clipPathId);
this._addBox("clip-rect", clipPathParent);
};
/**
* Checks if the Component has a given CSS class.
*
* @param {string} cssClass The CSS class to check for.
*/
Component.prototype.hasClass = function (cssClass) {
if (cssClass == null) {
return false;
}
if (this._element == null) {
return this._cssClasses.has(cssClass);
}
else {
return this._element.classed(cssClass);
}
};
/**
* Adds a given CSS class to the Component.
*
* @param {string} cssClass The CSS class to add.
* @returns {Component} The calling Component.
*/
Component.prototype.addClass = function (cssClass) {
if (cssClass == null) {
return this;
}
if (this._element == null) {
this._cssClasses.add(cssClass);
}
else {
this._element.classed(cssClass, true);
}
return this;
};
/**
* Removes a given CSS class from the Component.
*
* @param {string} cssClass The CSS class to remove.
* @returns {Component} The calling Component.
*/
Component.prototype.removeClass = function (cssClass) {
if (cssClass == null) {
return this;
}
if (this._element == null) {
this._cssClasses.delete(cssClass);
}
else {
this._element.classed(cssClass, false);
}
return this;
};
/**
* Checks if the Component has a fixed width or if it grows to fill available space.
* Returns false by default on the base Component class.
*/
Component.prototype.fixedWidth = function () {
return false;
};
/**
* Checks if the Component has a fixed height or if it grows to fill available space.
* Returns false by default on the base Component class.
*/
Component.prototype.fixedHeight = function () {
return false;
};
/**
* Detaches a Component from the DOM. The Component can be reused.
*
* This should only be used if you plan on reusing the calling Component. Otherwise, use destroy().
*
* @returns The calling Component.
*/
Component.prototype.detach = function () {
this.parent(null);
if (this._isAnchored) {
this._element.remove();
}
this._isAnchored = false;
this._onDetachCallbacks.callCallbacks(this);
return this;
};
/**
* Adds a callback to be called when the Component is detach()-ed.
*
* @param {ComponentCallback} callback
* @return {Component} The calling Component.
*/
Component.prototype.onDetach = function (callback) {
this._onDetachCallbacks.add(callback);
return this;
};
/**
* Removes a callback to be called when the Component is detach()-ed.
* The callback is identified by reference equality.
*
* @param {ComponentCallback} callback
* @return {Component} The calling Component.
*/
Component.prototype.offDetach = function (callback) {
this._onDetachCallbacks.delete(callback);
return this;
};
Component.prototype.parent = function (parent) {
if (parent === undefined) {
return this._parent;
}
if (parent !== null && !parent.has(this)) {
throw new Error("Passed invalid parent");
}
this._parent = parent;
return this;
};
/**
* Removes a Component from the DOM and disconnects all listeners.
*/
Component.prototype.destroy = function () {
this._destroyed = true;
this.detach();
};
/**
* Gets the width of the Component in pixels.
*/
Component.prototype.width = function () {
return this._width;
};
/**
* Gets the height of the Component in pixels.
*/
Component.prototype.height = function () {
return this._height;
};
/**
* Gets the origin of the Component relative to its parent.
*
* @return {Point}
*/
Component.prototype.origin = function () {
return {
x: this._origin.x,
y: this._origin.y
};
};
/**
* Gets the origin of the Component relative to the root <svg>.
*
* @return {Point}
*/
Component.prototype.originToSVG = function () {
var origin = this.origin();
var ancestor = this.parent();
while (ancestor != null) {
var ancestorOrigin = ancestor.origin();
origin.x += ancestorOrigin.x;
origin.y += ancestorOrigin.y;
ancestor = ancestor.parent();
}
return origin;
};
/**
* Gets the Selection containing the <g> in front of the visual elements of the Component.
*
* Will return undefined if the Component has not been anchored.
*
* @return {d3.Selection}
*/
Component.prototype.foreground = function () {
return this._foregroundContainer;
};
/**
* Gets a Selection containing a <g> that holds the visual elements of the Component.
*
* Will return undefined if the Component has not been anchored.
*
* @return {d3.Selection} content selection for the Component
*/
Component.prototype.content = function () {
return this._content;
};
/**
* Gets the Selection containing the <g> behind the visual elements of the Component.
*
* Will return undefined if the Component has not been anchored.
*
* @return {d3.Selection} background selection for the Component
*/
Component.prototype.background = function () {
return this._backgroundContainer;
};
Component._xAlignToProportion = {
"left": 0,
"center": 0.5,
"right": 1
};
Component._yAlignToProportion = {
"top": 0,
"center": 0.5,
"bottom": 1
};
return Component;
})();
Plottable.Component = Component;
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
/*
* ComponentContainer class encapsulates Table and ComponentGroup's shared functionality.
* It will not do anything if instantiated directly.
*/
var ComponentContainer = (function (_super) {
__extends(ComponentContainer, _super);
function ComponentContainer() {
var _this = this;
_super.call(this);
this._detachCallback = function (component) { return _this.remove(component); };
}
ComponentContainer.prototype.anchor = function (selection) {
var _this = this;
_super.prototype.anchor.call(this, selection);
this._forEach(function (c) { return c.anchor(_this.content()); });
return this;
};
ComponentContainer.prototype.render = function () {
this._forEach(function (c) { return c.render(); });
return this;
};
/**
* Checks whether the specified Component is in the ComponentContainer.
*/
ComponentContainer.prototype.has = function (component) {
throw new Error("has() is not implemented on ComponentContainer");
};
ComponentContainer.prototype._adoptAndAnchor = function (component) {
component.parent(this);
component.onDetach(this._detachCallback);
if (this._isAnchored) {
component.anchor(this.content());
}
};
/**
* Removes the specified Component from the ComponentContainer.
*/
ComponentContainer.prototype.remove = function (component) {
if (this.has(component)) {
component.offDetach(this._detachCallback);
this._remove(component);
component.detach();
this.redraw();
}
return this;
};
/**
* Carry out the actual removal of a Component.
* Implementation dependent on the type of container.
*
* @return {boolean} true if the Component was successfully removed, false otherwise.
*/
ComponentContainer.prototype._remove = function (component) {
return false;
};
/**
* Invokes a callback on each Component in the ComponentContainer.
*/
ComponentContainer.prototype._forEach = function (callback) {
throw new Error("_forEach() is not implemented on ComponentContainer");
};
/**
* Destroys the ComponentContainer and all Components within it.
*/
ComponentContainer.prototype.destroy = function () {
_super.prototype.destroy.call(this);
this._forEach(function (c) { return c.destroy(); });
};
return ComponentContainer;
})(Plottable.Component);
Plottable.ComponentContainer = ComponentContainer;
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Components;
(function (Components) {
var Group = (function (_super) {
__extends(Group, _super);
/**
* Constructs a Group.
*
* A Group contains Components that will be rendered on top of each other.
* Components added later will be rendered above Components already in the Group.
*
* @constructor
* @param {Component[]} [components=[]] Components to be added to the Group.
*/
function Group(components) {
var _this = this;
if (components === void 0) { components = []; }
_super.call(this);
this._components = [];
this.addClass("component-group");
components.forEach(function (c) { return _this.append(c); });
}
Group.prototype._forEach = function (callback) {
this.components().forEach(callback);
};
/**
* Checks whether the specified Component is in the Group.
*/
Group.prototype.has = function (component) {
return this._components.indexOf(component) >= 0;
};
Group.prototype.requestedSpace = function (offeredWidth, offeredHeight) {
var requests = this._components.map(function (c) { return c.requestedSpace(offeredWidth, offeredHeight); });
return {
minWidth: Plottable.Utils.Math.max(requests, function (request) { return request.minWidth; }, 0),
minHeight: Plottable.Utils.Math.max(requests, function (request) { return request.minHeight; }, 0)
};
};
Group.prototype.computeLayout = function (origin, availableWidth, availableHeight) {
var _this = this;
_super.prototype.computeLayout.call(this, origin, availableWidth, availableHeight);
this._forEach(function (component) {
component.computeLayout({ x: 0, y: 0 }, _this.width(), _this.height());
});
return this;
};
Group.prototype._sizeFromOffer = function (availableWidth, availableHeight) {
return {
width: availableWidth,
height: availableHeight
};
};
Group.prototype.fixedWidth = function () {
return this._components.every(function (c) { return c.fixedWidth(); });
};
Group.prototype.fixedHeight = function () {
return this._components.every(function (c) { return c.fixedHeight(); });
};
/**
* @return {Component[]} The Components in this Group.
*/
Group.prototype.components = function () {
return this._components.slice();
};
/**
* Adds a Component to this Group.
* The added Component will be rendered above Components already in the Group.
*/
Group.prototype.append = function (component) {
if (component != null && !this.has(component)) {
component.detach();
this._components.push(component);
this._adoptAndAnchor(component);
this.redraw();
}
return this;
};
Group.prototype._remove = function (component) {
var removeIndex = this._components.indexOf(component);
if (removeIndex >= 0) {
this._components.splice(removeIndex, 1);
return true;
}
return false;
};
return Group;
})(Plottable.ComponentContainer);
Components.Group = Group;
})(Components = Plottable.Components || (Plottable.Components = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Axis = (function (_super) {
__extends(Axis, _super);
/**
* Constructs an Axis.
* An Axis is a visual representation of a Scale.
*
* @constructor
* @param {Scale} scale
* @param {string} orientation One of "top"/"bottom"/"left"/"right".
*/
function Axis(scale, orientation) {
var _this = this;
_super.call(this);
this._endTickLength = 5;
this._innerTickLength = 5;
this._tickLabelPadding = 10;
this._margin = 15;
this._showEndTickLabels = false;
if (scale == null || orientation == null) {
throw new Error("Axis requires a scale and orientation");
}
this._scale = scale;
this.orientation(orientation);
this._setDefaultAlignment();
this.addClass("axis");
if (this._isHorizontal()) {
this.addClass("x-axis");
}
else {
this.addClass("y-axis");
}
this.formatter(Plottable.Formatters.identity());
this._rescaleCallback = function (scale) { return _this._rescale(); };
this._scale.onUpdate(this._rescaleCallback);
}
Axis.prototype.destroy = function () {
_super.prototype.destroy.call(this);
this._scale.offUpdate(this._rescaleCallback);
};
Axis.prototype._isHorizontal = function () {
return this._orientation === "top" || this._orientation === "bottom";
};
Axis.prototype._computeWidth = function () {
// to be overridden by subclass logic
this._computedWidth = this._maxLabelTickLength();
return this._computedWidth;
};
Axis.prototype._computeHeight = function () {
// to be overridden by subclass logic
this._computedHeight = this._maxLabelTickLength();
return this._computedHeight;
};
Axis.prototype.requestedSpace = function (offeredWidth, offeredHeight) {
var requestedWidth = 0;
var requestedHeight = 0;
if (this._isHorizontal()) {
if (this._computedHeight == null) {
this._computeHeight();
}
requestedHeight = this._computedHeight + this._margin;
}
else {
if (this._computedWidth == null) {
this._computeWidth();
}
requestedWidth = this._computedWidth + this._margin;
}
return {
minWidth: requestedWidth,
minHeight: requestedHeight
};
};
Axis.prototype.fixedHeight = function () {
return this._isHorizontal();
};
Axis.prototype.fixedWidth = function () {
return !this._isHorizontal();
};
Axis.prototype._rescale = function () {
// default implementation; subclasses may call redraw() here
this.render();
};
Axis.prototype.computeLayout = function (origin, availableWidth, availableHeight) {
_super.prototype.computeLayout.call(this, origin, availableWidth, availableHeight);
if (this._isHorizontal()) {
this._scale.range([0, this.width()]);
}
else {
this._scale.range([this.height(), 0]);
}
return this;
};
Axis.prototype._setup = function () {
_super.prototype._setup.call(this);
this._tickMarkContainer = this.content().append("g")
.classed(Axis.TICK_MARK_CLASS + "-container", true);
this._tickLabelContainer = this.content().append("g")
.classed(Axis.TICK_LABEL_CLASS + "-container", true);
this._baseline = this.content().append("line").classed("baseline", true);
};
/*
* Function for generating tick values in data-space (as opposed to pixel values).
* To be implemented by subclasses.
*/
Axis.prototype._getTickValues = function () {
return [];
};
Axis.prototype.renderImmediately = function () {
var tickMarkValues = this._getTickValues();
var tickMarks = this._tickMarkContainer.selectAll("." + Axis.TICK_MARK_CLASS).data(tickMarkValues);
tickMarks.enter().append("line").classed(Axis.TICK_MARK_CLASS, true);
tickMarks.attr(this._generateTickMarkAttrHash());
d3.select(tickMarks[0][0]).classed(Axis.END_TICK_MARK_CLASS, true)
.attr(this._generateTickMarkAttrHash(true));
d3.select(tickMarks[0][tickMarkValues.length - 1]).classed(Axis.END_TICK_MARK_CLASS, true)
.attr(this._generateTickMarkAttrHash(true));
tickMarks.exit().remove();
this._baseline.attr(this._generateBaselineAttrHash());
return this;
};
Axis.prototype._generateBaselineAttrHash = function () {
var baselineAttrHash = {
x1: 0,
y1: 0,
x2: 0,
y2: 0
};
switch (this._orientation) {
case "bottom":
baselineAttrHash["x2"] = this.width();
break;
case "top":
baselineAttrHash["x2"] = this.width();
baselineAttrHash["y1"] = this.height();
baselineAttrHash["y2"] = this.height();
break;
case "left":
baselineAttrHash["x1"] = this.width();
baselineAttrHash["x2"] = this.width();
baselineAttrHash["y2"] = this.height();
break;
case "right":
baselineAttrHash["y2"] = this.height();
break;
}
return baselineAttrHash;
};
Axis.prototype._generateTickMarkAttrHash = function (isEndTickMark) {
var _this = this;
if (isEndTickMark === void 0) { isEndTickMark = false; }
var tickMarkAttrHash = {
x1: 0,
y1: 0,
x2: 0,
y2: 0
};
var scalingFunction = function (d) { return _this._scale.scale(d); };
if (this._isHorizontal()) {
tickMarkAttrHash["x1"] = scalingFunction;
tickMarkAttrHash["x2"] = scalingFunction;
}
else {
tickMarkAttrHash["y1"] = scalingFunction;
tickMarkAttrHash["y2"] = scalingFunction;
}
var tickLength = isEndTickMark ? this._endTickLength : this._innerTickLength;
switch (this._orientation) {
case "bottom":
tickMarkAttrHash["y2"] = tickLength;
break;
case "top":
tickMarkAttrHash["y1"] = this.height();
tickMarkAttrHash["y2"] = this.height() - tickLength;
break;
case "left":
tickMarkAttrHash["x1"] = this.width();
tickMarkAttrHash["x2"] = this.width() - tickLength;
break;
case "right":
tickMarkAttrHash["x2"] = tickLength;
break;
}
return tickMarkAttrHash;
};
Axis.prototype.redraw = function () {
this._computedWidth = null;
this._computedHeight = null;
return _super.prototype.redraw.call(this);
};
Axis.prototype._setDefaultAlignment = function () {
switch (this._orientation) {
case "bottom":
this.yAlignment("top");
break;
case "top":
this.yAlignment("bottom");
break;
case "left":
this.xAlignment("right");
break;
case "right":
this.xAlignment("left");
break;
}
};
Axis.prototype.formatter = function (formatter) {
if (formatter == null) {
return this._formatter;
}
this._formatter = formatter;
this.redraw();
return this;
};
Axis.prototype.tickLength = function (length) {
Plottable.Utils.Window.deprecated("tickLength()", "v1.3.0", "Replaced by innerTickLength()");
return this.innerTickLength(length);
};
Axis.prototype.innerTickLength = function (length) {
if (length == null) {
return this._innerTickLength;
}
else {
if (length < 0) {
throw new Error("inner tick length must be positive");
}
this._innerTickLength = length;
this.redraw();
return this;
}
};
Axis.prototype.endTickLength = function (length) {
if (length == null) {
return this._endTickLength;
}
else {
if (length < 0) {
throw new Error("end tick length must be positive");
}
this._endTickLength = length;
this.redraw();
return this;
}
};
Axis.prototype._maxLabelTickLength = function () {
if (this.showEndTickLabels()) {
return Math.max(this.innerTickLength(), this.endTickLength());
}
else {
return this.innerTickLength();
}
};
Axis.prototype.tickLabelPadding = function (padding) {
if (padding == null) {
return this._tickLabelPadding;
}
else {
if (padding < 0) {
throw new Error("tick label padding must be positive");
}
this._tickLabelPadding = padding;
this.redraw();
return this;
}
};
Axis.prototype.margin = function (size) {
if (size == null) {
return this._margin;
}
else {
if (size < 0) {
throw new Error("margin size must be positive");
}
this._margin = size;
this.redraw();
return this;
}
};
Axis.prototype.orientation = function (orientation) {
if (orientation == null) {
return this._orientation;
}
else {
var newOrientationLC = orientation.toLowerCase();
if (newOrientationLC !== "top" &&
newOrientationLC !== "bottom" &&
newOrientationLC !== "left" &&
newOrientationLC !== "right") {
throw new Error("unsupported orientation");
}
this._orientation = newOrientationLC;
this.redraw();
return this;
}
};
Axis.prototype.showEndTickLabels = function (show) {
if (show == null) {
return this._showEndTickLabels;
}
this._showEndTickLabels = show;
this.render();
return this;
};
/**
* The css class applied to each end tick mark (the line on the end tick).
*/
Axis.END_TICK_MARK_CLASS = "end-tick-mark";
/**
* The css class applied to each tick mark (the line on the tick).
*/
Axis.TICK_MARK_CLASS = "tick-mark";
/**
* The css class applied to each tick label (the text associated with the tick).
*/
Axis.TICK_LABEL_CLASS = "tick-label";
return Axis;
})(Plottable.Component);
Plottable.Axis = Axis;
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var TimeInterval;
(function (TimeInterval) {
TimeInterval.second = "second";
TimeInterval.minute = "minute";
TimeInterval.hour = "hour";
TimeInterval.day = "day";
TimeInterval.week = "week";
TimeInterval.month = "month";
TimeInterval.year = "year";
})(TimeInterval = Plottable.TimeInterval || (Plottable.TimeInterval = {}));
;
var Axes;
(function (Axes) {
var Time = (function (_super) {
__extends(Time, _super);
/**
* Constructs a Time Axis.
*
* A Time Axis is a visual representation of a Time Scale.
*
* @constructor
* @param {Scales.Time} scale
* @param {string} orientation One of "top"/"bottom".
*/
function Time(scale, orientation) {
_super.call(this, scale, orientation);
this._tierLabelPositions = [];
this.addClass("time-axis");
this.tickLabelPadding(5);
this.axisConfigurations(Time._DEFAULT_TIME_AXIS_CONFIGURATIONS);
}
Time.prototype.tierLabelPositions = function (newPositions) {
if (newPositions == null) {
return this._tierLabelPositions;
}
else {
if (!newPositions.every(function (pos) { return pos.toLowerCase() === "between" || pos.toLowerCase() === "center"; })) {
throw new Error("Unsupported position for tier labels");
}
this._tierLabelPositions = newPositions;
this.redraw();
return this;
}
};
Time.prototype.axisConfigurations = function (configurations) {
if (configurations == null) {
return this._possibleTimeAxisConfigurations;
}
this._possibleTimeAxisConfigurations = configurations;
this._numTiers = Plottable.Utils.Math.max(this._possibleTimeAxisConfigurations.map(function (config) { return config.length; }), 0);
if (this._isAnchored) {
this._setupDomElements();
}
var oldLabelPositions = this.tierLabelPositions();
var newLabelPositions = [];
for (var i = 0; i < this._numTiers; i++) {
newLabelPositions.push(oldLabelPositions[i] || "between");
}
this.tierLabelPositions(newLabelPositions);
this.redraw();
return this;
};
/**
* Gets the index of the most precise TimeAxisConfiguration that will fit in the current width.
*/
Time.prototype._getMostPreciseConfigurationIndex = function () {
var _this = this;
var mostPreciseIndex = this._possibleTimeAxisConfigurations.length;
this._possibleTimeAxisConfigurations.forEach(function (interval, index) {
if (index < mostPreciseIndex && interval.every(function (tier) {
return _this._checkTimeAxisTierConfigurationWidth(tier);
})) {
mostPreciseIndex = index;
}
});
if (mostPreciseIndex === this._possibleTimeAxisConfigurations.length) {
Plottable.Utils.Window.warn("zoomed out too far: could not find suitable interval to display labels");
--mostPreciseIndex;
}
return mostPreciseIndex;
};
Time.prototype.orientation = function (orientation) {
if (orientation && (orientation.toLowerCase() === "right" || orientation.toLowerCase() === "left")) {
throw new Error(orientation + " is not a supported orientation for TimeAxis - only horizontal orientations are supported");
}
return _super.prototype.orientation.call(this, orientation); // maintains getter-setter functionality
};
Time.prototype._computeHeight = function () {
var textHeight = this._measurer.measure().height;
this._tierHeights = [];
for (var i = 0; i < this._numTiers; i++) {
this._tierHeights.push(textHeight + this.tickLabelPadding() +
((this._tierLabelPositions[i]) === "between" ? 0 : this._maxLabelTickLength()));
}
this._computedHeight = d3.sum(this._tierHeights);
return this._computedHeight;
};
Time.prototype._getIntervalLength = function (config) {
var startDate = this._scale.domain()[0];
var d3Interval = Plottable.Scales.Time.timeIntervalToD3Time(config.interval);
var endDate = d3Interval.offset(startDate, config.step);
if (endDate > this._scale.domain()[1]) {
// this offset is too large, so just return available width
return this.width();
}
// measure how much space one date can get
var stepLength = Math.abs(this._scale.scale(endDate) - this._scale.scale(startDate));
return stepLength;
};
Time.prototype._maxWidthForInterval = function (config) {
return this._measurer.measure(config.formatter(Time._LONG_DATE)).width;
};
/**
* Check if tier configuration fits in the current width.
*/
Time.prototype._checkTimeAxisTierConfigurationWidth = function (config) {
var worstWidth = this._maxWidthForInterval(config) + 2 * this.tickLabelPadding();
return Math.min(this._getIntervalLength(config), this.width()) >= worstWidth;
};
Time.prototype._sizeFromOffer = function (availableWidth, availableHeight) {
// Makes sure that the size it requires is a multiple of tier sizes, such that
// we have no leftover tiers
var size = _super.prototype._sizeFromOffer.call(this, availableWidth, availableHeight);
size.height = this._tierHeights.reduce(function (prevValue, currValue, index, arr) {
return (prevValue + currValue > size.height) ? prevValue : (prevValue + currValue);
});
return size;
};
Time.prototype._setup = function () {
_super.prototype._setup.call(this);
this._setupDomElements();
};
Time.prototype._setupDomElements = function () {
this.content().selectAll("." + Time.TIME_AXIS_TIER_CLASS).remove();
this._tierLabelContainers = [];
this._tierMarkContainers = [];
this._tierBaselines = [];
this._tickLabelContainer.remove();
this._baseline.remove();
for (var i = 0; i < this._numTiers; ++i) {
var tierContainer = this.content().append("g").classed(Time.TIME_AXIS_TIER_CLASS, true);
this._tierLabelContainers.push(tierContainer.append("g").classed(Plottable.Axis.TICK_LABEL_CLASS + "-container", true));
this._tierMarkContainers.push(tierContainer.append("g").classed(Plottable.Axis.TICK_MARK_CLASS + "-container", true));
this._tierBaselines.push(tierContainer.append("line").classed("baseline", true));
}
this._measurer = new SVGTypewriter.Measurers.Measurer(this._tierLabelContainers[0]);
};
Time.prototype._getTickIntervalValues = function (config) {
return this._scale.tickInterval(config.interval, config.step);
};
Time.prototype._getTickValues = function () {
var _this = this;
return this._possibleTimeAxisConfigurations[this._mostPreciseConfigIndex].reduce(function (ticks, config) { return ticks.concat(_this._getTickIntervalValues(config)); }, []);
};
Time.prototype._cleanTiers = function () {
for (var index = 0; index < this._tierLabelContainers.length; index++) {
this._tierLabelContainers[index].selectAll("." + Plottable.Axis.TICK_LABEL_CLASS).remove();
this._tierMarkContainers[index].selectAll("." + Plottable.Axis.TICK_MARK_CLASS).remove();
this._tierBaselines[index].style("visibility", "hidden");
}
};
Time.prototype._getTickValuesForConfiguration = function (config) {
var tickPos = this._scale.tickInterval(config.interval, config.step);
var domain = this._scale.domain();
var tickPosValues = tickPos.map(function (d) { return d.valueOf(); }); // can't indexOf with objects
if (tickPosValues.indexOf(domain[0].valueOf()) === -1) {
tickPos.unshift(domain[0]);
}
if (tickPosValues.indexOf(domain[1].valueOf()) === -1) {
tickPos.push(domain[1]);
}
return tickPos;
};
Time.prototype._renderTierLabels = function (container, config, index) {
var _this = this;
var tickPos = this._getTickValuesForConfiguration(config);
var labelPos = [];
if (this._tierLabelPositions[index] === "between" && config.step === 1) {
tickPos.map(function (datum, index) {
if (index + 1 >= tickPos.length) {
return;
}
labelPos.push(new Date((tickPos[index + 1].valueOf() - tickPos[index].valueOf()) / 2 + tickPos[index].valueOf()));
});
}
else {
labelPos = tickPos;
}
var tickLabels = container.selectAll("." + Plottable.Axis.TICK_LABEL_CLASS).data(labelPos, function (d) { return String(d.valueOf()); });
var tickLabelsEnter = tickLabels.enter().append("g").classed(Plottable.Axis.TICK_LABEL_CLASS, true);
tickLabelsEnter.append("text");
var xTranslate = (this._tierLabelPositions[index] === "center" || config.step === 1) ? 0 : this.tickLabelPadding();
var yTranslate = this.orientation() === "bottom" ?
d3.sum(this._tierHeights.slice(0, index + 1)) - this.tickLabelPadding() :
this.height() - d3.sum(this._tierHeights.slice(0, index)) - this.tickLabelPadding();
var textSelection = tickLabels.selectAll("text");
if (textSelection.size() > 0) {
Plottable.Utils.DOM.translate(textSelection, xTranslate, yTranslate);
}
tickLabels.exit().remove();
tickLabels.attr("transform", function (d) { return "translate(" + _this._scale.scale(d) + ",0)"; });
var anchor = (this._tierLabelPositions[index] === "center" || config.step === 1) ? "middle" : "start";
tickLabels.selectAll("text").text(config.formatter).style("text-anchor", anchor);
};
Time.prototype._renderTickMarks = function (tickValues, index) {
var tickMarks = this._tierMarkContainers[index].selectAll("." + Plottable.Axis.TICK_MARK_CLASS).data(tickValues);
tickMarks.enter().append("line").classed(Plottable.Axis.TICK_MARK_CLASS, true);
var attr = this._generateTickMarkAttrHash();
var offset = this._tierHeights.slice(0, index).reduce(function (translate, height) { return translate + height; }, 0);
if (this.orientation() === "bottom") {
attr["y1"] = offset;
attr["y2"] = offset + (this._tierLabelPositions[index] === "center" ? this.innerTickLength() : this._tierHeights[index]);
}
else {
attr["y1"] = this.height() - offset;
attr["y2"] = this.height() - (offset + (this._tierLabelPositions[index] === "center" ?
this.innerTickLength() : this._tierHeights[index]));
}
tickMarks.attr(attr);
if (this.orientation() === "bottom") {
attr["y1"] = offset;
attr["y2"] = offset + this._tierHeights[index];
}
else {
attr["y1"] = this.height() - offset;
attr["y2"] = this.height() - (offset + this._tierHeights[index]);
}
d3.select(tickMarks[0][0]).attr(attr);
// Add end-tick classes to first and last tick for CSS customization purposes
d3.select(tickMarks[0][0]).classed(Plottable.Axis.END_TICK_MARK_CLASS, true);
d3.select(tickMarks[0][tickMarks.size() - 1]).classed(Plottable.Axis.END_TICK_MARK_CLASS, true);
tickMarks.exit().remove();
};
Time.prototype._renderLabellessTickMarks = function (tickValues) {
var tickMarks = this._tickMarkContainer.selectAll("." + Plottable.Axis.TICK_MARK_CLASS).data(tickValues);
tickMarks.enter().append("line").classed(Plottable.Axis.TICK_MARK_CLASS, true);
var attr = this._generateTickMarkAttrHash();
attr["y2"] = (this.orientation() === "bottom") ? this.tickLabelPadding() : this.height() - this.tickLabelPadding();
tickMarks.attr(attr);
tickMarks.exit().remove();
};
Time.prototype._generateLabellessTicks = function () {
if (this._mostPreciseConfigIndex < 1) {
return [];
}
return this._getTickIntervalValues(this._possibleTimeAxisConfigurations[this._mostPreciseConfigIndex - 1][0]);
};
Time.prototype.renderImmediately = function () {
var _this = this;
this._mostPreciseConfigIndex = this._getMostPreciseConfigurationIndex();
var tierConfigs = this._possibleTimeAxisConfigurations[this._mostPreciseConfigIndex];
this._cleanTiers();
tierConfigs.forEach(function (config, i) {
return _this._renderTierLabels(_this._tierLabelContainers[i], config, i);
});
var tierTicks = tierConfigs.map(function (config, i) {
return _this._getTickValuesForConfiguration(config);
});
var baselineOffset = 0;
for (var i = 0; i < Math.max(tierConfigs.length, 1); ++i) {
var attr = this._generateBaselineAttrHash();
attr["y1"] += (this.orientation() === "bottom") ? baselineOffset : -baselineOffset;
attr["y2"] = attr["y1"];
this._tierBaselines[i].attr(attr).style("visibility", "inherit");
baselineOffset += this._tierHeights[i];
}
var labelLessTicks = [];
var domain = this._scale.domain();
var totalLength = this._scale.scale(domain[1]) - this._scale.scale(domain[0]);
if (this._getIntervalLength(tierConfigs[0]) * 1.5 >= totalLength) {
labelLessTicks = this._generateLabellessTicks();
}
this._renderLabellessTickMarks(labelLessTicks);
this._hideOverflowingTiers();
for (i = 0; i < tierConfigs.length; ++i) {
this._renderTickMarks(tierTicks[i], i);
this._hideOverlappingAndCutOffLabels(i);
}
return this;
};
Time.prototype._hideOverflowingTiers = function () {
var _this = this;
var availableHeight = this.height();
var usedHeight = 0;
this.content()
.selectAll("." + Time.TIME_AXIS_TIER_CLASS)
.attr("visibility", function (d, i) {
usedHeight += _this._tierHeights[i];
return usedHeight <= availableHeight ? "inherit" : "hidden";
});
};
Time.prototype._hideOverlappingAndCutOffLabels = function (index) {
var _this = this;
var boundingBox = this._boundingBox.node().getBoundingClientRect();
var isInsideBBox = function (tickBox) {
return (Math.floor(boundingBox.left) <= Math.ceil(tickBox.left) &&
Math.floor(boundingBox.top) <= Math.ceil(tickBox.top) &&
Math.floor(tickBox.right) <= Math.ceil(boundingBox.left + _this.width()) &&
Math.floor(tickBox.bottom) <= Math.ceil(boundingBox.top + _this.height()));
};
var visibleTickMarks = this._tierMarkContainers[index]
.selectAll("." + Plottable.Axis.TICK_MARK_CLASS)
.filter(function (d, i) {
var visibility = d3.select(this).style("visibility");
return visibility === "visible" || visibility === "inherit";
});
// We use the ClientRects because x1/x2 attributes are not comparable to ClientRects of labels
var visibleTickMarkRects = visibleTickMarks[0].map(function (mark) { return mark.getBoundingClientRect(); });
var visibleTickLabels = this._tierLabelContainers[index]
.selectAll("." + Plottable.Axis.TICK_LABEL_CLASS)
.filter(function (d, i) {
var visibility = d3.select(this).style("visibility");
return visibility === "visible" || visibility === "inherit";
});
var lastLabelClientRect;
visibleTickLabels.each(function (d, i) {
var clientRect = this.getBoundingClientRect();
var tickLabel = d3.select(this);
var leadingTickMark = visibleTickMarkRects[i];
var trailingTickMark = visibleTickMarkRects[i + 1];
if (!isInsideBBox(clientRect) || (lastLabelClientRect != null && Plottable.Utils.DOM.clientRectsOverlap(clientRect, lastLabelClientRect))
|| (leadingTickMark.right > clientRect.left || trailingTickMark.left < clientRect.right)) {
tickLabel.style("visibility", "hidden");
}
else {
lastLabelClientRect = clientRect;
tickLabel.style("visibility", "inherit");
}
});
};
/**
* The CSS class applied to each Time Axis tier
*/
Time.TIME_AXIS_TIER_CLASS = "time-axis-tier";
Time._DEFAULT_TIME_AXIS_CONFIGURATIONS = [
[
{ interval: TimeInterval.second, step: 1, formatter: Plottable.Formatters.time("%I:%M:%S %p") },
{ interval: TimeInterval.day, step: 1, formatter: Plottable.Formatters.time("%B %e, %Y") }
],
[
{ interval: TimeInterval.second, step: 5, formatter: Plottable.Formatters.time("%I:%M:%S %p") },
{ interval: TimeInterval.day, step: 1, formatter: Plottable.Formatters.time("%B %e, %Y") }
],
[
{ interval: TimeInterval.second, step: 10, formatter: Plottable.Formatters.time("%I:%M:%S %p") },
{ interval: TimeInterval.day, step: 1, formatter: Plottable.Formatters.time("%B %e, %Y") }
],
[
{ interval: TimeInterval.second, step: 15, formatter: Plottable.Formatters.time("%I:%M:%S %p") },
{ interval: TimeInterval.day, step: 1, formatter: Plottable.Formatters.time("%B %e, %Y") }
],
[
{ interval: TimeInterval.second, step: 30, formatter: Plottable.Formatters.time("%I:%M:%S %p") },
{ interval: TimeInterval.day, step: 1, formatter: Plottable.Formatters.time("%B %e, %Y") }
],
[
{ interval: TimeInterval.minute, step: 1, formatter: Plottable.Formatters.time("%I:%M %p") },
{ interval: TimeInterval.day, step: 1, formatter: Plottable.Formatters.time("%B %e, %Y") }
],
[
{ interval: TimeInterval.minute, step: 5, formatter: Plottable.Formatters.time("%I:%M %p") },
{ interval: TimeInterval.day, step: 1, formatter: Plottable.Formatters.time("%B %e, %Y") }
],
[
{ interval: TimeInterval.minute, step: 10, formatter: Plottable.Formatters.time("%I:%M %p") },
{ interval: TimeInterval.day, step: 1, formatter: Plottable.Formatters.time("%B %e, %Y") }
],
[
{ interval: TimeInterval.minute, step: 15, formatter: Plottable.Formatters.time("%I:%M %p") },
{ interval: TimeInterval.day, step: 1, formatter: Plottable.Formatters.time("%B %e, %Y") }
],
[
{ interval: TimeInterval.minute, step: 30, formatter: Plottable.Formatters.time("%I:%M %p") },
{ interval: TimeInterval.day, step: 1, formatter: Plottable.Formatters.time("%B %e, %Y") }
],
[
{ interval: TimeInterval.hour, step: 1, formatter: Plottable.Formatters.time("%I %p") },
{ interval: TimeInterval.day, step: 1, formatter: Plottable.Formatters.time("%B %e, %Y") }
],
[
{ interval: TimeInterval.hour, step: 3, formatter: Plottable.Formatters.time("%I %p") },
{ interval: TimeInterval.day, step: 1, formatter: Plottable.Formatters.time("%B %e, %Y") }
],
[
{ interval: TimeInterval.hour, step: 6, formatter: Plottable.Formatters.time("%I %p") },
{ interval: TimeInterval.day, step: 1, formatter: Plottable.Formatters.time("%B %e, %Y") }
],
[
{ interval: TimeInterval.hour, step: 12, formatter: Plottable.Formatters.time("%I %p") },
{ interval: TimeInterval.day, step: 1, formatter: Plottable.Formatters.time("%B %e, %Y") }
],
[
{ interval: TimeInterval.day, step: 1, formatter: Plottable.Formatters.time("%a %e") },
{ interval: TimeInterval.month, step: 1, formatter: Plottable.Formatters.time("%B %Y") }
],
[
{ interval: TimeInterval.day, step: 1, formatter: Plottable.Formatters.time("%e") },
{ interval: TimeInterval.month, step: 1, formatter: Plottable.Formatters.time("%B %Y") }
],
[
{ interval: TimeInterval.month, step: 1, formatter: Plottable.Formatters.time("%B") },
{ interval: TimeInterval.year, step: 1, formatter: Plottable.Formatters.time("%Y") }
],
[
{ interval: TimeInterval.month, step: 1, formatter: Plottable.Formatters.time("%b") },
{ interval: TimeInterval.year, step: 1, formatter: Plottable.Formatters.time("%Y") }
],
[
{ interval: TimeInterval.month, step: 3, formatter: Plottable.Formatters.time("%b") },
{ interval: TimeInterval.year, step: 1, formatter: Plottable.Formatters.time("%Y") }
],
[
{ interval: TimeInterval.month, step: 6, formatter: Plottable.Formatters.time("%b") },
{ interval: TimeInterval.year, step: 1, formatter: Plottable.Formatters.time("%Y") }
],
[
{ interval: TimeInterval.year, step: 1, formatter: Plottable.Formatters.time("%Y") }
],
[
{ interval: TimeInterval.year, step: 1, formatter: Plottable.Formatters.time("%y") }
],
[
{ interval: TimeInterval.year, step: 5, formatter: Plottable.Formatters.time("%Y") }
],
[
{ interval: TimeInterval.year, step: 25, formatter: Plottable.Formatters.time("%Y") }
],
[
{ interval: TimeInterval.year, step: 50, formatter: Plottable.Formatters.time("%Y") }
],
[
{ interval: TimeInterval.year, step: 100, formatter: Plottable.Formatters.time("%Y") }
],
[
{ interval: TimeInterval.year, step: 200, formatter: Plottable.Formatters.time("%Y") }
],
[
{ interval: TimeInterval.year, step: 500, formatter: Plottable.Formatters.time("%Y") }
],
[
{ interval: TimeInterval.year, step: 1000, formatter: Plottable.Formatters.time("%Y") }
]
];
Time._LONG_DATE = new Date(9999, 8, 29, 12, 59, 9999);
return Time;
})(Plottable.Axis);
Axes.Time = Time;
})(Axes = Plottable.Axes || (Plottable.Axes = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Axes;
(function (Axes) {
var Numeric = (function (_super) {
__extends(Numeric, _super);
/**
* Constructs a Numeric Axis.
*
* A Numeric Axis is a visual representation of a QuantitativeScale.
*
* @constructor
* @param {QuantitativeScale} scale
* @param {string} orientation One of "top"/"bottom"/"left"/"right".
*/
function Numeric(scale, orientation) {
_super.call(this, scale, orientation);
this._tickLabelPositioning = "center";
this._usesTextWidthApproximation = false;
this.formatter(Plottable.Formatters.general());
}
Numeric.prototype._setup = function () {
_super.prototype._setup.call(this);
this._measurer = new SVGTypewriter.Measurers.Measurer(this._tickLabelContainer, Plottable.Axis.TICK_LABEL_CLASS);
this._wrapper = new SVGTypewriter.Wrappers.Wrapper().maxLines(1);
};
Numeric.prototype._computeWidth = function () {
var maxTextWidth = this._usesTextWidthApproximation ? this._computeApproximateTextWidth() : this._computeExactTextWidth();
if (this._tickLabelPositioning === "center") {
this._computedWidth = this._maxLabelTickLength() + this.tickLabelPadding() + maxTextWidth;
}
else {
this._computedWidth = Math.max(this._maxLabelTickLength(), this.tickLabelPadding() + maxTextWidth);
}
return this._computedWidth;
};
Numeric.prototype._computeExactTextWidth = function () {
var _this = this;
var tickValues = this._getTickValues();
var textLengths = tickValues.map(function (v) {
var formattedValue = _this.formatter()(v);
return _this._measurer.measure(formattedValue).width;
});
return Plottable.Utils.Math.max(textLengths, 0);
};
Numeric.prototype._computeApproximateTextWidth = function () {
var _this = this;
var tickValues = this._getTickValues();
var mWidth = this._measurer.measure("M").width;
var textLengths = tickValues.map(function (v) {
var formattedValue = _this.formatter()(v);
return formattedValue.length * mWidth;
});
return Plottable.Utils.Math.max(textLengths, 0);
};
Numeric.prototype._computeHeight = function () {
var textHeight = this._measurer.measure().height;
if (this._tickLabelPositioning === "center") {
this._computedHeight = this._maxLabelTickLength() + this.tickLabelPadding() + textHeight;
}
else {
this._computedHeight = Math.max(this._maxLabelTickLength(), this.tickLabelPadding() + textHeight);
}
return this._computedHeight;
};
Numeric.prototype._getTickValues = function () {
var scale = this._scale;
var domain = scale.domain();
var min = domain[0] <= domain[1] ? domain[0] : domain[1];
var max = domain[0] >= domain[1] ? domain[0] : domain[1];
if (min === domain[0]) {
return scale.ticks().filter(function (i) { return i >= min && i <= max; });
}
else {
return scale.ticks().filter(function (i) { return i >= min && i <= max; }).reverse();
}
};
Numeric.prototype._rescale = function () {
if (!this._isSetup) {
return;
}
if (!this._isHorizontal()) {
var reComputedWidth = this._computeWidth();
if (reComputedWidth > this.width() || reComputedWidth < (this.width() - this.margin())) {
this.redraw();
return;
}
}
this.render();
};
Numeric.prototype.renderImmediately = function () {
var _this = this;
_super.prototype.renderImmediately.call(this);
var tickLabelAttrHash = {
x: 0,
y: 0,
dx: "0em",
dy: "0.3em"
};
var tickMarkLength = this._maxLabelTickLength();
var tickLabelPadding = this.tickLabelPadding();
var tickLabelTextAnchor = "middle";
var labelGroupTransformX = 0;
var labelGroupTransformY = 0;
var labelGroupShiftX = 0;
var labelGroupShiftY = 0;
if (this._isHorizontal()) {
switch (this._tickLabelPositioning) {
case "left":
tickLabelTextAnchor = "end";
labelGroupTransformX = -tickLabelPadding;
labelGroupShiftY = tickLabelPadding;
break;
case "center":
labelGroupShiftY = tickMarkLength + tickLabelPadding;
break;
case "right":
tickLabelTextAnchor = "start";
labelGroupTransformX = tickLabelPadding;
labelGroupShiftY = tickLabelPadding;
break;
}
}
else {
switch (this._tickLabelPositioning) {
case "top":
tickLabelAttrHash["dy"] = "-0.3em";
labelGroupShiftX = tickLabelPadding;
labelGroupTransformY = -tickLabelPadding;
break;
case "center":
labelGroupShiftX = tickMarkLength + tickLabelPadding;
break;
case "bottom":
tickLabelAttrHash["dy"] = "1em";
labelGroupShiftX = tickLabelPadding;
labelGroupTransformY = tickLabelPadding;
break;
}
}
var tickMarkAttrHash = this._generateTickMarkAttrHash();
switch (this.orientation()) {
case "bottom":
tickLabelAttrHash["x"] = tickMarkAttrHash["x1"];
tickLabelAttrHash["dy"] = "0.95em";
labelGroupTransformY = tickMarkAttrHash["y1"] + labelGroupShiftY;
break;
case "top":
tickLabelAttrHash["x"] = tickMarkAttrHash["x1"];
tickLabelAttrHash["dy"] = "-.25em";
labelGroupTransformY = tickMarkAttrHash["y1"] - labelGroupShiftY;
break;
case "left":
tickLabelTextAnchor = "end";
labelGroupTransformX = tickMarkAttrHash["x1"] - labelGroupShiftX;
tickLabelAttrHash["y"] = tickMarkAttrHash["y1"];
break;
case "right":
tickLabelTextAnchor = "start";
labelGroupTransformX = tickMarkAttrHash["x1"] + labelGroupShiftX;
tickLabelAttrHash["y"] = tickMarkAttrHash["y1"];
break;
}
var tickLabelValues = this._getTickValues();
var tickLabels = this._tickLabelContainer
.selectAll("." + Plottable.Axis.TICK_LABEL_CLASS)
.data(tickLabelValues);
tickLabels.enter().append("text").classed(Plottable.Axis.TICK_LABEL_CLASS, true);
tickLabels.exit().remove();
tickLabels.style("text-anchor", tickLabelTextAnchor)
.style("visibility", "inherit")
.attr(tickLabelAttrHash)
.text(function (s) { return _this.formatter()(s); });
var labelGroupTransform = "translate(" + labelGroupTransformX + ", " + labelGroupTransformY + ")";
this._tickLabelContainer.attr("transform", labelGroupTransform);
this._showAllTickMarks();
if (!this.showEndTickLabels()) {
this._hideEndTickLabels();
}
this._hideOverflowingTickLabels();
this._hideOverlappingTickLabels();
if (this._tickLabelPositioning === "bottom" ||
this._tickLabelPositioning === "top" ||
this._tickLabelPositioning === "left" ||
this._tickLabelPositioning === "right") {
this._hideTickMarksWithoutLabel();
}
return this;
};
Numeric.prototype._showAllTickMarks = function () {
this._tickMarkContainer.selectAll("." + Plottable.Axis.TICK_MARK_CLASS)
.each(function () {
d3.select(this).style("visibility", "inherit");
});
};
/**
* Hides the Tick Marks which have no corresponding Tick Labels
*/
Numeric.prototype._hideTickMarksWithoutLabel = function () {
var visibleTickMarks = this._tickMarkContainer.selectAll("." + Plottable.Axis.TICK_MARK_CLASS);
var visibleTickLabels = this._tickLabelContainer
.selectAll("." + Plottable.Axis.TICK_LABEL_CLASS)
.filter(function (d, i) {
var visibility = d3.select(this).style("visibility");
return (visibility === "inherit") || (visibility === "visible");
});
var labelNumbersShown = [];
visibleTickLabels.each(function (labelNumber) { return labelNumbersShown.push(labelNumber); });
visibleTickMarks.each(function (e, i) {
if (labelNumbersShown.indexOf(e) === -1) {
d3.select(this).style("visibility", "hidden");
}
});
};
Numeric.prototype.tickLabelPosition = function (position) {
if (position == null) {
return this._tickLabelPositioning;
}
else {
var positionLC = position.toLowerCase();
if (this._isHorizontal()) {
if (!(positionLC === "left" || positionLC === "center" || positionLC === "right")) {
throw new Error(positionLC + " is not a valid tick label position for a horizontal NumericAxis");
}
}
else {
if (!(positionLC === "top" || positionLC === "center" || positionLC === "bottom")) {
throw new Error(positionLC + " is not a valid tick label position for a vertical NumericAxis");
}
}
this._tickLabelPositioning = positionLC;
this.redraw();
return this;
}
};
Numeric.prototype.usesTextWidthApproximation = function (enable) {
if (enable == null) {
return this._usesTextWidthApproximation;
}
else {
this._usesTextWidthApproximation = enable;
return this;
}
};
Numeric.prototype._hideEndTickLabels = function () {
var boundingBox = this._boundingBox.node().getBoundingClientRect();
var tickLabels = this._tickLabelContainer.selectAll("." + Plottable.Axis.TICK_LABEL_CLASS);
if (tickLabels[0].length === 0) {
return;
}
var firstTickLabel = tickLabels[0][0];
if (!Plottable.Utils.DOM.clientRectInside(firstTickLabel.getBoundingClientRect(), boundingBox)) {
d3.select(firstTickLabel).style("visibility", "hidden");
}
var lastTickLabel = tickLabels[0][tickLabels[0].length - 1];
if (!Plottable.Utils.DOM.clientRectInside(lastTickLabel.getBoundingClientRect(), boundingBox)) {
d3.select(lastTickLabel).style("visibility", "hidden");
}
};
// Responsible for hiding any tick labels that break out of the bounding container
Numeric.prototype._hideOverflowingTickLabels = function () {
var boundingBox = this._boundingBox.node().getBoundingClientRect();
var tickLabels = this._tickLabelContainer.selectAll("." + Plottable.Axis.TICK_LABEL_CLASS);
if (tickLabels.empty()) {
return;
}
tickLabels.each(function (d, i) {
if (!Plottable.Utils.DOM.clientRectInside(this.getBoundingClientRect(), boundingBox)) {
d3.select(this).style("visibility", "hidden");
}
});
};
Numeric.prototype._hideOverlappingTickLabels = function () {
var visibleTickLabels = this._tickLabelContainer
.selectAll("." + Plottable.Axis.TICK_LABEL_CLASS)
.filter(function (d, i) {
var visibility = d3.select(this).style("visibility");
return (visibility === "inherit") || (visibility === "visible");
});
var visibleTickLabelRects = visibleTickLabels[0].map(function (label) { return label.getBoundingClientRect(); });
var interval = 1;
while (!this._hasOverlapWithInterval(interval, visibleTickLabelRects) && interval < visibleTickLabelRects.length) {
interval += 1;
}
visibleTickLabels.each(function (d, i) {
var tickLabel = d3.select(this);
if (i % interval !== 0) {
tickLabel.style("visibility", "hidden");
}
});
};
/**
* The method is responsible for evenly spacing the labels on the axis.
* @return test to see if taking every `interval` recrangle from `rects`
* will result in labels not overlapping
*
* For top, bottom, left, right positioning of the thicks, we want the padding
* between the labels to be 3x, such that the label will be `padding` distance
* from the tick and 2 * `padding` distance (or more) from the next tick
*
*/
Numeric.prototype._hasOverlapWithInterval = function (interval, rects) {
var padding = this.tickLabelPadding();
if (this._tickLabelPositioning === "bottom" ||
this._tickLabelPositioning === "top" ||
this._tickLabelPositioning === "left" ||
this._tickLabelPositioning === "right") {
padding *= 3;
}
for (var i = 0; i < rects.length - (interval); i += interval) {
var currRect = rects[i];
var nextRect = rects[i + interval];
if (this._isHorizontal()) {
if (currRect.right + padding >= nextRect.left) {
return false;
}
}
else {
if (currRect.top - padding <= nextRect.bottom) {
return false;
}
}
}
return true;
};
return Numeric;
})(Plottable.Axis);
Axes.Numeric = Numeric;
})(Axes = Plottable.Axes || (Plottable.Axes = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Axes;
(function (Axes) {
var Category = (function (_super) {
__extends(Category, _super);
/**
* Constructs a Category Axis.
*
* A Category Axis is a visual representation of a Category Scale.
*
* @constructor
* @param {Scales.Category} scale
* @param {string} [orientation="bottom"] One of "top"/"bottom"/"left"/"right".
*/
function Category(scale, orientation) {
_super.call(this, scale, orientation);
this._tickLabelAngle = 0;
this.addClass("category-axis");
}
Category.prototype._setup = function () {
_super.prototype._setup.call(this);
this._measurer = new SVGTypewriter.Measurers.CacheCharacterMeasurer(this._tickLabelContainer);
this._wrapper = new SVGTypewriter.Wrappers.SingleLineWrapper();
this._writer = new SVGTypewriter.Writers.Writer(this._measurer, this._wrapper);
};
Category.prototype._rescale = function () {
return this.redraw();
};
Category.prototype.requestedSpace = function (offeredWidth, offeredHeight) {
var widthRequiredByTicks = this._isHorizontal() ? 0 : this._maxLabelTickLength() + this.tickLabelPadding() + this.margin();
var heightRequiredByTicks = this._isHorizontal() ? this._maxLabelTickLength() + this.tickLabelPadding() + this.margin() : 0;
if (this._scale.domain().length === 0) {
return {
minWidth: 0,
minHeight: 0
};
}
var categoryScale = this._scale;
var measureResult = this._measureTicks(offeredWidth, offeredHeight, categoryScale, categoryScale.domain());
return {
minWidth: measureResult.usedWidth + widthRequiredByTicks,
minHeight: measureResult.usedHeight + heightRequiredByTicks
};
};
Category.prototype._getTickValues = function () {
return this._scale.domain();
};
Category.prototype.tickLabelAngle = function (angle) {
if (angle == null) {
return this._tickLabelAngle;
}
if (angle !== 0 && angle !== 90 && angle !== -90) {
throw new Error("Angle " + angle + " not supported; only 0, 90, and -90 are valid values");
}
this._tickLabelAngle = angle;
this.redraw();
return this;
};
/**
* Measures the size of the ticks while also writing them to the DOM.
* @param {d3.Selection} ticks The tick elements to be written to.
*/
Category.prototype._drawTicks = function (axisWidth, axisHeight, scale, ticks) {
var self = this;
var xAlign;
var yAlign;
switch (this.tickLabelAngle()) {
case 0:
xAlign = { left: "right", right: "left", top: "center", bottom: "center" };
yAlign = { left: "center", right: "center", top: "bottom", bottom: "top" };
break;
case 90:
xAlign = { left: "center", right: "center", top: "right", bottom: "left" };
yAlign = { left: "top", right: "bottom", top: "center", bottom: "center" };
break;
case -90:
xAlign = { left: "center", right: "center", top: "left", bottom: "right" };
yAlign = { left: "bottom", right: "top", top: "center", bottom: "center" };
break;
}
ticks.each(function (d) {
var bandWidth = scale.stepWidth();
var width = self._isHorizontal() ? bandWidth : axisWidth - self._maxLabelTickLength() - self.tickLabelPadding();
var height = self._isHorizontal() ? axisHeight - self._maxLabelTickLength() - self.tickLabelPadding() : bandWidth;
var writeOptions = {
selection: d3.select(this),
xAlign: xAlign[self.orientation()],
yAlign: yAlign[self.orientation()],
textRotation: self.tickLabelAngle()
};
self._writer.write(self.formatter()(d), width, height, writeOptions);
});
};
/**
* Measures the size of the ticks without making any (permanent) DOM
* changes.
*
* @param {string[]} ticks The strings that will be printed on the ticks.
*/
Category.prototype._measureTicks = function (axisWidth, axisHeight, scale, ticks) {
var _this = this;
var axisSpace = this._isHorizontal() ? axisWidth : axisHeight;
var totalOuterPaddingRatio = 2 * scale.outerPadding();
var totalInnerPaddingRatio = (ticks.length - 1) * scale.innerPadding();
var expectedRangeBand = axisSpace / (totalOuterPaddingRatio + totalInnerPaddingRatio + ticks.length);
var stepWidth = expectedRangeBand * (1 + scale.innerPadding());
var wrappingResults = ticks.map(function (s) {
// HACKHACK: https://github.com/palantir/svg-typewriter/issues/25
var width = axisWidth - _this._maxLabelTickLength() - _this.tickLabelPadding(); // default for left/right
if (_this._isHorizontal()) {
width = stepWidth; // defaults to the band width
if (_this._tickLabelAngle !== 0) {
width = axisHeight - _this._maxLabelTickLength() - _this.tickLabelPadding(); // use the axis height
}
// HACKHACK: Wrapper fails under negative circumstances
width = Math.max(width, 0);
}
// HACKHACK: https://github.com/palantir/svg-typewriter/issues/25
var height = stepWidth; // default for left/right
if (_this._isHorizontal()) {
height = axisHeight - _this._maxLabelTickLength() - _this.tickLabelPadding();
if (_this._tickLabelAngle !== 0) {
height = axisWidth - _this._maxLabelTickLength() - _this.tickLabelPadding();
}
// HACKHACK: Wrapper fails under negative circumstances
height = Math.max(height, 0);
}
return _this._wrapper.wrap(_this.formatter()(s), _this._measurer, width, height);
});
// HACKHACK: https://github.com/palantir/svg-typewriter/issues/25
var widthFn = (this._isHorizontal() && this._tickLabelAngle === 0) ? d3.sum : Plottable.Utils.Math.max;
var heightFn = (this._isHorizontal() && this._tickLabelAngle === 0) ? Plottable.Utils.Math.max : d3.sum;
var textFits = wrappingResults.every(function (t) {
return !SVGTypewriter.Utils.StringMethods.isNotEmptyString(t.truncatedText) && t.noLines === 1;
});
var usedWidth = widthFn(wrappingResults, function (t) { return _this._measurer.measure(t.wrappedText).width; }, 0);
var usedHeight = heightFn(wrappingResults, function (t) { return _this._measurer.measure(t.wrappedText).height; }, 0);
// If the tick labels are rotated, reverse usedWidth and usedHeight
// HACKHACK: https://github.com/palantir/svg-typewriter/issues/25
if (this._tickLabelAngle !== 0) {
var tempHeight = usedHeight;
usedHeight = usedWidth;
usedWidth = tempHeight;
}
return {
textFits: textFits,
usedWidth: usedWidth,
usedHeight: usedHeight
};
};
Category.prototype.renderImmediately = function () {
var _this = this;
_super.prototype.renderImmediately.call(this);
var catScale = this._scale;
var tickLabels = this._tickLabelContainer.selectAll("." + Plottable.Axis.TICK_LABEL_CLASS).data(this._scale.domain(), function (d) { return d; });
var getTickLabelTransform = function (d, i) {
var innerPaddingWidth = catScale.stepWidth() - catScale.rangeBand();
var scaledValue = catScale.scale(d) - catScale.rangeBand() / 2 - innerPaddingWidth / 2;
var x = _this._isHorizontal() ? scaledValue : 0;
var y = _this._isHorizontal() ? 0 : scaledValue;
return "translate(" + x + "," + y + ")";
};
tickLabels.enter().append("g").classed(Plottable.Axis.TICK_LABEL_CLASS, true);
tickLabels.exit().remove();
tickLabels.attr("transform", getTickLabelTransform);
// erase all text first, then rewrite
tickLabels.text("");
this._drawTicks(this.width(), this.height(), catScale, tickLabels);
var xTranslate = this.orientation() === "right" ? this._maxLabelTickLength() + this.tickLabelPadding() : 0;
var yTranslate = this.orientation() === "bottom" ? this._maxLabelTickLength() + this.tickLabelPadding() : 0;
Plottable.Utils.DOM.translate(this._tickLabelContainer, xTranslate, yTranslate);
return this;
};
Category.prototype.computeLayout = function (origin, availableWidth, availableHeight) {
// When anyone calls redraw(), computeLayout() will be called
// on everyone, including this. Since CSS or something might have
// affected the size of the characters, clear the cache.
this._measurer.reset();
return _super.prototype.computeLayout.call(this, origin, availableWidth, availableHeight);
};
return Category;
})(Plottable.Axis);
Axes.Category = Category;
})(Axes = Plottable.Axes || (Plottable.Axes = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Components;
(function (Components) {
var Label = (function (_super) {
__extends(Label, _super);
/**
* A Label is a Component that displays a single line of text.
*
* @constructor
* @param {string} [displayText=""] The text of the Label.
* @param {number} [angle=0] The angle of the Label in degrees (-90/0/90). 0 is horizontal.
*/
function Label(displayText, angle) {
if (displayText === void 0) { displayText = ""; }
if (angle === void 0) { angle = 0; }
_super.call(this);
this.addClass("label");
this.text(displayText);
this.angle(angle);
this.xAlignment("center").yAlignment("center");
this._padding = 0;
}
Label.prototype.requestedSpace = function (offeredWidth, offeredHeight) {
var desiredWH = this._measurer.measure(this._text);
var desiredWidth = (this.angle() === 0 ? desiredWH.width : desiredWH.height) + 2 * this.padding();
var desiredHeight = (this.angle() === 0 ? desiredWH.height : desiredWH.width) + 2 * this.padding();
return {
minWidth: desiredWidth,
minHeight: desiredHeight
};
};
Label.prototype._setup = function () {
_super.prototype._setup.call(this);
this._textContainer = this.content().append("g");
this._measurer = new SVGTypewriter.Measurers.Measurer(this._textContainer);
this._wrapper = new SVGTypewriter.Wrappers.Wrapper();
this._writer = new SVGTypewriter.Writers.Writer(this._measurer, this._wrapper);
this.text(this._text);
};
Label.prototype.text = function (displayText) {
if (displayText === undefined) {
return this._text;
}
else {
this._text = displayText;
this.redraw();
return this;
}
};
Label.prototype.angle = function (angle) {
if (angle == null) {
return this._angle;
}
else {
angle %= 360;
if (angle > 180) {
angle -= 360;
}
else if (angle < -180) {
angle += 360;
}
if (angle === -90 || angle === 0 || angle === 90) {
this._angle = angle;
}
else {
throw new Error(angle + " is not a valid angle for Label");
}
this.redraw();
return this;
}
};
Label.prototype.padding = function (padAmount) {
if (padAmount == null) {
return this._padding;
}
else {
padAmount = +padAmount;
if (padAmount < 0) {
throw new Error(padAmount + " is not a valid padding value. Cannot be less than 0.");
}
this._padding = padAmount;
this.redraw();
return this;
}
};
Label.prototype.fixedWidth = function () {
return true;
};
Label.prototype.fixedHeight = function () {
return true;
};
Label.prototype.renderImmediately = function () {
_super.prototype.renderImmediately.call(this);
// HACKHACK SVGTypewriter should remove existing content - #21 on SVGTypewriter.
this._textContainer.selectAll("g").remove();
var textMeasurement = this._measurer.measure(this._text);
var heightPadding = Math.max(Math.min((this.height() - textMeasurement.height) / 2, this.padding()), 0);
var widthPadding = Math.max(Math.min((this.width() - textMeasurement.width) / 2, this.padding()), 0);
this._textContainer.attr("transform", "translate(" + widthPadding + "," + heightPadding + ")");
var writeWidth = this.width() - 2 * widthPadding;
var writeHeight = this.height() - 2 * heightPadding;
var writeOptions = {
selection: this._textContainer,
xAlign: this.xAlignment(),
yAlign: this.yAlignment(),
textRotation: this.angle()
};
this._writer.write(this._text, writeWidth, writeHeight, writeOptions);
return this;
};
return Label;
})(Plottable.Component);
Components.Label = Label;
var TitleLabel = (function (_super) {
__extends(TitleLabel, _super);
/**
* @constructor
* @param {string} [text]
* @param {number} [angle] One of -90/0/90. 0 is horizontal.
*/
function TitleLabel(text, angle) {
_super.call(this, text, angle);
this.addClass(TitleLabel.TITLE_LABEL_CLASS);
}
TitleLabel.TITLE_LABEL_CLASS = "title-label";
return TitleLabel;
})(Label);
Components.TitleLabel = TitleLabel;
var AxisLabel = (function (_super) {
__extends(AxisLabel, _super);
/**
* @constructor
* @param {string} [text]
* @param {number} [angle] One of -90/0/90. 0 is horizontal.
*/
function AxisLabel(text, angle) {
_super.call(this, text, angle);
this.addClass(AxisLabel.AXIS_LABEL_CLASS);
}
AxisLabel.AXIS_LABEL_CLASS = "axis-label";
return AxisLabel;
})(Label);
Components.AxisLabel = AxisLabel;
})(Components = Plottable.Components || (Plottable.Components = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Components;
(function (Components) {
var Legend = (function (_super) {
__extends(Legend, _super);
/**
* The Legend consists of a series of entries, each with a color and label taken from the Color Scale.
*
* @constructor
* @param {Scale.Color} scale
*/
function Legend(colorScale) {
var _this = this;
_super.call(this);
this._padding = 5;
this.addClass("legend");
this.maxEntriesPerRow(1);
if (colorScale == null) {
throw new Error("Legend requires a colorScale");
}
this._colorScale = colorScale;
this._redrawCallback = function (scale) { return _this.redraw(); };
this._colorScale.onUpdate(this._redrawCallback);
this.xAlignment("right").yAlignment("top");
this.comparator(function (a, b) { return _this._colorScale.domain().indexOf(a) - _this._colorScale.domain().indexOf(b); });
this._symbolFactoryAccessor = function () { return Plottable.SymbolFactories.circle(); };
}
Legend.prototype._setup = function () {
_super.prototype._setup.call(this);
var fakeLegendRow = this.content().append("g").classed(Legend.LEGEND_ROW_CLASS, true);
var fakeLegendEntry = fakeLegendRow.append("g").classed(Legend.LEGEND_ENTRY_CLASS, true);
fakeLegendEntry.append("text");
this._measurer = new SVGTypewriter.Measurers.Measurer(fakeLegendRow);
this._wrapper = new SVGTypewriter.Wrappers.Wrapper().maxLines(1);
this._writer = new SVGTypewriter.Writers.Writer(this._measurer, this._wrapper).addTitleElement(true);
};
Legend.prototype.maxEntriesPerRow = function (maxEntriesPerRow) {
if (maxEntriesPerRow == null) {
return this._maxEntriesPerRow;
}
else {
this._maxEntriesPerRow = maxEntriesPerRow;
this.redraw();
return this;
}
};
Legend.prototype.comparator = function (comparator) {
if (comparator == null) {
return this._comparator;
}
else {
this._comparator = comparator;
this.redraw();
return this;
}
};
Legend.prototype.colorScale = function (colorScale) {
if (colorScale != null) {
this._colorScale.offUpdate(this._redrawCallback);
this._colorScale = colorScale;
this._colorScale.onUpdate(this._redrawCallback);
this.redraw();
return this;
}
else {
return this._colorScale;
}
};
Legend.prototype.destroy = function () {
_super.prototype.destroy.call(this);
this._colorScale.offUpdate(this._redrawCallback);
};
Legend.prototype._calculateLayoutInfo = function (availableWidth, availableHeight) {
var _this = this;
var textHeight = this._measurer.measure().height;
var availableWidthForEntries = Math.max(0, (availableWidth - this._padding));
var entryNames = this._colorScale.domain().slice();
entryNames.sort(this.comparator());
var entryLengths = d3.map();
var untruncatedEntryLengths = d3.map();
entryNames.forEach(function (entryName) {
var untruncatedEntryLength = textHeight + _this._measurer.measure(entryName).width + _this._padding;
var entryLength = Math.min(untruncatedEntryLength, availableWidthForEntries);
entryLengths.set(entryName, entryLength);
untruncatedEntryLengths.set(entryName, untruncatedEntryLength);
});
var rows = this._packRows(availableWidthForEntries, entryNames, entryLengths);
var rowsAvailable = Math.floor((availableHeight - 2 * this._padding) / textHeight);
if (rowsAvailable !== rowsAvailable) {
rowsAvailable = 0;
}
return {
textHeight: textHeight,
entryLengths: entryLengths,
untruncatedEntryLengths: untruncatedEntryLengths,
rows: rows,
numRowsToDraw: Math.max(Math.min(rowsAvailable, rows.length), 0)
};
};
Legend.prototype.requestedSpace = function (offeredWidth, offeredHeight) {
var estimatedLayout = this._calculateLayoutInfo(offeredWidth, offeredHeight);
var untruncatedRowLengths = estimatedLayout.rows.map(function (row) {
return d3.sum(row, function (entry) { return estimatedLayout.untruncatedEntryLengths.get(entry); });
});
var longestUntruncatedRowLength = Plottable.Utils.Math.max(untruncatedRowLengths, 0);
return {
minWidth: this._padding + longestUntruncatedRowLength,
minHeight: estimatedLayout.rows.length * estimatedLayout.textHeight + 2 * this._padding
};
};
Legend.prototype._packRows = function (availableWidth, entries, entryLengths) {
var _this = this;
var rows = [];
var currentRow = [];
var spaceLeft = availableWidth;
entries.forEach(function (e) {
var entryLength = entryLengths.get(e);
if (entryLength > spaceLeft || currentRow.length === _this._maxEntriesPerRow) {
rows.push(currentRow);
currentRow = [];
spaceLeft = availableWidth;
}
currentRow.push(e);
spaceLeft -= entryLength;
});
if (currentRow.length !== 0) {
rows.push(currentRow);
}
return rows;
};
/**
* Gets the Entities (representing Legend entries) at a particular point.
* Returns an empty array if no Entities are present at that location.
*
* @param {Point} p
* @returns {Entity<Legend>[]}
*/
Legend.prototype.entitiesAt = function (p) {
if (!this._isSetup) {
return [];
}
var entities = [];
var layout = this._calculateLayoutInfo(this.width(), this.height());
var legendPadding = this._padding;
var legend = this;
this.content().selectAll("g." + Legend.LEGEND_ROW_CLASS).each(function (d, i) {
var lowY = i * layout.textHeight + legendPadding;
var highY = (i + 1) * layout.textHeight + legendPadding;
var symbolY = (lowY + highY) / 2;
var lowX = legendPadding;
var highX = legendPadding;
d3.select(this).selectAll("g." + Legend.LEGEND_ENTRY_CLASS).each(function (value) {
highX += layout.entryLengths.get(value);
var symbolX = lowX + layout.textHeight / 2;
if (highX >= p.x && lowX <= p.x &&
highY >= p.y && lowY <= p.y) {
var entrySelection = d3.select(this);
var datum = entrySelection.datum();
entities.push({
datum: datum,
position: { x: symbolX, y: symbolY },
selection: entrySelection,
component: legend
});
}
lowX += layout.entryLengths.get(value);
});
});
return entities;
};
Legend.prototype.renderImmediately = function () {
var _this = this;
_super.prototype.renderImmediately.call(this);
var layout = this._calculateLayoutInfo(this.width(), this.height());
var rowsToDraw = layout.rows.slice(0, layout.numRowsToDraw);
var rows = this.content().selectAll("g." + Legend.LEGEND_ROW_CLASS).data(rowsToDraw);
rows.enter().append("g").classed(Legend.LEGEND_ROW_CLASS, true);
rows.exit().remove();
rows.attr("transform", function (d, i) { return "translate(0, " + (i * layout.textHeight + _this._padding) + ")"; });
var entries = rows.selectAll("g." + Legend.LEGEND_ENTRY_CLASS).data(function (d) { return d; });
var entriesEnter = entries.enter().append("g").classed(Legend.LEGEND_ENTRY_CLASS, true);
entriesEnter.append("path");
entriesEnter.append("g").classed("text-container", true);
entries.exit().remove();
var legendPadding = this._padding;
rows.each(function (values) {
var xShift = legendPadding;
var entriesInRow = d3.select(this).selectAll("g." + Legend.LEGEND_ENTRY_CLASS);
entriesInRow.attr("transform", function (value, i) {
var translateString = "translate(" + xShift + ", 0)";
xShift += layout.entryLengths.get(value);
return translateString;
});
});
entries.select("path").attr("d", function (d, i, j) { return _this.symbol()(d, j)(layout.textHeight * 0.6); })
.attr("transform", "translate(" + (layout.textHeight / 2) + "," + layout.textHeight / 2 + ")")
.attr("fill", function (value) { return _this._colorScale.scale(value); })
.classed(Legend.LEGEND_SYMBOL_CLASS, true);
var padding = this._padding;
var textContainers = entries.select("g.text-container");
textContainers.text(""); // clear out previous results
textContainers.append("title").text(function (value) { return value; });
var self = this;
textContainers.attr("transform", "translate(" + layout.textHeight + ", 0)")
.each(function (value) {
var container = d3.select(this);
var maxTextLength = layout.entryLengths.get(value) - layout.textHeight - padding;
var writeOptions = {
selection: container,
xAlign: "left",
yAlign: "top",
textRotation: 0
};
self._writer.write(value, maxTextLength, self.height(), writeOptions);
});
return this;
};
Legend.prototype.symbol = function (symbol) {
if (symbol == null) {
return this._symbolFactoryAccessor;
}
else {
this._symbolFactoryAccessor = symbol;
this.render();
return this;
}
};
Legend.prototype.fixedWidth = function () {
return true;
};
Legend.prototype.fixedHeight = function () {
return true;
};
/**
* The css class applied to each legend row
*/
Legend.LEGEND_ROW_CLASS = "legend-row";
/**
* The css class applied to each legend entry
*/
Legend.LEGEND_ENTRY_CLASS = "legend-entry";
/**
* The css class applied to each legend symbol
*/
Legend.LEGEND_SYMBOL_CLASS = "legend-symbol";
return Legend;
})(Plottable.Component);
Components.Legend = Legend;
})(Components = Plottable.Components || (Plottable.Components = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Components;
(function (Components) {
var InterpolatedColorLegend = (function (_super) {
__extends(InterpolatedColorLegend, _super);
/**
* Creates an InterpolatedColorLegend.
*
* The InterpolatedColorLegend consists of a sequence of swatches that show the
* associated InterpolatedColor Scale sampled at various points.
* Two labels show the maximum and minimum values of the InterpolatedColor Scale.
*
* @constructor
* @param {Scales.InterpolatedColor} interpolatedColorScale
*/
function InterpolatedColorLegend(interpolatedColorScale) {
var _this = this;
_super.call(this);
this._padding = 5;
this._numSwatches = 10;
if (interpolatedColorScale == null) {
throw new Error("InterpolatedColorLegend requires a interpolatedColorScale");
}
this._scale = interpolatedColorScale;
this._redrawCallback = function (scale) { return _this.redraw(); };
this._scale.onUpdate(this._redrawCallback);
this._formatter = Plottable.Formatters.general();
this._orientation = "horizontal";
this.addClass("legend");
this.addClass("interpolated-color-legend");
}
InterpolatedColorLegend.prototype.destroy = function () {
_super.prototype.destroy.call(this);
this._scale.offUpdate(this._redrawCallback);
};
InterpolatedColorLegend.prototype.formatter = function (formatter) {
if (formatter === undefined) {
return this._formatter;
}
this._formatter = formatter;
this.redraw();
return this;
};
InterpolatedColorLegend._ensureOrientation = function (orientation) {
orientation = orientation.toLowerCase();
if (orientation === "horizontal" || orientation === "left" || orientation === "right") {
return orientation;
}
else {
throw new Error("\"" + orientation + "\" is not a valid orientation for InterpolatedColorLegend");
}
};
InterpolatedColorLegend.prototype.orientation = function (orientation) {
if (orientation == null) {
return this._orientation;
}
else {
this._orientation = InterpolatedColorLegend._ensureOrientation(orientation);
this.redraw();
return this;
}
};
InterpolatedColorLegend.prototype.fixedWidth = function () {
return true;
};
InterpolatedColorLegend.prototype.fixedHeight = function () {
return true;
};
InterpolatedColorLegend.prototype._generateTicks = function () {
var domain = this._scale.domain();
var slope = (domain[1] - domain[0]) / this._numSwatches;
var ticks = [];
for (var i = 0; i <= this._numSwatches; i++) {
ticks.push(domain[0] + slope * i);
}
return ticks;
};
InterpolatedColorLegend.prototype._setup = function () {
_super.prototype._setup.call(this);
this._swatchContainer = this.content().append("g").classed("swatch-container", true);
this._swatchBoundingBox = this.content().append("rect").classed("swatch-bounding-box", true);
this._lowerLabel = this.content().append("g").classed(InterpolatedColorLegend.LEGEND_LABEL_CLASS, true);
this._upperLabel = this.content().append("g").classed(InterpolatedColorLegend.LEGEND_LABEL_CLASS, true);
this._measurer = new SVGTypewriter.Measurers.Measurer(this.content());
this._wrapper = new SVGTypewriter.Wrappers.Wrapper();
this._writer = new SVGTypewriter.Writers.Writer(this._measurer, this._wrapper);
};
InterpolatedColorLegend.prototype.requestedSpace = function (offeredWidth, offeredHeight) {
var _this = this;
var textHeight = this._measurer.measure().height;
var ticks = this._generateTicks();
var numSwatches = ticks.length;
var domain = this._scale.domain();
var labelWidths = domain.map(function (d) { return _this._measurer.measure(_this._formatter(d)).width; });
var desiredHeight;
var desiredWidth;
if (this._isVertical()) {
var longestWidth = Plottable.Utils.Math.max(labelWidths, 0);
desiredWidth = this._padding + textHeight + this._padding + longestWidth + this._padding;
desiredHeight = this._padding + numSwatches * textHeight + this._padding;
}
else {
desiredHeight = this._padding + textHeight + this._padding;
desiredWidth = this._padding + labelWidths[0] + this._padding
+ numSwatches * textHeight
+ this._padding + labelWidths[1] + this._padding;
}
return {
minWidth: desiredWidth,
minHeight: desiredHeight
};
};
InterpolatedColorLegend.prototype._isVertical = function () {
return this._orientation !== "horizontal";
};
InterpolatedColorLegend.prototype.renderImmediately = function () {
var _this = this;
_super.prototype.renderImmediately.call(this);
var domain = this._scale.domain();
var text0 = this._formatter(domain[0]);
var text0Width = this._measurer.measure(text0).width;
var text1 = this._formatter(domain[1]);
var text1Width = this._measurer.measure(text1).width;
var ticks = this._generateTicks();
var numSwatches = ticks.length;
var padding = this._padding;
var upperLabelShift = { x: 0, y: 0 };
var lowerLabelShift = { x: 0, y: 0 };
var lowerWriteOptions = {
selection: this._lowerLabel,
xAlign: "center",
yAlign: "center",
textRotation: 0
};
var upperWriteOptions = {
selection: this._upperLabel,
xAlign: "center",
yAlign: "center",
textRotation: 0
};
var swatchWidth;
var swatchHeight;
var swatchX;
var swatchY;
var boundingBoxAttr = {
x: 0,
y: padding,
width: 0,
height: 0
};
if (this._isVertical()) {
var longestTextWidth = Math.max(text0Width, text1Width);
swatchWidth = Math.max((this.width() - 3 * padding - longestTextWidth), 0);
swatchHeight = Math.max(((this.height() - 2 * padding) / numSwatches), 0);
swatchY = function (d, i) { return padding + (numSwatches - (i + 1)) * swatchHeight; };
upperWriteOptions.yAlign = "top";
upperLabelShift.y = padding;
lowerWriteOptions.yAlign = "bottom";
lowerLabelShift.y = -padding;
if (this._orientation === "left") {
swatchX = function (d, i) { return padding + longestTextWidth + padding; };
upperWriteOptions.xAlign = "right";
upperLabelShift.x = -(padding + swatchWidth + padding);
lowerWriteOptions.xAlign = "right";
lowerLabelShift.x = -(padding + swatchWidth + padding);
}
else {
swatchX = function (d, i) { return padding; };
upperWriteOptions.xAlign = "left";
upperLabelShift.x = padding + swatchWidth + padding;
lowerWriteOptions.xAlign = "left";
lowerLabelShift.x = padding + swatchWidth + padding;
}
boundingBoxAttr["width"] = swatchWidth;
boundingBoxAttr["height"] = numSwatches * swatchHeight;
}
else {
swatchWidth = Math.max(((this.width() - 4 * padding - text0Width - text1Width) / numSwatches), 0);
swatchHeight = Math.max((this.height() - 2 * padding), 0);
swatchX = function (d, i) { return (padding + text0Width + padding) + i * swatchWidth; };
swatchY = function (d, i) { return padding; };
upperWriteOptions.xAlign = "right";
upperLabelShift.x = -padding;
lowerWriteOptions.xAlign = "left";
lowerLabelShift.x = padding;
boundingBoxAttr["width"] = numSwatches * swatchWidth;
boundingBoxAttr["height"] = swatchHeight;
}
boundingBoxAttr["x"] = swatchX(null, 0); // position of the first swatch
this._upperLabel.text(""); // clear the upper label
this._writer.write(text1, this.width(), this.height(), upperWriteOptions);
var upperTranslateString = "translate(" + upperLabelShift.x + ", " + upperLabelShift.y + ")";
this._upperLabel.attr("transform", upperTranslateString);
this._lowerLabel.text(""); // clear the lower label
this._writer.write(text0, this.width(), this.height(), lowerWriteOptions);
var lowerTranslateString = "translate(" + lowerLabelShift.x + ", " + lowerLabelShift.y + ")";
this._lowerLabel.attr("transform", lowerTranslateString);
this._swatchBoundingBox.attr(boundingBoxAttr);
var swatches = this._swatchContainer.selectAll("rect.swatch").data(ticks);
swatches.enter().append("rect").classed("swatch", true);
swatches.exit().remove();
swatches.attr({
"fill": function (d, i) { return _this._scale.scale(d); },
"width": swatchWidth,
"height": swatchHeight,
"x": swatchX,
"y": swatchY
});
return this;
};
/**
* The css class applied to the legend labels.
*/
InterpolatedColorLegend.LEGEND_LABEL_CLASS = "legend-label";
return InterpolatedColorLegend;
})(Plottable.Component);
Components.InterpolatedColorLegend = InterpolatedColorLegend;
})(Components = Plottable.Components || (Plottable.Components = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Components;
(function (Components) {
var Gridlines = (function (_super) {
__extends(Gridlines, _super);
/**
* @constructor
* @param {QuantitativeScale} xScale The scale to base the x gridlines on. Pass null if no gridlines are desired.
* @param {QuantitativeScale} yScale The scale to base the y gridlines on. Pass null if no gridlines are desired.
*/
function Gridlines(xScale, yScale) {
var _this = this;
if (xScale != null && !(Plottable.QuantitativeScale.prototype.isPrototypeOf(xScale))) {
throw new Error("xScale needs to inherit from Scale.QuantitativeScale");
}
if (yScale != null && !(Plottable.QuantitativeScale.prototype.isPrototypeOf(yScale))) {
throw new Error("yScale needs to inherit from Scale.QuantitativeScale");
}
_super.call(this);
this.addClass("gridlines");
this._xScale = xScale;
this._yScale = yScale;
this._renderCallback = function (scale) { return _this.render(); };
if (this._xScale) {
this._xScale.onUpdate(this._renderCallback);
}
if (this._yScale) {
this._yScale.onUpdate(this._renderCallback);
}
}
Gridlines.prototype.destroy = function () {
_super.prototype.destroy.call(this);
if (this._xScale) {
this._xScale.offUpdate(this._renderCallback);
}
if (this._yScale) {
this._yScale.offUpdate(this._renderCallback);
}
return this;
};
Gridlines.prototype._setup = function () {
_super.prototype._setup.call(this);
this._xLinesContainer = this.content().append("g").classed("x-gridlines", true);
this._yLinesContainer = this.content().append("g").classed("y-gridlines", true);
};
Gridlines.prototype.renderImmediately = function () {
_super.prototype.renderImmediately.call(this);
this._redrawXLines();
this._redrawYLines();
return this;
};
Gridlines.prototype.computeLayout = function (origin, availableWidth, availableHeight) {
_super.prototype.computeLayout.call(this, origin, availableWidth, availableHeight);
if (this._xScale != null) {
this._xScale.range([0, this.width()]);
}
if (this._yScale != null) {
this._yScale.range([this.height(), 0]);
}
return this;
};
Gridlines.prototype._redrawXLines = function () {
var _this = this;
if (this._xScale) {
var xTicks = this._xScale.ticks();
var getScaledXValue = function (tickVal) { return _this._xScale.scale(tickVal); };
var xLines = this._xLinesContainer.selectAll("line").data(xTicks);
xLines.enter().append("line");
xLines.attr("x1", getScaledXValue)
.attr("y1", 0)
.attr("x2", getScaledXValue)
.attr("y2", this.height())
.classed("zeroline", function (t) { return t === 0; });
xLines.exit().remove();
}
};
Gridlines.prototype._redrawYLines = function () {
var _this = this;
if (this._yScale) {
var yTicks = this._yScale.ticks();
var getScaledYValue = function (tickVal) { return _this._yScale.scale(tickVal); };
var yLines = this._yLinesContainer.selectAll("line").data(yTicks);
yLines.enter().append("line");
yLines.attr("x1", 0)
.attr("y1", getScaledYValue)
.attr("x2", this.width())
.attr("y2", getScaledYValue)
.classed("zeroline", function (t) { return t === 0; });
yLines.exit().remove();
}
};
return Gridlines;
})(Plottable.Component);
Components.Gridlines = Gridlines;
})(Components = Plottable.Components || (Plottable.Components = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Components;
(function (Components) {
var Table = (function (_super) {
__extends(Table, _super);
/**
* A Table combines Components in the form of a grid. A
* common case is combining a y-axis, x-axis, and the plotted data via
* ```typescript
* new Table([[yAxis, plot],
* [null, xAxis]]);
* ```
*
* @constructor
* @param {Component[][]} [rows=[]] A 2-D array of Components to be added to the Table.
* null can be used if a cell is empty.
*/
function Table(rows) {
var _this = this;
if (rows === void 0) { rows = []; }
_super.call(this);
this._rowPadding = 0;
this._columnPadding = 0;
this._rows = [];
this._rowWeights = [];
this._columnWeights = [];
this._nRows = 0;
this._nCols = 0;
this._calculatedLayout = null;
this.addClass("table");
rows.forEach(function (row, rowIndex) {
row.forEach(function (component, colIndex) {
if (component != null) {
_this.add(component, rowIndex, colIndex);
}
});
});
}
Table.prototype._forEach = function (callback) {
for (var r = 0; r < this._nRows; r++) {
for (var c = 0; c < this._nCols; c++) {
if (this._rows[r][c] != null) {
callback(this._rows[r][c]);
}
}
}
};
/**
* Checks whether the specified Component is in the Table.
*/
Table.prototype.has = function (component) {
for (var r = 0; r < this._nRows; r++) {
for (var c = 0; c < this._nCols; c++) {
if (this._rows[r][c] === component) {
return true;
}
}
}
return false;
};
/**
* Adds a Component in the specified row and column position.
*
* For example, instead of calling `new Table([[a, b], [null, c]])`, you
* could call
* ```typescript
* var table = new Table();
* table.add(a, 0, 0);
* table.add(b, 0, 1);
* table.add(c, 1, 1);
* ```
*
* @param {Component} component The Component to be added.
* @param {number} row
* @param {number} col
* @returns {Table} The calling Table.
*/
Table.prototype.add = function (component, row, col) {
if (component == null) {
throw Error("Cannot add null to a table cell");
}
if (!this.has(component)) {
var currentComponent = this._rows[row] && this._rows[row][col];
if (currentComponent != null) {
throw new Error("cell is occupied");
}
component.detach();
this._nRows = Math.max(row + 1, this._nRows);
this._nCols = Math.max(col + 1, this._nCols);
this._padTableToSize(this._nRows, this._nCols);
this._rows[row][col] = component;
this._adoptAndAnchor(component);
this.redraw();
}
return this;
};
Table.prototype._remove = function (component) {
for (var r = 0; r < this._nRows; r++) {
for (var c = 0; c < this._nCols; c++) {
if (this._rows[r][c] === component) {
this._rows[r][c] = null;
return true;
}
}
}
return false;
};
Table.prototype._iterateLayout = function (availableWidth, availableHeight, isFinalOffer) {
if (isFinalOffer === void 0) { isFinalOffer = false; }
/*
* Given availableWidth and availableHeight, figure out how to allocate it between rows and columns using an iterative algorithm.
*
* For both dimensions, keeps track of "guaranteedSpace", which the fixed-size components have requested, and
* "proportionalSpace", which is being given to proportionally-growing components according to the weights on the table.
* Here is how it works (example uses width but it is the same for height). First, columns are guaranteed no width, and
* the free width is allocated to columns based on their colWeights. Then, in determineGuarantees, every component is
* offered its column's width and may request some amount of it, which increases that column's guaranteed
* width. If there are some components that were not satisfied with the width they were offered, and there is free
* width that has not already been guaranteed, then the remaining width is allocated to the unsatisfied columns and the
* algorithm runs again. If all components are satisfied, then the remaining width is allocated as proportional space
* according to the colWeights.
*
* The guaranteed width for each column is monotonically increasing as the algorithm iterates. Since it is deterministic
* and monotonically increasing, if the freeWidth does not change during an iteration it implies that no further progress
* is possible, so the algorithm will not continue iterating on that dimension's account.
*
* If the algorithm runs more than 5 times, we stop and just use whatever we arrived at. It's not clear under what
* circumstances this will happen or if it will happen at all. A message will be printed to the console if this occurs.
*
*/
var rows = this._rows;
var cols = d3.transpose(this._rows);
var availableWidthAfterPadding = availableWidth - this._columnPadding * (this._nCols - 1);
var availableHeightAfterPadding = availableHeight - this._rowPadding * (this._nRows - 1);
var rowWeights = Table._calcComponentWeights(this._rowWeights, rows, function (c) { return (c == null) || c.fixedHeight(); });
var colWeights = Table._calcComponentWeights(this._columnWeights, cols, function (c) { return (c == null) || c.fixedWidth(); });
// To give the table a good starting position to iterate from, we give the fixed-width components half-weight
// so that they will get some initial space allocated to work with
var heuristicColWeights = colWeights.map(function (c) { return c === 0 ? 0.5 : c; });
var heuristicRowWeights = rowWeights.map(function (c) { return c === 0 ? 0.5 : c; });
var colProportionalSpace = Table._calcProportionalSpace(heuristicColWeights, availableWidthAfterPadding);
var rowProportionalSpace = Table._calcProportionalSpace(heuristicRowWeights, availableHeightAfterPadding);
var guaranteedWidths = Plottable.Utils.Array.createFilledArray(0, this._nCols);
var guaranteedHeights = Plottable.Utils.Array.createFilledArray(0, this._nRows);
var freeWidth;
var freeHeight;
var nIterations = 0;
while (true) {
var offeredHeights = Plottable.Utils.Array.add(guaranteedHeights, rowProportionalSpace);
var offeredWidths = Plottable.Utils.Array.add(guaranteedWidths, colProportionalSpace);
var guarantees = this._determineGuarantees(offeredWidths, offeredHeights, isFinalOffer);
guaranteedWidths = guarantees.guaranteedWidths;
guaranteedHeights = guarantees.guaranteedHeights;
var wantsWidth = guarantees.wantsWidthArr.some(function (x) { return x; });
var wantsHeight = guarantees.wantsHeightArr.some(function (x) { return x; });
var lastFreeWidth = freeWidth;
var lastFreeHeight = freeHeight;
freeWidth = availableWidthAfterPadding - d3.sum(guarantees.guaranteedWidths);
freeHeight = availableHeightAfterPadding - d3.sum(guarantees.guaranteedHeights);
var xWeights;
if (wantsWidth) {
xWeights = guarantees.wantsWidthArr.map(function (x) { return x ? 0.1 : 0; });
xWeights = Plottable.Utils.Array.add(xWeights, colWeights);
}
else {
xWeights = colWeights;
}
var yWeights;
if (wantsHeight) {
yWeights = guarantees.wantsHeightArr.map(function (x) { return x ? 0.1 : 0; });
yWeights = Plottable.Utils.Array.add(yWeights, rowWeights);
}
else {
yWeights = rowWeights;
}
colProportionalSpace = Table._calcProportionalSpace(xWeights, freeWidth);
rowProportionalSpace = Table._calcProportionalSpace(yWeights, freeHeight);
nIterations++;
var canImproveWidthAllocation = freeWidth > 0 && freeWidth !== lastFreeWidth;
var canImproveHeightAllocation = freeHeight > 0 && freeHeight !== lastFreeHeight;
if (!(canImproveWidthAllocation || canImproveHeightAllocation)) {
break;
}
if (nIterations > 5) {
break;
}
}
// Redo the proportional space one last time, to ensure we use the real weights not the wantsWidth/Height weights
freeWidth = availableWidthAfterPadding - d3.sum(guarantees.guaranteedWidths);
freeHeight = availableHeightAfterPadding - d3.sum(guarantees.guaranteedHeights);
colProportionalSpace = Table._calcProportionalSpace(colWeights, freeWidth);
rowProportionalSpace = Table._calcProportionalSpace(rowWeights, freeHeight);
return { colProportionalSpace: colProportionalSpace,
rowProportionalSpace: rowProportionalSpace,
guaranteedWidths: guarantees.guaranteedWidths,
guaranteedHeights: guarantees.guaranteedHeights,
wantsWidth: wantsWidth,
wantsHeight: wantsHeight };
};
Table.prototype._determineGuarantees = function (offeredWidths, offeredHeights, isFinalOffer) {
if (isFinalOffer === void 0) { isFinalOffer = false; }
var requestedWidths = Plottable.Utils.Array.createFilledArray(0, this._nCols);
var requestedHeights = Plottable.Utils.Array.createFilledArray(0, this._nRows);
var columnNeedsWidth = Plottable.Utils.Array.createFilledArray(false, this._nCols);
var rowNeedsHeight = Plottable.Utils.Array.createFilledArray(false, this._nRows);
this._rows.forEach(function (row, rowIndex) {
row.forEach(function (component, colIndex) {
var spaceRequest;
if (component != null) {
spaceRequest = component.requestedSpace(offeredWidths[colIndex], offeredHeights[rowIndex]);
}
else {
spaceRequest = {
minWidth: 0,
minHeight: 0
};
}
var columnWidth = isFinalOffer ? Math.min(spaceRequest.minWidth, offeredWidths[colIndex]) : spaceRequest.minWidth;
requestedWidths[colIndex] = Math.max(requestedWidths[colIndex], columnWidth);
var rowHeight = isFinalOffer ? Math.min(spaceRequest.minHeight, offeredHeights[rowIndex]) : spaceRequest.minHeight;
requestedHeights[rowIndex] = Math.max(requestedHeights[rowIndex], rowHeight);
var componentNeedsWidth = spaceRequest.minWidth > offeredWidths[colIndex];
columnNeedsWidth[colIndex] = columnNeedsWidth[colIndex] || componentNeedsWidth;
var componentNeedsHeight = spaceRequest.minHeight > offeredHeights[rowIndex];
rowNeedsHeight[rowIndex] = rowNeedsHeight[rowIndex] || componentNeedsHeight;
});
});
return {
guaranteedWidths: requestedWidths,
guaranteedHeights: requestedHeights,
wantsWidthArr: columnNeedsWidth,
wantsHeightArr: rowNeedsHeight
};
};
Table.prototype.requestedSpace = function (offeredWidth, offeredHeight) {
this._calculatedLayout = this._iterateLayout(offeredWidth, offeredHeight);
return {
minWidth: d3.sum(this._calculatedLayout.guaranteedWidths),
minHeight: d3.sum(this._calculatedLayout.guaranteedHeights)
};
};
Table.prototype.computeLayout = function (origin, availableWidth, availableHeight) {
var _this = this;
_super.prototype.computeLayout.call(this, origin, availableWidth, availableHeight);
var lastLayoutWidth = d3.sum(this._calculatedLayout.guaranteedWidths);
var lastLayoutHeight = d3.sum(this._calculatedLayout.guaranteedHeights);
var layout = this._calculatedLayout;
if (lastLayoutWidth > this.width() || lastLayoutHeight > this.height()) {
layout = this._iterateLayout(this.width(), this.height(), true);
}
var childYOrigin = 0;
var rowHeights = Plottable.Utils.Array.add(layout.rowProportionalSpace, layout.guaranteedHeights);
var colWidths = Plottable.Utils.Array.add(layout.colProportionalSpace, layout.guaranteedWidths);
this._rows.forEach(function (row, rowIndex) {
var childXOrigin = 0;
row.forEach(function (component, colIndex) {
// recursively compute layout
if (component != null) {
component.computeLayout({ x: childXOrigin, y: childYOrigin }, colWidths[colIndex], rowHeights[rowIndex]);
}
childXOrigin += colWidths[colIndex] + _this._columnPadding;
});
childYOrigin += rowHeights[rowIndex] + _this._rowPadding;
});
return this;
};
Table.prototype.rowPadding = function (rowPadding) {
if (rowPadding == null) {
return this._rowPadding;
}
this._rowPadding = rowPadding;
this.redraw();
return this;
};
Table.prototype.columnPadding = function (columnPadding) {
if (columnPadding == null) {
return this._columnPadding;
}
this._columnPadding = columnPadding;
this.redraw();
return this;
};
Table.prototype.rowWeight = function (index, weight) {
if (weight == null) {
return this._rowWeights[index];
}
this._rowWeights[index] = weight;
this.redraw();
return this;
};
Table.prototype.columnWeight = function (index, weight) {
if (weight == null) {
return this._columnWeights[index];
}
this._columnWeights[index] = weight;
this.redraw();
return this;
};
Table.prototype.fixedWidth = function () {
var cols = d3.transpose(this._rows);
return Table._fixedSpace(cols, function (c) { return (c == null) || c.fixedWidth(); });
};
Table.prototype.fixedHeight = function () {
return Table._fixedSpace(this._rows, function (c) { return (c == null) || c.fixedHeight(); });
};
Table.prototype._padTableToSize = function (nRows, nCols) {
for (var i = 0; i < nRows; i++) {
if (this._rows[i] === undefined) {
this._rows[i] = [];
this._rowWeights[i] = null;
}
for (var j = 0; j < nCols; j++) {
if (this._rows[i][j] === undefined) {
this._rows[i][j] = null;
}
}
}
for (j = 0; j < nCols; j++) {
if (this._columnWeights[j] === undefined) {
this._columnWeights[j] = null;
}
}
};
Table._calcComponentWeights = function (setWeights, componentGroups, fixityAccessor) {
// If the row/col weight was explicitly set, then return it outright
// If the weight was not explicitly set, then guess it using the heuristic that if all components are fixed-space
// then weight is 0, otherwise weight is 1
return setWeights.map(function (w, i) {
if (w != null) {
return w;
}
var fixities = componentGroups[i].map(fixityAccessor);
var allFixed = fixities.reduce(function (a, b) { return a && b; }, true);
return allFixed ? 0 : 1;
});
};
Table._calcProportionalSpace = function (weights, freeSpace) {
var weightSum = d3.sum(weights);
if (weightSum === 0) {
return Plottable.Utils.Array.createFilledArray(0, weights.length);
}
else {
return weights.map(function (w) { return freeSpace * w / weightSum; });
}
};
Table._fixedSpace = function (componentGroup, fixityAccessor) {
var all = function (bools) { return bools.reduce(function (a, b) { return a && b; }, true); };
var groupIsFixed = function (components) { return all(components.map(fixityAccessor)); };
return all(componentGroup.map(groupIsFixed));
};
return Table;
})(Plottable.ComponentContainer);
Components.Table = Table;
})(Components = Plottable.Components || (Plottable.Components = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Components;
(function (Components) {
var SelectionBoxLayer = (function (_super) {
__extends(SelectionBoxLayer, _super);
function SelectionBoxLayer() {
var _this = this;
_super.call(this);
this._boxVisible = false;
this._boxBounds = {
topLeft: { x: 0, y: 0 },
bottomRight: { x: 0, y: 0 }
};
this.addClass("selection-box-layer");
this._adjustBoundsCallback = function () {
_this.bounds({
topLeft: {
x: _this._xScale ? _this._xScale.scale(_this._boxLeftDataValue) : _this._boxBounds.topLeft.x,
y: _this._yScale ? _this._yScale.scale(_this._boxTopDataValue) : _this._boxBounds.topLeft.y
},
bottomRight: {
x: _this._xScale ? _this._xScale.scale(_this._boxRightDataValue) : _this._boxBounds.bottomRight.x,
y: _this._yScale ? _this._yScale.scale(_this._boxBottomDataValue) : _this._boxBounds.bottomRight.y
}
});
};
}
SelectionBoxLayer.prototype._setup = function () {
_super.prototype._setup.call(this);
this._box = this.content().append("g").classed("selection-box", true).remove();
this._boxArea = this._box.append("rect").classed("selection-area", true);
};
SelectionBoxLayer.prototype._sizeFromOffer = function (availableWidth, availableHeight) {
return {
width: availableWidth,
height: availableHeight
};
};
SelectionBoxLayer.prototype.bounds = function (newBounds) {
if (newBounds == null) {
return this._boxBounds;
}
this._setBounds(newBounds);
this.render();
return this;
};
SelectionBoxLayer.prototype._setBounds = function (newBounds) {
var topLeft = {
x: Math.min(newBounds.topLeft.x, newBounds.bottomRight.x),
y: Math.min(newBounds.topLeft.y, newBounds.bottomRight.y)
};
var bottomRight = {
x: Math.max(newBounds.topLeft.x, newBounds.bottomRight.x),
y: Math.max(newBounds.topLeft.y, newBounds.bottomRight.y)
};
this._boxBounds = {
topLeft: topLeft,
bottomRight: bottomRight
};
this._bindBoxDataValues();
};
SelectionBoxLayer.prototype.renderImmediately = function () {
if (this._boxVisible) {
var t = this._boxBounds.topLeft.y;
var b = this._boxBounds.bottomRight.y;
var l = this._boxBounds.topLeft.x;
var r = this._boxBounds.bottomRight.x;
this._boxArea.attr({
x: l, y: t, width: r - l, height: b - t
});
this.content().node().appendChild(this._box.node());
}
else {
this._box.remove();
}
return this;
};
SelectionBoxLayer.prototype.boxVisible = function (show) {
if (show == null) {
return this._boxVisible;
}
this._boxVisible = show;
this.render();
return this;
};
SelectionBoxLayer.prototype.fixedWidth = function () {
return true;
};
SelectionBoxLayer.prototype.fixedHeight = function () {
return true;
};
SelectionBoxLayer.prototype.xScale = function (xScale) {
if (xScale == null) {
return this._xScale;
}
if (this._xScale != null) {
this._xScale.offUpdate(this._adjustBoundsCallback);
}
this._xScale = xScale;
this._xScale.onUpdate(this._adjustBoundsCallback);
this._bindBoxDataValues();
return this;
};
SelectionBoxLayer.prototype.yScale = function (yScale) {
if (yScale == null) {
return this._yScale;
}
if (this._yScale != null) {
this._yScale.offUpdate(this._adjustBoundsCallback);
}
this._yScale = yScale;
this._yScale.onUpdate(this._adjustBoundsCallback);
this._bindBoxDataValues();
return this;
};
/**
* Gets the data values backing the left and right edges of the box.
*
* Returns an undefined array if the edges are not backed by a scale.
*/
SelectionBoxLayer.prototype.xExtent = function () {
// Explicit typing for Typescript 1.4
return [this._boxLeftDataValue, this._boxRightDataValue];
};
/**
* Gets the data values backing the top and bottom edges of the box.
*
* Returns an undefined array if the edges are not backed by a scale.
*/
SelectionBoxLayer.prototype.yExtent = function () {
// Explicit typing for Typescript 1.4
return [this._boxTopDataValue, this._boxBottomDataValue];
};
SelectionBoxLayer.prototype._bindBoxDataValues = function () {
this._boxLeftDataValue = this._xScale ? this._xScale.invert(this._boxBounds.topLeft.x) : null;
this._boxTopDataValue = this._yScale ? this._yScale.invert(this._boxBounds.topLeft.y) : null;
this._boxRightDataValue = this._xScale ? this._xScale.invert(this._boxBounds.bottomRight.x) : null;
this._boxBottomDataValue = this._yScale ? this._yScale.invert(this._boxBounds.bottomRight.y) : null;
};
SelectionBoxLayer.prototype.destroy = function () {
_super.prototype.destroy.call(this);
if (this._xScale != null) {
this.xScale().offUpdate(this._adjustBoundsCallback);
}
if (this._yScale != null) {
this.yScale().offUpdate(this._adjustBoundsCallback);
}
};
return SelectionBoxLayer;
})(Plottable.Component);
Components.SelectionBoxLayer = SelectionBoxLayer;
})(Components = Plottable.Components || (Plottable.Components = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Plots;
(function (Plots) {
var Animator;
(function (Animator) {
Animator.MAIN = "main";
Animator.RESET = "reset";
})(Animator = Plots.Animator || (Plots.Animator = {}));
})(Plots = Plottable.Plots || (Plottable.Plots = {}));
var Plot = (function (_super) {
__extends(Plot, _super);
/**
* A Plot draws some visualization of the inputted Datasets.
*
* @constructor
*/
function Plot() {
var _this = this;
_super.call(this);
this._dataChanged = false;
this._animate = false;
this._animators = {};
this._clipPathEnabled = true;
this.addClass("plot");
this._datasetToDrawer = new Plottable.Utils.Map();
this._attrBindings = d3.map();
this._attrExtents = d3.map();
this._includedValuesProvider = function (scale) { return _this._includedValuesForScale(scale); };
this._renderCallback = function (scale) { return _this.render(); };
this._onDatasetUpdateCallback = function () { return _this._onDatasetUpdate(); };
this._propertyBindings = d3.map();
this._propertyExtents = d3.map();
var mainAnimator = new Plottable.Animators.Easing().maxTotalDuration(Plot._ANIMATION_MAX_DURATION);
this.animator(Plots.Animator.MAIN, mainAnimator);
this.animator(Plots.Animator.RESET, new Plottable.Animators.Null());
}
Plot.prototype.anchor = function (selection) {
_super.prototype.anchor.call(this, selection);
this._dataChanged = true;
this._updateExtents();
return this;
};
Plot.prototype._setup = function () {
var _this = this;
_super.prototype._setup.call(this);
this._renderArea = this.content().append("g").classed("render-area", true);
this.datasets().forEach(function (dataset) { return _this._createNodesForDataset(dataset); });
};
Plot.prototype.destroy = function () {
var _this = this;
_super.prototype.destroy.call(this);
this._scales().forEach(function (scale) { return scale.offUpdate(_this._renderCallback); });
this.datasets().forEach(function (dataset) { return _this.removeDataset(dataset); });
};
/**
* Adds a Dataset to the Plot.
*
* @param {Dataset} dataset
* @returns {Plot} The calling Plot.
*/
Plot.prototype.addDataset = function (dataset) {
if (this.datasets().indexOf(dataset) > -1) {
this.removeDataset(dataset);
}
;
var drawer = this._createDrawer(dataset);
this._datasetToDrawer.set(dataset, drawer);
if (this._isSetup) {
this._createNodesForDataset(dataset);
}
dataset.onUpdate(this._onDatasetUpdateCallback);
this._onDatasetUpdate();
return this;
};
Plot.prototype._createNodesForDataset = function (dataset) {
var drawer = this._datasetToDrawer.get(dataset);
drawer.renderArea(this._renderArea.append("g"));
return drawer;
};
Plot.prototype._createDrawer = function (dataset) {
return new Plottable.Drawer(dataset);
};
Plot.prototype._getAnimator = function (key) {
if (this._animateOnNextRender()) {
return this._animators[key] || new Plottable.Animators.Null();
}
else {
return new Plottable.Animators.Null();
}
};
Plot.prototype._onDatasetUpdate = function () {
this._updateExtents();
this._dataChanged = true;
this.render();
};
Plot.prototype.attr = function (attr, attrValue, scale) {
if (attrValue == null) {
return this._attrBindings.get(attr);
}
this._bindAttr(attr, attrValue, scale);
this.render(); // queue a re-render upon changing projector
return this;
};
Plot.prototype._bindProperty = function (property, value, scale) {
this._bind(property, value, scale, this._propertyBindings, this._propertyExtents);
this._updateExtentsForProperty(property);
};
Plot.prototype._bindAttr = function (attr, value, scale) {
this._bind(attr, value, scale, this._attrBindings, this._attrExtents);
this._updateExtentsForAttr(attr);
};
Plot.prototype._bind = function (key, value, scale, bindings, extents) {
var binding = bindings.get(key);
var oldScale = binding != null ? binding.scale : null;
if (oldScale != null) {
this._uninstallScaleForKey(oldScale, key);
}
if (scale != null) {
this._installScaleForKey(scale, key);
}
bindings.set(key, { accessor: d3.functor(value), scale: scale });
};
Plot.prototype._generateAttrToProjector = function () {
var h = {};
this._attrBindings.forEach(function (attr, binding) {
var accessor = binding.accessor;
var scale = binding.scale;
var fn = scale ? function (d, i, dataset) { return scale.scale(accessor(d, i, dataset)); } : accessor;
h[attr] = fn;
});
var propertyProjectors = this._propertyProjectors();
Object.keys(propertyProjectors).forEach(function (key) {
if (h[key] == null) {
h[key] = propertyProjectors[key];
}
});
return h;
};
Plot.prototype.renderImmediately = function () {
if (this._isAnchored) {
this._paint();
this._dataChanged = false;
}
return this;
};
Plot.prototype.animated = function (willAnimate) {
if (willAnimate == null) {
return this._animate;
}
this._animate = willAnimate;
return this;
};
Plot.prototype.detach = function () {
_super.prototype.detach.call(this);
// make the domain resize
this._updateExtents();
return this;
};
/**
* @returns {Scale[]} A unique array of all scales currently used by the Plot.
*/
Plot.prototype._scales = function () {
var scales = [];
this._attrBindings.forEach(function (attr, binding) {
var scale = binding.scale;
if (scale != null && scales.indexOf(scale) === -1) {
scales.push(scale);
}
});
this._propertyBindings.forEach(function (property, binding) {
var scale = binding.scale;
if (scale != null && scales.indexOf(scale) === -1) {
scales.push(scale);
}
});
return scales;
};
/**
* Updates the extents associated with each attribute, then autodomains all scales the Plot uses.
*/
Plot.prototype._updateExtents = function () {
var _this = this;
this._attrBindings.forEach(function (attr) { return _this._updateExtentsForAttr(attr); });
this._propertyExtents.forEach(function (property) { return _this._updateExtentsForProperty(property); });
this._scales().forEach(function (scale) { return scale.addIncludedValuesProvider(_this._includedValuesProvider); });
};
Plot.prototype._updateExtentsForAttr = function (attr) {
// Filters should never be applied to attributes
this._updateExtentsForKey(attr, this._attrBindings, this._attrExtents, null);
};
Plot.prototype._updateExtentsForProperty = function (property) {
this._updateExtentsForKey(property, this._propertyBindings, this._propertyExtents, this._filterForProperty(property));
};
Plot.prototype._filterForProperty = function (property) {
return null;
};
Plot.prototype._updateExtentsForKey = function (key, bindings, extents, filter) {
var _this = this;
var accScaleBinding = bindings.get(key);
if (accScaleBinding == null || accScaleBinding.accessor == null) {
return;
}
extents.set(key, this.datasets().map(function (dataset) { return _this._computeExtent(dataset, accScaleBinding, filter); }));
};
Plot.prototype._computeExtent = function (dataset, accScaleBinding, filter) {
var accessor = accScaleBinding.accessor;
var scale = accScaleBinding.scale;
if (scale == null) {
return [];
}
var data = dataset.data();
if (filter != null) {
data = data.filter(function (d, i) { return filter(d, i, dataset); });
}
var appliedAccessor = function (d, i) { return accessor(d, i, dataset); };
var mappedData = data.map(appliedAccessor);
return scale.extentOfValues(mappedData);
};
/**
* Override in subclass to add special extents, such as included values
*/
Plot.prototype._extentsForProperty = function (property) {
return this._propertyExtents.get(property);
};
Plot.prototype._includedValuesForScale = function (scale) {
var _this = this;
if (!this._isAnchored) {
return [];
}
var includedValues = [];
this._attrBindings.forEach(function (attr, binding) {
if (binding.scale === scale) {
var extents = _this._attrExtents.get(attr);
if (extents != null) {
includedValues = includedValues.concat(d3.merge(extents));
}
}
});
this._propertyBindings.forEach(function (property, binding) {
if (binding.scale === scale) {
var extents = _this._extentsForProperty(property);
if (extents != null) {
includedValues = includedValues.concat(d3.merge(extents));
}
}
});
return includedValues;
};
Plot.prototype.animator = function (animatorKey, animator) {
if (animator === undefined) {
return this._animators[animatorKey];
}
else {
this._animators[animatorKey] = animator;
return this;
}
};
/**
* Removes a Dataset from the Plot.
*
* @param {Dataset} dataset
* @returns {Plot} The calling Plot.
*/
Plot.prototype.removeDataset = function (dataset) {
if (this.datasets().indexOf(dataset) > -1) {
this._removeDatasetNodes(dataset);
dataset.offUpdate(this._onDatasetUpdateCallback);
this._datasetToDrawer.delete(dataset);
this._onDatasetUpdate();
}
return this;
};
Plot.prototype._removeDatasetNodes = function (dataset) {
var drawer = this._datasetToDrawer.get(dataset);
drawer.remove();
};
Plot.prototype.datasets = function (datasets) {
var _this = this;
var currentDatasets = [];
this._datasetToDrawer.forEach(function (drawer, dataset) { return currentDatasets.push(dataset); });
if (datasets == null) {
return currentDatasets;
}
currentDatasets.forEach(function (dataset) { return _this.removeDataset(dataset); });
datasets.forEach(function (dataset) { return _this.addDataset(dataset); });
return this;
};
Plot.prototype._getDrawersInOrder = function () {
var _this = this;
return this.datasets().map(function (dataset) { return _this._datasetToDrawer.get(dataset); });
};
Plot.prototype._generateDrawSteps = function () {
return [{ attrToProjector: this._generateAttrToProjector(), animator: new Plottable.Animators.Null() }];
};
Plot.prototype._additionalPaint = function (time) {
// no-op
};
Plot.prototype._getDataToDraw = function () {
var dataToDraw = new Plottable.Utils.Map();
this.datasets().forEach(function (dataset) { return dataToDraw.set(dataset, dataset.data()); });
return dataToDraw;
};
Plot.prototype._paint = function () {
var drawSteps = this._generateDrawSteps();
var dataToDraw = this._getDataToDraw();
var drawers = this._getDrawersInOrder();
this.datasets().forEach(function (ds, i) { return drawers[i].draw(dataToDraw.get(ds), drawSteps); });
var times = this.datasets().map(function (ds, i) { return drawers[i].totalDrawTime(dataToDraw.get(ds), drawSteps); });
var maxTime = Plottable.Utils.Math.max(times, 0);
this._additionalPaint(maxTime);
};
/**
* Retrieves Selections of this Plot for the specified Datasets.
*
* @param {Dataset[]} [datasets] The Datasets to retrieve the Selections for.
* If not provided, Selections will be retrieved for all Datasets on the Plot.
* @returns {d3.Selection}
*/
Plot.prototype.selections = function (datasets) {
var _this = this;
if (datasets === void 0) { datasets = this.datasets(); }
var selections = [];
datasets.forEach(function (dataset) {
var drawer = _this._datasetToDrawer.get(dataset);
if (drawer == null) {
return;
}
drawer.renderArea().selectAll(drawer.selector()).each(function () {
selections.push(this);
});
});
return d3.selectAll(selections);
};
/**
* Gets the Entities associated with the specified Datasets.
*
* @param {dataset[]} datasets The Datasets to retrieve the Entities for.
* If not provided, returns defaults to all Datasets on the Plot.
* @return {Plots.PlotEntity[]}
*/
Plot.prototype.entities = function (datasets) {
var _this = this;
if (datasets === void 0) { datasets = this.datasets(); }
return this._lightweightEntities(datasets).map(function (entity) { return _this._lightweightPlotEntityToPlotEntity(entity); });
};
Plot.prototype._lightweightEntities = function (datasets) {
var _this = this;
if (datasets === void 0) { datasets = this.datasets(); }
var lightweightEntities = [];
datasets.forEach(function (dataset) {
var drawer = _this._datasetToDrawer.get(dataset);
var validDatumIndex = 0;
dataset.data().forEach(function (datum, datasetIndex) {
var position = _this._pixelPoint(datum, datasetIndex, dataset);
if (Plottable.Utils.Math.isNaN(position.x) || Plottable.Utils.Math.isNaN(position.y)) {
return;
}
lightweightEntities.push({
datum: datum,
index: datasetIndex,
dataset: dataset,
position: position,
component: _this,
drawer: drawer,
validDatumIndex: validDatumIndex
});
validDatumIndex++;
});
});
return lightweightEntities;
};
Plot.prototype._lightweightPlotEntityToPlotEntity = function (entity) {
var plotEntity = {
datum: entity.datum,
position: entity.position,
dataset: entity.dataset,
index: entity.index,
component: entity.component,
selection: entity.drawer.selectionForIndex(entity.validDatumIndex)
};
return plotEntity;
};
/**
* Returns the PlotEntity nearest to the query point by the Euclidian norm, or undefined if no PlotEntity can be found.
*
* @param {Point} queryPoint
* @returns {Plots.PlotEntity} The nearest PlotEntity, or undefined if no PlotEntity can be found.
*/
Plot.prototype.entityNearest = function (queryPoint) {
var _this = this;
var closestDistanceSquared = Infinity;
var closestPointEntity;
var entities = this._lightweightEntities();
entities.forEach(function (entity) {
if (!_this._entityVisibleOnPlot(entity.position, entity.datum, entity.index, entity.dataset)) {
return;
}
var distanceSquared = Plottable.Utils.Math.distanceSquared(entity.position, queryPoint);
if (distanceSquared < closestDistanceSquared) {
closestDistanceSquared = distanceSquared;
closestPointEntity = entity;
}
});
return this._lightweightPlotEntityToPlotEntity(closestPointEntity);
};
Plot.prototype._visibleOnPlot = function (datum, pixelPoint, selection) {
Plottable.Utils.Window.deprecated("Plot._visibleOnPlot()", "v1.1.0");
return !(pixelPoint.x < 0 || pixelPoint.y < 0 ||
pixelPoint.x > this.width() || pixelPoint.y > this.height());
};
Plot.prototype._entityVisibleOnPlot = function (pixelPoint, datum, index, dataset) {
return !(pixelPoint.x < 0 || pixelPoint.y < 0 ||
pixelPoint.x > this.width() || pixelPoint.y > this.height());
};
Plot.prototype._uninstallScaleForKey = function (scale, key) {
scale.offUpdate(this._renderCallback);
scale.removeIncludedValuesProvider(this._includedValuesProvider);
};
Plot.prototype._installScaleForKey = function (scale, key) {
scale.onUpdate(this._renderCallback);
scale.addIncludedValuesProvider(this._includedValuesProvider);
};
Plot.prototype._propertyProjectors = function () {
return {};
};
Plot._scaledAccessor = function (binding) {
return binding.scale == null ?
binding.accessor :
function (d, i, ds) { return binding.scale.scale(binding.accessor(d, i, ds)); };
};
Plot.prototype._pixelPoint = function (datum, index, dataset) {
return { x: 0, y: 0 };
};
Plot.prototype._animateOnNextRender = function () {
return this._animate && this._dataChanged;
};
Plot._ANIMATION_MAX_DURATION = 600;
return Plot;
})(Plottable.Component);
Plottable.Plot = Plot;
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Plots;
(function (Plots) {
var Pie = (function (_super) {
__extends(Pie, _super);
/**
* @constructor
*/
function Pie() {
var _this = this;
_super.call(this);
this._labelFormatter = Plottable.Formatters.identity();
this._labelsEnabled = false;
this.innerRadius(0);
this.outerRadius(function () { return Math.min(_this.width(), _this.height()) / 2; });
this.addClass("pie-plot");
this.attr("fill", function (d, i) { return String(i); }, new Plottable.Scales.Color());
}
Pie.prototype.computeLayout = function (origin, availableWidth, availableHeight) {
_super.prototype.computeLayout.call(this, origin, availableWidth, availableHeight);
this._renderArea.attr("transform", "translate(" + this.width() / 2 + "," + this.height() / 2 + ")");
var radiusLimit = Math.min(this.width(), this.height()) / 2;
if (this.innerRadius().scale != null) {
this.innerRadius().scale.range([0, radiusLimit]);
}
if (this.outerRadius().scale != null) {
this.outerRadius().scale.range([0, radiusLimit]);
}
return this;
};
Pie.prototype.addDataset = function (dataset) {
if (this.datasets().length === 1) {
Plottable.Utils.Window.warn("Only one dataset is supported in Pie plots");
return this;
}
this._updatePieAngles();
_super.prototype.addDataset.call(this, dataset);
return this;
};
Pie.prototype.removeDataset = function (dataset) {
_super.prototype.removeDataset.call(this, dataset);
this._startAngles = [];
this._endAngles = [];
return this;
};
Pie.prototype._onDatasetUpdate = function () {
this._updatePieAngles();
_super.prototype._onDatasetUpdate.call(this);
};
Pie.prototype._createDrawer = function (dataset) {
return new Plottable.Drawers.Arc(dataset);
};
Pie.prototype.entities = function (datasets) {
var _this = this;
if (datasets === void 0) { datasets = this.datasets(); }
var entities = _super.prototype.entities.call(this, datasets);
entities.forEach(function (entity) {
entity.position.x += _this.width() / 2;
entity.position.y += _this.height() / 2;
});
return entities;
};
Pie.prototype.sectorValue = function (sectorValue, scale) {
if (sectorValue == null) {
return this._propertyBindings.get(Pie._SECTOR_VALUE_KEY);
}
this._bindProperty(Pie._SECTOR_VALUE_KEY, sectorValue, scale);
this._updatePieAngles();
this.render();
return this;
};
Pie.prototype.innerRadius = function (innerRadius, scale) {
if (innerRadius == null) {
return this._propertyBindings.get(Pie._INNER_RADIUS_KEY);
}
this._bindProperty(Pie._INNER_RADIUS_KEY, innerRadius, scale);
this.render();
return this;
};
Pie.prototype.outerRadius = function (outerRadius, scale) {
if (outerRadius == null) {
return this._propertyBindings.get(Pie._OUTER_RADIUS_KEY);
}
this._bindProperty(Pie._OUTER_RADIUS_KEY, outerRadius, scale);
this.render();
return this;
};
Pie.prototype.labelsEnabled = function (enabled) {
if (enabled === undefined) {
return this._labelsEnabled;
}
else {
this._labelsEnabled = enabled;
this.render();
return this;
}
};
Pie.prototype.labelFormatter = function (formatter) {
if (formatter == null) {
return this._labelFormatter;
}
else {
this._labelFormatter = formatter;
this.render();
return this;
}
};
/*
* Gets the Entities at a particular Point.
*
* @param {Point} p
* @param {PlotEntity[]}
*/
Pie.prototype.entitiesAt = function (queryPoint) {
var center = { x: this.width() / 2, y: this.height() / 2 };
var adjustedQueryPoint = { x: queryPoint.x - center.x, y: queryPoint.y - center.y };
var index = this._sliceIndexForPoint(adjustedQueryPoint);
return index == null ? [] : [this.entities()[index]];
};
Pie.prototype._propertyProjectors = function () {
var _this = this;
var attrToProjector = _super.prototype._propertyProjectors.call(this);
var innerRadiusAccessor = Plottable.Plot._scaledAccessor(this.innerRadius());
var outerRadiusAccessor = Plottable.Plot._scaledAccessor(this.outerRadius());
attrToProjector["d"] = function (datum, index, ds) {
return d3.svg.arc().innerRadius(innerRadiusAccessor(datum, index, ds))
.outerRadius(outerRadiusAccessor(datum, index, ds))
.startAngle(_this._startAngles[index])
.endAngle(_this._endAngles[index])(datum, index);
};
return attrToProjector;
};
Pie.prototype._updatePieAngles = function () {
if (this.sectorValue() == null) {
return;
}
if (this.datasets().length === 0) {
return;
}
var sectorValueAccessor = Plottable.Plot._scaledAccessor(this.sectorValue());
var dataset = this.datasets()[0];
var data = dataset.data().filter(function (d, i) { return Plottable.Utils.Math.isValidNumber(sectorValueAccessor(d, i, dataset)); });
var pie = d3.layout.pie().sort(null).value(function (d, i) { return sectorValueAccessor(d, i, dataset); })(data);
if (pie.some(function (slice) { return slice.value < 0; })) {
Plottable.Utils.Window.warn("Negative values will not render correctly in a Pie Plot.");
}
this._startAngles = pie.map(function (slice) { return slice.startAngle; });
this._endAngles = pie.map(function (slice) { return slice.endAngle; });
};
Pie.prototype._getDataToDraw = function () {
var dataToDraw = _super.prototype._getDataToDraw.call(this);
if (this.datasets().length === 0) {
return dataToDraw;
}
var sectorValueAccessor = Plottable.Plot._scaledAccessor(this.sectorValue());
var ds = this.datasets()[0];
var data = dataToDraw.get(ds);
var filteredData = data.filter(function (d, i) { return Plottable.Utils.Math.isValidNumber(sectorValueAccessor(d, i, ds)); });
dataToDraw.set(ds, filteredData);
return dataToDraw;
};
Pie.prototype._pixelPoint = function (datum, index, dataset) {
var innerRadius = Plottable.Plot._scaledAccessor(this.innerRadius())(datum, index, dataset);
var outerRadius = Plottable.Plot._scaledAccessor(this.outerRadius())(datum, index, dataset);
var avgRadius = (innerRadius + outerRadius) / 2;
var scaledValueAccessor = Plottable.Plot._scaledAccessor(this.sectorValue());
var pie = d3.layout.pie()
.sort(null)
.value(function (d, i) { return scaledValueAccessor(d, i, dataset); })(dataset.data());
var startAngle = pie[index].startAngle;
var endAngle = pie[index].endAngle;
var avgAngle = (startAngle + endAngle) / 2;
return { x: avgRadius * Math.sin(avgAngle), y: -avgRadius * Math.cos(avgAngle) };
};
Pie.prototype._additionalPaint = function (time) {
var _this = this;
this._renderArea.select(".label-area").remove();
if (this._labelsEnabled) {
Plottable.Utils.Window.setTimeout(function () { return _this._drawLabels(); }, time);
}
};
Pie.prototype._sliceIndexForPoint = function (p) {
var pointRadius = Math.sqrt(Math.pow(p.x, 2) + Math.pow(p.y, 2));
var pointAngle = Math.acos(-p.y / pointRadius);
if (p.x < 0) {
pointAngle = Math.PI * 2 - pointAngle;
}
var index;
for (var i = 0; i < this._startAngles.length; i++) {
if (this._startAngles[i] < pointAngle && this._endAngles[i] > pointAngle) {
index = i;
break;
}
}
if (index !== undefined) {
var dataset = this.datasets()[0];
var datum = dataset.data()[index];
var innerRadius = this.innerRadius().accessor(datum, index, dataset);
var outerRadius = this.outerRadius().accessor(datum, index, dataset);
if (pointRadius > innerRadius && pointRadius < outerRadius) {
return index;
}
}
return null;
};
Pie.prototype._drawLabels = function () {
var _this = this;
var attrToProjector = this._generateAttrToProjector();
var labelArea = this._renderArea.append("g").classed("label-area", true);
var measurer = new SVGTypewriter.Measurers.Measurer(labelArea);
var writer = new SVGTypewriter.Writers.Writer(measurer);
var dataset = this.datasets()[0];
for (var datumIndex = 0; datumIndex < dataset.data().length; datumIndex++) {
var datum = dataset.data()[datumIndex];
var value = this._labelFormatter(this.sectorValue().accessor(datum, datumIndex, dataset));
var measurement = measurer.measure(value);
var theta = (this._endAngles[datumIndex] + this._startAngles[datumIndex]) / 2;
var outerRadius = this.outerRadius().accessor(datum, datumIndex, dataset);
if (this.outerRadius().scale) {
outerRadius = this.outerRadius().scale.scale(outerRadius);
}
var innerRadius = this.innerRadius().accessor(datum, datumIndex, dataset);
if (this.innerRadius().scale) {
innerRadius = this.innerRadius().scale.scale(innerRadius);
}
var labelRadius = (outerRadius + innerRadius) / 2;
var x = Math.sin(theta) * labelRadius - measurement.width / 2;
var y = -Math.cos(theta) * labelRadius - measurement.height / 2;
var corners = [
{ x: x, y: y },
{ x: x, y: y + measurement.height },
{ x: x + measurement.width, y: y },
{ x: x + measurement.width, y: y + measurement.height }
];
var showLabel = corners.every(function (corner) {
return Math.abs(corner.x) <= _this.width() / 2 && Math.abs(corner.y) <= _this.height() / 2;
});
if (showLabel) {
var sliceIndices = corners.map(function (corner) { return _this._sliceIndexForPoint(corner); });
showLabel = sliceIndices.every(function (index) { return index === datumIndex; });
}
var color = attrToProjector["fill"](datum, datumIndex, dataset);
var dark = Plottable.Utils.Color.contrast("white", color) * 1.6 < Plottable.Utils.Color.contrast("black", color);
var g = labelArea.append("g").attr("transform", "translate(" + x + "," + y + ")");
var className = dark ? "dark-label" : "light-label";
g.classed(className, true);
g.style("visibility", showLabel ? "inherit" : "hidden");
writer.write(value, measurement.width, measurement.height, {
selection: g,
xAlign: "center",
yAlign: "center",
textRotation: 0
});
}
};
Pie._INNER_RADIUS_KEY = "inner-radius";
Pie._OUTER_RADIUS_KEY = "outer-radius";
Pie._SECTOR_VALUE_KEY = "sector-value";
return Pie;
})(Plottable.Plot);
Plots.Pie = Pie;
})(Plots = Plottable.Plots || (Plottable.Plots = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var XYPlot = (function (_super) {
__extends(XYPlot, _super);
/**
* An XYPlot is a Plot that displays data along two primary directions, X and Y.
*
* @constructor
* @param {Scale} xScale The x scale to use.
* @param {Scale} yScale The y scale to use.
*/
function XYPlot() {
var _this = this;
_super.call(this);
this._autoAdjustXScaleDomain = false;
this._autoAdjustYScaleDomain = false;
this._deferredRendering = false;
this._cachedDomainX = [null, null];
this._cachedDomainY = [null, null];
this.addClass("xy-plot");
this._adjustYDomainOnChangeFromXCallback = function (scale) { return _this._adjustYDomainOnChangeFromX(); };
this._adjustXDomainOnChangeFromYCallback = function (scale) { return _this._adjustXDomainOnChangeFromY(); };
var _deltaX = 0;
var _deltaY = 0;
var _scalingX = 1;
var _scalingY = 1;
var _lastSeenDomainX = null;
var _lastSeenDomainY = null;
var _timeoutReference = 0;
var _deferredRenderingTimeout = 500;
var _registerDeferredRendering = function () {
if (_this._renderArea == null) {
return;
}
_this._renderArea.attr("transform", "translate(" + _deltaX + ", " + _deltaY + ")" +
"scale(" + _scalingX + ", " + _scalingY + ")");
clearTimeout(_timeoutReference);
_timeoutReference = setTimeout(function () {
_this._cachedDomainX = _lastSeenDomainX;
_this._cachedDomainY = _lastSeenDomainY;
_deltaX = 0;
_deltaY = 0;
_this.render();
_this._renderArea.attr("transform", "translate(0, 0) scale(1, 1)");
}, _deferredRenderingTimeout);
};
var _lazyDomainChangeCallbackX = function (scale) {
if (!_this._isAnchored) {
return;
}
_lastSeenDomainX = scale.domain();
_scalingX = (scale.scale(_this._cachedDomainX[1]) - scale.scale(_this._cachedDomainX[0])) /
(scale.scale(_lastSeenDomainX[1]) - scale.scale(_lastSeenDomainX[0])) || 1;
_deltaX = scale.scale(_this._cachedDomainX[0]) - scale.scale(_lastSeenDomainX[0]) || 0;
_registerDeferredRendering();
};
var _lazyDomainChangeCallbackY = function (scale) {
if (!_this._isAnchored) {
return;
}
_lastSeenDomainY = scale.domain();
_scalingY = (scale.scale(_this._cachedDomainY[1]) - scale.scale(_this._cachedDomainY[0])) /
(scale.scale(_lastSeenDomainY[1]) - scale.scale(_lastSeenDomainY[0])) || 1;
_deltaY = scale.scale(_this._cachedDomainY[0]) - scale.scale(_lastSeenDomainY[0]) * _scalingY || 0;
_registerDeferredRendering();
};
this._renderCallback = function (scale) {
if (_this.deferredRendering() && _this.x() && _this.x().scale === scale) {
_lazyDomainChangeCallbackX(scale);
}
else if (_this.deferredRendering() && _this.y() && _this.y().scale === scale) {
_lazyDomainChangeCallbackY(scale);
}
else {
_this.render();
}
};
}
XYPlot.prototype.deferredRendering = function (deferredRendering) {
if (deferredRendering == null) {
return this._deferredRendering;
}
if (deferredRendering) {
if (this.x() && this.x().scale) {
this._cachedDomainX = this.x().scale.domain();
}
if (this.y() && this.y().scale) {
this._cachedDomainY = this.y().scale.domain();
}
}
this._deferredRendering = deferredRendering;
return this;
};
XYPlot.prototype.x = function (x, xScale) {
if (x == null) {
return this._propertyBindings.get(XYPlot._X_KEY);
}
this._bindProperty(XYPlot._X_KEY, x, xScale);
if (this._autoAdjustYScaleDomain) {
this._updateYExtentsAndAutodomain();
}
this.render();
return this;
};
XYPlot.prototype.y = function (y, yScale) {
if (y == null) {
return this._propertyBindings.get(XYPlot._Y_KEY);
}
this._bindProperty(XYPlot._Y_KEY, y, yScale);
if (this._autoAdjustXScaleDomain) {
this._updateXExtentsAndAutodomain();
}
this.render();
return this;
};
XYPlot.prototype._filterForProperty = function (property) {
if (property === "x" && this._autoAdjustXScaleDomain) {
return this._makeFilterByProperty("y");
}
else if (property === "y" && this._autoAdjustYScaleDomain) {
return this._makeFilterByProperty("x");
}
return null;
};
XYPlot.prototype._makeFilterByProperty = function (property) {
var binding = this._propertyBindings.get(property);
if (binding != null) {
var accessor = binding.accessor;
var scale = binding.scale;
if (scale != null) {
return function (datum, index, dataset) {
var range = scale.range();
return Plottable.Utils.Math.inRange(scale.scale(accessor(datum, index, dataset)), range[0], range[1]);
};
}
}
return null;
};
XYPlot.prototype._uninstallScaleForKey = function (scale, key) {
_super.prototype._uninstallScaleForKey.call(this, scale, key);
var adjustCallback = key === XYPlot._X_KEY ? this._adjustYDomainOnChangeFromXCallback
: this._adjustXDomainOnChangeFromYCallback;
scale.offUpdate(adjustCallback);
};
XYPlot.prototype._installScaleForKey = function (scale, key) {
_super.prototype._installScaleForKey.call(this, scale, key);
var adjustCallback = key === XYPlot._X_KEY ? this._adjustYDomainOnChangeFromXCallback
: this._adjustXDomainOnChangeFromYCallback;
scale.onUpdate(adjustCallback);
};
XYPlot.prototype.destroy = function () {
_super.prototype.destroy.call(this);
if (this.x().scale) {
this.x().scale.offUpdate(this._adjustYDomainOnChangeFromXCallback);
}
if (this.y().scale) {
this.y().scale.offUpdate(this._adjustXDomainOnChangeFromYCallback);
}
return this;
};
XYPlot.prototype.autorangeMode = function (autorangeMode) {
if (autorangeMode == null) {
if (this._autoAdjustXScaleDomain) {
return "x";
}
if (this._autoAdjustYScaleDomain) {
return "y";
}
return "none";
}
switch (autorangeMode) {
case "x":
this._autoAdjustXScaleDomain = true;
this._autoAdjustYScaleDomain = false;
this._adjustXDomainOnChangeFromY();
break;
case "y":
this._autoAdjustXScaleDomain = false;
this._autoAdjustYScaleDomain = true;
this._adjustYDomainOnChangeFromX();
break;
case "none":
this._autoAdjustXScaleDomain = false;
this._autoAdjustYScaleDomain = false;
break;
default:
throw new Error("Invalid scale name '" + autorangeMode + "', must be 'x', 'y' or 'none'");
}
return this;
};
XYPlot.prototype.computeLayout = function (origin, availableWidth, availableHeight) {
_super.prototype.computeLayout.call(this, origin, availableWidth, availableHeight);
var xBinding = this.x();
var xScale = xBinding && xBinding.scale;
if (xScale != null) {
xScale.range([0, this.width()]);
}
var yBinding = this.y();
var yScale = yBinding && yBinding.scale;
if (yScale != null) {
if (this.y().scale instanceof Plottable.Scales.Category) {
this.y().scale.range([0, this.height()]);
}
else {
this.y().scale.range([this.height(), 0]);
}
}
return this;
};
XYPlot.prototype._updateXExtentsAndAutodomain = function () {
this._updateExtentsForProperty("x");
var xScale = this.x().scale;
if (xScale != null) {
xScale.autoDomain();
}
};
XYPlot.prototype._updateYExtentsAndAutodomain = function () {
this._updateExtentsForProperty("y");
var yScale = this.y().scale;
if (yScale != null) {
yScale.autoDomain();
}
};
/**
* Adjusts the domains of both X and Y scales to show all data.
* This call does not override the autorange() behavior.
*
* @returns {XYPlot} The calling XYPlot.
*/
XYPlot.prototype.showAllData = function () {
this._updateXExtentsAndAutodomain();
this._updateYExtentsAndAutodomain();
return this;
};
XYPlot.prototype._adjustYDomainOnChangeFromX = function () {
if (!this._projectorsReady()) {
return;
}
if (this._autoAdjustYScaleDomain) {
this._updateYExtentsAndAutodomain();
}
};
XYPlot.prototype._adjustXDomainOnChangeFromY = function () {
if (!this._projectorsReady()) {
return;
}
if (this._autoAdjustXScaleDomain) {
this._updateXExtentsAndAutodomain();
}
};
XYPlot.prototype._projectorsReady = function () {
var xBinding = this.x();
var yBinding = this.y();
return xBinding != null &&
xBinding.accessor != null &&
yBinding != null &&
yBinding.accessor != null;
};
XYPlot.prototype._pixelPoint = function (datum, index, dataset) {
var xProjector = Plottable.Plot._scaledAccessor(this.x());
var yProjector = Plottable.Plot._scaledAccessor(this.y());
return { x: xProjector(datum, index, dataset), y: yProjector(datum, index, dataset) };
};
XYPlot.prototype._getDataToDraw = function () {
var _this = this;
var dataToDraw = _super.prototype._getDataToDraw.call(this);
var definedFunction = function (d, i, dataset) {
var positionX = Plottable.Plot._scaledAccessor(_this.x())(d, i, dataset);
var positionY = Plottable.Plot._scaledAccessor(_this.y())(d, i, dataset);
return Plottable.Utils.Math.isValidNumber(positionX) &&
Plottable.Utils.Math.isValidNumber(positionY);
};
this.datasets().forEach(function (dataset) {
dataToDraw.set(dataset, dataToDraw.get(dataset).filter(function (d, i) { return definedFunction(d, i, dataset); }));
});
return dataToDraw;
};
XYPlot._X_KEY = "x";
XYPlot._Y_KEY = "y";
return XYPlot;
})(Plottable.Plot);
Plottable.XYPlot = XYPlot;
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Plots;
(function (Plots) {
var Rectangle = (function (_super) {
__extends(Rectangle, _super);
/**
* A Rectangle Plot displays rectangles based on the data.
* The left and right edges of each rectangle can be set with x() and x2().
* If only x() is set the Rectangle Plot will attempt to compute the correct left and right edge positions.
* The top and bottom edges of each rectangle can be set with y() and y2().
* If only y() is set the Rectangle Plot will attempt to compute the correct top and bottom edge positions.
*
* @constructor
* @param {Scale.Scale} xScale
* @param {Scale.Scale} yScale
*/
function Rectangle() {
_super.call(this);
this.animator("rectangles", new Plottable.Animators.Null());
this.addClass("rectangle-plot");
}
Rectangle.prototype._createDrawer = function (dataset) {
return new Plottable.Drawers.Rectangle(dataset);
};
Rectangle.prototype._generateAttrToProjector = function () {
var _this = this;
var attrToProjector = _super.prototype._generateAttrToProjector.call(this);
// Copy each of the different projectors.
var xAttr = Plottable.Plot._scaledAccessor(this.x());
var x2Attr = attrToProjector[Rectangle._X2_KEY];
var yAttr = Plottable.Plot._scaledAccessor(this.y());
var y2Attr = attrToProjector[Rectangle._Y2_KEY];
var xScale = this.x().scale;
var yScale = this.y().scale;
if (x2Attr != null) {
attrToProjector["width"] = function (d, i, dataset) { return Math.abs(x2Attr(d, i, dataset) - xAttr(d, i, dataset)); };
attrToProjector["x"] = function (d, i, dataset) { return Math.min(x2Attr(d, i, dataset), xAttr(d, i, dataset)); };
}
else {
attrToProjector["width"] = function (d, i, dataset) { return _this._rectangleWidth(xScale); };
attrToProjector["x"] = function (d, i, dataset) { return xAttr(d, i, dataset) - 0.5 * attrToProjector["width"](d, i, dataset); };
}
if (y2Attr != null) {
attrToProjector["height"] = function (d, i, dataset) { return Math.abs(y2Attr(d, i, dataset) - yAttr(d, i, dataset)); };
attrToProjector["y"] = function (d, i, dataset) {
return Math.max(y2Attr(d, i, dataset), yAttr(d, i, dataset)) - attrToProjector["height"](d, i, dataset);
};
}
else {
attrToProjector["height"] = function (d, i, dataset) { return _this._rectangleWidth(yScale); };
attrToProjector["y"] = function (d, i, dataset) { return yAttr(d, i, dataset) - 0.5 * attrToProjector["height"](d, i, dataset); };
}
// Clean up the attributes projected onto the SVG elements
delete attrToProjector[Rectangle._X2_KEY];
delete attrToProjector[Rectangle._Y2_KEY];
return attrToProjector;
};
Rectangle.prototype._generateDrawSteps = function () {
return [{ attrToProjector: this._generateAttrToProjector(), animator: this._getAnimator("rectangles") }];
};
Rectangle.prototype._updateExtentsForProperty = function (property) {
_super.prototype._updateExtentsForProperty.call(this, property);
if (property === "x") {
_super.prototype._updateExtentsForProperty.call(this, "x2");
}
else if (property === "y") {
_super.prototype._updateExtentsForProperty.call(this, "y2");
}
};
Rectangle.prototype._filterForProperty = function (property) {
if (property === "x2") {
return _super.prototype._filterForProperty.call(this, "x");
}
else if (property === "y2") {
return _super.prototype._filterForProperty.call(this, "y");
}
return _super.prototype._filterForProperty.call(this, property);
};
Rectangle.prototype.x = function (x, xScale) {
if (x == null) {
return _super.prototype.x.call(this);
}
if (xScale == null) {
_super.prototype.x.call(this, x);
}
else {
_super.prototype.x.call(this, x, xScale);
}
if (xScale != null) {
var x2Binding = this.x2();
var x2 = x2Binding && x2Binding.accessor;
if (x2 != null) {
this._bindProperty(Rectangle._X2_KEY, x2, xScale);
}
}
// The x and y scales should render in bands with no padding for category scales
if (xScale instanceof Plottable.Scales.Category) {
xScale.innerPadding(0).outerPadding(0);
}
return this;
};
Rectangle.prototype.x2 = function (x2) {
if (x2 == null) {
return this._propertyBindings.get(Rectangle._X2_KEY);
}
var xBinding = this.x();
var xScale = xBinding && xBinding.scale;
this._bindProperty(Rectangle._X2_KEY, x2, xScale);
this.render();
return this;
};
Rectangle.prototype.y = function (y, yScale) {
if (y == null) {
return _super.prototype.y.call(this);
}
if (yScale == null) {
_super.prototype.y.call(this, y);
}
else {
_super.prototype.y.call(this, y, yScale);
}
if (yScale != null) {
var y2Binding = this.y2();
var y2 = y2Binding && y2Binding.accessor;
if (y2 != null) {
this._bindProperty(Rectangle._Y2_KEY, y2, yScale);
}
}
// The x and y scales should render in bands with no padding for category scales
if (yScale instanceof Plottable.Scales.Category) {
yScale.innerPadding(0).outerPadding(0);
}
return this;
};
Rectangle.prototype.y2 = function (y2) {
if (y2 == null) {
return this._propertyBindings.get(Rectangle._Y2_KEY);
}
var yBinding = this.y();
var yScale = yBinding && yBinding.scale;
this._bindProperty(Rectangle._Y2_KEY, y2, yScale);
this.render();
return this;
};
/**
* Gets the PlotEntities at a particular Point.
*
* @param {Point} point The point to query.
* @returns {PlotEntity[]} The PlotEntities at the particular point
*/
Rectangle.prototype.entitiesAt = function (point) {
var attrToProjector = this._generateAttrToProjector();
return this.entities().filter(function (entity) {
var datum = entity.datum;
var index = entity.index;
var dataset = entity.dataset;
var x = attrToProjector["x"](datum, index, dataset);
var y = attrToProjector["y"](datum, index, dataset);
var width = attrToProjector["width"](datum, index, dataset);
var height = attrToProjector["height"](datum, index, dataset);
return x <= point.x && point.x <= x + width && y <= point.y && point.y <= y + height;
});
};
Rectangle.prototype._propertyProjectors = function () {
var attrToProjector = _super.prototype._propertyProjectors.call(this);
if (this.x2() != null) {
attrToProjector["x2"] = Plottable.Plot._scaledAccessor(this.x2());
}
if (this.y2() != null) {
attrToProjector["y2"] = Plottable.Plot._scaledAccessor(this.y2());
}
return attrToProjector;
};
Rectangle.prototype._pixelPoint = function (datum, index, dataset) {
var attrToProjector = this._generateAttrToProjector();
var rectX = attrToProjector["x"](datum, index, dataset);
var rectY = attrToProjector["y"](datum, index, dataset);
var rectWidth = attrToProjector["width"](datum, index, dataset);
var rectHeight = attrToProjector["height"](datum, index, dataset);
var x = rectX + rectWidth / 2;
var y = rectY + rectHeight / 2;
return { x: x, y: y };
};
Rectangle.prototype._rectangleWidth = function (scale) {
if (scale instanceof Plottable.Scales.Category) {
return scale.rangeBand();
}
else {
var accessor = scale === this.x().scale ? this.x().accessor : this.y().accessor;
var accessorData = d3.set(Plottable.Utils.Array.flatten(this.datasets().map(function (dataset) {
return dataset.data().map(function (d, i) { return accessor(d, i, dataset).valueOf(); });
}))).values().map(function (value) { return +value; });
// Get the absolute difference between min and max
var min = Plottable.Utils.Math.min(accessorData, 0);
var max = Plottable.Utils.Math.max(accessorData, 0);
var scaledMin = scale.scale(min);
var scaledMax = scale.scale(max);
return (scaledMax - scaledMin) / Math.abs(max - min);
}
};
Rectangle.prototype._getDataToDraw = function () {
var dataToDraw = new Plottable.Utils.Map();
var attrToProjector = this._generateAttrToProjector();
this.datasets().forEach(function (dataset) {
var data = dataset.data().filter(function (d, i) { return Plottable.Utils.Math.isValidNumber(attrToProjector["x"](d, i, dataset)) &&
Plottable.Utils.Math.isValidNumber(attrToProjector["y"](d, i, dataset)) &&
Plottable.Utils.Math.isValidNumber(attrToProjector["width"](d, i, dataset)) &&
Plottable.Utils.Math.isValidNumber(attrToProjector["height"](d, i, dataset)); });
dataToDraw.set(dataset, data);
});
return dataToDraw;
};
Rectangle._X2_KEY = "x2";
Rectangle._Y2_KEY = "y2";
return Rectangle;
})(Plottable.XYPlot);
Plots.Rectangle = Rectangle;
})(Plots = Plottable.Plots || (Plottable.Plots = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Plots;
(function (Plots) {
var Scatter = (function (_super) {
__extends(Scatter, _super);
/**
* A Scatter Plot draws a symbol at each data point.
*
* @constructor
*/
function Scatter() {
_super.call(this);
this.addClass("scatter-plot");
var animator = new Plottable.Animators.Easing();
animator.startDelay(5);
animator.stepDuration(250);
animator.maxTotalDuration(Plottable.Plot._ANIMATION_MAX_DURATION);
this.animator(Plots.Animator.MAIN, animator);
this.attr("opacity", 0.6);
this.attr("fill", new Plottable.Scales.Color().range()[0]);
this.size(6);
var circleSymbolFactory = Plottable.SymbolFactories.circle();
this.symbol(function () { return circleSymbolFactory; });
}
Scatter.prototype._createDrawer = function (dataset) {
return new Plottable.Drawers.Symbol(dataset);
};
Scatter.prototype.size = function (size, scale) {
if (size == null) {
return this._propertyBindings.get(Scatter._SIZE_KEY);
}
this._bindProperty(Scatter._SIZE_KEY, size, scale);
this.render();
return this;
};
Scatter.prototype.symbol = function (symbol) {
if (symbol == null) {
return this._propertyBindings.get(Scatter._SYMBOL_KEY);
}
this._propertyBindings.set(Scatter._SYMBOL_KEY, { accessor: symbol });
this.render();
return this;
};
Scatter.prototype._generateDrawSteps = function () {
var drawSteps = [];
if (this._animateOnNextRender()) {
var resetAttrToProjector = this._generateAttrToProjector();
resetAttrToProjector["d"] = function () { return ""; };
drawSteps.push({ attrToProjector: resetAttrToProjector, animator: this._getAnimator(Plots.Animator.RESET) });
}
drawSteps.push({ attrToProjector: this._generateAttrToProjector(), animator: this._getAnimator(Plots.Animator.MAIN) });
return drawSteps;
};
Scatter.prototype._visibleOnPlot = function (datum, pixelPoint, selection) {
Plottable.Utils.Window.deprecated("Scatter._visibleOnPlot()", "v1.1.0");
var xRange = { min: 0, max: this.width() };
var yRange = { min: 0, max: this.height() };
var translation = d3.transform(selection.attr("transform")).translate;
var bbox = Plottable.Utils.DOM.elementBBox(selection);
var translatedBbox = {
x: bbox.x + translation[0],
y: bbox.y + translation[1],
width: bbox.width,
height: bbox.height
};
return Plottable.Utils.DOM.intersectsBBox(xRange, yRange, translatedBbox);
};
Scatter.prototype._entityVisibleOnPlot = function (pixelPoint, datum, index, dataset) {
var xRange = { min: 0, max: this.width() };
var yRange = { min: 0, max: this.height() };
var diameter = Plottable.Plot._scaledAccessor(this.size())(datum, index, dataset);
var translatedBbox = {
x: pixelPoint.x - diameter,
y: pixelPoint.y - diameter,
width: diameter,
height: diameter
};
return Plottable.Utils.DOM.intersectsBBox(xRange, yRange, translatedBbox);
};
Scatter.prototype._propertyProjectors = function () {
var propertyToProjectors = _super.prototype._propertyProjectors.call(this);
var xProjector = Plottable.Plot._scaledAccessor(this.x());
var yProjector = Plottable.Plot._scaledAccessor(this.y());
var sizeProjector = Plottable.Plot._scaledAccessor(this.size());
propertyToProjectors["transform"] = function (datum, index, dataset) {
return "translate(" + xProjector(datum, index, dataset) + "," + yProjector(datum, index, dataset) + ")";
};
var symbolProjector = Plottable.Plot._scaledAccessor(this.symbol());
propertyToProjectors["d"] = function (datum, index, dataset) {
return symbolProjector(datum, index, dataset)(sizeProjector(datum, index, dataset));
};
return propertyToProjectors;
};
Scatter._SIZE_KEY = "size";
Scatter._SYMBOL_KEY = "symbol";
return Scatter;
})(Plottable.XYPlot);
Plots.Scatter = Scatter;
})(Plots = Plottable.Plots || (Plottable.Plots = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Plots;
(function (Plots) {
var Bar = (function (_super) {
__extends(Bar, _super);
/**
* A Bar Plot draws bars growing out from a baseline to some value
*
* @constructor
* @param {string} [orientation="vertical"] One of "vertical"/"horizontal".
*/
function Bar(orientation) {
var _this = this;
if (orientation === void 0) { orientation = Bar.ORIENTATION_VERTICAL; }
_super.call(this);
this._labelFormatter = Plottable.Formatters.identity();
this._labelsEnabled = false;
this._hideBarsIfAnyAreTooWide = true;
this._barPixelWidth = 0;
this.addClass("bar-plot");
if (orientation !== Bar.ORIENTATION_VERTICAL && orientation !== Bar.ORIENTATION_HORIZONTAL) {
throw new Error(orientation + " is not a valid orientation for Plots.Bar");
}
this._isVertical = orientation === Bar.ORIENTATION_VERTICAL;
this.animator("baseline", new Plottable.Animators.Null());
this.attr("fill", new Plottable.Scales.Color().range()[0]);
this.attr("width", function () { return _this._barPixelWidth; });
this._labelConfig = new Plottable.Utils.Map();
this._baselineValueProvider = function () { return [_this.baselineValue()]; };
this._updateBarPixelWidthCallback = function () { return _this._updateBarPixelWidth(); };
}
Bar.prototype.x = function (x, xScale) {
if (x == null) {
return _super.prototype.x.call(this);
}
if (xScale == null) {
_super.prototype.x.call(this, x);
}
else {
_super.prototype.x.call(this, x, xScale);
xScale.onUpdate(this._updateBarPixelWidthCallback);
}
this._updateValueScale();
return this;
};
Bar.prototype.y = function (y, yScale) {
if (y == null) {
return _super.prototype.y.call(this);
}
if (yScale == null) {
_super.prototype.y.call(this, y);
}
else {
_super.prototype.y.call(this, y, yScale);
yScale.onUpdate(this._updateBarPixelWidthCallback);
}
this._updateValueScale();
return this;
};
/**
* Gets the orientation of the plot
*
* @return "vertical" | "horizontal"
*/
Bar.prototype.orientation = function () {
return this._isVertical ? Bar.ORIENTATION_VERTICAL : Bar.ORIENTATION_HORIZONTAL;
};
Bar.prototype.render = function () {
_super.prototype.render.call(this);
this._updateBarPixelWidth();
return this;
};
Bar.prototype._createDrawer = function (dataset) {
return new Plottable.Drawers.Rectangle(dataset);
};
Bar.prototype._setup = function () {
_super.prototype._setup.call(this);
this._baseline = this._renderArea.append("line").classed("baseline", true);
};
Bar.prototype.baselineValue = function (value) {
if (value == null) {
if (this._baselineValue != null) {
return this._baselineValue;
}
if (!this._projectorsReady()) {
return 0;
}
var valueScale = this._isVertical ? this.y().scale : this.x().scale;
if (!valueScale) {
return 0;
}
if (valueScale instanceof Plottable.Scales.Time) {
return new Date(0);
}
return 0;
}
this._baselineValue = value;
this._updateValueScale();
this.render();
return this;
};
Bar.prototype.addDataset = function (dataset) {
dataset.onUpdate(this._updateBarPixelWidthCallback);
_super.prototype.addDataset.call(this, dataset);
this._updateBarPixelWidth();
return this;
};
Bar.prototype.removeDataset = function (dataset) {
dataset.offUpdate(this._updateBarPixelWidthCallback);
_super.prototype.removeDataset.call(this, dataset);
this._updateBarPixelWidth();
return this;
};
Bar.prototype.labelsEnabled = function (enabled) {
if (enabled === undefined) {
return this._labelsEnabled;
}
else {
this._labelsEnabled = enabled;
this.render();
return this;
}
};
Bar.prototype.labelFormatter = function (formatter) {
if (formatter == null) {
return this._labelFormatter;
}
else {
this._labelFormatter = formatter;
this.render();
return this;
}
};
Bar.prototype._createNodesForDataset = function (dataset) {
var drawer = _super.prototype._createNodesForDataset.call(this, dataset);
drawer.renderArea().classed(Bar._BAR_AREA_CLASS, true);
var labelArea = this._renderArea.append("g").classed(Bar._LABEL_AREA_CLASS, true);
var measurer = new SVGTypewriter.Measurers.CacheCharacterMeasurer(labelArea);
var writer = new SVGTypewriter.Writers.Writer(measurer);
this._labelConfig.set(dataset, { labelArea: labelArea, measurer: measurer, writer: writer });
return drawer;
};
Bar.prototype._removeDatasetNodes = function (dataset) {
_super.prototype._removeDatasetNodes.call(this, dataset);
var labelConfig = this._labelConfig.get(dataset);
if (labelConfig != null) {
labelConfig.labelArea.remove();
this._labelConfig.delete(dataset);
}
};
/**
* Returns the PlotEntity nearest to the query point according to the following algorithm:
* - If the query point is inside a bar, returns the PlotEntity for that bar.
* - Otherwise, gets the nearest PlotEntity by the primary direction (X for vertical, Y for horizontal),
* breaking ties with the secondary direction.
* Returns undefined if no PlotEntity can be found.
*
* @param {Point} queryPoint
* @returns {PlotEntity} The nearest PlotEntity, or undefined if no PlotEntity can be found.
*/
Bar.prototype.entityNearest = function (queryPoint) {
var _this = this;
var minPrimaryDist = Infinity;
var minSecondaryDist = Infinity;
var queryPtPrimary = this._isVertical ? queryPoint.x : queryPoint.y;
var queryPtSecondary = this._isVertical ? queryPoint.y : queryPoint.x;
// SVGRects are positioned with sub-pixel accuracy (the default unit
// for the x, y, height & width attributes), but user selections (e.g. via
// mouse events) usually have pixel accuracy. We add a tolerance of 0.5 pixels.
var tolerance = 0.5;
var closest;
this.entities().forEach(function (entity) {
if (!_this._entityVisibleOnPlot(entity.position, entity.datum, entity.index, entity.dataset)) {
return;
}
var primaryDist = 0;
var secondaryDist = 0;
var plotPt = entity.position;
// if we're inside a bar, distance in both directions should stay 0
var barBBox = Plottable.Utils.DOM.elementBBox(entity.selection);
if (!Plottable.Utils.DOM.intersectsBBox(queryPoint.x, queryPoint.y, barBBox, tolerance)) {
var plotPtPrimary = _this._isVertical ? plotPt.x : plotPt.y;
primaryDist = Math.abs(queryPtPrimary - plotPtPrimary);
// compute this bar's min and max along the secondary axis
var barMinSecondary = _this._isVertical ? barBBox.y : barBBox.x;
var barMaxSecondary = barMinSecondary + (_this._isVertical ? barBBox.height : barBBox.width);
if (queryPtSecondary >= barMinSecondary - tolerance && queryPtSecondary <= barMaxSecondary + tolerance) {
// if we're within a bar's secondary axis span, it is closest in that direction
secondaryDist = 0;
}
else {
var plotPtSecondary = _this._isVertical ? plotPt.y : plotPt.x;
secondaryDist = Math.abs(queryPtSecondary - plotPtSecondary);
}
}
// if we find a closer bar, record its distance and start new closest lists
if (primaryDist < minPrimaryDist
|| primaryDist === minPrimaryDist && secondaryDist < minSecondaryDist) {
closest = entity;
minPrimaryDist = primaryDist;
minSecondaryDist = secondaryDist;
}
});
return closest;
};
Bar.prototype._visibleOnPlot = function (datum, pixelPoint, selection) {
Plottable.Utils.Window.deprecated("Bar._visibleOnPlot()", "v1.1.0");
var xRange = { min: 0, max: this.width() };
var yRange = { min: 0, max: this.height() };
var barBBox = Plottable.Utils.DOM.elementBBox(selection);
return Plottable.Utils.DOM.intersectsBBox(xRange, yRange, barBBox);
};
Bar.prototype._entityVisibleOnPlot = function (pixelPoint, datum, index, dataset) {
var xRange = { min: 0, max: this.width() };
var yRange = { min: 0, max: this.height() };
var attrToProjector = this._generateAttrToProjector();
var width = attrToProjector["width"](datum, index, dataset);
var height = attrToProjector["height"](datum, index, dataset);
var barBBox = {
x: pixelPoint.x - width / 2,
y: pixelPoint.y,
width: width,
height: height
};
return Plottable.Utils.DOM.intersectsBBox(xRange, yRange, barBBox);
};
/**
* Gets the Entities at a particular Point.
*
* @param {Point} p
* @returns {PlotEntity[]}
*/
Bar.prototype.entitiesAt = function (p) {
return this._entitiesIntersecting(p.x, p.y);
};
Bar.prototype.entitiesIn = function (xRangeOrBounds, yRange) {
var dataXRange;
var dataYRange;
if (yRange == null) {
var bounds = xRangeOrBounds;
dataXRange = { min: bounds.topLeft.x, max: bounds.bottomRight.x };
dataYRange = { min: bounds.topLeft.y, max: bounds.bottomRight.y };
}
else {
dataXRange = xRangeOrBounds;
dataYRange = yRange;
}
return this._entitiesIntersecting(dataXRange, dataYRange);
};
Bar.prototype._entitiesIntersecting = function (xValOrRange, yValOrRange) {
var intersected = [];
this.entities().forEach(function (entity) {
if (Plottable.Utils.DOM.intersectsBBox(xValOrRange, yValOrRange, Plottable.Utils.DOM.elementBBox(entity.selection))) {
intersected.push(entity);
}
});
return intersected;
};
Bar.prototype._updateValueScale = function () {
if (!this._projectorsReady()) {
return;
}
var valueScale = this._isVertical ? this.y().scale : this.x().scale;
if (valueScale instanceof Plottable.QuantitativeScale) {
var qscale = valueScale;
qscale.addPaddingExceptionsProvider(this._baselineValueProvider);
qscale.addIncludedValuesProvider(this._baselineValueProvider);
}
};
Bar.prototype._additionalPaint = function (time) {
var _this = this;
var primaryScale = this._isVertical ? this.y().scale : this.x().scale;
var scaledBaseline = primaryScale.scale(this.baselineValue());
var baselineAttr = {
"x1": this._isVertical ? 0 : scaledBaseline,
"y1": this._isVertical ? scaledBaseline : 0,
"x2": this._isVertical ? this.width() : scaledBaseline,
"y2": this._isVertical ? scaledBaseline : this.height()
};
this._getAnimator("baseline").animate(this._baseline, baselineAttr);
this.datasets().forEach(function (dataset) { return _this._labelConfig.get(dataset).labelArea.selectAll("g").remove(); });
if (this._labelsEnabled) {
Plottable.Utils.Window.setTimeout(function () { return _this._drawLabels(); }, time);
}
};
Bar.prototype._drawLabels = function () {
var _this = this;
var dataToDraw = this._getDataToDraw();
var labelsTooWide = false;
this.datasets().forEach(function (dataset) { return labelsTooWide = labelsTooWide || _this._drawLabel(dataToDraw.get(dataset), dataset); });
if (this._hideBarsIfAnyAreTooWide && labelsTooWide) {
this.datasets().forEach(function (dataset) { return _this._labelConfig.get(dataset).labelArea.selectAll("g").remove(); });
}
};
Bar.prototype._drawLabel = function (data, dataset) {
var _this = this;
var attrToProjector = this._generateAttrToProjector();
var labelConfig = this._labelConfig.get(dataset);
var labelArea = labelConfig.labelArea;
var measurer = labelConfig.measurer;
var writer = labelConfig.writer;
var labelTooWide = data.map(function (d, i) {
var primaryAccessor = _this._isVertical ? _this.y().accessor : _this.x().accessor;
var originalPositionFn = _this._isVertical ? Plottable.Plot._scaledAccessor(_this.y()) : Plottable.Plot._scaledAccessor(_this.x());
var primaryScale = _this._isVertical ? _this.y().scale : _this.x().scale;
var scaledBaseline = primaryScale.scale(_this.baselineValue());
var text = _this._labelFormatter(primaryAccessor(d, i, dataset)).toString();
var w = attrToProjector["width"](d, i, dataset);
var h = attrToProjector["height"](d, i, dataset);
var x = attrToProjector["x"](d, i, dataset);
var y = attrToProjector["y"](d, i, dataset);
var positive = originalPositionFn(d, i, dataset) <= scaledBaseline;
var measurement = measurer.measure(text);
var color = attrToProjector["fill"](d, i, dataset);
var dark = Plottable.Utils.Color.contrast("white", color) * 1.6 < Plottable.Utils.Color.contrast("black", color);
var primary = _this._isVertical ? h : w;
var primarySpace = _this._isVertical ? measurement.height : measurement.width;
var secondaryAttrTextSpace = _this._isVertical ? measurement.width : measurement.height;
var secondaryAttrAvailableSpace = _this._isVertical ? w : h;
var tooWide = secondaryAttrTextSpace + 2 * Bar._LABEL_HORIZONTAL_PADDING > secondaryAttrAvailableSpace;
if (measurement.height <= h && measurement.width <= w) {
var offset = Math.min((primary - primarySpace) / 2, Bar._LABEL_VERTICAL_PADDING);
if (!positive) {
offset = offset * -1;
}
if (_this._isVertical) {
y += offset;
}
else {
x += offset;
}
var showLabel = true;
var labelPosition = {
x: x,
y: positive ? y : y + h - measurement.height
};
if (_this._isVertical) {
labelPosition.x = x + w / 2 - measurement.width / 2;
}
else {
if (!positive) {
labelPosition.x = x + w - measurement.width;
}
else {
labelPosition.x = x;
}
}
if (labelPosition.x < 0 || labelPosition.x + measurement.width > _this.width() ||
labelPosition.y < 0 || labelPosition.y + measurement.height > _this.height()) {
showLabel = false;
}
var g = labelArea.append("g").attr("transform", "translate(" + x + "," + y + ")");
var className = dark ? "dark-label" : "light-label";
g.classed(className, true);
g.style("visibility", showLabel ? "inherit" : "hidden");
var xAlign;
var yAlign;
if (_this._isVertical) {
xAlign = "center";
yAlign = positive ? "top" : "bottom";
}
else {
xAlign = positive ? "left" : "right";
yAlign = "center";
}
var writeOptions = {
selection: g,
xAlign: xAlign,
yAlign: yAlign,
textRotation: 0
};
writer.write(text, w, h, writeOptions);
}
return tooWide;
});
return labelTooWide.some(function (d) { return d; });
};
Bar.prototype._generateDrawSteps = function () {
var drawSteps = [];
if (this._animateOnNextRender()) {
var resetAttrToProjector = this._generateAttrToProjector();
var primaryScale = this._isVertical ? this.y().scale : this.x().scale;
var scaledBaseline = primaryScale.scale(this.baselineValue());
var positionAttr = this._isVertical ? "y" : "x";
var dimensionAttr = this._isVertical ? "height" : "width";
resetAttrToProjector[positionAttr] = function () { return scaledBaseline; };
resetAttrToProjector[dimensionAttr] = function () { return 0; };
drawSteps.push({ attrToProjector: resetAttrToProjector, animator: this._getAnimator(Plots.Animator.RESET) });
}
drawSteps.push({ attrToProjector: this._generateAttrToProjector(), animator: this._getAnimator(Plots.Animator.MAIN) });
return drawSteps;
};
Bar.prototype._generateAttrToProjector = function () {
// Primary scale/direction: the "length" of the bars
// Secondary scale/direction: the "width" of the bars
var attrToProjector = _super.prototype._generateAttrToProjector.call(this);
var primaryScale = this._isVertical ? this.y().scale : this.x().scale;
var primaryAttr = this._isVertical ? "y" : "x";
var secondaryAttr = this._isVertical ? "x" : "y";
var scaledBaseline = primaryScale.scale(this.baselineValue());
var positionF = this._isVertical ? Plottable.Plot._scaledAccessor(this.x()) : Plottable.Plot._scaledAccessor(this.y());
var widthF = attrToProjector["width"];
var originalPositionFn = this._isVertical ? Plottable.Plot._scaledAccessor(this.y()) : Plottable.Plot._scaledAccessor(this.x());
var heightF = function (d, i, dataset) {
return Math.abs(scaledBaseline - originalPositionFn(d, i, dataset));
};
attrToProjector["width"] = this._isVertical ? widthF : heightF;
attrToProjector["height"] = this._isVertical ? heightF : widthF;
attrToProjector[secondaryAttr] = function (d, i, dataset) {
return positionF(d, i, dataset) - widthF(d, i, dataset) / 2;
};
attrToProjector[primaryAttr] = function (d, i, dataset) {
var originalPos = originalPositionFn(d, i, dataset);
// If it is past the baseline, it should start at the baselin then width/height
// carries it over. If it's not past the baseline, leave it at original position and
// then width/height carries it to baseline
return (originalPos > scaledBaseline) ? scaledBaseline : originalPos;
};
return attrToProjector;
};
/**
* Computes the barPixelWidth of all the bars in the plot.
*
* If the position scale of the plot is a CategoryScale and in bands mode, then the rangeBands function will be used.
* If the position scale of the plot is a CategoryScale and in points mode, then
* from https://github.com/mbostock/d3/wiki/Ordinal-Scales#ordinal_rangePoints, the max barPixelWidth is step * padding
* If the position scale of the plot is a QuantitativeScale, then _getMinimumDataWidth is scaled to compute the barPixelWidth
*/
Bar.prototype._getBarPixelWidth = function () {
if (!this._projectorsReady()) {
return 0;
}
var barPixelWidth;
var barScale = this._isVertical ? this.x().scale : this.y().scale;
if (barScale instanceof Plottable.Scales.Category) {
barPixelWidth = barScale.rangeBand();
}
else {
var barAccessor = this._isVertical ? this.x().accessor : this.y().accessor;
var numberBarAccessorData = d3.set(Plottable.Utils.Array.flatten(this.datasets().map(function (dataset) {
return dataset.data().map(function (d, i) { return barAccessor(d, i, dataset); })
.filter(function (d) { return d != null; })
.map(function (d) { return d.valueOf(); });
}))).values().map(function (value) { return +value; });
numberBarAccessorData.sort(function (a, b) { return a - b; });
var scaledData = numberBarAccessorData.map(function (datum) { return barScale.scale(datum); });
var barAccessorDataPairs = d3.pairs(scaledData);
var barWidthDimension = this._isVertical ? this.width() : this.height();
barPixelWidth = Plottable.Utils.Math.min(barAccessorDataPairs, function (pair, i) {
return Math.abs(pair[1] - pair[0]);
}, barWidthDimension * Bar._SINGLE_BAR_DIMENSION_RATIO);
var minScaledDatum = Plottable.Utils.Math.min(scaledData, 0);
if (minScaledDatum > 0) {
barPixelWidth = Math.min(barPixelWidth, minScaledDatum * 2);
}
var maxScaledDatum = Plottable.Utils.Math.max(scaledData, 0);
if (maxScaledDatum < barWidthDimension) {
var margin = barWidthDimension - maxScaledDatum;
barPixelWidth = Math.min(barPixelWidth, margin * 2);
}
barPixelWidth *= Bar._BAR_WIDTH_RATIO;
}
return barPixelWidth;
};
Bar.prototype._updateBarPixelWidth = function () {
this._barPixelWidth = this._getBarPixelWidth();
};
Bar.prototype.entities = function (datasets) {
var _this = this;
if (datasets === void 0) { datasets = this.datasets(); }
if (!this._projectorsReady()) {
return [];
}
var entities = _super.prototype.entities.call(this, datasets);
var scaledBaseline = (this._isVertical ? this.y().scale : this.x().scale).scale(this.baselineValue());
entities.forEach(function (entity) {
var bar = entity.selection;
// Using floored pixel values to account for pixel accuracy inconsistencies across browsers
if (_this._isVertical && Math.floor(+bar.attr("y")) >= Math.floor(scaledBaseline)) {
entity.position.y += +bar.attr("height");
}
else if (!_this._isVertical && Math.floor(+bar.attr("x")) < Math.floor(scaledBaseline)) {
entity.position.x -= +bar.attr("width");
}
if (_this._isVertical) {
entity.position.x = +bar.attr("x") + +bar.attr("width") / 2;
}
else {
entity.position.y = +bar.attr("y") + +bar.attr("height") / 2;
}
});
return entities;
};
Bar.prototype._pixelPoint = function (datum, index, dataset) {
var attrToProjector = this._generateAttrToProjector();
var rectX = attrToProjector["x"](datum, index, dataset);
var rectY = attrToProjector["y"](datum, index, dataset);
var rectWidth = attrToProjector["width"](datum, index, dataset);
var rectHeight = attrToProjector["height"](datum, index, dataset);
var x = this._isVertical ? rectX + rectWidth / 2 : rectX + rectWidth;
var y = this._isVertical ? rectY : rectY + rectHeight / 2;
return { x: x, y: y };
};
Bar.prototype._uninstallScaleForKey = function (scale, key) {
scale.offUpdate(this._updateBarPixelWidthCallback);
_super.prototype._uninstallScaleForKey.call(this, scale, key);
};
Bar.prototype._getDataToDraw = function () {
var dataToDraw = new Plottable.Utils.Map();
var attrToProjector = this._generateAttrToProjector();
this.datasets().forEach(function (dataset) {
var data = dataset.data().filter(function (d, i) { return Plottable.Utils.Math.isValidNumber(attrToProjector["x"](d, i, dataset)) &&
Plottable.Utils.Math.isValidNumber(attrToProjector["y"](d, i, dataset)) &&
Plottable.Utils.Math.isValidNumber(attrToProjector["width"](d, i, dataset)) &&
Plottable.Utils.Math.isValidNumber(attrToProjector["height"](d, i, dataset)); });
dataToDraw.set(dataset, data);
});
return dataToDraw;
};
Bar.ORIENTATION_VERTICAL = "vertical";
Bar.ORIENTATION_HORIZONTAL = "horizontal";
Bar._BAR_WIDTH_RATIO = 0.95;
Bar._SINGLE_BAR_DIMENSION_RATIO = 0.4;
Bar._BAR_AREA_CLASS = "bar-area";
Bar._LABEL_AREA_CLASS = "bar-label-text-area";
Bar._LABEL_VERTICAL_PADDING = 5;
Bar._LABEL_HORIZONTAL_PADDING = 5;
return Bar;
})(Plottable.XYPlot);
Plots.Bar = Bar;
})(Plots = Plottable.Plots || (Plottable.Plots = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Plots;
(function (Plots) {
var Line = (function (_super) {
__extends(Line, _super);
/**
* A Line Plot draws line segments starting from the first data point to the next.
*
* @constructor
*/
function Line() {
_super.call(this);
this.addClass("line-plot");
var animator = new Plottable.Animators.Easing();
animator.stepDuration(Plottable.Plot._ANIMATION_MAX_DURATION);
animator.easingMode("exp-in-out");
animator.maxTotalDuration(Plottable.Plot._ANIMATION_MAX_DURATION);
this.animator(Plots.Animator.MAIN, animator);
this.attr("stroke", new Plottable.Scales.Color().range()[0]);
this.attr("stroke-width", "2px");
}
Line.prototype._createDrawer = function (dataset) {
return new Plottable.Drawers.Line(dataset);
};
Line.prototype._getResetYFunction = function () {
// gets the y-value generator for the animation start point
var yDomain = this.y().scale.domain();
var domainMax = Math.max(yDomain[0], yDomain[1]);
var domainMin = Math.min(yDomain[0], yDomain[1]);
// start from zero, or the closest domain value to zero
// avoids lines zooming on from offscreen.
var startValue = (domainMax < 0 && domainMax) || (domainMin > 0 && domainMin) || 0;
var scaledStartValue = this.y().scale.scale(startValue);
return function (d, i, dataset) { return scaledStartValue; };
};
Line.prototype._generateDrawSteps = function () {
var drawSteps = [];
if (this._animateOnNextRender()) {
var attrToProjector = this._generateAttrToProjector();
attrToProjector["d"] = this._constructLineProjector(Plottable.Plot._scaledAccessor(this.x()), this._getResetYFunction());
drawSteps.push({ attrToProjector: attrToProjector, animator: this._getAnimator(Plots.Animator.RESET) });
}
drawSteps.push({ attrToProjector: this._generateAttrToProjector(), animator: this._getAnimator(Plots.Animator.MAIN) });
return drawSteps;
};
Line.prototype._generateAttrToProjector = function () {
var attrToProjector = _super.prototype._generateAttrToProjector.call(this);
Object.keys(attrToProjector).forEach(function (attribute) {
if (attribute === "d") {
return;
}
var projector = attrToProjector[attribute];
attrToProjector[attribute] = function (data, i, dataset) {
return data.length > 0 ? projector(data[0], i, dataset) : null;
};
});
return attrToProjector;
};
/**
* Returns the PlotEntity nearest to the query point by X then by Y, or undefined if no PlotEntity can be found.
*
* @param {Point} queryPoint
* @returns {PlotEntity} The nearest PlotEntity, or undefined if no PlotEntity can be found.
*/
Line.prototype.entityNearest = function (queryPoint) {
var _this = this;
var minXDist = Infinity;
var minYDist = Infinity;
var closest;
this.entities().forEach(function (entity) {
if (!_this._entityVisibleOnPlot(entity.position, entity.datum, entity.index, entity.dataset)) {
return;
}
var xDist = Math.abs(queryPoint.x - entity.position.x);
var yDist = Math.abs(queryPoint.y - entity.position.y);
if (xDist < minXDist || xDist === minXDist && yDist < minYDist) {
closest = entity;
minXDist = xDist;
minYDist = yDist;
}
});
return closest;
};
Line.prototype._propertyProjectors = function () {
var propertyToProjectors = _super.prototype._propertyProjectors.call(this);
propertyToProjectors["d"] = this._constructLineProjector(Plottable.Plot._scaledAccessor(this.x()), Plottable.Plot._scaledAccessor(this.y()));
return propertyToProjectors;
};
Line.prototype._constructLineProjector = function (xProjector, yProjector) {
var _this = this;
var definedProjector = function (d, i, dataset) {
var positionX = Plottable.Plot._scaledAccessor(_this.x())(d, i, dataset);
var positionY = Plottable.Plot._scaledAccessor(_this.y())(d, i, dataset);
return positionX != null && !Plottable.Utils.Math.isNaN(positionX) &&
positionY != null && !Plottable.Utils.Math.isNaN(positionY);
};
return function (datum, index, dataset) {
return d3.svg.line()
.x(function (innerDatum, innerIndex) { return xProjector(innerDatum, innerIndex, dataset); })
.y(function (innerDatum, innerIndex) { return yProjector(innerDatum, innerIndex, dataset); })
.defined(function (innerDatum, innerIndex) { return definedProjector(innerDatum, innerIndex, dataset); })(datum);
};
};
Line.prototype._getDataToDraw = function () {
var dataToDraw = new Plottable.Utils.Map();
this.datasets().forEach(function (dataset) { return dataToDraw.set(dataset, [dataset.data()]); });
return dataToDraw;
};
return Line;
})(Plottable.XYPlot);
Plots.Line = Line;
})(Plots = Plottable.Plots || (Plottable.Plots = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Plots;
(function (Plots) {
var Area = (function (_super) {
__extends(Area, _super);
/**
* An Area Plot draws a filled region (area) between Y and Y0.
*
* @constructor
*/
function Area() {
_super.call(this);
this.addClass("area-plot");
this.y0(0); // default
this.attr("fill-opacity", 0.25);
this.attr("fill", new Plottable.Scales.Color().range()[0]);
this._lineDrawers = new Plottable.Utils.Map();
}
Area.prototype._setup = function () {
var _this = this;
_super.prototype._setup.call(this);
this._lineDrawers.forEach(function (d) { return d.renderArea(_this._renderArea.append("g")); });
};
Area.prototype.y = function (y, yScale) {
if (y == null) {
return _super.prototype.y.call(this);
}
if (yScale == null) {
_super.prototype.y.call(this, y);
}
else {
_super.prototype.y.call(this, y, yScale);
}
if (yScale != null) {
var y0 = this.y0().accessor;
if (y0 != null) {
this._bindProperty(Area._Y0_KEY, y0, yScale);
}
this._updateYScale();
}
return this;
};
Area.prototype.y0 = function (y0) {
if (y0 == null) {
return this._propertyBindings.get(Area._Y0_KEY);
}
var yBinding = this.y();
var yScale = yBinding && yBinding.scale;
this._bindProperty(Area._Y0_KEY, y0, yScale);
this._updateYScale();
this.render();
return this;
};
Area.prototype._onDatasetUpdate = function () {
_super.prototype._onDatasetUpdate.call(this);
this._updateYScale();
};
Area.prototype.addDataset = function (dataset) {
var lineDrawer = new Plottable.Drawers.Line(dataset);
if (this._isSetup) {
lineDrawer.renderArea(this._renderArea.append("g"));
}
this._lineDrawers.set(dataset, lineDrawer);
_super.prototype.addDataset.call(this, dataset);
return this;
};
Area.prototype._removeDatasetNodes = function (dataset) {
_super.prototype._removeDatasetNodes.call(this, dataset);
this._lineDrawers.get(dataset).remove();
};
Area.prototype._additionalPaint = function () {
var _this = this;
var drawSteps = this._generateLineDrawSteps();
var dataToDraw = this._getDataToDraw();
this.datasets().forEach(function (dataset) { return _this._lineDrawers.get(dataset).draw(dataToDraw.get(dataset), drawSteps); });
};
Area.prototype._generateLineDrawSteps = function () {
var drawSteps = [];
if (this._animateOnNextRender()) {
var attrToProjector = this._generateLineAttrToProjector();
attrToProjector["d"] = this._constructLineProjector(Plottable.Plot._scaledAccessor(this.x()), this._getResetYFunction());
drawSteps.push({ attrToProjector: attrToProjector, animator: this._getAnimator(Plots.Animator.RESET) });
}
drawSteps.push({ attrToProjector: this._generateLineAttrToProjector(), animator: this._getAnimator(Plots.Animator.MAIN) });
return drawSteps;
};
Area.prototype._generateLineAttrToProjector = function () {
var lineAttrToProjector = this._generateAttrToProjector();
lineAttrToProjector["d"] = this._constructLineProjector(Plottable.Plot._scaledAccessor(this.x()), Plottable.Plot._scaledAccessor(this.y()));
return lineAttrToProjector;
};
Area.prototype._createDrawer = function (dataset) {
return new Plottable.Drawers.Area(dataset);
};
Area.prototype._generateDrawSteps = function () {
var drawSteps = [];
if (this._animateOnNextRender()) {
var attrToProjector = this._generateAttrToProjector();
attrToProjector["d"] = this._constructAreaProjector(Plottable.Plot._scaledAccessor(this.x()), this._getResetYFunction(), Plottable.Plot._scaledAccessor(this.y0()));
drawSteps.push({ attrToProjector: attrToProjector, animator: this._getAnimator(Plots.Animator.RESET) });
}
drawSteps.push({ attrToProjector: this._generateAttrToProjector(), animator: this._getAnimator(Plots.Animator.MAIN) });
return drawSteps;
};
Area.prototype._updateYScale = function () {
var extents = this._propertyExtents.get("y0");
var extent = Plottable.Utils.Array.flatten(extents);
var uniqExtentVals = Plottable.Utils.Array.uniq(extent);
var constantBaseline = uniqExtentVals.length === 1 ? uniqExtentVals[0] : null;
var yBinding = this.y();
var yScale = (yBinding && yBinding.scale);
if (yScale == null) {
return;
}
if (this._constantBaselineValueProvider != null) {
yScale.removePaddingExceptionsProvider(this._constantBaselineValueProvider);
this._constantBaselineValueProvider = null;
}
if (constantBaseline != null) {
this._constantBaselineValueProvider = function () { return [constantBaseline]; };
yScale.addPaddingExceptionsProvider(this._constantBaselineValueProvider);
}
};
Area.prototype._getResetYFunction = function () {
return Plottable.Plot._scaledAccessor(this.y0());
};
Area.prototype._propertyProjectors = function () {
var propertyToProjectors = _super.prototype._propertyProjectors.call(this);
propertyToProjectors["d"] = this._constructAreaProjector(Plottable.Plot._scaledAccessor(this.x()), Plottable.Plot._scaledAccessor(this.y()), Plottable.Plot._scaledAccessor(this.y0()));
return propertyToProjectors;
};
Area.prototype.selections = function (datasets) {
var _this = this;
if (datasets === void 0) { datasets = this.datasets(); }
var allSelections = _super.prototype.selections.call(this, datasets)[0];
var lineDrawers = datasets.map(function (dataset) { return _this._lineDrawers.get(dataset); })
.filter(function (drawer) { return drawer != null; });
lineDrawers.forEach(function (ld, i) { return allSelections.push(ld.selectionForIndex(i).node()); });
return d3.selectAll(allSelections);
};
Area.prototype._constructAreaProjector = function (xProjector, yProjector, y0Projector) {
var _this = this;
var definedProjector = function (d, i, dataset) {
var positionX = Plottable.Plot._scaledAccessor(_this.x())(d, i, dataset);
var positionY = Plottable.Plot._scaledAccessor(_this.y())(d, i, dataset);
return Plottable.Utils.Math.isValidNumber(positionX) && Plottable.Utils.Math.isValidNumber(positionY);
};
return function (datum, index, dataset) {
var areaGenerator = d3.svg.area()
.x(function (innerDatum, innerIndex) { return xProjector(innerDatum, innerIndex, dataset); })
.y1(function (innerDatum, innerIndex) { return yProjector(innerDatum, innerIndex, dataset); })
.y0(function (innerDatum, innerIndex) { return y0Projector(innerDatum, innerIndex, dataset); })
.defined(function (innerDatum, innerIndex) { return definedProjector(innerDatum, innerIndex, dataset); });
return areaGenerator(datum);
};
};
Area._Y0_KEY = "y0";
return Area;
})(Plots.Line);
Plots.Area = Area;
})(Plots = Plottable.Plots || (Plottable.Plots = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Plots;
(function (Plots) {
var ClusteredBar = (function (_super) {
__extends(ClusteredBar, _super);
/**
* A ClusteredBar Plot groups bars across Datasets based on the primary value of the bars.
* On a vertical ClusteredBar Plot, the bars with the same X value are grouped.
* On a horizontal ClusteredBar Plot, the bars with the same Y value are grouped.
*
* @constructor
* @param {string} [orientation="vertical"] One of "vertical"/"horizontal".
*/
function ClusteredBar(orientation) {
if (orientation === void 0) { orientation = Plots.Bar.ORIENTATION_VERTICAL; }
_super.call(this, orientation);
this._clusterOffsets = new Plottable.Utils.Map();
}
ClusteredBar.prototype._generateAttrToProjector = function () {
var _this = this;
var attrToProjector = _super.prototype._generateAttrToProjector.call(this);
// the width is constant, so set the inner scale range to that
var innerScale = this._makeInnerScale();
var innerWidthF = function (d, i) { return innerScale.rangeBand(); };
attrToProjector["width"] = this._isVertical ? innerWidthF : attrToProjector["width"];
attrToProjector["height"] = !this._isVertical ? innerWidthF : attrToProjector["height"];
var xAttr = attrToProjector["x"];
var yAttr = attrToProjector["y"];
attrToProjector["x"] = this._isVertical ?
function (d, i, ds) { return xAttr(d, i, ds) + _this._clusterOffsets.get(ds); } :
function (d, i, ds) { return xAttr(d, i, ds); };
attrToProjector["y"] = this._isVertical ?
function (d, i, ds) { return yAttr(d, i, ds); } :
function (d, i, ds) { return yAttr(d, i, ds) + _this._clusterOffsets.get(ds); };
return attrToProjector;
};
ClusteredBar.prototype._updateClusterPosition = function () {
var _this = this;
var innerScale = this._makeInnerScale();
this.datasets().forEach(function (d, i) { return _this._clusterOffsets.set(d, innerScale.scale(String(i)) - innerScale.rangeBand() / 2); });
};
ClusteredBar.prototype._makeInnerScale = function () {
var innerScale = new Plottable.Scales.Category();
innerScale.domain(this.datasets().map(function (d, i) { return String(i); }));
var widthProjector = Plottable.Plot._scaledAccessor(this.attr("width"));
innerScale.range([0, widthProjector(null, 0, null)]);
return innerScale;
};
ClusteredBar.prototype._getDataToDraw = function () {
this._updateClusterPosition();
return _super.prototype._getDataToDraw.call(this);
};
return ClusteredBar;
})(Plots.Bar);
Plots.ClusteredBar = ClusteredBar;
})(Plots = Plottable.Plots || (Plottable.Plots = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Plots;
(function (Plots) {
var StackedArea = (function (_super) {
__extends(StackedArea, _super);
/**
* @constructor
*/
function StackedArea() {
var _this = this;
_super.call(this);
this._baselineValue = 0;
this.addClass("stacked-area-plot");
this.attr("fill-opacity", 1);
this._stackingResult = new Plottable.Utils.Map();
this._stackedExtent = [];
this._baselineValueProvider = function () { return [_this._baselineValue]; };
}
StackedArea.prototype._getAnimator = function (key) {
return new Plottable.Animators.Null();
};
StackedArea.prototype._setup = function () {
_super.prototype._setup.call(this);
this._baseline = this._renderArea.append("line").classed("baseline", true);
};
StackedArea.prototype.x = function (x, xScale) {
if (x == null) {
return _super.prototype.x.call(this);
}
if (xScale == null) {
_super.prototype.x.call(this, x);
}
else {
_super.prototype.x.call(this, x, xScale);
}
this._updateStackExtentsAndOffsets();
return this;
};
StackedArea.prototype.y = function (y, yScale) {
if (y == null) {
return _super.prototype.y.call(this);
}
if (yScale == null) {
_super.prototype.y.call(this, y);
}
else {
_super.prototype.y.call(this, y, yScale);
}
this._updateStackExtentsAndOffsets();
return this;
};
StackedArea.prototype._additionalPaint = function () {
var scaledBaseline = this.y().scale.scale(this._baselineValue);
var baselineAttr = {
"x1": 0,
"y1": scaledBaseline,
"x2": this.width(),
"y2": scaledBaseline
};
this._getAnimator("baseline").animate(this._baseline, baselineAttr);
};
StackedArea.prototype._updateYScale = function () {
var yBinding = this.y();
var scale = (yBinding && yBinding.scale);
if (scale == null) {
return;
}
scale.addPaddingExceptionsProvider(this._baselineValueProvider);
scale.addIncludedValuesProvider(this._baselineValueProvider);
};
StackedArea.prototype._onDatasetUpdate = function () {
this._updateStackExtentsAndOffsets();
_super.prototype._onDatasetUpdate.call(this);
return this;
};
StackedArea.prototype._updateExtentsForProperty = function (property) {
_super.prototype._updateExtentsForProperty.call(this, property);
if ((property === "x" || property === "y") && this._projectorsReady()) {
this._updateStackExtentsAndOffsets();
}
};
StackedArea.prototype._extentsForProperty = function (attr) {
var primaryAttr = "y";
if (attr === primaryAttr) {
return [this._stackedExtent];
}
else {
return _super.prototype._extentsForProperty.call(this, attr);
}
};
StackedArea.prototype._updateStackExtentsAndOffsets = function () {
if (!this._projectorsReady()) {
return;
}
var datasets = this.datasets();
var keyAccessor = this.x().accessor;
var valueAccessor = this.y().accessor;
var filter = this._filterForProperty("y");
this._checkSameDomain(datasets, keyAccessor);
this._stackingResult = Plottable.Utils.Stacking.stack(datasets, keyAccessor, valueAccessor);
this._stackedExtent = Plottable.Utils.Stacking.stackedExtent(this._stackingResult, keyAccessor, filter);
};
StackedArea.prototype._checkSameDomain = function (datasets, keyAccessor) {
var keySets = datasets.map(function (dataset) {
return d3.set(dataset.data().map(function (datum, i) { return keyAccessor(datum, i, dataset).toString(); })).values();
});
var domainKeys = StackedArea._domainKeys(datasets, keyAccessor);
if (keySets.some(function (keySet) { return keySet.length !== domainKeys.length; })) {
Plottable.Utils.Window.warn("the domains across the datasets are not the same. Plot may produce unintended behavior.");
}
};
/**
* Given an array of Datasets and the accessor function for the key, computes the
* set reunion (no duplicates) of the domain of each Dataset. The keys are stringified
* before being returned.
*
* @param {Dataset[]} datasets The Datasets for which we extract the domain keys
* @param {Accessor<any>} keyAccessor The accessor for the key of the data
* @return {string[]} An array of stringified keys
*/
StackedArea._domainKeys = function (datasets, keyAccessor) {
var domainKeys = d3.set();
datasets.forEach(function (dataset) {
dataset.data().forEach(function (datum, index) {
domainKeys.add(keyAccessor(datum, index, dataset));
});
});
return domainKeys.values();
};
StackedArea.prototype._propertyProjectors = function () {
var _this = this;
var propertyToProjectors = _super.prototype._propertyProjectors.call(this);
var yAccessor = this.y().accessor;
var xAccessor = this.x().accessor;
var normalizedXAccessor = function (datum, index, dataset) {
return Plottable.Utils.Stacking.normalizeKey(xAccessor(datum, index, dataset));
};
var stackYProjector = function (d, i, dataset) {
return _this.y().scale.scale(+yAccessor(d, i, dataset) + _this._stackingResult.get(dataset).get(normalizedXAccessor(d, i, dataset)).offset);
};
var stackY0Projector = function (d, i, dataset) {
return _this.y().scale.scale(_this._stackingResult.get(dataset).get(normalizedXAccessor(d, i, dataset)).offset);
};
propertyToProjectors["d"] = this._constructAreaProjector(Plottable.Plot._scaledAccessor(this.x()), stackYProjector, stackY0Projector);
return propertyToProjectors;
};
StackedArea.prototype._pixelPoint = function (datum, index, dataset) {
var pixelPoint = _super.prototype._pixelPoint.call(this, datum, index, dataset);
var xValue = this.x().accessor(datum, index, dataset);
var yValue = this.y().accessor(datum, index, dataset);
var scaledYValue = this.y().scale.scale(+yValue + this._stackingResult.get(dataset).get(Plottable.Utils.Stacking.normalizeKey(xValue)).offset);
return { x: pixelPoint.x, y: scaledYValue };
};
return StackedArea;
})(Plots.Area);
Plots.StackedArea = StackedArea;
})(Plots = Plottable.Plots || (Plottable.Plots = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Plots;
(function (Plots) {
var StackedBar = (function (_super) {
__extends(StackedBar, _super);
/**
* A StackedBar Plot stacks bars across Datasets based on the primary value of the bars.
* On a vertical StackedBar Plot, the bars with the same X value are stacked.
* On a horizontal StackedBar Plot, the bars with the same Y value are stacked.
*
* @constructor
* @param {Scale} xScale
* @param {Scale} yScale
* @param {string} [orientation="vertical"] One of "vertical"/"horizontal".
*/
function StackedBar(orientation) {
if (orientation === void 0) { orientation = Plots.Bar.ORIENTATION_VERTICAL; }
_super.call(this, orientation);
this.addClass("stacked-bar-plot");
this._stackingResult = new Plottable.Utils.Map();
this._stackedExtent = [];
}
StackedBar.prototype.x = function (x, xScale) {
if (x == null) {
return _super.prototype.x.call(this);
}
if (xScale == null) {
_super.prototype.x.call(this, x);
}
else {
_super.prototype.x.call(this, x, xScale);
}
this._updateStackExtentsAndOffsets();
return this;
};
StackedBar.prototype.y = function (y, yScale) {
if (y == null) {
return _super.prototype.y.call(this);
}
if (yScale == null) {
_super.prototype.y.call(this, y);
}
else {
_super.prototype.y.call(this, y, yScale);
}
this._updateStackExtentsAndOffsets();
return this;
};
StackedBar.prototype._generateAttrToProjector = function () {
var _this = this;
var attrToProjector = _super.prototype._generateAttrToProjector.call(this);
var valueAttr = this._isVertical ? "y" : "x";
var keyAttr = this._isVertical ? "x" : "y";
var primaryScale = this._isVertical ? this.y().scale : this.x().scale;
var primaryAccessor = this._propertyBindings.get(valueAttr).accessor;
var keyAccessor = this._propertyBindings.get(keyAttr).accessor;
var normalizedKeyAccessor = function (datum, index, dataset) {
return Plottable.Utils.Stacking.normalizeKey(keyAccessor(datum, index, dataset));
};
var getStart = function (d, i, dataset) {
return primaryScale.scale(_this._stackingResult.get(dataset).get(normalizedKeyAccessor(d, i, dataset)).offset);
};
var getEnd = function (d, i, dataset) {
return primaryScale.scale(+primaryAccessor(d, i, dataset) +
_this._stackingResult.get(dataset).get(normalizedKeyAccessor(d, i, dataset)).offset);
};
var heightF = function (d, i, dataset) {
return Math.abs(getEnd(d, i, dataset) - getStart(d, i, dataset));
};
attrToProjector[this._isVertical ? "height" : "width"] = heightF;
var attrFunction = function (d, i, dataset) {
return +primaryAccessor(d, i, dataset) < 0 ? getStart(d, i, dataset) : getEnd(d, i, dataset);
};
attrToProjector[valueAttr] = function (d, i, dataset) {
return _this._isVertical ? attrFunction(d, i, dataset) : attrFunction(d, i, dataset) - heightF(d, i, dataset);
};
return attrToProjector;
};
StackedBar.prototype._onDatasetUpdate = function () {
this._updateStackExtentsAndOffsets();
_super.prototype._onDatasetUpdate.call(this);
return this;
};
StackedBar.prototype._updateExtentsForProperty = function (property) {
_super.prototype._updateExtentsForProperty.call(this, property);
if ((property === "x" || property === "y") && this._projectorsReady()) {
this._updateStackExtentsAndOffsets();
}
};
StackedBar.prototype._extentsForProperty = function (attr) {
var primaryAttr = this._isVertical ? "y" : "x";
if (attr === primaryAttr) {
return [this._stackedExtent];
}
else {
return _super.prototype._extentsForProperty.call(this, attr);
}
};
StackedBar.prototype._updateStackExtentsAndOffsets = function () {
if (!this._projectorsReady()) {
return;
}
var datasets = this.datasets();
var keyAccessor = this._isVertical ? this.x().accessor : this.y().accessor;
var valueAccessor = this._isVertical ? this.y().accessor : this.x().accessor;
var filter = this._filterForProperty(this._isVertical ? "y" : "x");
this._stackingResult = Plottable.Utils.Stacking.stack(datasets, keyAccessor, valueAccessor);
this._stackedExtent = Plottable.Utils.Stacking.stackedExtent(this._stackingResult, keyAccessor, filter);
};
return StackedBar;
})(Plots.Bar);
Plots.StackedBar = StackedBar;
})(Plots = Plottable.Plots || (Plottable.Plots = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Plots;
(function (Plots) {
var Segment = (function (_super) {
__extends(Segment, _super);
/**
* A Segment Plot displays line segments based on the data.
*
* @constructor
*/
function Segment() {
_super.call(this);
this.addClass("segment-plot");
this.attr("stroke", new Plottable.Scales.Color().range()[0]);
this.attr("stroke-width", "2px");
}
Segment.prototype._createDrawer = function (dataset) {
return new Plottable.Drawers.Segment(dataset);
};
Segment.prototype._generateDrawSteps = function () {
return [{ attrToProjector: this._generateAttrToProjector(), animator: new Plottable.Animators.Null() }];
};
Segment.prototype._updateExtentsForProperty = function (property) {
_super.prototype._updateExtentsForProperty.call(this, property);
if (property === "x") {
_super.prototype._updateExtentsForProperty.call(this, "x2");
}
else if (property === "y") {
_super.prototype._updateExtentsForProperty.call(this, "y2");
}
};
Segment.prototype._filterForProperty = function (property) {
if (property === "x2") {
return _super.prototype._filterForProperty.call(this, "x");
}
else if (property === "y2") {
return _super.prototype._filterForProperty.call(this, "y");
}
return _super.prototype._filterForProperty.call(this, property);
};
Segment.prototype.x = function (x, xScale) {
if (x == null) {
return _super.prototype.x.call(this);
}
if (xScale == null) {
_super.prototype.x.call(this, x);
}
else {
_super.prototype.x.call(this, x, xScale);
var x2Binding = this.x2();
var x2 = x2Binding && x2Binding.accessor;
if (x2 != null) {
this._bindProperty(Segment._X2_KEY, x2, xScale);
}
}
return this;
};
Segment.prototype.x2 = function (x2) {
if (x2 == null) {
return this._propertyBindings.get(Segment._X2_KEY);
}
var xBinding = this.x();
var xScale = xBinding && xBinding.scale;
this._bindProperty(Segment._X2_KEY, x2, xScale);
this.render();
return this;
};
Segment.prototype.y = function (y, yScale) {
if (y == null) {
return _super.prototype.y.call(this);
}
if (yScale == null) {
_super.prototype.y.call(this, y);
}
else {
_super.prototype.y.call(this, y, yScale);
var y2Binding = this.y2();
var y2 = y2Binding && y2Binding.accessor;
if (y2 != null) {
this._bindProperty(Segment._Y2_KEY, y2, yScale);
}
}
return this;
};
Segment.prototype.y2 = function (y2) {
if (y2 == null) {
return this._propertyBindings.get(Segment._Y2_KEY);
}
var yBinding = this.y();
var yScale = yBinding && yBinding.scale;
this._bindProperty(Segment._Y2_KEY, y2, yScale);
this.render();
return this;
};
Segment.prototype._propertyProjectors = function () {
var attrToProjector = _super.prototype._propertyProjectors.call(this);
attrToProjector["x1"] = Plottable.Plot._scaledAccessor(this.x());
attrToProjector["x2"] = this.x2() == null ? Plottable.Plot._scaledAccessor(this.x()) : Plottable.Plot._scaledAccessor(this.x2());
attrToProjector["y1"] = Plottable.Plot._scaledAccessor(this.y());
attrToProjector["y2"] = this.y2() == null ? Plottable.Plot._scaledAccessor(this.y()) : Plottable.Plot._scaledAccessor(this.y2());
return attrToProjector;
};
Segment._X2_KEY = "x2";
Segment._Y2_KEY = "y2";
return Segment;
})(Plottable.XYPlot);
Plots.Segment = Segment;
})(Plots = Plottable.Plots || (Plottable.Plots = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Plots;
(function (Plots) {
var Waterfall = (function (_super) {
__extends(Waterfall, _super);
function Waterfall() {
_super.call(this);
this._connectorsEnabled = false;
this.addClass("waterfall-plot");
}
Waterfall.prototype.connectorsEnabled = function (enabled) {
if (enabled == null) {
return this._connectorsEnabled;
}
this._connectorsEnabled = enabled;
return this;
};
Waterfall.prototype.total = function (total) {
if (total == null) {
return this._propertyBindings.get(Waterfall._TOTAL_KEY);
}
this._bindProperty(Waterfall._TOTAL_KEY, total, null);
return this;
};
Waterfall.prototype._additionalPaint = function (time) {
var _this = this;
this._connectorArea.selectAll("line").remove();
if (this._connectorsEnabled) {
Plottable.Utils.Window.setTimeout(function () { return _this._drawConnectors(); }, time);
}
};
Waterfall.prototype._createNodesForDataset = function (dataset) {
var drawer = _super.prototype._createNodesForDataset.call(this, dataset);
this._connectorArea = this._renderArea.append("g").classed(Waterfall._CONNECTOR_AREA_CLASS, true);
return drawer;
};
Waterfall.prototype._extentsForProperty = function (attr) {
var primaryAttr = "y";
if (attr === primaryAttr) {
return [this._extent];
}
else {
return _super.prototype._extentsForProperty.call(this, attr);
}
};
Waterfall.prototype._generateAttrToProjector = function () {
var _this = this;
var attrToProjector = _super.prototype._generateAttrToProjector.call(this);
var yScale = this.y().scale;
var totalAccessor = Plottable.Plot._scaledAccessor(this.total());
var yAttr = this.attr("y");
if (yAttr == null) {
attrToProjector["y"] = function (d, i, dataset) {
var currentValue = _this.y().accessor(d, i, dataset);
var isTotal = totalAccessor(d, i, dataset);
if (isTotal) {
return Math.min(yScale.scale(currentValue), yScale.scale(0));
}
else {
var currentSubtotal = _this._subtotals[i];
if (i === 0) {
if (currentValue < 0) {
return yScale.scale(currentSubtotal - currentValue);
}
else {
return yScale.scale(currentSubtotal);
}
}
var priorSubtotal = _this._subtotals[i - 1];
if (currentSubtotal > priorSubtotal) {
return yScale.scale(currentSubtotal);
}
else {
return yScale.scale(priorSubtotal);
}
}
};
}
var heightAttr = this.attr("height");
if (heightAttr == null) {
attrToProjector["height"] = function (d, i, dataset) {
var isTotal = totalAccessor(d, i, dataset);
var currentValue = _this.y().accessor(d, i, dataset);
if (isTotal) {
return Math.abs(yScale.scale(currentValue) - yScale.scale(0));
}
else {
var currentSubtotal = _this._subtotals[i];
if (i === 0) {
return Math.abs(yScale.scale(currentSubtotal) - yScale.scale(currentSubtotal - currentValue));
}
else {
var priorSubtotal = _this._subtotals[i - 1];
return Math.abs(yScale.scale(currentSubtotal) - yScale.scale(priorSubtotal));
}
}
};
}
attrToProjector["class"] = function (d, i, dataset) {
var baseClass = "";
if (_this.attr("class") != null) {
baseClass = _this.attr("class").accessor(d, i, dataset) + " ";
}
var isTotal = totalAccessor(d, i, dataset);
if (isTotal) {
return baseClass + Waterfall._BAR_TOTAL_CLASS;
}
else {
var delta = _this.y().accessor(d, i, dataset);
return baseClass + (delta > 0 ? Waterfall._BAR_GROWTH_CLASS : Waterfall._BAR_DECLINE_CLASS);
}
};
return attrToProjector;
};
Waterfall.prototype._onDatasetUpdate = function () {
this._updateSubtotals();
_super.prototype._onDatasetUpdate.call(this);
return this;
};
Waterfall.prototype._calculateSubtotalsAndExtent = function (dataset) {
var _this = this;
var min = Number.MAX_VALUE;
var max = Number.MIN_VALUE;
var total = 0;
var startValue = -Infinity;
dataset.data().forEach(function (datum, index) {
var currentValue = _this.y().accessor(datum, index, dataset);
var isTotal = _this.total().accessor(datum, index, dataset);
if (!isTotal || index === 0) {
total += currentValue;
}
_this._subtotals.push(total);
if (total < min) {
min = total;
}
if (total > max) {
max = total;
}
if (isTotal) {
if (currentValue < min) {
min = currentValue;
}
if (currentValue > max) {
max = currentValue;
}
}
if (startValue === -Infinity && isTotal) {
var startTotal = currentValue - total;
for (var i = 0; i < _this._subtotals.length; i++) {
_this._subtotals[i] += startTotal;
}
startValue = _this._subtotals[i];
total += startTotal;
min += startTotal;
max += startTotal;
}
});
this._extent = [min, max];
};
Waterfall.prototype._drawConnectors = function () {
var attrToProjector = this._generateAttrToProjector();
var dataset = this.datasets()[0];
for (var datumIndex = 1; datumIndex < dataset.data().length; datumIndex++) {
var prevIndex = datumIndex - 1;
var datum = dataset.data()[datumIndex];
var prevDatum = dataset.data()[prevIndex];
var x = attrToProjector["x"](prevDatum, prevIndex, dataset);
var x2 = attrToProjector["x"](datum, datumIndex, dataset) + attrToProjector["width"](datum, datumIndex, dataset);
var y = attrToProjector["y"](datum, datumIndex, dataset);
if ((this._subtotals[datumIndex] > 0 && this._subtotals[datumIndex] > this._subtotals[prevIndex]) ||
(this._subtotals[datumIndex] < 0 && this._subtotals[datumIndex] >= this._subtotals[prevIndex])) {
y = attrToProjector["y"](datum, datumIndex, dataset) + attrToProjector["height"](datum, datumIndex, dataset);
}
this._connectorArea.append("line").classed(Waterfall._CONNECTOR_CLASS, true)
.attr("x1", x).attr("x2", x2).attr("y1", y).attr("y2", y);
}
};
Waterfall.prototype._updateSubtotals = function () {
var datasets = this.datasets();
if (datasets.length > 0) {
var dataset = datasets[datasets.length - 1];
this._subtotals = new Array();
this._calculateSubtotalsAndExtent(dataset);
}
};
Waterfall._BAR_DECLINE_CLASS = "waterfall-decline";
Waterfall._BAR_GROWTH_CLASS = "waterfall-growth";
Waterfall._BAR_TOTAL_CLASS = "waterfall-total";
Waterfall._CONNECTOR_CLASS = "connector";
Waterfall._CONNECTOR_AREA_CLASS = "connector-area";
Waterfall._TOTAL_KEY = "total";
return Waterfall;
})(Plots.Bar);
Plots.Waterfall = Waterfall;
})(Plots = Plottable.Plots || (Plottable.Plots = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
///<reference path="../reference.ts" />
var Plottable;
(function (Plottable) {
var Animators;
(function (Animators) {
/**
* An animator implementation with no animation. The attributes are
* immediately set on the selection.
*/
var Null = (function () {
function Null() {
}
Null.prototype.totalTime = function (selection) {
return 0;
};
Null.prototype.animate = function (selection, attrToAppliedProjector) {
return selection.attr(attrToAppliedProjector);
};
return Null;
})();
Animators.Null = Null;
})(Animators = Plottable.Animators || (Plottable.Animators = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var Plottable;
(function (Plottable) {
var Animators;
(function (Animators) {
/**
* An Animator with easing and configurable durations and delays.
*/
var Easing = (function () {
/**
* Constructs the default animator
*
* @constructor
*/
function Easing() {
this._startDelay = Easing._DEFAULT_START_DELAY_MILLISECONDS;
this._stepDuration = Easing._DEFAULT_STEP_DURATION_MILLISECONDS;
this._stepDelay = Easing._DEFAULT_ITERATIVE_DELAY_MILLISECONDS;
this._maxTotalDuration = Easing._DEFAULT_MAX_TOTAL_DURATION_MILLISECONDS;
this._easingMode = Easing._DEFAULT_EASING_MODE;
}
Easing.prototype.totalTime = function (numberOfSteps) {
var adjustedIterativeDelay = this._getAdjustedIterativeDelay(numberOfSteps);
return this.startDelay() + adjustedIterativeDelay * (Math.max(numberOfSteps - 1, 0)) + this.stepDuration();
};
Easing.prototype.animate = function (selection, attrToAppliedProjector) {
var _this = this;
var numberOfSteps = selection[0].length;
var adjustedIterativeDelay = this._getAdjustedIterativeDelay(numberOfSteps);
return selection.transition()
.ease(this.easingMode())
.duration(this.stepDuration())
.delay(function (d, i) { return _this.startDelay() + adjustedIterativeDelay * i; })
.attr(attrToAppliedProjector);
};
Easing.prototype.startDelay = function (startDelay) {
if (startDelay == null) {
return this._startDelay;
}
else {
this._startDelay = startDelay;
return this;
}
};
Easing.prototype.stepDuration = function (stepDuration) {
if (stepDuration == null) {
return Math.min(this._stepDuration, this._maxTotalDuration);
}
else {
this._stepDuration = stepDuration;
return this;
}
};
Easing.prototype.stepDelay = function (stepDelay) {
if (stepDelay == null) {
return this._stepDelay;
}
else {
this._stepDelay = stepDelay;
return this;
}
};
Easing.prototype.maxTotalDuration = function (maxTotalDuration) {
if (maxTotalDuration == null) {
return this._maxTotalDuration;
}
else {
this._maxTotalDuration = maxTotalDuration;
return this;
}
};
Easing.prototype.easingMode = function (easingMode) {
if (easingMode == null) {
return this._easingMode;
}
else {
this._easingMode = easingMode;
return this;
}
};
/**
* Adjust the iterative delay, such that it takes into account the maxTotalDuration constraint
*/
Easing.prototype._getAdjustedIterativeDelay = function (numberOfSteps) {
var stepStartTimeInterval = this.maxTotalDuration() - this.stepDuration();
stepStartTimeInterval = Math.max(stepStartTimeInterval, 0);
var maxPossibleIterativeDelay = stepStartTimeInterval / Math.max(numberOfSteps - 1, 1);
return Math.min(this.stepDelay(), maxPossibleIterativeDelay);
};
/**
* The default starting delay of the animation in milliseconds
*/
Easing._DEFAULT_START_DELAY_MILLISECONDS = 0;
/**
* The default duration of one animation step in milliseconds
*/
Easing._DEFAULT_STEP_DURATION_MILLISECONDS = 300;
/**
* The default maximum start delay between each step of an animation
*/
Easing._DEFAULT_ITERATIVE_DELAY_MILLISECONDS = 15;
/**
* The default maximum total animation duration
*/
Easing._DEFAULT_MAX_TOTAL_DURATION_MILLISECONDS = Infinity;
/**
* The default easing of the animation
*/
Easing._DEFAULT_EASING_MODE = "exp-out";
return Easing;
})();
Animators.Easing = Easing;
})(Animators = Plottable.Animators || (Plottable.Animators = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var Plottable;
(function (Plottable) {
var Dispatcher = (function () {
function Dispatcher() {
this._eventToCallback = {};
this._callbacks = [];
this._connected = false;
}
Dispatcher.prototype._hasNoListeners = function () {
return this._callbacks.every(function (cbs) { return cbs.size === 0; });
};
Dispatcher.prototype._connect = function () {
var _this = this;
if (this._connected) {
return;
}
Object.keys(this._eventToCallback).forEach(function (event) {
var callback = _this._eventToCallback[event];
document.addEventListener(event, callback);
});
this._connected = true;
};
Dispatcher.prototype._disconnect = function () {
var _this = this;
if (this._connected && this._hasNoListeners()) {
Object.keys(this._eventToCallback).forEach(function (event) {
var callback = _this._eventToCallback[event];
document.removeEventListener(event, callback);
});
this._connected = false;
}
};
Dispatcher.prototype._setCallback = function (callbackSet, callback) {
this._connect();
callbackSet.add(callback);
};
Dispatcher.prototype._unsetCallback = function (callbackSet, callback) {
callbackSet.delete(callback);
this._disconnect();
};
return Dispatcher;
})();
Plottable.Dispatcher = Dispatcher;
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Dispatchers;
(function (Dispatchers) {
var Mouse = (function (_super) {
__extends(Mouse, _super);
/**
* This constructor not be invoked directly.
*
* @constructor
* @param {SVGElement} svg The root <svg> to attach to.
*/
function Mouse(svg) {
var _this = this;
_super.call(this);
this._translator = Plottable.Utils.ClientToSVGTranslator.getTranslator(svg);
this._lastMousePosition = { x: -1, y: -1 };
this._moveCallbacks = new Plottable.Utils.CallbackSet();
this._downCallbacks = new Plottable.Utils.CallbackSet();
this._upCallbacks = new Plottable.Utils.CallbackSet();
this._wheelCallbacks = new Plottable.Utils.CallbackSet();
this._dblClickCallbacks = new Plottable.Utils.CallbackSet();
this._callbacks = [this._moveCallbacks, this._downCallbacks, this._upCallbacks, this._wheelCallbacks,
this._dblClickCallbacks];
var processMoveCallback = function (e) { return _this._measureAndDispatch(e, _this._moveCallbacks, "page"); };
this._eventToCallback["mouseover"] = processMoveCallback;
this._eventToCallback["mousemove"] = processMoveCallback;
this._eventToCallback["mouseout"] = processMoveCallback;
this._eventToCallback["mousedown"] = function (e) { return _this._measureAndDispatch(e, _this._downCallbacks); };
this._eventToCallback["mouseup"] = function (e) { return _this._measureAndDispatch(e, _this._upCallbacks, "page"); };
this._eventToCallback["wheel"] = function (e) { return _this._measureAndDispatch(e, _this._wheelCallbacks); };
this._eventToCallback["dblclick"] = function (e) { return _this._measureAndDispatch(e, _this._dblClickCallbacks); };
}
/**
* Get a Mouse Dispatcher for the <svg> containing elem.
* If one already exists on that <svg>, it will be returned; otherwise, a new one will be created.
*
* @param {SVGElement} elem
* @return {Dispatchers.Mouse}
*/
Mouse.getDispatcher = function (elem) {
var svg = Plottable.Utils.DOM.boundingSVG(elem);
var dispatcher = svg[Mouse._DISPATCHER_KEY];
if (dispatcher == null) {
dispatcher = new Mouse(svg);
svg[Mouse._DISPATCHER_KEY] = dispatcher;
}
return dispatcher;
};
/**
* Registers a callback to be called when the mouse position changes.
*
* @param {MouseCallback} callback
* @return {Dispatchers.Mouse} The calling Mouse Dispatcher.
*/
Mouse.prototype.onMouseMove = function (callback) {
this._setCallback(this._moveCallbacks, callback);
return this;
};
/**
* Removes a callback that would be called when the mouse position changes.
*
* @param {MouseCallback} callback
* @return {Dispatchers.Mouse} The calling Mouse Dispatcher.
*/
Mouse.prototype.offMouseMove = function (callback) {
this._unsetCallback(this._moveCallbacks, callback);
return this;
};
/**
* Registers a callback to be called when a mousedown occurs.
*
* @param {MouseCallback} callback
* @return {Dispatchers.Mouse} The calling Mouse Dispatcher.
*/
Mouse.prototype.onMouseDown = function (callback) {
this._setCallback(this._downCallbacks, callback);
return this;
};
/**
* Removes a callback that would be called when a mousedown occurs.
*
* @param {MouseCallback} callback
* @return {Dispatchers.Mouse} The calling Mouse Dispatcher.
*/
Mouse.prototype.offMouseDown = function (callback) {
this._unsetCallback(this._downCallbacks, callback);
return this;
};
/**
* Registers a callback to be called when a mouseup occurs.
*
* @param {MouseCallback} callback
* @return {Dispatchers.Mouse} The calling Mouse Dispatcher.
*/
Mouse.prototype.onMouseUp = function (callback) {
this._setCallback(this._upCallbacks, callback);
return this;
};
/**
* Removes a callback that would be called when a mouseup occurs.
*
* @param {MouseCallback} callback
* @return {Dispatchers.Mouse} The calling Mouse Dispatcher.
*/
Mouse.prototype.offMouseUp = function (callback) {
this._unsetCallback(this._upCallbacks, callback);
return this;
};
/**
* Registers a callback to be called when a wheel event occurs.
*
* @param {MouseCallback} callback
* @return {Dispatchers.Mouse} The calling Mouse Dispatcher.
*/
Mouse.prototype.onWheel = function (callback) {
this._setCallback(this._wheelCallbacks, callback);
return this;
};
/**
* Removes a callback that would be called when a wheel event occurs.
*
* @param {MouseCallback} callback
* @return {Dispatchers.Mouse} The calling Mouse Dispatcher.
*/
Mouse.prototype.offWheel = function (callback) {
this._unsetCallback(this._wheelCallbacks, callback);
return this;
};
/**
* Registers a callback to be called when a dblClick occurs.
*
* @param {MouseCallback} callback
* @return {Dispatchers.Mouse} The calling Mouse Dispatcher.
*/
Mouse.prototype.onDblClick = function (callback) {
this._setCallback(this._dblClickCallbacks, callback);
return this;
};
/**
* Removes a callback that would be called when a dblClick occurs.
*
* @param {MouseCallback} callback
* @return {Dispatchers.Mouse} The calling Mouse Dispatcher.
*/
Mouse.prototype.offDblClick = function (callback) {
this._unsetCallback(this._dblClickCallbacks, callback);
return this;
};
/**
* Computes the mouse position from the given event, and if successful
* calls all the callbacks in the provided callbackSet.
*/
Mouse.prototype._measureAndDispatch = function (event, callbackSet, scope) {
if (scope === void 0) { scope = "element"; }
if (event.type == "mousedown") {
console.log("mousedown");
}
if (scope !== "page" && scope !== "element") {
throw new Error("Invalid scope '" + scope + "', must be 'element' or 'page'");
}
if (scope === "page" || this._translator.insideSVG(event)) {
var newMousePosition = this._translator.computePosition(event.clientX, event.clientY);
if (newMousePosition != null) {
this._lastMousePosition = newMousePosition;
callbackSet.callCallbacks(this.lastMousePosition(), event);
}
}
};
/**
* Returns the last computed mouse position in <svg> coordinate space.
*
* @return {Point}
*/
Mouse.prototype.lastMousePosition = function () {
return this._lastMousePosition;
};
Mouse._DISPATCHER_KEY = "__Plottable_Dispatcher_Mouse";
return Mouse;
})(Plottable.Dispatcher);
Dispatchers.Mouse = Mouse;
})(Dispatchers = Plottable.Dispatchers || (Plottable.Dispatchers = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Dispatchers;
(function (Dispatchers) {
var Touch = (function (_super) {
__extends(Touch, _super);
/**
* This constructor should not be invoked directly.
*
* @constructor
* @param {SVGElement} svg The root <svg> to attach to.
*/
function Touch(svg) {
var _this = this;
_super.call(this);
this._translator = Plottable.Utils.ClientToSVGTranslator.getTranslator(svg);
this._startCallbacks = new Plottable.Utils.CallbackSet();
this._moveCallbacks = new Plottable.Utils.CallbackSet();
this._endCallbacks = new Plottable.Utils.CallbackSet();
this._cancelCallbacks = new Plottable.Utils.CallbackSet();
this._callbacks = [this._moveCallbacks, this._startCallbacks, this._endCallbacks, this._cancelCallbacks];
this._eventToCallback["touchstart"] = function (e) { return _this._measureAndDispatch(e, _this._startCallbacks); };
this._eventToCallback["touchmove"] = function (e) { return _this._measureAndDispatch(e, _this._moveCallbacks); };
this._eventToCallback["touchend"] = function (e) { return _this._measureAndDispatch(e, _this._endCallbacks); };
this._eventToCallback["touchcancel"] = function (e) { return _this._measureAndDispatch(e, _this._cancelCallbacks); };
}
/**
* Gets a Touch Dispatcher for the <svg> containing elem.
* If one already exists on that <svg>, it will be returned; otherwise, a new one will be created.
*
* @param {SVGElement} elem
* @return {Dispatchers.Touch}
*/
Touch.getDispatcher = function (elem) {
var svg = Plottable.Utils.DOM.boundingSVG(elem);
var dispatcher = svg[Touch._DISPATCHER_KEY];
if (dispatcher == null) {
dispatcher = new Touch(svg);
svg[Touch._DISPATCHER_KEY] = dispatcher;
}
return dispatcher;
};
/**
* Registers a callback to be called when a touch starts.
*
* @param {TouchCallback} callback
* @return {Dispatchers.Touch} The calling Touch Dispatcher.
*/
Touch.prototype.onTouchStart = function (callback) {
this._setCallback(this._startCallbacks, callback);
return this;
};
/**
* Removes a callback that would be called when a touch starts.
*
* @param {TouchCallback} callback
* @return {Dispatchers.Touch} The calling Touch Dispatcher.
*/
Touch.prototype.offTouchStart = function (callback) {
this._unsetCallback(this._startCallbacks, callback);
return this;
};
/**
* Registers a callback to be called when the touch position changes.
*
* @param {TouchCallback} callback
* @return {Dispatchers.Touch} The calling Touch Dispatcher.
*/
Touch.prototype.onTouchMove = function (callback) {
this._setCallback(this._moveCallbacks, callback);
return this;
};
/**
* Removes a callback that would be called when the touch position changes.
*
* @param {TouchCallback} callback
* @return {Dispatchers.Touch} The calling Touch Dispatcher.
*/
Touch.prototype.offTouchMove = function (callback) {
this._unsetCallback(this._moveCallbacks, callback);
return this;
};
/**
* Registers a callback to be called when a touch ends.
*
* @param {TouchCallback} callback
* @return {Dispatchers.Touch} The calling Touch Dispatcher.
*/
Touch.prototype.onTouchEnd = function (callback) {
this._setCallback(this._endCallbacks, callback);
return this;
};
/**
* Removes a callback that would be called when a touch ends.
*
* @param {TouchCallback} callback
* @return {Dispatchers.Touch} The calling Touch Dispatcher.
*/
Touch.prototype.offTouchEnd = function (callback) {
this._unsetCallback(this._endCallbacks, callback);
return this;
};
/**
* Registers a callback to be called when a touch is cancelled.
*
* @param {TouchCallback} callback
* @return {Dispatchers.Touch} The calling Touch Dispatcher.
*/
Touch.prototype.onTouchCancel = function (callback) {
this._setCallback(this._cancelCallbacks, callback);
return this;
};
/**
* Removes a callback that would be called when a touch is cancelled.
*
* @param {TouchCallback} callback
* @return {Dispatchers.Touch} The calling Touch Dispatcher.
*/
Touch.prototype.offTouchCancel = function (callback) {
this._unsetCallback(this._cancelCallbacks, callback);
return this;
};
/**
* Computes the Touch position from the given event, and if successful
* calls all the callbacks in the provided callbackSet.
*/
Touch.prototype._measureAndDispatch = function (event, callbackSet) {
var touches = event.changedTouches;
var touchPositions = {};
var touchIdentifiers = [];
for (var i = 0; i < touches.length; i++) {
var touch = touches[i];
var touchID = touch.identifier;
var newTouchPosition = this._translator.computePosition(touch.clientX, touch.clientY);
if (newTouchPosition != null) {
touchPositions[touchID] = newTouchPosition;
touchIdentifiers.push(touchID);
}
}
;
if (touchIdentifiers.length > 0) {
callbackSet.callCallbacks(touchIdentifiers, touchPositions, event);
}
};
Touch._DISPATCHER_KEY = "__Plottable_Dispatcher_Touch";
return Touch;
})(Plottable.Dispatcher);
Dispatchers.Touch = Touch;
})(Dispatchers = Plottable.Dispatchers || (Plottable.Dispatchers = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Dispatchers;
(function (Dispatchers) {
var Key = (function (_super) {
__extends(Key, _super);
/**
* This constructor should not be invoked directly.
*
* @constructor
*/
function Key() {
var _this = this;
_super.call(this);
this._eventToCallback["keydown"] = function (e) { return _this._processKeydown(e); };
this._eventToCallback["keyup"] = function (e) { return _this._processKeyup(e); };
this._keydownCallbacks = new Plottable.Utils.CallbackSet();
this._keyupCallbacks = new Plottable.Utils.CallbackSet();
this._callbacks = [this._keydownCallbacks, this._keyupCallbacks];
}
/**
* Gets a Key Dispatcher. If one already exists it will be returned;
* otherwise, a new one will be created.
*
* @return {Dispatchers.Key}
*/
Key.getDispatcher = function () {
var dispatcher = document[Key._DISPATCHER_KEY];
if (dispatcher == null) {
dispatcher = new Key();
document[Key._DISPATCHER_KEY] = dispatcher;
}
return dispatcher;
};
/**
* Registers a callback to be called whenever a key is pressed.
*
* @param {KeyCallback} callback
* @return {Dispatchers.Key} The calling Key Dispatcher.
*/
Key.prototype.onKeyDown = function (callback) {
this._setCallback(this._keydownCallbacks, callback);
return this;
};
/**
* Removes the callback to be called whenever a key is pressed.
*
* @param {KeyCallback} callback
* @return {Dispatchers.Key} The calling Key Dispatcher.
*/
Key.prototype.offKeyDown = function (callback) {
this._unsetCallback(this._keydownCallbacks, callback);
return this;
};
/** Registers a callback to be called whenever a key is released.
*
* @param {KeyCallback} callback
* @return {Dispatchers.Key} The calling Key Dispatcher.
*/
Key.prototype.onKeyUp = function (callback) {
this._setCallback(this._keyupCallbacks, callback);
return this;
};
/**
* Removes the callback to be called whenever a key is released.
*
* @param {KeyCallback} callback
* @return {Dispatchers.Key} The calling Key Dispatcher.
*/
Key.prototype.offKeyUp = function (callback) {
this._unsetCallback(this._keyupCallbacks, callback);
return this;
};
Key.prototype._processKeydown = function (event) {
this._keydownCallbacks.callCallbacks(event.keyCode, event);
};
Key.prototype._processKeyup = function (event) {
this._keyupCallbacks.callCallbacks(event.keyCode, event);
};
Key._DISPATCHER_KEY = "__Plottable_Dispatcher_Key";
return Key;
})(Plottable.Dispatcher);
Dispatchers.Key = Key;
})(Dispatchers = Plottable.Dispatchers || (Plottable.Dispatchers = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var Plottable;
(function (Plottable) {
var Interaction = (function () {
function Interaction() {
var _this = this;
this._anchorCallback = function (component) { return _this._anchor(component); };
this._enabled = true;
}
Interaction.prototype._anchor = function (component) {
this._isAnchored = true;
};
Interaction.prototype._unanchor = function () {
this._isAnchored = false;
};
/**
* Attaches this Interaction to a Component.
* If the Interaction was already attached to a Component, it first detaches itself from the old Component.
*
* @param {Component} component
* @returns {Interaction} The calling Interaction.
*/
Interaction.prototype.attachTo = function (component) {
this._disconnect();
this._componentAttachedTo = component;
this._connect();
return this;
};
Interaction.prototype._connect = function () {
if (this.enabled() && this._componentAttachedTo != null && !this._isAnchored) {
this._componentAttachedTo.onAnchor(this._anchorCallback);
}
};
/**
* Detaches this Interaction from the Component.
* This Interaction can be reused.
*
* @param {Component} component
* @returns {Interaction} The calling Interaction.
*/
Interaction.prototype.detachFrom = function (component) {
this._disconnect();
this._componentAttachedTo = null;
return this;
};
Interaction.prototype._disconnect = function () {
if (this._isAnchored) {
this._unanchor();
}
if (this._componentAttachedTo != null) {
this._componentAttachedTo.offAnchor(this._anchorCallback);
}
};
Interaction.prototype.enabled = function (enabled) {
if (enabled == null) {
return this._enabled;
}
this._enabled = enabled;
if (this._enabled) {
this._connect();
}
else {
this._disconnect();
}
return this;
};
/**
* Translates an <svg>-coordinate-space point to Component-space coordinates.
*
* @param {Point} p A Point in <svg>-space coordinates.
* @return {Point} The same location in Component-space coordinates.
*/
Interaction.prototype._translateToComponentSpace = function (p) {
var origin = this._componentAttachedTo.originToSVG();
return {
x: p.x - origin.x,
y: p.y - origin.y
};
};
/**
* Checks whether a Component-coordinate-space Point is inside the Component.
*
* @param {Point} p A Point in Compoennt-space coordinates.
* @return {boolean} Whether or not the point is inside the Component.
*/
Interaction.prototype._isInsideComponent = function (p) {
return 0 <= p.x && 0 <= p.y
&& p.x <= this._componentAttachedTo.width()
&& p.y <= this._componentAttachedTo.height();
};
return Interaction;
})();
Plottable.Interaction = Interaction;
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Interactions;
(function (Interactions) {
var Click = (function (_super) {
__extends(Click, _super);
function Click() {
var _this = this;
_super.apply(this, arguments);
this._clickedDown = false;
this._onClickCallbacks = new Plottable.Utils.CallbackSet();
this._mouseDownCallback = function (p) { return _this._handleClickDown(p); };
this._mouseUpCallback = function (p) { return _this._handleClickUp(p); };
this._touchStartCallback = function (ids, idToPoint) { return _this._handleClickDown(idToPoint[ids[0]]); };
this._touchEndCallback = function (ids, idToPoint) { return _this._handleClickUp(idToPoint[ids[0]]); };
this._touchCancelCallback = function (ids, idToPoint) { return _this._clickedDown = false; };
}
Click.prototype._anchor = function (component) {
_super.prototype._anchor.call(this, component);
this._mouseDispatcher = Plottable.Dispatchers.Mouse.getDispatcher(component.content().node());
this._mouseDispatcher.onMouseDown(this._mouseDownCallback);
this._mouseDispatcher.onMouseUp(this._mouseUpCallback);
this._touchDispatcher = Plottable.Dispatchers.Touch.getDispatcher(component.content().node());
this._touchDispatcher.onTouchStart(this._touchStartCallback);
this._touchDispatcher.onTouchEnd(this._touchEndCallback);
this._touchDispatcher.onTouchCancel(this._touchCancelCallback);
};
Click.prototype._unanchor = function () {
_super.prototype._unanchor.call(this);
this._mouseDispatcher.offMouseDown(this._mouseDownCallback);
this._mouseDispatcher.offMouseUp(this._mouseUpCallback);
this._mouseDispatcher = null;
this._touchDispatcher.offTouchStart(this._touchStartCallback);
this._touchDispatcher.offTouchEnd(this._touchEndCallback);
this._touchDispatcher.offTouchCancel(this._touchCancelCallback);
this._touchDispatcher = null;
};
Click.prototype._handleClickDown = function (p) {
var translatedPoint = this._translateToComponentSpace(p);
if (this._isInsideComponent(translatedPoint)) {
this._clickedDown = true;
}
};
Click.prototype._handleClickUp = function (p) {
var translatedPoint = this._translateToComponentSpace(p);
if (this._clickedDown && this._isInsideComponent(translatedPoint)) {
this._onClickCallbacks.callCallbacks(translatedPoint);
}
this._clickedDown = false;
};
/**
* Adds a callback to be called when the Component is clicked.
*
* @param {ClickCallback} callback
* @return {Interactions.Click} The calling Click Interaction.
*/
Click.prototype.onClick = function (callback) {
this._onClickCallbacks.add(callback);
return this;
};
/**
* Removes a callback that would be called when the Component is clicked.
*
* @param {ClickCallback} callback
* @return {Interactions.Click} The calling Click Interaction.
*/
Click.prototype.offClick = function (callback) {
this._onClickCallbacks.delete(callback);
return this;
};
return Click;
})(Plottable.Interaction);
Interactions.Click = Click;
})(Interactions = Plottable.Interactions || (Plottable.Interactions = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Interactions;
(function (Interactions) {
var ClickState;
(function (ClickState) {
ClickState[ClickState["NotClicked"] = 0] = "NotClicked";
ClickState[ClickState["SingleClicked"] = 1] = "SingleClicked";
ClickState[ClickState["DoubleClicked"] = 2] = "DoubleClicked";
})(ClickState || (ClickState = {}));
;
var DoubleClick = (function (_super) {
__extends(DoubleClick, _super);
function DoubleClick() {
var _this = this;
_super.apply(this, arguments);
this._clickState = ClickState.NotClicked;
this._clickedDown = false;
this._onDoubleClickCallbacks = new Plottable.Utils.CallbackSet();
this._mouseDownCallback = function (p) { return _this._handleClickDown(p); };
this._mouseUpCallback = function (p) { return _this._handleClickUp(p); };
this._dblClickCallback = function (p) { return _this._handleDblClick(); };
this._touchStartCallback = function (ids, idToPoint) { return _this._handleClickDown(idToPoint[ids[0]]); };
this._touchEndCallback = function (ids, idToPoint) { return _this._handleClickUp(idToPoint[ids[0]]); };
this._touchCancelCallback = function (ids, idToPoint) { return _this._handleClickCancel(); };
}
DoubleClick.prototype._anchor = function (component) {
_super.prototype._anchor.call(this, component);
this._mouseDispatcher = Plottable.Dispatchers.Mouse.getDispatcher(component.content().node());
this._mouseDispatcher.onMouseDown(this._mouseDownCallback);
this._mouseDispatcher.onMouseUp(this._mouseUpCallback);
this._mouseDispatcher.onDblClick(this._dblClickCallback);
this._touchDispatcher = Plottable.Dispatchers.Touch.getDispatcher(component.content().node());
this._touchDispatcher.onTouchStart(this._touchStartCallback);
this._touchDispatcher.onTouchEnd(this._touchEndCallback);
this._touchDispatcher.onTouchCancel(this._touchCancelCallback);
};
DoubleClick.prototype._unanchor = function () {
_super.prototype._unanchor.call(this);
this._mouseDispatcher.offMouseDown(this._mouseDownCallback);
this._mouseDispatcher.offMouseUp(this._mouseUpCallback);
this._mouseDispatcher.offDblClick(this._dblClickCallback);
this._mouseDispatcher = null;
this._touchDispatcher.offTouchStart(this._touchStartCallback);
this._touchDispatcher.offTouchEnd(this._touchEndCallback);
this._touchDispatcher.offTouchCancel(this._touchCancelCallback);
this._touchDispatcher = null;
};
DoubleClick.prototype._handleClickDown = function (p) {
var translatedP = this._translateToComponentSpace(p);
if (this._isInsideComponent(translatedP)) {
if (!(this._clickState === ClickState.SingleClicked) || !DoubleClick._pointsEqual(translatedP, this._clickedPoint)) {
this._clickState = ClickState.NotClicked;
}
this._clickedPoint = translatedP;
this._clickedDown = true;
}
};
DoubleClick.prototype._handleClickUp = function (p) {
var translatedP = this._translateToComponentSpace(p);
if (this._clickedDown && DoubleClick._pointsEqual(translatedP, this._clickedPoint)) {
this._clickState = this._clickState === ClickState.NotClicked ? ClickState.SingleClicked : ClickState.DoubleClicked;
}
else {
this._clickState = ClickState.NotClicked;
}
this._clickedDown = false;
};
DoubleClick.prototype._handleDblClick = function () {
if (this._clickState === ClickState.DoubleClicked) {
this._onDoubleClickCallbacks.callCallbacks(this._clickedPoint);
this._clickState = ClickState.NotClicked;
}
};
DoubleClick.prototype._handleClickCancel = function () {
this._clickState = ClickState.NotClicked;
this._clickedDown = false;
};
DoubleClick._pointsEqual = function (p1, p2) {
return p1.x === p2.x && p1.y === p2.y;
};
/**
* Adds a callback to be called when the Component is double-clicked.
*
* @param {ClickCallback} callback
* @return {Interactions.DoubleClick} The calling DoubleClick Interaction.
*/
DoubleClick.prototype.onDoubleClick = function (callback) {
this._onDoubleClickCallbacks.add(callback);
return this;
};
/**
* Removes a callback that would be called when the Component is double-clicked.
*
* @param {ClickCallback} callback
* @return {Interactions.DoubleClick} The calling DoubleClick Interaction.
*/
DoubleClick.prototype.offDoubleClick = function (callback) {
this._onDoubleClickCallbacks.delete(callback);
return this;
};
return DoubleClick;
})(Plottable.Interaction);
Interactions.DoubleClick = DoubleClick;
})(Interactions = Plottable.Interactions || (Plottable.Interactions = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Interactions;
(function (Interactions) {
var Key = (function (_super) {
__extends(Key, _super);
function Key() {
var _this = this;
_super.apply(this, arguments);
this._keyPressCallbacks = {};
this._keyReleaseCallbacks = {};
this._mouseMoveCallback = function (point) { return false; }; // HACKHACK: registering a listener
this._downedKeys = new Plottable.Utils.Set();
this._keyDownCallback = function (keyCode) { return _this._handleKeyDownEvent(keyCode); };
this._keyUpCallback = function (keyCode) { return _this._handleKeyUpEvent(keyCode); };
}
Key.prototype._anchor = function (component) {
_super.prototype._anchor.call(this, component);
this._positionDispatcher = Plottable.Dispatchers.Mouse.getDispatcher(this._componentAttachedTo._element.node());
this._positionDispatcher.onMouseMove(this._mouseMoveCallback);
this._keyDispatcher = Plottable.Dispatchers.Key.getDispatcher();
this._keyDispatcher.onKeyDown(this._keyDownCallback);
this._keyDispatcher.onKeyUp(this._keyUpCallback);
};
Key.prototype._unanchor = function () {
_super.prototype._unanchor.call(this);
this._positionDispatcher.offMouseMove(this._mouseMoveCallback);
this._positionDispatcher = null;
this._keyDispatcher.offKeyDown(this._keyDownCallback);
this._keyDispatcher.offKeyUp(this._keyUpCallback);
this._keyDispatcher = null;
};
Key.prototype._handleKeyDownEvent = function (keyCode) {
var p = this._translateToComponentSpace(this._positionDispatcher.lastMousePosition());
if (this._isInsideComponent(p)) {
if (this._keyPressCallbacks[keyCode]) {
this._keyPressCallbacks[keyCode].callCallbacks(keyCode);
}
this._downedKeys.add(keyCode);
}
};
Key.prototype._handleKeyUpEvent = function (keyCode) {
if (this._downedKeys.has(keyCode) && this._keyReleaseCallbacks[keyCode]) {
this._keyReleaseCallbacks[keyCode].callCallbacks(keyCode);
}
this._downedKeys.delete(keyCode);
};
/**
* Adds a callback to be called when the key with the given keyCode is
* pressed and the user is moused over the Component.
*
* @param {number} keyCode
* @param {KeyCallback} callback
* @returns {Interactions.Key} The calling Key Interaction.
*/
Key.prototype.onKeyPress = function (keyCode, callback) {
if (!this._keyPressCallbacks[keyCode]) {
this._keyPressCallbacks[keyCode] = new Plottable.Utils.CallbackSet();
}
this._keyPressCallbacks[keyCode].add(callback);
return this;
};
/**
* Removes a callback that would be called when the key with the given keyCode is
* pressed and the user is moused over the Component.
*
* @param {number} keyCode
* @param {KeyCallback} callback
* @returns {Interactions.Key} The calling Key Interaction.
*/
Key.prototype.offKeyPress = function (keyCode, callback) {
this._keyPressCallbacks[keyCode].delete(callback);
if (this._keyPressCallbacks[keyCode].size === 0) {
delete this._keyPressCallbacks[keyCode];
}
return this;
};
/**
* Adds a callback to be called when the key with the given keyCode is
* released if the key was pressed with the mouse inside of the Component.
*
* @param {number} keyCode
* @param {KeyCallback} callback
* @returns {Interactions.Key} The calling Key Interaction.
*/
Key.prototype.onKeyRelease = function (keyCode, callback) {
if (!this._keyReleaseCallbacks[keyCode]) {
this._keyReleaseCallbacks[keyCode] = new Plottable.Utils.CallbackSet();
}
this._keyReleaseCallbacks[keyCode].add(callback);
return this;
};
/**
* Removes a callback that would be called when the key with the given keyCode is
* released if the key was pressed with the mouse inside of the Component.
*
* @param {number} keyCode
* @param {KeyCallback} callback
* @returns {Interactions.Key} The calling Key Interaction.
*/
Key.prototype.offKeyRelease = function (keyCode, callback) {
this._keyReleaseCallbacks[keyCode].delete(callback);
if (this._keyReleaseCallbacks[keyCode].size === 0) {
delete this._keyReleaseCallbacks[keyCode];
}
return this;
};
return Key;
})(Plottable.Interaction);
Interactions.Key = Key;
})(Interactions = Plottable.Interactions || (Plottable.Interactions = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Interactions;
(function (Interactions) {
var Pointer = (function (_super) {
__extends(Pointer, _super);
function Pointer() {
var _this = this;
_super.apply(this, arguments);
this._overComponent = false;
this._pointerEnterCallbacks = new Plottable.Utils.CallbackSet();
this._pointerMoveCallbacks = new Plottable.Utils.CallbackSet();
this._pointerExitCallbacks = new Plottable.Utils.CallbackSet();
this._mouseMoveCallback = function (p) { return _this._handlePointerEvent(p); };
this._touchStartCallback = function (ids, idToPoint) { return _this._handlePointerEvent(idToPoint[ids[0]]); };
}
Pointer.prototype._anchor = function (component) {
_super.prototype._anchor.call(this, component);
this._mouseDispatcher = Plottable.Dispatchers.Mouse.getDispatcher(this._componentAttachedTo.content().node());
this._mouseDispatcher.onMouseMove(this._mouseMoveCallback);
this._touchDispatcher = Plottable.Dispatchers.Touch.getDispatcher(this._componentAttachedTo.content().node());
this._touchDispatcher.onTouchStart(this._touchStartCallback);
};
Pointer.prototype._unanchor = function () {
_super.prototype._unanchor.call(this);
this._mouseDispatcher.offMouseMove(this._mouseMoveCallback);
this._mouseDispatcher = null;
this._touchDispatcher.offTouchStart(this._touchStartCallback);
this._touchDispatcher = null;
};
Pointer.prototype._handlePointerEvent = function (p) {
var translatedP = this._translateToComponentSpace(p);
if (this._isInsideComponent(translatedP)) {
var wasOverComponent = this._overComponent;
this._overComponent = true;
if (!wasOverComponent) {
this._pointerEnterCallbacks.callCallbacks(translatedP);
}
this._pointerMoveCallbacks.callCallbacks(translatedP);
}
else if (this._overComponent) {
this._overComponent = false;
this._pointerExitCallbacks.callCallbacks(translatedP);
}
};
/**
* Adds a callback to be called when the pointer enters the Component.
*
* @param {PointerCallback} callback
* @return {Interactions.Pointer} The calling Pointer Interaction.
*/
Pointer.prototype.onPointerEnter = function (callback) {
this._pointerEnterCallbacks.add(callback);
return this;
};
/**
* Removes a callback that would be called when the pointer enters the Component.
*
* @param {PointerCallback} callback
* @return {Interactions.Pointer} The calling Pointer Interaction.
*/
Pointer.prototype.offPointerEnter = function (callback) {
this._pointerEnterCallbacks.delete(callback);
return this;
};
/**
* Adds a callback to be called when the pointer moves within the Component.
*
* @param {PointerCallback} callback
* @return {Interactions.Pointer} The calling Pointer Interaction.
*/
Pointer.prototype.onPointerMove = function (callback) {
this._pointerMoveCallbacks.add(callback);
return this;
};
/**
* Removes a callback that would be called when the pointer moves within the Component.
*
* @param {PointerCallback} callback
* @return {Interactions.Pointer} The calling Pointer Interaction.
*/
Pointer.prototype.offPointerMove = function (callback) {
this._pointerMoveCallbacks.delete(callback);
return this;
};
/**
* Adds a callback to be called when the pointer exits the Component.
*
* @param {PointerCallback} callback
* @return {Interactions.Pointer} The calling Pointer Interaction.
*/
Pointer.prototype.onPointerExit = function (callback) {
this._pointerExitCallbacks.add(callback);
return this;
};
/**
* Removes a callback that would be called when the pointer exits the Component.
*
* @param {PointerCallback} callback
* @return {Interactions.Pointer} The calling Pointer Interaction.
*/
Pointer.prototype.offPointerExit = function (callback) {
this._pointerExitCallbacks.delete(callback);
return this;
};
return Pointer;
})(Plottable.Interaction);
Interactions.Pointer = Pointer;
})(Interactions = Plottable.Interactions || (Plottable.Interactions = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Interactions;
(function (Interactions) {
var PanZoom = (function (_super) {
__extends(PanZoom, _super);
/**
* A PanZoom Interaction updates the domains of an x-scale and/or a y-scale
* in response to the user panning or zooming.
*
* @constructor
* @param {QuantitativeScale} [xScale] The x-scale to update on panning/zooming.
* @param {QuantitativeScale} [yScale] The y-scale to update on panning/zooming.
*/
function PanZoom(xScale, yScale) {
var _this = this;
_super.call(this);
this._wheelCallback = function (p, e) { return _this._handleWheelEvent(p, e); };
this._touchStartCallback = function (ids, idToPoint, e) { return _this._handleTouchStart(ids, idToPoint, e); };
this._touchMoveCallback = function (ids, idToPoint, e) { return _this._handlePinch(ids, idToPoint, e); };
this._touchEndCallback = function (ids, idToPoint, e) { return _this._handleTouchEnd(ids, idToPoint, e); };
this._touchCancelCallback = function (ids, idToPoint, e) { return _this._handleTouchEnd(ids, idToPoint, e); };
this._xScales = new Plottable.Utils.Set();
this._yScales = new Plottable.Utils.Set();
this._dragInteraction = new Interactions.Drag();
this._setupDragInteraction();
this._touchIds = d3.map();
this._minDomainExtents = new Plottable.Utils.Map();
this._maxDomainExtents = new Plottable.Utils.Map();
if (xScale != null) {
this.addXScale(xScale);
}
if (yScale != null) {
this.addYScale(yScale);
}
}
PanZoom.prototype._anchor = function (component) {
_super.prototype._anchor.call(this, component);
this._dragInteraction.attachTo(component);
this._mouseDispatcher = Plottable.Dispatchers.Mouse.getDispatcher(this._componentAttachedTo.content().node());
this._mouseDispatcher.onWheel(this._wheelCallback);
this._touchDispatcher = Plottable.Dispatchers.Touch.getDispatcher(this._componentAttachedTo.content().node());
this._touchDispatcher.onTouchStart(this._touchStartCallback);
this._touchDispatcher.onTouchMove(this._touchMoveCallback);
this._touchDispatcher.onTouchEnd(this._touchEndCallback);
this._touchDispatcher.onTouchCancel(this._touchCancelCallback);
};
PanZoom.prototype._unanchor = function () {
_super.prototype._unanchor.call(this);
this._mouseDispatcher.offWheel(this._wheelCallback);
this._mouseDispatcher = null;
this._touchDispatcher.offTouchStart(this._touchStartCallback);
this._touchDispatcher.offTouchMove(this._touchMoveCallback);
this._touchDispatcher.offTouchEnd(this._touchEndCallback);
this._touchDispatcher.offTouchCancel(this._touchCancelCallback);
this._touchDispatcher = null;
this._dragInteraction.detachFrom(this._componentAttachedTo);
};
PanZoom.prototype._handleTouchStart = function (ids, idToPoint, e) {
for (var i = 0; i < ids.length && this._touchIds.size() < 2; i++) {
var id = ids[i];
this._touchIds.set(id.toString(), this._translateToComponentSpace(idToPoint[id]));
}
};
PanZoom.prototype._handlePinch = function (ids, idToPoint, e) {
var _this = this;
if (this._touchIds.size() < 2) {
return;
}
var oldPoints = this._touchIds.values();
var oldCornerDistance = PanZoom._pointDistance(oldPoints[0], oldPoints[1]);
if (oldCornerDistance === 0) {
return;
}
ids.forEach(function (id) {
if (_this._touchIds.has(id.toString())) {
_this._touchIds.set(id.toString(), _this._translateToComponentSpace(idToPoint[id]));
}
});
var points = this._touchIds.values();
var newCornerDistance = PanZoom._pointDistance(points[0], points[1]);
if (newCornerDistance === 0) {
return;
}
var magnifyAmount = oldCornerDistance / newCornerDistance;
var normalizedPointDiffs = points.map(function (point, i) {
return { x: (point.x - oldPoints[i].x) / magnifyAmount, y: (point.y - oldPoints[i].y) / magnifyAmount };
});
this.xScales().forEach(function (xScale) {
magnifyAmount = _this._constrainedZoomAmount(xScale, magnifyAmount);
});
this.yScales().forEach(function (yScale) {
magnifyAmount = _this._constrainedZoomAmount(yScale, magnifyAmount);
});
var constrainedPoints = oldPoints.map(function (oldPoint, i) {
return {
x: normalizedPointDiffs[i].x * magnifyAmount + oldPoint.x,
y: normalizedPointDiffs[i].y * magnifyAmount + oldPoint.y
};
});
var oldCenterPoint = PanZoom._centerPoint(oldPoints[0], oldPoints[1]);
var translateAmountX = oldCenterPoint.x - ((constrainedPoints[0].x + constrainedPoints[1].x) / 2);
this.xScales().forEach(function (xScale) {
_this._magnifyScale(xScale, magnifyAmount, oldCenterPoint.x);
_this._translateScale(xScale, translateAmountX);
});
var translateAmountY = oldCenterPoint.y - ((constrainedPoints[0].y + constrainedPoints[1].y) / 2);
this.yScales().forEach(function (yScale) {
_this._magnifyScale(yScale, magnifyAmount, oldCenterPoint.y);
_this._translateScale(yScale, translateAmountY);
});
};
PanZoom._centerPoint = function (point1, point2) {
var leftX = Math.min(point1.x, point2.x);
var rightX = Math.max(point1.x, point2.x);
var topY = Math.min(point1.y, point2.y);
var bottomY = Math.max(point1.y, point2.y);
return { x: (leftX + rightX) / 2, y: (bottomY + topY) / 2 };
};
PanZoom._pointDistance = function (point1, point2) {
var leftX = Math.min(point1.x, point2.x);
var rightX = Math.max(point1.x, point2.x);
var topY = Math.min(point1.y, point2.y);
var bottomY = Math.max(point1.y, point2.y);
return Math.sqrt(Math.pow(rightX - leftX, 2) + Math.pow(bottomY - topY, 2));
};
PanZoom.prototype._handleTouchEnd = function (ids, idToPoint, e) {
var _this = this;
ids.forEach(function (id) {
_this._touchIds.remove(id.toString());
});
};
PanZoom.prototype._magnifyScale = function (scale, magnifyAmount, centerValue) {
var magnifyTransform = function (rangeValue) { return scale.invert(centerValue - (centerValue - rangeValue) * magnifyAmount); };
scale.domain(scale.range().map(magnifyTransform));
};
PanZoom.prototype._translateScale = function (scale, translateAmount) {
var translateTransform = function (rangeValue) { return scale.invert(rangeValue + translateAmount); };
scale.domain(scale.range().map(translateTransform));
};
PanZoom.prototype._handleWheelEvent = function (p, e) {
var _this = this;
var translatedP = this._translateToComponentSpace(p);
if (this._isInsideComponent(translatedP)) {
e.preventDefault();
var deltaPixelAmount = e.deltaY * (e.deltaMode ? PanZoom._PIXELS_PER_LINE : 1);
var zoomAmount = Math.pow(2, deltaPixelAmount * .002);
this.xScales().forEach(function (xScale) {
zoomAmount = _this._constrainedZoomAmount(xScale, zoomAmount);
});
this.yScales().forEach(function (yScale) {
zoomAmount = _this._constrainedZoomAmount(yScale, zoomAmount);
});
this.xScales().forEach(function (xScale) {
_this._magnifyScale(xScale, zoomAmount, translatedP.x);
});
this.yScales().forEach(function (yScale) {
_this._magnifyScale(yScale, zoomAmount, translatedP.y);
});
}
};
PanZoom.prototype._constrainedZoomAmount = function (scale, zoomAmount) {
var extentIncreasing = zoomAmount > 1;
var boundingDomainExtent = extentIncreasing ? this.maxDomainExtent(scale) : this.minDomainExtent(scale);
if (boundingDomainExtent == null) {
return zoomAmount;
}
var scaleDomain = scale.domain();
var domainExtent = Math.abs(scaleDomain[1] - scaleDomain[0]);
var compareF = extentIncreasing ? Math.min : Math.max;
return compareF(zoomAmount, boundingDomainExtent / domainExtent);
};
PanZoom.prototype._setupDragInteraction = function () {
var _this = this;
this._dragInteraction.constrainedToComponent(false);
var lastDragPoint;
this._dragInteraction.onDragStart(function () { return lastDragPoint = null; });
this._dragInteraction.onDrag(function (startPoint, endPoint) {
if (_this._touchIds.size() >= 2) {
return;
}
var translateAmountX = (lastDragPoint == null ? startPoint.x : lastDragPoint.x) - endPoint.x;
_this.xScales().forEach(function (xScale) {
_this._translateScale(xScale, translateAmountX);
});
var translateAmountY = (lastDragPoint == null ? startPoint.y : lastDragPoint.y) - endPoint.y;
_this.yScales().forEach(function (yScale) {
_this._translateScale(yScale, translateAmountY);
});
lastDragPoint = endPoint;
});
};
PanZoom.prototype._nonLinearScaleWithExtents = function (scale) {
return this.minDomainExtent(scale) != null && this.maxDomainExtent(scale) != null &&
!(scale instanceof Plottable.Scales.Linear) && !(scale instanceof Plottable.Scales.Time);
};
PanZoom.prototype.xScales = function (xScales) {
var _this = this;
if (xScales == null) {
var scales = [];
this._xScales.forEach(function (xScale) {
scales.push(xScale);
});
return scales;
}
this._xScales = new Plottable.Utils.Set();
xScales.forEach(function (xScale) {
_this.addXScale(xScale);
});
return this;
};
PanZoom.prototype.yScales = function (yScales) {
var _this = this;
if (yScales == null) {
var scales = [];
this._yScales.forEach(function (yScale) {
scales.push(yScale);
});
return scales;
}
this._yScales = new Plottable.Utils.Set();
yScales.forEach(function (yScale) {
_this.addYScale(yScale);
});
return this;
};
/**
* Adds an x scale to this PanZoom Interaction
*
* @param {QuantitativeScale<any>} An x scale to add
* @returns {Interactions.PanZoom} The calling PanZoom Interaction.
*/
PanZoom.prototype.addXScale = function (xScale) {
this._xScales.add(xScale);
return this;
};
/**
* Removes an x scale from this PanZoom Interaction
*
* @param {QuantitativeScale<any>} An x scale to remove
* @returns {Interactions.PanZoom} The calling PanZoom Interaction.
*/
PanZoom.prototype.removeXScale = function (xScale) {
this._xScales.delete(xScale);
this._minDomainExtents.delete(xScale);
this._maxDomainExtents.delete(xScale);
return this;
};
/**
* Adds a y scale to this PanZoom Interaction
*
* @param {QuantitativeScale<any>} A y scale to add
* @returns {Interactions.PanZoom} The calling PanZoom Interaction.
*/
PanZoom.prototype.addYScale = function (yScale) {
this._yScales.add(yScale);
return this;
};
/**
* Removes a y scale from this PanZoom Interaction
*
* @param {QuantitativeScale<any>} A y scale to remove
* @returns {Interactions.PanZoom} The calling PanZoom Interaction.
*/
PanZoom.prototype.removeYScale = function (yScale) {
this._yScales.delete(yScale);
this._minDomainExtents.delete(yScale);
this._maxDomainExtents.delete(yScale);
return this;
};
PanZoom.prototype.minDomainExtent = function (quantitativeScale, minDomainExtent) {
if (minDomainExtent == null) {
return this._minDomainExtents.get(quantitativeScale);
}
if (minDomainExtent.valueOf() < 0) {
throw new Error("extent must be non-negative");
}
var maxExtentForScale = this.maxDomainExtent(quantitativeScale);
if (maxExtentForScale != null && maxExtentForScale.valueOf() < minDomainExtent.valueOf()) {
throw new Error("minDomainExtent must be smaller than maxDomainExtent for the same Scale");
}
if (this._nonLinearScaleWithExtents(quantitativeScale)) {
Plottable.Utils.Window.warn("Panning and zooming with extents on a nonlinear scale may have unintended behavior.");
}
this._minDomainExtents.set(quantitativeScale, minDomainExtent);
return this;
};
PanZoom.prototype.maxDomainExtent = function (quantitativeScale, maxDomainExtent) {
if (maxDomainExtent == null) {
return this._maxDomainExtents.get(quantitativeScale);
}
if (maxDomainExtent.valueOf() <= 0) {
throw new Error("extent must be positive");
}
var minExtentForScale = this.minDomainExtent(quantitativeScale);
if (minExtentForScale != null && maxDomainExtent.valueOf() < minExtentForScale.valueOf()) {
throw new Error("maxDomainExtent must be larger than minDomainExtent for the same Scale");
}
if (this._nonLinearScaleWithExtents(quantitativeScale)) {
Plottable.Utils.Window.warn("Panning and zooming with extents on a nonlinear scale may have unintended behavior.");
}
this._maxDomainExtents.set(quantitativeScale, maxDomainExtent);
return this;
};
/**
* The number of pixels occupied in a line.
*/
PanZoom._PIXELS_PER_LINE = 120;
return PanZoom;
})(Plottable.Interaction);
Interactions.PanZoom = PanZoom;
})(Interactions = Plottable.Interactions || (Plottable.Interactions = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Interactions;
(function (Interactions) {
var Drag = (function (_super) {
__extends(Drag, _super);
function Drag() {
var _this = this;
_super.apply(this, arguments);
this._dragging = false;
this._constrainedToComponent = true;
this._dragStartCallbacks = new Plottable.Utils.CallbackSet();
this._dragCallbacks = new Plottable.Utils.CallbackSet();
this._dragEndCallbacks = new Plottable.Utils.CallbackSet();
this._mouseDownCallback = function (p, e) { return _this._startDrag(p, e); };
this._mouseMoveCallback = function (p, e) { return _this._doDrag(p, e); };
this._mouseUpCallback = function (p, e) { return _this._endDrag(p, e); };
this._touchStartCallback = function (ids, idToPoint, e) { return _this._startDrag(idToPoint[ids[0]], e); };
this._touchMoveCallback = function (ids, idToPoint, e) { return _this._doDrag(idToPoint[ids[0]], e); };
this._touchEndCallback = function (ids, idToPoint, e) { return _this._endDrag(idToPoint[ids[0]], e); };
}
Drag.prototype._anchor = function (component) {
_super.prototype._anchor.call(this, component);
this._mouseDispatcher = Plottable.Dispatchers.Mouse.getDispatcher(this._componentAttachedTo.content().node());
this._mouseDispatcher.onMouseDown(this._mouseDownCallback);
this._mouseDispatcher.onMouseMove(this._mouseMoveCallback);
this._mouseDispatcher.onMouseUp(this._mouseUpCallback);
this._touchDispatcher = Plottable.Dispatchers.Touch.getDispatcher(this._componentAttachedTo.content().node());
this._touchDispatcher.onTouchStart(this._touchStartCallback);
this._touchDispatcher.onTouchMove(this._touchMoveCallback);
this._touchDispatcher.onTouchEnd(this._touchEndCallback);
};
Drag.prototype._unanchor = function () {
_super.prototype._unanchor.call(this);
this._mouseDispatcher.offMouseDown(this._mouseDownCallback);
this._mouseDispatcher.offMouseMove(this._mouseMoveCallback);
this._mouseDispatcher.offMouseUp(this._mouseUpCallback);
this._mouseDispatcher = null;
this._touchDispatcher.offTouchStart(this._touchStartCallback);
this._touchDispatcher.offTouchMove(this._touchMoveCallback);
this._touchDispatcher.offTouchEnd(this._touchEndCallback);
this._touchDispatcher = null;
};
Drag.prototype._translateAndConstrain = function (p) {
var translatedP = this._translateToComponentSpace(p);
if (!this._constrainedToComponent) {
return translatedP;
}
return {
x: Plottable.Utils.Math.clamp(translatedP.x, 0, this._componentAttachedTo.width()),
y: Plottable.Utils.Math.clamp(translatedP.y, 0, this._componentAttachedTo.height())
};
};
Drag.prototype._startDrag = function (point, event) {
if (event instanceof MouseEvent && event.button !== 0) {
return;
}
var translatedP = this._translateToComponentSpace(point);
if (this._isInsideComponent(translatedP)) {
event.preventDefault();
this._dragging = true;
this._dragOrigin = translatedP;
this._dragStartCallbacks.callCallbacks(this._dragOrigin);
}
};
Drag.prototype._doDrag = function (point, event) {
if (this._dragging) {
this._dragCallbacks.callCallbacks(this._dragOrigin, this._translateAndConstrain(point));
}
};
Drag.prototype._endDrag = function (point, event) {
if (event instanceof MouseEvent && event.button !== 0) {
return;
}
if (this._dragging) {
this._dragging = false;
this._dragEndCallbacks.callCallbacks(this._dragOrigin, this._translateAndConstrain(point));
}
};
Drag.prototype.constrainedToComponent = function (constrainedToComponent) {
if (constrainedToComponent == null) {
return this._constrainedToComponent;
}
this._constrainedToComponent = constrainedToComponent;
return this;
};
/**
* Adds a callback to be called when dragging starts.
*
* @param {DragCallback} callback
* @returns {Drag} The calling Drag Interaction.
*/
Drag.prototype.onDragStart = function (callback) {
this._dragStartCallbacks.add(callback);
return this;
};
/**
* Removes a callback that would be called when dragging starts.
*
* @param {DragCallback} callback
* @returns {Drag} The calling Drag Interaction.
*/
Drag.prototype.offDragStart = function (callback) {
this._dragStartCallbacks.delete(callback);
return this;
};
/**
* Adds a callback to be called during dragging.
*
* @param {DragCallback} callback
* @returns {Drag} The calling Drag Interaction.
*/
Drag.prototype.onDrag = function (callback) {
this._dragCallbacks.add(callback);
return this;
};
/**
* Removes a callback that would be called during dragging.
*
* @param {DragCallback} callback
* @returns {Drag} The calling Drag Interaction.
*/
Drag.prototype.offDrag = function (callback) {
this._dragCallbacks.delete(callback);
return this;
};
/**
* Adds a callback to be called when dragging ends.
*
* @param {DragCallback} callback
* @returns {Drag} The calling Drag Interaction.
*/
Drag.prototype.onDragEnd = function (callback) {
this._dragEndCallbacks.add(callback);
return this;
};
/**
* Removes a callback that would be called when dragging ends.
*
* @param {DragCallback} callback
* @returns {Drag} The calling Drag Interaction.
*/
Drag.prototype.offDragEnd = function (callback) {
this._dragEndCallbacks.delete(callback);
return this;
};
return Drag;
})(Plottable.Interaction);
Interactions.Drag = Drag;
})(Interactions = Plottable.Interactions || (Plottable.Interactions = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Components;
(function (Components) {
var DragBoxLayer = (function (_super) {
__extends(DragBoxLayer, _super);
/**
* Constructs a DragBoxLayer.
*
* A DragBoxLayer is a SelectionBoxLayer with a built-in Drag Interaction.
* A drag gesture will set the Bounds of the box.
* If resizing is enabled using resizable(true), the edges of box can be repositioned.
*
* @constructor
*/
function DragBoxLayer() {
_super.call(this);
this._detectionRadius = 3;
this._resizable = false;
this._movable = false;
this._hasCorners = true;
/*
* Enable clipPath to hide _detectionEdge s and _detectionCorner s
* that overlap with the edge of the DragBoxLayer. This prevents the
* user's cursor from changing outside the DragBoxLayer, where they
* wouldn't be able to grab the edges or corners for resizing.
*/
this._clipPathEnabled = true;
this.addClass("drag-box-layer");
this._dragInteraction = new Plottable.Interactions.Drag();
this._setUpCallbacks();
this._dragInteraction.attachTo(this);
this._dragStartCallbacks = new Plottable.Utils.CallbackSet();
this._dragCallbacks = new Plottable.Utils.CallbackSet();
this._dragEndCallbacks = new Plottable.Utils.CallbackSet();
}
DragBoxLayer.prototype._setUpCallbacks = function () {
var _this = this;
var resizingEdges;
var topLeft;
var bottomRight;
var lastEndPoint;
var DRAG_MODES = {
newBox: 0,
resize: 1,
move: 2
};
var mode = DRAG_MODES.newBox;
this._dragInteraction.onDragStart(function (startPoint) {
resizingEdges = _this._getResizingEdges(startPoint);
var bounds = _this.bounds();
var isInsideBox = bounds.topLeft.x <= startPoint.x && startPoint.x <= bounds.bottomRight.x &&
bounds.topLeft.y <= startPoint.y && startPoint.y <= bounds.bottomRight.y;
if (_this.boxVisible() && (resizingEdges.top || resizingEdges.bottom || resizingEdges.left || resizingEdges.right)) {
mode = DRAG_MODES.resize;
}
else if (_this.boxVisible() && _this.movable() && isInsideBox) {
mode = DRAG_MODES.move;
}
else {
mode = DRAG_MODES.newBox;
_this.bounds({
topLeft: startPoint,
bottomRight: startPoint
});
}
_this.boxVisible(true);
bounds = _this.bounds();
// copy points so changes to topLeft and bottomRight don't mutate bounds
topLeft = { x: bounds.topLeft.x, y: bounds.topLeft.y };
bottomRight = { x: bounds.bottomRight.x, y: bounds.bottomRight.y };
lastEndPoint = startPoint;
_this._dragStartCallbacks.callCallbacks(bounds);
});
this._dragInteraction.onDrag(function (startPoint, endPoint) {
switch (mode) {
case DRAG_MODES.newBox:
bottomRight.x = endPoint.x;
bottomRight.y = endPoint.y;
break;
case DRAG_MODES.resize:
if (resizingEdges.bottom) {
bottomRight.y = endPoint.y;
}
else if (resizingEdges.top) {
topLeft.y = endPoint.y;
}
if (resizingEdges.right) {
bottomRight.x = endPoint.x;
}
else if (resizingEdges.left) {
topLeft.x = endPoint.x;
}
break;
case DRAG_MODES.move:
var dx = endPoint.x - lastEndPoint.x;
var dy = endPoint.y - lastEndPoint.y;
topLeft.x += dx;
topLeft.y += dy;
bottomRight.x += dx;
bottomRight.y += dy;
lastEndPoint = endPoint;
break;
}
_this.bounds({
topLeft: topLeft,
bottomRight: bottomRight
});
_this._dragCallbacks.callCallbacks(_this.bounds());
});
this._dragInteraction.onDragEnd(function (startPoint, endPoint) {
if (mode === DRAG_MODES.newBox && startPoint.x === endPoint.x && startPoint.y === endPoint.y) {
_this.boxVisible(false);
}
_this._dragEndCallbacks.callCallbacks(_this.bounds());
});
};
DragBoxLayer.prototype._setup = function () {
var _this = this;
_super.prototype._setup.call(this);
var createLine = function () { return _this._box.append("line").style({
"opacity": 0,
"stroke": "pink"
}); };
this._detectionEdgeT = createLine().classed("drag-edge-tb", true);
this._detectionEdgeB = createLine().classed("drag-edge-tb", true);
this._detectionEdgeL = createLine().classed("drag-edge-lr", true);
this._detectionEdgeR = createLine().classed("drag-edge-lr", true);
if (this._hasCorners) {
var createCorner = function () { return _this._box.append("circle")
.style({
"opacity": 0,
"fill": "pink"
}); };
this._detectionCornerTL = createCorner().classed("drag-corner-tl", true);
this._detectionCornerTR = createCorner().classed("drag-corner-tr", true);
this._detectionCornerBL = createCorner().classed("drag-corner-bl", true);
this._detectionCornerBR = createCorner().classed("drag-corner-br", true);
}
};
DragBoxLayer.prototype._getResizingEdges = function (p) {
var edges = {
top: false,
bottom: false,
left: false,
right: false
};
if (!this.resizable()) {
return edges;
}
var bounds = this.bounds();
var t = bounds.topLeft.y;
var b = bounds.bottomRight.y;
var l = bounds.topLeft.x;
var r = bounds.bottomRight.x;
var rad = this._detectionRadius;
if (l - rad <= p.x && p.x <= r + rad) {
edges.top = (t - rad <= p.y && p.y <= t + rad);
edges.bottom = (b - rad <= p.y && p.y <= b + rad);
}
if (t - rad <= p.y && p.y <= b + rad) {
edges.left = (l - rad <= p.x && p.x <= l + rad);
edges.right = (r - rad <= p.x && p.x <= r + rad);
}
return edges;
};
DragBoxLayer.prototype.renderImmediately = function () {
_super.prototype.renderImmediately.call(this);
if (this.boxVisible()) {
var bounds = this.bounds();
var t = bounds.topLeft.y;
var b = bounds.bottomRight.y;
var l = bounds.topLeft.x;
var r = bounds.bottomRight.x;
this._detectionEdgeT.attr({
x1: l, y1: t, x2: r, y2: t,
"stroke-width": this._detectionRadius * 2
});
this._detectionEdgeB.attr({
x1: l, y1: b, x2: r, y2: b,
"stroke-width": this._detectionRadius * 2
});
this._detectionEdgeL.attr({
x1: l, y1: t, x2: l, y2: b,
"stroke-width": this._detectionRadius * 2
});
this._detectionEdgeR.attr({
x1: r, y1: t, x2: r, y2: b,
"stroke-width": this._detectionRadius * 2
});
if (this._hasCorners) {
this._detectionCornerTL.attr({ cx: l, cy: t, r: this._detectionRadius });
this._detectionCornerTR.attr({ cx: r, cy: t, r: this._detectionRadius });
this._detectionCornerBL.attr({ cx: l, cy: b, r: this._detectionRadius });
this._detectionCornerBR.attr({ cx: r, cy: b, r: this._detectionRadius });
}
return this;
}
};
DragBoxLayer.prototype.detectionRadius = function (r) {
if (r == null) {
return this._detectionRadius;
}
if (r < 0) {
throw new Error("detection radius cannot be negative.");
}
this._detectionRadius = r;
this.render();
return this;
};
DragBoxLayer.prototype.resizable = function (canResize) {
if (canResize == null) {
return this._resizable;
}
this._resizable = canResize;
this._setResizableClasses(canResize);
return this;
};
// Sets resizable classes. Overridden by subclasses that only resize in one dimension.
DragBoxLayer.prototype._setResizableClasses = function (canResize) {
if (canResize) {
this.addClass("x-resizable");
this.addClass("y-resizable");
}
else {
this.removeClass("x-resizable");
this.removeClass("y-resizable");
}
};
DragBoxLayer.prototype.movable = function (movable) {
if (movable == null) {
return this._movable;
}
this._movable = movable;
if (movable) {
this.addClass("movable");
}
else {
this.removeClass("movable");
}
return this;
};
/**
* Sets the callback to be called when dragging starts.
*
* @param {DragBoxCallback} callback
* @returns {DragBoxLayer} The calling DragBoxLayer.
*/
DragBoxLayer.prototype.onDragStart = function (callback) {
this._dragStartCallbacks.add(callback);
return this;
};
/**
* Removes a callback to be called when dragging starts.
*
* @param {DragBoxCallback} callback
* @returns {DragBoxLayer} The calling DragBoxLayer.
*/
DragBoxLayer.prototype.offDragStart = function (callback) {
this._dragStartCallbacks.delete(callback);
return this;
};
/**
* Sets a callback to be called during dragging.
*
* @param {DragBoxCallback} callback
* @returns {DragBoxLayer} The calling DragBoxLayer.
*/
DragBoxLayer.prototype.onDrag = function (callback) {
this._dragCallbacks.add(callback);
return this;
};
/**
* Removes a callback to be called during dragging.
*
* @param {DragBoxCallback} callback
* @returns {DragBoxLayer} The calling DragBoxLayer.
*/
DragBoxLayer.prototype.offDrag = function (callback) {
this._dragCallbacks.delete(callback);
return this;
};
/**
* Sets a callback to be called when dragging ends.
*
* @param {DragBoxCallback} callback
* @returns {DragBoxLayer} The calling DragBoxLayer.
*/
DragBoxLayer.prototype.onDragEnd = function (callback) {
this._dragEndCallbacks.add(callback);
return this;
};
/**
* Removes a callback to be called when dragging ends.
*
* @param {DragBoxCallback} callback
* @returns {DragBoxLayer} The calling DragBoxLayer.
*/
DragBoxLayer.prototype.offDragEnd = function (callback) {
this._dragEndCallbacks.delete(callback);
return this;
};
/**
* Gets the internal Interactions.Drag of the DragBoxLayer.
*/
DragBoxLayer.prototype.dragInteraction = function () {
return this._dragInteraction;
};
DragBoxLayer.prototype.enabled = function (enabled) {
if (enabled == null) {
return this._dragInteraction.enabled();
}
this._dragInteraction.enabled(enabled);
return this;
};
return DragBoxLayer;
})(Components.SelectionBoxLayer);
Components.DragBoxLayer = DragBoxLayer;
})(Components = Plottable.Components || (Plottable.Components = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Components;
(function (Components) {
var XDragBoxLayer = (function (_super) {
__extends(XDragBoxLayer, _super);
/**
* An XDragBoxLayer is a DragBoxLayer whose size can only be set in the X-direction.
* The y-values of the bounds() are always set to 0 and the height() of the XDragBoxLayer.
*
* @constructor
*/
function XDragBoxLayer() {
_super.call(this);
this.addClass("x-drag-box-layer");
this._hasCorners = false;
}
XDragBoxLayer.prototype.computeLayout = function (origin, availableWidth, availableHeight) {
_super.prototype.computeLayout.call(this, origin, availableWidth, availableHeight);
this.bounds(this.bounds()); // set correct bounds when width/height changes
return this;
};
XDragBoxLayer.prototype._setBounds = function (newBounds) {
_super.prototype._setBounds.call(this, {
topLeft: { x: newBounds.topLeft.x, y: 0 },
bottomRight: { x: newBounds.bottomRight.x, y: this.height() }
});
};
XDragBoxLayer.prototype._setResizableClasses = function (canResize) {
if (canResize) {
this.addClass("x-resizable");
}
else {
this.removeClass("x-resizable");
}
};
XDragBoxLayer.prototype.yScale = function (yScale) {
if (yScale == null) {
throw new Error("XDragBoxLayer has no yScale");
}
throw new Error("yScales cannot be set on an XDragBoxLayer");
};
XDragBoxLayer.prototype.yExtent = function () {
throw new Error("XDragBoxLayer has no yExtent");
};
return XDragBoxLayer;
})(Components.DragBoxLayer);
Components.XDragBoxLayer = XDragBoxLayer;
})(Components = Plottable.Components || (Plottable.Components = {}));
})(Plottable || (Plottable = {}));
///<reference path="../reference.ts" />
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var Plottable;
(function (Plottable) {
var Components;
(function (Components) {
var YDragBoxLayer = (function (_super) {
__extends(YDragBoxLayer, _super);
/**
* A YDragBoxLayer is a DragBoxLayer whose size can only be set in the Y-direction.
* The x-values of the bounds() are always set to 0 and the width() of the YDragBoxLayer.
*
* @constructor
*/
function YDragBoxLayer() {
_super.call(this);
this.addClass("y-drag-box-layer");
this._hasCorners = false;
}
YDragBoxLayer.prototype.computeLayout = function (origin, availableWidth, availableHeight) {
_super.prototype.computeLayout.call(this, origin, availableWidth, availableHeight);
this.bounds(this.bounds()); // set correct bounds when width/height changes
return this;
};
YDragBoxLayer.prototype._setBounds = function (newBounds) {
_super.prototype._setBounds.call(this, {
topLeft: { x: 0, y: newBounds.topLeft.y },
bottomRight: { x: this.width(), y: newBounds.bottomRight.y }
});
};
YDragBoxLayer.prototype._setResizableClasses = function (canResize) {
if (canResize) {
this.addClass("y-resizable");
}
else {
this.removeClass("y-resizable");
}
};
YDragBoxLayer.prototype.xScale = function (xScale) {
if (xScale == null) {
throw new Error("YDragBoxLayer has no xScale");
}
throw new Error("xScales cannot be set on an YDragBoxLayer");
};
YDragBoxLayer.prototype.xExtent = function () {
throw new Error("YDragBoxLayer has no xExtent");
};
return YDragBoxLayer;
})(Components.DragBoxLayer);
Components.YDragBoxLayer = YDragBoxLayer;
})(Components = Plottable.Components || (Plottable.Components = {}));
})(Plottable || (Plottable = {}));
/*!
SVG Typewriter 0.3.0 (https://github.com/palantir/svg-typewriter)
Copyright 2014 Palantir Technologies
Licensed under MIT (https://github.com/palantir/svg-typewriter/blob/develop/LICENSE)
*/
///<reference path="../reference.ts" />
var SVGTypewriter;
(function (SVGTypewriter) {
var Utils;
(function (Utils) {
var Methods;
(function (Methods) {
/**
* Check if two arrays are equal by strict equality.
*/
function arrayEq(a, b) {
// Technically, null and undefined are arrays too
if (a == null || b == null) {
return a === b;
}
if (a.length !== b.length) {
return false;
}
for (var i = 0; i < a.length; i++) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}
Methods.arrayEq = arrayEq;
/**
* @param {any} a Object to check against b for equality.
* @param {any} b Object to check against a for equality.
*
* @returns {boolean} whether or not two objects share the same keys, and
* values associated with those keys. Values will be compared
* with ===.
*/
function objEq(a, b) {
if (a == null || b == null) {
return a === b;
}
var keysA = Object.keys(a).sort();
var keysB = Object.keys(b).sort();
var valuesA = keysA.map(function (k) { return a[k]; });
var valuesB = keysB.map(function (k) { return b[k]; });
return arrayEq(keysA, keysB) && arrayEq(valuesA, valuesB);
}
Methods.objEq = objEq;
})(Methods = Utils.Methods || (Utils.Methods = {}));
})(Utils = SVGTypewriter.Utils || (SVGTypewriter.Utils = {}));
})(SVGTypewriter || (SVGTypewriter = {}));
var SVGTypewriter;
(function (SVGTypewriter) {
var Utils;
(function (Utils) {
var DOM;
(function (DOM) {
function transform(s, x, y) {
var xform = d3.transform(s.attr("transform"));
if (x == null) {
return xform.translate;
}
else {
y = (y == null) ? 0 : y;
xform.translate[0] = x;
xform.translate[1] = y;
s.attr("transform", xform.toString());
return s;
}
}
DOM.transform = transform;
function getBBox(element) {
var bbox;
try {
bbox = element.node().getBBox();
}
catch (err) {
bbox = {
x: 0,
y: 0,
width: 0,
height: 0
};
}
return bbox;
}
DOM.getBBox = getBBox;
})(DOM = Utils.DOM || (Utils.DOM = {}));
})(Utils = SVGTypewriter.Utils || (SVGTypewriter.Utils = {}));
})(SVGTypewriter || (SVGTypewriter = {}));
///<reference path="../reference.ts" />
var SVGTypewriter;
(function (SVGTypewriter) {
var Utils;
(function (Utils) {
var Cache = (function () {
/**
* @constructor
*
* @param {string} compute The function whose results will be cached.
* @param {(v: T, w: T) => boolean} [valueEq]
* Used to determine if the value of canonicalKey has changed.
* If omitted, defaults to === comparision.
*/
function Cache(compute, valueEq) {
if (valueEq === void 0) { valueEq = function (v, w) { return v === w; }; }
this.cache = d3.map();
this.compute = compute;
this.valueEq = valueEq;
}
/**
* Attempt to look up k in the cache, computing the result if it isn't
* found.
*
* @param {string} k The key to look up in the cache.
* @return {T} The value associated with k; the result of compute(k).
*/
Cache.prototype.get = function (k) {
if (!this.cache.has(k)) {
this.cache.set(k, this.compute(k));
}
return this.cache.get(k);
};
/**
* Reset the cache empty.
*
* @return {Cache<T>} The calling Cache.
*/
Cache.prototype.clear = function () {
this.cache = d3.map();
return this;
};
return Cache;
})();
Utils.Cache = Cache;
})(Utils = SVGTypewriter.Utils || (SVGTypewriter.Utils = {}));
})(SVGTypewriter || (SVGTypewriter = {}));
///<reference path="../reference.ts" />
var SVGTypewriter;
(function (SVGTypewriter) {
var Utils;
(function (Utils) {
var Tokenizer = (function () {
function Tokenizer() {
this.WordDividerRegExp = new RegExp("\\W");
this.WhitespaceRegExp = new RegExp("\\s");
}
Tokenizer.prototype.tokenize = function (line) {
var _this = this;
return line.split("").reduce(function (tokens, c) { return tokens.slice(0, -1).concat(_this.shouldCreateNewToken(tokens[tokens.length - 1], c)); }, [""]);
};
Tokenizer.prototype.shouldCreateNewToken = function (token, newCharacter) {
if (!token) {
return [newCharacter];
}
var lastCharacter = token[token.length - 1];
if (this.WhitespaceRegExp.test(lastCharacter) && this.WhitespaceRegExp.test(newCharacter)) {
return [token + newCharacter];
}
else if (this.WhitespaceRegExp.test(lastCharacter) || this.WhitespaceRegExp.test(newCharacter)) {
return [token, newCharacter];
}
else if (!(this.WordDividerRegExp.test(lastCharacter) || this.WordDividerRegExp.test(newCharacter))) {
return [token + newCharacter];
}
else if (lastCharacter === newCharacter) {
return [token + newCharacter];
}
else {
return [token, newCharacter];
}
};
return Tokenizer;
})();
Utils.Tokenizer = Tokenizer;
})(Utils = SVGTypewriter.Utils || (SVGTypewriter.Utils = {}));
})(SVGTypewriter || (SVGTypewriter = {}));
///<reference path="../reference.ts" />
var SVGTypewriter;
(function (SVGTypewriter) {
var Utils;
(function (Utils) {
var StringMethods;
(function (StringMethods) {
/**
* Treat all sequences of consecutive whitespace as a single " ".
*/
function combineWhitespace(str) {
return str.replace(/\s+/g, " ");
}
StringMethods.combineWhitespace = combineWhitespace;
function isNotEmptyString(str) {
return str && str.trim() !== "";
}
StringMethods.isNotEmptyString = isNotEmptyString;
function trimStart(str, c) {
if (!str) {
return str;
}
var chars = str.split("");
var reduceFunction = c ? function (s) { return s.split(c).some(isNotEmptyString); } : isNotEmptyString;
return chars.reduce(function (s, c) { return reduceFunction(s + c) ? s + c : s; }, "");
}
StringMethods.trimStart = trimStart;
function trimEnd(str, c) {
if (!str) {
return str;
}
var reversedChars = str.split("");
reversedChars.reverse();
reversedChars = trimStart(reversedChars.join(""), c).split("");
reversedChars.reverse();
return reversedChars.join("");
}
StringMethods.trimEnd = trimEnd;
})(StringMethods = Utils.StringMethods || (Utils.StringMethods = {}));
})(Utils = SVGTypewriter.Utils || (SVGTypewriter.Utils = {}));
})(SVGTypewriter || (SVGTypewriter = {}));
///<reference path="../reference.ts" />
var SVGTypewriter;
(function (SVGTypewriter) {
var Animators;
(function (Animators) {
var BaseAnimator = (function () {
function BaseAnimator() {
this.duration(BaseAnimator.DEFAULT_DURATION_MILLISECONDS);
this.delay(0);
this.easing(BaseAnimator.DEFAULT_EASING);
this.moveX(0);
this.moveY(0);
}
BaseAnimator.prototype.animate = function (selection) {
var xForm = d3.transform("");
xForm.translate = [this.moveX(), this.moveY()];
selection.attr("transform", xForm.toString());
xForm.translate = [0, 0];
return this._animate(selection, { transform: xForm.toString() });
};
BaseAnimator.prototype._animate = function (selection, attr) {
return selection.transition().ease(this.easing()).duration(this.duration()).delay(this.delay()).attr(attr);
};
BaseAnimator.prototype.duration = function (duration) {
if (duration == null) {
return this._duration;
}
else {
this._duration = duration;
return this;
}
};
BaseAnimator.prototype.moveX = function (shift) {
if (shift == null) {
return this._moveX;
}
else {
this._moveX = shift;
return this;
}
};
BaseAnimator.prototype.moveY = function (shift) {
if (shift == null) {
return this._moveY;
}
else {
this._moveY = shift;
return this;
}
};
BaseAnimator.prototype.delay = function (delay) {
if (delay == null) {
return this._delay;
}
else {
this._delay = delay;
return this;
}
};
BaseAnimator.prototype.easing = function (easing) {
if (easing == null) {
return this._easing;
}
else {
this._easing = easing;
return this;
}
};
/**
* The default duration of the animation in milliseconds
*/
BaseAnimator.DEFAULT_DURATION_MILLISECONDS = 300;
/**
* The default easing of the animation
*/
BaseAnimator.DEFAULT_EASING = "exp-out";
return BaseAnimator;
})();
Animators.BaseAnimator = BaseAnimator;
})(Animators = SVGTypewriter.Animators || (SVGTypewriter.Animators = {}));
})(SVGTypewriter || (SVGTypewriter = {}));
///<reference path="../reference.ts" />
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var SVGTypewriter;
(function (SVGTypewriter) {
var Animators;
(function (Animators) {
var UnveilAnimator = (function (_super) {
__extends(UnveilAnimator, _super);
function UnveilAnimator() {
this.direction("bottom");
_super.call(this);
}
UnveilAnimator.prototype.direction = function (direction) {
if (direction == null) {
return this._direction;
}
else {
if (UnveilAnimator.SupportedDirections.indexOf(direction) === -1) {
throw new Error("unsupported direction - " + direction);
}
this._direction = direction;
return this;
}
};
UnveilAnimator.prototype.animate = function (selection) {
var attr = SVGTypewriter.Utils.DOM.getBBox(selection);
var mask = selection.select(".clip-rect");
mask.attr("width", 0);
mask.attr("height", 0);
switch (this._direction) {
case "top":
mask.attr("y", attr.y + attr.height);
mask.attr("x", attr.x);
mask.attr("width", attr.width);
break;
case "bottom":
mask.attr("y", attr.y);
mask.attr("x", attr.x);
mask.attr("width", attr.width);
break;
case "left":
mask.attr("y", attr.y);
mask.attr("x", attr.x);
mask.attr("height", attr.height);
break;
case "right":
mask.attr("y", attr.y);
mask.attr("x", attr.x + attr.width);
mask.attr("height", attr.height);
break;
}
this._animate(mask, attr);
return _super.prototype.animate.call(this, selection);
};
UnveilAnimator.SupportedDirections = ["top", "bottom", "left", "right"];
return UnveilAnimator;
})(Animators.BaseAnimator);
Animators.UnveilAnimator = UnveilAnimator;
})(Animators = SVGTypewriter.Animators || (SVGTypewriter.Animators = {}));
})(SVGTypewriter || (SVGTypewriter = {}));
///<reference path="../reference.ts" />
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var SVGTypewriter;
(function (SVGTypewriter) {
var Animators;
(function (Animators) {
var OpacityAnimator = (function (_super) {
__extends(OpacityAnimator, _super);
function OpacityAnimator() {
_super.apply(this, arguments);
}
OpacityAnimator.prototype.animate = function (selection) {
var area = selection.select(".text-area");
area.attr("opacity", 0);
var attr = {
opacity: 1
};
this._animate(area, attr);
return _super.prototype.animate.call(this, selection);
};
return OpacityAnimator;
})(Animators.BaseAnimator);
Animators.OpacityAnimator = OpacityAnimator;
})(Animators = SVGTypewriter.Animators || (SVGTypewriter.Animators = {}));
})(SVGTypewriter || (SVGTypewriter = {}));
///<reference path="../reference.ts" />
var SVGTypewriter;
(function (SVGTypewriter) {
var Wrappers;
(function (Wrappers) {
var Wrapper = (function () {
function Wrapper() {
this.maxLines(Infinity);
this.textTrimming("ellipsis");
this.allowBreakingWords(true);
this._tokenizer = new SVGTypewriter.Utils.Tokenizer();
this._breakingCharacter = "-";
}
Wrapper.prototype.maxLines = function (noLines) {
if (noLines == null) {
return this._maxLines;
}
else {
this._maxLines = noLines;
return this;
}
};
Wrapper.prototype.textTrimming = function (option) {
if (option == null) {
return this._textTrimming;
}
else {
if (option !== "ellipsis" && option !== "none") {
throw new Error(option + " - unsupported text trimming option.");
}
this._textTrimming = option;
return this;
}
};
Wrapper.prototype.allowBreakingWords = function (allow) {
if (allow == null) {
return this._allowBreakingWords;
}
else {
this._allowBreakingWords = allow;
return this;
}
};
Wrapper.prototype.wrap = function (text, measurer, width, height) {
var _this = this;
if (height === void 0) { height = Infinity; }
var initialWrappingResult = {
originalText: text,
wrappedText: "",
noLines: 0,
noBrokeWords: 0,
truncatedText: ""
};
var state = {
wrapping: initialWrappingResult,
currentLine: "",
availableWidth: width,
availableLines: Math.min(Math.floor(height / measurer.measure().height), this._maxLines),
canFitText: true
};
var lines = text.split("\n");
return lines.reduce(function (state, line, i) { return _this.breakLineToFitWidth(state, line, i !== lines.length - 1, measurer); }, state).wrapping;
};
Wrapper.prototype.breakLineToFitWidth = function (state, line, hasNextLine, measurer) {
var _this = this;
if (!state.canFitText && state.wrapping.truncatedText !== "") {
state.wrapping.truncatedText += "\n";
}
var tokens = this._tokenizer.tokenize(line);
state = tokens.reduce(function (state, token) { return _this.wrapNextToken(token, state, measurer); }, state);
var wrappedText = SVGTypewriter.Utils.StringMethods.trimEnd(state.currentLine);
state.wrapping.noLines += +(wrappedText !== "");
if (state.wrapping.noLines === state.availableLines && this._textTrimming !== "none" && hasNextLine) {
var ellipsisResult = this.addEllipsis(wrappedText, state.availableWidth, measurer);
state.wrapping.wrappedText += ellipsisResult.wrappedToken;
state.wrapping.truncatedText += ellipsisResult.remainingToken;
state.canFitText = false;
}
else {
state.wrapping.wrappedText += wrappedText;
}
state.currentLine = "\n";
return state;
};
Wrapper.prototype.canFitToken = function (token, width, measurer) {
var _this = this;
var possibleBreaks = this._allowBreakingWords ? token.split("").map(function (c, i) { return (i !== token.length - 1) ? c + _this._breakingCharacter : c; }) : [token];
return (measurer.measure(token).width <= width) || possibleBreaks.every(function (c) { return measurer.measure(c).width <= width; });
};
Wrapper.prototype.addEllipsis = function (line, width, measurer) {
if (this._textTrimming === "none") {
return {
wrappedToken: line,
remainingToken: ""
};
}
var truncatedLine = line.substring(0).trim();
var lineWidth = measurer.measure(truncatedLine).width;
var ellipsesWidth = measurer.measure("...").width;
var prefix = (line.length > 0 && line[0] === "\n") ? "\n" : "";
if (width <= ellipsesWidth) {
var periodWidth = ellipsesWidth / 3;
var numPeriodsThatFit = Math.floor(width / periodWidth);
return {
wrappedToken: prefix + "...".substr(0, numPeriodsThatFit),
remainingToken: line
};
}
while (lineWidth + ellipsesWidth > width) {
truncatedLine = SVGTypewriter.Utils.StringMethods.trimEnd(truncatedLine.substr(0, truncatedLine.length - 1));
lineWidth = measurer.measure(truncatedLine).width;
}
return {
wrappedToken: prefix + truncatedLine + "...",
remainingToken: SVGTypewriter.Utils.StringMethods.trimEnd(line.substring(truncatedLine.length), "-").trim()
};
};
Wrapper.prototype.wrapNextToken = function (token, state, measurer) {
if (!state.canFitText || state.availableLines === state.wrapping.noLines || !this.canFitToken(token, state.availableWidth, measurer)) {
return this.finishWrapping(token, state, measurer);
}
var remainingToken = token;
while (remainingToken) {
var result = this.breakTokenToFitInWidth(remainingToken, state.currentLine, state.availableWidth, measurer);
state.currentLine = result.line;
remainingToken = result.remainingToken;
if (remainingToken != null) {
state.wrapping.noBrokeWords += +result.breakWord;
++state.wrapping.noLines;
if (state.availableLines === state.wrapping.noLines) {
var ellipsisResult = this.addEllipsis(state.currentLine, state.availableWidth, measurer);
state.wrapping.wrappedText += ellipsisResult.wrappedToken;
state.wrapping.truncatedText += ellipsisResult.remainingToken + remainingToken;
state.currentLine = "\n";
return state;
}
else {
state.wrapping.wrappedText += SVGTypewriter.Utils.StringMethods.trimEnd(state.currentLine);
state.currentLine = "\n";
}
}
}
return state;
};
Wrapper.prototype.finishWrapping = function (token, state, measurer) {
// Token is really long, but we have a space to put part of the word.
if (state.canFitText && state.availableLines !== state.wrapping.noLines && this._allowBreakingWords && this._textTrimming !== "none") {
var res = this.addEllipsis(state.currentLine + token, state.availableWidth, measurer);
state.wrapping.wrappedText += res.wrappedToken;
state.wrapping.truncatedText += res.remainingToken;
state.wrapping.noBrokeWords += +(res.remainingToken.length < token.length);
state.wrapping.noLines += +(res.wrappedToken.length > 0);
state.currentLine = "";
}
else {
state.wrapping.truncatedText += token;
}
state.canFitText = false;
return state;
};
/**
* Breaks single token to fit current line.
* If token contains only whitespaces then they will not be populated to next line.
*/
Wrapper.prototype.breakTokenToFitInWidth = function (token, line, availableWidth, measurer, breakingCharacter) {
if (breakingCharacter === void 0) { breakingCharacter = this._breakingCharacter; }
if (measurer.measure(line + token).width <= availableWidth) {
return {
remainingToken: null,
line: line + token,
breakWord: false
};
}
if (token.trim() === "") {
return {
remainingToken: "",
line: line,
breakWord: false
};
}
if (!this._allowBreakingWords) {
return {
remainingToken: token,
line: line,
breakWord: false
};
}
var fitTokenLength = 0;
while (fitTokenLength < token.length) {
if (measurer.measure(line + token.substring(0, fitTokenLength + 1) + breakingCharacter).width <= availableWidth) {
++fitTokenLength;
}
else {
break;
}
}
var suffix = "";
if (fitTokenLength > 0) {
suffix = breakingCharacter;
}
return {
remainingToken: token.substring(fitTokenLength),
line: line + token.substring(0, fitTokenLength) + suffix,
breakWord: fitTokenLength > 0
};
};
return Wrapper;
})();
Wrappers.Wrapper = Wrapper;
})(Wrappers = SVGTypewriter.Wrappers || (SVGTypewriter.Wrappers = {}));
})(SVGTypewriter || (SVGTypewriter = {}));
///<reference path="../reference.ts" />
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var SVGTypewriter;
(function (SVGTypewriter) {
var Wrappers;
(function (Wrappers) {
var SingleLineWrapper = (function (_super) {
__extends(SingleLineWrapper, _super);
function SingleLineWrapper() {
_super.apply(this, arguments);
}
SingleLineWrapper.prototype.wrap = function (text, measurer, width, height) {
var _this = this;
if (height === void 0) { height = Infinity; }
var lines = text.split("\n");
if (lines.length > 1) {
throw new Error("SingleLineWrapper is designed to work only on single line");
}
var wrapFN = function (w) { return _super.prototype.wrap.call(_this, text, measurer, w, height); };
var result = wrapFN(width);
if (result.noLines < 2) {
return result;
}
var left = 0;
var right = width;
for (var i = 0; i < SingleLineWrapper.NO_WRAP_ITERATIONS && right > left; ++i) {
var currentWidth = (right + left) / 2;
var currentResult = wrapFN(currentWidth);
if (this.areSameResults(result, currentResult)) {
right = currentWidth;
result = currentResult;
}
else {
left = currentWidth;
}
}
return result;
};
SingleLineWrapper.prototype.areSameResults = function (one, two) {
return one.noLines === two.noLines && one.truncatedText === two.truncatedText;
};
SingleLineWrapper.NO_WRAP_ITERATIONS = 5;
return SingleLineWrapper;
})(Wrappers.Wrapper);
Wrappers.SingleLineWrapper = SingleLineWrapper;
})(Wrappers = SVGTypewriter.Wrappers || (SVGTypewriter.Wrappers = {}));
})(SVGTypewriter || (SVGTypewriter = {}));
///<reference path="reference.ts" />
var SVGTypewriter;
(function (SVGTypewriter) {
var Writers;
(function (Writers) {
var Writer = (function () {
function Writer(measurer, wrapper) {
this._writerID = Writer.nextID++;
this._elementID = 0;
this.measurer(measurer);
if (wrapper) {
this.wrapper(wrapper);
}
this.addTitleElement(false);
}
Writer.prototype.measurer = function (newMeasurer) {
this._measurer = newMeasurer;
return this;
};
Writer.prototype.wrapper = function (newWrapper) {
this._wrapper = newWrapper;
return this;
};
Writer.prototype.addTitleElement = function (add) {
this._addTitleElement = add;
return this;
};
Writer.prototype.writeLine = function (line, g, width, xAlign, yOffset) {
var textEl = g.append("text");
textEl.text(line);
var xOffset = width * Writer.XOffsetFactor[xAlign];
var anchor = Writer.AnchorConverter[xAlign];
textEl.attr("text-anchor", anchor).classed("text-line", true);
SVGTypewriter.Utils.DOM.transform(textEl, xOffset, yOffset).attr("y", "-0.25em");
;
};
Writer.prototype.writeText = function (text, writingArea, width, height, xAlign, yAlign) {
var _this = this;
var lines = text.split("\n");
var lineHeight = this._measurer.measure().height;
var yOffset = Writer.YOffsetFactor[yAlign] * (height - lines.length * lineHeight);
lines.forEach(function (line, i) {
_this.writeLine(line, writingArea, width, xAlign, (i + 1) * lineHeight + yOffset);
});
};
Writer.prototype.write = function (text, width, height, options) {
if (Writer.SupportedRotation.indexOf(options.textRotation) === -1) {
throw new Error("unsupported rotation - " + options.textRotation);
}
var orientHorizontally = Math.abs(Math.abs(options.textRotation) - 90) > 45;
var primaryDimension = orientHorizontally ? width : height;
var secondaryDimension = orientHorizontally ? height : width;
var textContainer = options.selection.append("g").classed("text-container", true);
if (this._addTitleElement) {
textContainer.append("title").text(text);
}
var textArea = textContainer.append("g").classed("text-area", true);
var wrappedText = this._wrapper ? this._wrapper.wrap(text, this._measurer, primaryDimension, secondaryDimension).wrappedText : text;
this.writeText(wrappedText, textArea, primaryDimension, secondaryDimension, options.xAlign, options.yAlign);
var xForm = d3.transform("");
var xForm2 = d3.transform("");
xForm.rotate = options.textRotation;
switch (options.textRotation) {
case 90:
xForm.translate = [width, 0];
xForm2.rotate = -90;
xForm2.translate = [0, 200];
break;
case -90:
xForm.translate = [0, height];
xForm2.rotate = 90;
xForm2.translate = [width, 0];
break;
case 180:
xForm.translate = [width, height];
xForm2.translate = [width, height];
xForm2.rotate = 180;
break;
}
textArea.attr("transform", xForm.toString());
this.addClipPath(textContainer, xForm2);
if (options.animator) {
options.animator.animate(textContainer);
}
};
Writer.prototype.addClipPath = function (selection, transform) {
var elementID = this._elementID++;
var prefix = /MSIE [5-9]/.test(navigator.userAgent) ? "" : document.location.href;
prefix = prefix.split("#")[0]; // To fix cases where an anchor tag was used
var clipPathID = "clipPath" + this._writerID + "_" + elementID;
selection.select(".text-area").attr("clip-path", "url(\"" + prefix + "#" + clipPathID + "\")");
var clipPathParent = selection.append("clipPath").attr("id", clipPathID);
var bboxAttrs = SVGTypewriter.Utils.DOM.getBBox(selection.select(".text-area"));
var box = clipPathParent.append("rect");
box.classed("clip-rect", true).attr({
x: bboxAttrs.x,
y: bboxAttrs.y,
width: bboxAttrs.width,
height: bboxAttrs.height
});
};
Writer.nextID = 0;
Writer.SupportedRotation = [-90, 0, 180, 90];
Writer.AnchorConverter = {
left: "start",
center: "middle",
right: "end"
};
Writer.XOffsetFactor = {
left: 0,
center: 0.5,
right: 1
};
Writer.YOffsetFactor = {
top: 0,
center: 0.5,
bottom: 1
};
return Writer;
})();
Writers.Writer = Writer;
})(Writers = SVGTypewriter.Writers || (SVGTypewriter.Writers = {}));
})(SVGTypewriter || (SVGTypewriter = {}));
///<reference path="../reference.ts" />
var SVGTypewriter;
(function (SVGTypewriter) {
var Measurers;
(function (Measurers) {
;
var AbstractMeasurer = (function () {
function AbstractMeasurer(area, className) {
this.textMeasurer = this.getTextMeasurer(area, className);
}
AbstractMeasurer.prototype.checkSelectionIsText = function (d) {
return d[0][0].tagName === "text" || !d.select("text").empty();
};
AbstractMeasurer.prototype.getTextMeasurer = function (area, className) {
var _this = this;
if (!this.checkSelectionIsText(area)) {
var textElement = area.append("text");
if (className) {
textElement.classed(className, true);
}
textElement.remove();
return function (text) {
area.node().appendChild(textElement.node());
var areaDimension = _this.measureBBox(textElement, text);
textElement.remove();
return areaDimension;
};
}
else {
var parentNode = area.node().parentNode;
var textSelection;
if (area[0][0].tagName === "text") {
textSelection = area;
}
else {
textSelection = area.select("text");
}
area.remove();
return function (text) {
parentNode.appendChild(area.node());
var areaDimension = _this.measureBBox(textSelection, text);
area.remove();
return areaDimension;
};
}
};
AbstractMeasurer.prototype.measureBBox = function (d, text) {
d.text(text);
var bb = SVGTypewriter.Utils.DOM.getBBox(d);
return { width: bb.width, height: bb.height };
};
AbstractMeasurer.prototype.measure = function (text) {
if (text === void 0) { text = AbstractMeasurer.HEIGHT_TEXT; }
return this.textMeasurer(text);
};
AbstractMeasurer.HEIGHT_TEXT = "bqpdl";
return AbstractMeasurer;
})();
Measurers.AbstractMeasurer = AbstractMeasurer;
})(Measurers = SVGTypewriter.Measurers || (SVGTypewriter.Measurers = {}));
})(SVGTypewriter || (SVGTypewriter = {}));
///<reference path="../reference.ts" />
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var SVGTypewriter;
(function (SVGTypewriter) {
var Measurers;
(function (Measurers) {
var Measurer = (function (_super) {
__extends(Measurer, _super);
function Measurer(area, className, useGuards) {
if (className === void 0) { className = null; }
if (useGuards === void 0) { useGuards = false; }
_super.call(this, area, className);
this.useGuards = useGuards;
}
// Guards assures same line height and width of whitespaces on both ends.
Measurer.prototype._addGuards = function (text) {
return Measurers.AbstractMeasurer.HEIGHT_TEXT + text + Measurers.AbstractMeasurer.HEIGHT_TEXT;
};
Measurer.prototype.getGuardWidth = function () {
if (this.guardWidth == null) {
this.guardWidth = _super.prototype.measure.call(this).width;
}
return this.guardWidth;
};
Measurer.prototype._measureLine = function (line) {
var measuredLine = this.useGuards ? this._addGuards(line) : line;
var measuredLineDimensions = _super.prototype.measure.call(this, measuredLine);
measuredLineDimensions.width -= this.useGuards ? (2 * this.getGuardWidth()) : 0;
return measuredLineDimensions;
};
Measurer.prototype.measure = function (text) {
var _this = this;
if (text === void 0) { text = Measurers.AbstractMeasurer.HEIGHT_TEXT; }
if (text.trim() === "") {
return { width: 0, height: 0 };
}
var linesDimensions = text.trim().split("\n").map(function (line) { return _this._measureLine(line); });
return {
width: d3.max(linesDimensions, function (dim) { return dim.width; }),
height: d3.sum(linesDimensions, function (dim) { return dim.height; })
};
};
return Measurer;
})(Measurers.AbstractMeasurer);
Measurers.Measurer = Measurer;
})(Measurers = SVGTypewriter.Measurers || (SVGTypewriter.Measurers = {}));
})(SVGTypewriter || (SVGTypewriter = {}));
///<reference path="../reference.ts" />
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var SVGTypewriter;
(function (SVGTypewriter) {
var Measurers;
(function (Measurers) {
var CharacterMeasurer = (function (_super) {
__extends(CharacterMeasurer, _super);
function CharacterMeasurer() {
_super.apply(this, arguments);
}
CharacterMeasurer.prototype._measureCharacter = function (c) {
return _super.prototype._measureLine.call(this, c);
};
CharacterMeasurer.prototype._measureLine = function (line) {
var _this = this;
var charactersDimensions = line.split("").map(function (c) { return _this._measureCharacter(c); });
return {
width: d3.sum(charactersDimensions, function (dim) { return dim.width; }),
height: d3.max(charactersDimensions, function (dim) { return dim.height; })
};
};
return CharacterMeasurer;
})(Measurers.Measurer);
Measurers.CharacterMeasurer = CharacterMeasurer;
})(Measurers = SVGTypewriter.Measurers || (SVGTypewriter.Measurers = {}));
})(SVGTypewriter || (SVGTypewriter = {}));
///<reference path="../reference.ts" />
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var SVGTypewriter;
(function (SVGTypewriter) {
var Measurers;
(function (Measurers) {
var CacheCharacterMeasurer = (function (_super) {
__extends(CacheCharacterMeasurer, _super);
function CacheCharacterMeasurer(area, className) {
var _this = this;
_super.call(this, area, className);
this.cache = new SVGTypewriter.Utils.Cache(function (c) { return _this._measureCharacterNotFromCache(c); }, SVGTypewriter.Utils.Methods.objEq);
}
CacheCharacterMeasurer.prototype._measureCharacterNotFromCache = function (c) {
return _super.prototype._measureCharacter.call(this, c);
};
CacheCharacterMeasurer.prototype._measureCharacter = function (c) {
return this.cache.get(c);
};
CacheCharacterMeasurer.prototype.reset = function () {
this.cache.clear();
};
return CacheCharacterMeasurer;
})(Measurers.CharacterMeasurer);
Measurers.CacheCharacterMeasurer = CacheCharacterMeasurer;
})(Measurers = SVGTypewriter.Measurers || (SVGTypewriter.Measurers = {}));
})(SVGTypewriter || (SVGTypewriter = {}));
return Plottable;
}));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment