diff --git a/bower.json b/bower.json index 12e7877f98..df937e9add 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "plottable", "description": "A library for creating charts out of D3", - "version": "0.23.2", + "version": "0.24.0", "main": ["plottable.js", "plottable.css"], "license": "MIT", "ignore": [ diff --git a/package.json b/package.json index bbcdea5e53..ac01b42cbd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "plottable.js", - "version": "0.23.2", + "version": "0.24.0", "description": "Build flexible, performant, interactive charts using D3", "repository": { "type": "git", diff --git a/plottable.d.ts b/plottable.d.ts index c8c4a0340f..37c3c56ae8 100644 --- a/plottable.d.ts +++ b/plottable.d.ts @@ -2,18 +2,80 @@ declare module Plottable { module Util { module Methods { + /** + * 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: number, a: number, b: number): boolean; + /** Print a warning message to the console, if it is available. + * + * @param {string} The warnings to print + */ function warn(warning: string): void; + /** + * 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 addArrays(alist: number[], blist: number[]): number[]; + /** + * Takes two sets and returns the intersection + * + * @param {D3.Set} set1 The first set + * @param {D3.Set} set2 The second set + * @return {D3.Set} A set that contains elements that appear in both set1 and set2 + */ function intersection(set1: D3.Set, set2: D3.Set): D3.Set; + /** + * Take an accessor object (may be a string to be made into a key, or a value, or a color code) + * and "activate" it by turning it into a function in (datum, index, metadata) + */ function _accessorize(accessor: any): IAccessor; + /** + * Takes two sets and returns the union + * + * @param{D3.Set} set1 The first set + * @param{D3.Set} set2 The second set + * @return{D3.Set} A set that contains elements that appear in either set1 or set2 + */ function union(set1: D3.Set, set2: D3.Set): D3.Set; - function _applyAccessor(accessor: IAccessor, plot: Plottable.Abstract.Plot): (d: any, i: number) => any; + /** + * Take an accessor object, activate it, and partially apply it to a Plot's datasource's metadata + */ + function _applyAccessor(accessor: IAccessor, plot: Abstract.Plot): (d: any, i: number) => any; function uniq(strings: string[]): string[]; function uniqNumbers(a: number[]): number[]; + /** + * Creates an array of length `count`, filled with value or (if value is a function), value() + * + * @param {any} value The value to fill the array with, or, if a function, a generator for values + * @param {number} count The length of the array to generate + * @return {any[]} + */ function createFilledArray(value: any, count: number): any[]; + /** + * @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: T[][]): T[]; + /** + * Check if two arrays are equal by strict equality. + */ function arrayEq(a: T[], b: T[]): boolean; + /** + * @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: any, b: any): boolean; } } @@ -23,6 +85,42 @@ declare module Plottable { declare module Plottable { module Util { module OpenSource { + /** + * Returns the sortedIndex for inserting a value into an array. + * Takes a number and an array of numbers OR an array of objects and an accessor that returns a number. + * @param {number} value: The numerical value to insert + * @param {any[]} arr: Array to find insertion index, can be number[] or any[] (if accessor provided) + * @param {IAccessor} accessor: If provided, this function is called on members of arr to determine insertion index + * @returns {number} The insertion index. + * The behavior is undefined for arrays that are unsorted + * If there are multiple valid insertion indices that maintain sorted order (e.g. addign 1 to [1,1,1,1,1]) then + * the behavior must satisfy that the array is sorted post-insertion, but is otherwise unspecified. + * This is a modified version of Underscore.js's implementation of sortedIndex. + * Underscore.js is released under the MIT License: + * Copyright (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative + * Reporters & Editors + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ function sortedIndex(val: number, arr: number[]): number; function sortedIndex(val: number, arr: any[], accessor: IAccessor): number; } @@ -33,9 +131,9 @@ declare module Plottable { declare module Plottable { module Util { class IDCounter { - increment(id: any): number; - decrement(id: any): number; - get(id: any): number; + public increment(id: any): number; + public decrement(id: any): number; + public get(id: any): number; } } } @@ -43,14 +141,63 @@ declare module Plottable { declare module Plottable { module Util { + /** + * An associative array that can be keyed by anything (inc objects). + * Uses pointer equality checks which is why this works. + * This power has a price: everything is linear time since it is actually backed by an array... + */ class StrictEqualityAssociativeArray { - set(key: any, value: any): boolean; - get(key: any): any; - has(key: any): boolean; - values(): any[]; - keys(): any[]; - map(cb: (key?: any, val?: any, index?: number) => any): any[]; - delete(key: any): boolean; + /** + * Set a new key/value pair in the store. + * + * @param {any} key Key to set in the store + * @param {any} value Value to set in the store + * @return {boolean} True if key already in store, false otherwise + */ + public set(key: any, value: any): boolean; + /** + * Get a value from the store, given a key. + * + * @param {any} key Key associated with value to retrieve + * @return {any} Value if found, undefined otherwise + */ + public get(key: any): any; + /** + * Test whether store has a value associated with given key. + * + * Will return true if there is a key/value entry, + * even if the value is explicitly `undefined`. + * + * @param {any} key Key to test for presence of an entry + * @return {boolean} Whether there was a matching entry for that key + */ + public has(key: any): boolean; + /** + * Return an array of the values in the key-value store + * + * @return {any[]} The values in the store + */ + public values(): any[]; + /** + * Return an array of keys in the key-value store + * + * @return {any[]} The keys in the store + */ + public keys(): any[]; + /** + * Execute a callback for each entry in the array. + * + * @param {(key: any, val?: any, index?: number) => any} callback The callback to eecute + * @return {any[]} The results of mapping the callback over the entries + */ + public map(cb: (key?: any, val?: any, index?: number) => any): any[]; + /** + * Delete a key from the key-value store. Return whether the key was present. + * + * @param {any} The key to remove + * @return {boolean} Whether a matching entry was found and removed + */ + public delete(key: any): boolean; } } } @@ -59,9 +206,36 @@ declare module Plottable { declare module Plottable { module Util { class Cache { + /** + * @constructor + * + * @param {string} compute The function whose results will be cached. + * @param {string} [canonicalKey] If present, when clear() is called, + * this key will be re-computed. If its result hasn't been changed, + * the cache will not be cleared. + * @param {(v: T, w: T) => boolean} [valueEq] + * Used to determine if the value of canonicalKey has changed. + * If omitted, defaults to === comparision. + */ constructor(compute: (k: string) => T, canonicalKey?: string, valueEq?: (v: T, w: T) => boolean); - get(k: string): T; - clear(): Cache; + /** + * 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). + */ + public get(k: string): T; + /** + * Reset the cache empty. + * + * If canonicalKey was provided at construction, compute(canonicalKey) + * will be re-run. If the result matches what is already in the cache, + * it will not clear the cache. + * + * @return {Cache} The calling Cache. + */ + public clear(): Cache; } } } @@ -77,15 +251,62 @@ declare module Plottable { interface TextMeasurer { (s: string): Dimensions; } + /** + * Returns a quasi-pure function of typesignature (t: string) => Dimensions which measures height and width of text + * + * @param {D3.Selection} selection: The selection in which text will be drawn and measured + * @returns {Dimensions} width and height of the text + */ function getTextMeasure(selection: D3.Selection): TextMeasurer; + /** + * This class will measure text by measuring each character individually, + * then adding up the dimensions. It will also cache the dimensions of each + * letter. + */ class CachingCharacterMeasurer { - measure: TextMeasurer; + /** + * @param {string} s The string to be measured. + * @return {Dimensions} The width and height of the measured text. + */ + public measure: TextMeasurer; + /** + * @param {D3.Selection} g The element that will have text inserted into + * it in order to measure text. The styles present for text in + * this element will to the text being measured. + */ constructor(g: D3.Selection); - clear(): CachingCharacterMeasurer; + /** + * Clear the cache, if it seems that the text has changed size. + */ + public clear(): CachingCharacterMeasurer; } + /** + * Gets a truncated version of a sting that fits in the available space, given the element in which to draw the text + * + * @param {string} text: The string to be truncated + * @param {number} availableWidth: The available width, in pixels + * @param {D3.Selection} element: The text element used to measure the text + * @returns {string} text - the shortened text + */ function getTruncatedText(text: string, availableWidth: number, measurer: TextMeasurer): string; + /** + * Gets the height of a text element, as rendered. + * + * @param {D3.Selection} textElement + * @return {number} The height of the text element, in pixels. + */ function getTextHeight(selection: D3.Selection): number; + /** + * Gets the width of a text element, as rendered. + * + * @param {D3.Selection} textElement + * @return {number} The width of the text element, in pixels. + */ function getTextWidth(textElement: D3.Selection, text: string): number; + /** + * Takes a line, a width to fit it in, and a text measurer. Will attempt to add ellipses to the end of the line, + * shortening the line as required to ensure that it fits within width. + */ function _addEllipsesToLine(line: string, width: number, measureText: TextMeasurer): string; function writeLineHorizontally(line: string, g: D3.Selection, width: number, height: number, xAlign?: string, yAlign?: string): { width: number; @@ -113,6 +334,12 @@ declare module Plottable { xAlign: string; yAlign: string; } + /** + * @param {write} [IWriteOptions] If supplied, the text will be written + * To the given g. Will align the text vertically if it seems like + * that is appropriate. + * Returns an IWriteTextResult with info on whether the text fit, and how much width/height was used. + */ function writeText(text: string, width: number, height: number, tm: TextMeasurer, horizontally?: boolean, write?: IWriteOptions): IWriteTextResult; } } @@ -127,7 +354,16 @@ declare module Plottable { lines: string[]; textFits: boolean; } + /** + * Takes a block of text, a width and height to fit it in, and a 2-d text measurement function. + * Wraps words and fits as much of the text as possible into the given width and height. + */ function breakTextToFitRect(text: string, width: number, height: number, measureText: Text.TextMeasurer): IWrappedText; + /** + * Determines if it is possible to fit a given text within width without breaking any of the words. + * Simple algorithm, split the text up into tokens, and make sure that the widest token doesn't exceed + * allowed width. + */ function canWrapWithoutBreakingWords(text: string, width: number, widthMeasure: (s: string) => number): boolean; } } @@ -136,6 +372,11 @@ declare module Plottable { declare module Plottable { module Util { module DOM { + /** + * Gets the bounding box of an element. + * @param {D3.Selection} element + * @returns {SVGRed} The bounding box. + */ function getBBox(element: D3.Selection): SVGRect; var POLYFILL_TIMEOUT_MSEC: number; function requestAnimationFramePolyfill(fn: () => any): void; @@ -156,13 +397,76 @@ declare module Plottable { } var MILLISECONDS_IN_ONE_DAY: number; class 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. + */ static currency(precision?: number, symbol?: string, prefix?: boolean, onlyShowUnchanged?: boolean): (d: any) => string; + /** + * 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. + */ static fixed(precision?: number, onlyShowUnchanged?: boolean): (d: any) => string; + /** + * 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. + */ static general(precision?: number, onlyShowUnchanged?: boolean): (d: any) => string; + /** + * Creates a formatter that stringifies its input. + * + * @returns {Formatter} A formatter that stringifies its input. + */ static identity(): (d: any) => string; + /** + * 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. + */ static percentage(precision?: number, onlyShowUnchanged?: boolean): (d: any) => string; + /** + * 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. + */ static siSuffix(precision?: number): (d: any) => string; + /** + * Creates a formatter that displays dates. + * + * @returns {Formatter} A formatter for time/date values. + */ static time(): (d: any) => string; + /** + * 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. + */ static relativeDate(baseValue?: number, increment?: number, label?: string): (d: any) => string; } } @@ -202,32 +506,119 @@ declare module Plottable { declare module Plottable { module Core { + /** + * This interface represents anything in Plottable which can have a listener attached. + * Listeners attach by referencing the Listenable's broadcaster, and calling registerListener + * on it. + * + * e.g.: + * listenable: Plottable.IListenable; + * listenable.broadcaster.registerListener(callbackToCallOnBroadcast) + */ interface IListenable { broadcaster: Broadcaster; } + /** + * This interface represents the callback that should be passed to the Broadcaster on a Listenable. + * + * The callback will be called with the attached Listenable as the first object, and optional arguments + * as the subsequent arguments. + * + * The Listenable is passed as the first argument so that it is easy for the callback to reference the + * current state of the Listenable in the resolution logic. + */ interface IBroadcasterCallback { (listenable: IListenable, ...args: any[]): any; } - class Broadcaster extends Plottable.Abstract.PlottableObject { - listenable: IListenable; + /** + * The Broadcaster class is owned by an IListenable. Third parties can register and deregister listeners + * from the broadcaster. When the broadcaster.broadcast method is activated, all registered callbacks are + * called. The registered callbacks are called with the registered Listenable that the broadcaster is attached + * to, along with optional arguments passed to the `broadcast` method. + * + * The listeners are called synchronously. + */ + class Broadcaster extends Abstract.PlottableObject { + public listenable: IListenable; + /** + * Construct a broadcaster, taking the Listenable that the broadcaster will be attached to. + * + * @constructor + * @param {IListenable} listenable The Listenable-object that this broadcaster is attached to. + */ constructor(listenable: IListenable); - registerListener(key: any, callback: IBroadcasterCallback): Broadcaster; - broadcast(...args: any[]): Broadcaster; - deregisterListener(key: any): Broadcaster; - deregisterAllListeners(): void; - } - } -} - - -declare module Plottable { - class DataSource extends Plottable.Abstract.PlottableObject implements Plottable.Core.IListenable { - broadcaster: any; + /** + * Registers a callback to be called when the broadcast method is called. Also takes a key which + * is used to support deregistering the same callback later, by passing in the same key. + * If there is already a callback associated with that key, then the callback will be replaced. + * + * @param key The key associated with the callback. Key uniqueness is determined by deep equality. + * @param {IBroadcasterCallback} callback A callback to be called when the Scale's domain changes. + * @returns {Broadcaster} this object + */ + public registerListener(key: any, callback: IBroadcasterCallback): Broadcaster; + /** + * Call all listening callbacks, optionally with arguments passed through. + * + * @param ...args A variable number of optional arguments + * @returns {Broadcaster} this object + */ + public broadcast(...args: any[]): Broadcaster; + /** + * Deregisters the callback associated with a key. + * + * @param key The key to deregister. + * @returns {Broadcaster} this object + */ + public deregisterListener(key: any): Broadcaster; + /** + * Deregisters all listeners and callbacks associated with the broadcaster. + * + * @returns {Broadcaster} this object + */ + public deregisterAllListeners(): void; + } + } +} + + +declare module Plottable { + class DataSource extends Abstract.PlottableObject implements Core.IListenable { + public broadcaster: Core.Broadcaster; + /** + * Creates a new DataSource. + * + * @constructor + * @param {any[]} data + * @param {any} metadata An object containing additional information. + */ constructor(data?: any[], metadata?: any); - data(): any[]; - data(data: any[]): DataSource; - metadata(): any; - metadata(metadata: any): DataSource; + /** + * Gets the data. + * + * @returns {any[]} The current data. + */ + public data(): any[]; + /** + * Sets new data. + * + * @param {any[]} data The new data. + * @returns {DataSource} The calling DataSource. + */ + public data(data: any[]): DataSource; + /** + * Gets the metadata. + * + * @returns {any} The current metadata. + */ + public metadata(): any; + /** + * Sets the metadata. + * + * @param {any} metadata The new metadata. + * @returns {DataSource} The calling DataSource. + */ + public metadata(metadata: any): DataSource; } } @@ -235,29 +626,107 @@ declare module Plottable { declare module Plottable { module Abstract { class Component extends PlottableObject { - element: D3.Selection; - content: D3.Selection; - backgroundContainer: D3.Selection; - foregroundContainer: D3.Selection; - clipPathEnabled: boolean; - availableWidth: number; - availableHeight: number; - xOrigin: number; - yOrigin: number; + public element: D3.Selection; + public content: D3.Selection; + public backgroundContainer: D3.Selection; + public foregroundContainer: D3.Selection; + public clipPathEnabled: boolean; + public availableWidth: number; + public availableHeight: number; + public xOrigin: number; + public yOrigin: number; static AUTORESIZE_BY_DEFAULT: boolean; - renderTo(element: any): Component; - resize(width?: number, height?: number): Component; - autoResize(flag: boolean): Component; - xAlign(alignment: string): Component; - yAlign(alignment: string): Component; - xOffset(offset: number): Component; - yOffset(offset: number): Component; - registerInteraction(interaction: Interaction): Component; - classed(cssClass: string): boolean; - classed(cssClass: string, addClass: boolean): Component; - merge(c: Component): Plottable.Component.Group; - detach(): Component; - remove(): void; + /** + * Renders the Component into a given DOM element. + * + * @param {String|D3.Selection} element A D3 selection or a selector for getting the element to render into. + * @return {Component} The calling component. + */ + public renderTo(element: any): Component; + /** + * Cause the Component to recompute layout and redraw. If passed arguments, will resize the root SVG it lives in. + * + * @param {number} [availableWidth] - the width of the container element + * @param {number} [availableHeight] - the height of the container element + */ + public resize(width?: number, height?: number): Component; + /** + * Enables and disables auto-resize. + * + * If enabled, window resizes will enqueue this component for a re-layout + * and re-render. Animations are disabled during window resizes when auto- + * resize is enabled. + * + * @param {boolean} flag - Enables (true) or disables (false) auto-resize. + */ + public autoResize(flag: boolean): Component; + /** + * Sets the x alignment of the Component. + * + * @param {string} alignment The x alignment of the Component (one of LEFT/CENTER/RIGHT). + * @returns {Component} The calling Component. + */ + public xAlign(alignment: string): Component; + /** + * Sets the y alignment of the Component. + * + * @param {string} alignment The y alignment of the Component (one of TOP/CENTER/BOTTOM). + * @returns {Component} The calling Component. + */ + public yAlign(alignment: string): Component; + /** + * Sets the x offset of the Component. + * + * @param {number} offset The desired x offset, in pixels. + * @returns {Component} The calling Component. + */ + public xOffset(offset: number): Component; + /** + * Sets the y offset of the Component. + * + * @param {number} offset The desired y offset, in pixels. + * @returns {Component} The calling Component. + */ + public yOffset(offset: number): Component; + /** + * Attaches an Interaction to the Component, so that the Interaction will listen for events on the Component. + * + * @param {Interaction} interaction The Interaction to attach to the Component. + * @return {Component} The calling Component. + */ + public registerInteraction(interaction: Interaction): Component; + /** + * Adds/removes a given CSS class to/from the Component, or checks if the Component has a particular CSS class. + * + * @param {string} cssClass The CSS class to add/remove/check for. + * @param {boolean} [addClass] Whether to add or remove the CSS class. If not supplied, checks for the CSS class. + * @return {boolean|Component} Whether the Component has the given CSS class, or the calling Component (if addClass is supplied). + */ + public classed(cssClass: string): boolean; + public classed(cssClass: string, addClass: boolean): Component; + /** + * Merges this Component with another Component, returning a ComponentGroup. + * There are four cases: + * Component + Component: Returns a ComponentGroup with both components inside it. + * ComponentGroup + Component: Returns the ComponentGroup with the Component appended. + * Component + ComponentGroup: Returns the ComponentGroup with the Component prepended. + * ComponentGroup + ComponentGroup: Returns a new ComponentGroup with two ComponentGroups inside it. + * + * @param {Component} c The component to merge in. + * @return {ComponentGroup} + */ + public merge(c: Component): Component.Group; + /** + * Detaches a Component from the DOM. The component can be reused. + * + * @returns The calling Component. + */ + public detach(): Component; + /** + * Removes a Component from the DOM and disconnects it from everything it's + * listening to (effectively destroying it). + */ + public remove(): void; } } } @@ -266,10 +735,26 @@ declare module Plottable { declare module Plottable { module Abstract { class ComponentContainer extends Component { - components(): Component[]; - empty(): boolean; - detachAll(): ComponentContainer; - remove(): void; + /** + * Returns a list of components in the ComponentContainer + * + * @returns{Component[]} the contained Components + */ + public components(): Component[]; + /** + * Returns true iff the ComponentContainer is empty. + * + * @returns {boolean} Whether the calling ComponentContainer is empty. + */ + public empty(): boolean; + /** + * Detaches all components contained in the ComponentContainer, and + * empties the ComponentContainer. + * + * @returns {ComponentContainer} The calling ComponentContainer + */ + public detachAll(): ComponentContainer; + public remove(): void; } } } @@ -277,9 +762,15 @@ declare module Plottable { declare module Plottable { module Component { - class Group extends Plottable.Abstract.ComponentContainer { - constructor(components?: Plottable.Abstract.Component[]); - merge(c: Plottable.Abstract.Component): Group; + class Group extends Abstract.ComponentContainer { + /** + * Creates a ComponentGroup. + * + * @constructor + * @param {Component[]} [components] The Components in the Group. + */ + constructor(components?: Abstract.Component[]); + public merge(c: Abstract.Component): Group; } } } @@ -295,12 +786,49 @@ declare module Plottable { wantsWidth: boolean; wantsHeight: boolean; } - class Table extends Plottable.Abstract.ComponentContainer { - constructor(rows?: Plottable.Abstract.Component[][]); - addComponent(row: number, col: number, component: Plottable.Abstract.Component): Table; - padding(rowPadding: number, colPadding: number): Table; - rowWeight(index: number, weight: number): Table; - colWeight(index: number, weight: number): Table; + class Table extends Abstract.ComponentContainer { + /** + * Creates a Table. + * + * @constructor + * @param {Component[][]} [rows] A 2-D array of the Components to place in the table. + * null can be used if a cell is empty. + */ + constructor(rows?: Abstract.Component[][]); + /** + * Adds a Component in the specified cell. + * + * @param {number} row The row in which to add the Component. + * @param {number} col The column in which to add the Component. + * @param {Component} component The Component to be added. + */ + public addComponent(row: number, col: number, component: Abstract.Component): Table; + /** + * Sets the row and column padding on the Table. + * + * @param {number} rowPadding The padding above and below each row, in pixels. + * @param {number} colPadding the padding to the left and right of each column, in pixels. + * @returns {Table} The calling Table. + */ + public padding(rowPadding: number, colPadding: number): Table; + /** + * Sets the layout weight of a particular row. + * Space is allocated to rows based on their weight. Rows with higher weights receive proportionally more space. + * + * @param {number} index The index of the row. + * @param {number} weight The weight to be set on the row. + * @returns {Table} The calling Table. + */ + public rowWeight(index: number, weight: number): Table; + /** + * Sets the layout weight of a particular column. + * Space is allocated to columns based on their weight. Columns with higher weights receive proportionally more space. + * + * @param {number} index The index of the column. + * @param {number} weight The weight to be set on the column. + * @returns {Table} The calling Table. + */ + public colWeight(index: number, weight: number): Table; } } } @@ -308,18 +836,77 @@ declare module Plottable { declare module Plottable { module Abstract { - class Scale extends PlottableObject implements Plottable.Core.IListenable { - broadcaster: any; + class Scale extends PlottableObject implements Core.IListenable { + public broadcaster: Core.Broadcaster; + /** + * Creates a new Scale. + * + * @constructor + * @param {D3.Scale.Scale} scale The D3 scale backing the Scale. + */ constructor(scale: D3.Scale.Scale); - autoDomain(): Scale; - scale(value: any): any; - domain(): any[]; - domain(values: any[]): Scale; - range(): any[]; - range(values: any[]): Scale; - copy(): Scale; - updateExtent(rendererID: number, attr: string, extent: any[]): Scale; - removeExtent(rendererID: number, attr: string): Scale; + /** + * Modify the domain on the scale so that it includes the extent of all + * perspectives it depends on. Extent: The (min, max) pair for a + * QuantitiativeScale, all covered strings for an OrdinalScale. + * Perspective: A combination of a DataSource and an Accessor that + * represents a view in to the data. + */ + public autoDomain(): Scale; + /** + * Returns the range value corresponding to a given domain value. + * + * @param value {any} A domain value to be scaled. + * @returns {any} The range value corresponding to the supplied domain value. + */ + public scale(value: any): any; + /** + * Gets the domain. + * + * @returns {any[]} The current domain. + */ + public domain(): any[]; + /** + * Sets the Scale's domain to the specified values. + * + * @param {any[]} values The new value for the domain. This array may + * contain more than 2 values if the scale type allows it (e.g. + * ordinal scales). Other scales such as quantitative scales accept + * only a 2-value extent array. + * @returns {Scale} The calling Scale. + */ + public domain(values: any[]): Scale; + /** + * Gets the range. + * + * @returns {any[]} The current range. + */ + public range(): any[]; + /** + * Sets the Scale's range to the specified values. + * + * @param {any[]} values The new values for the range. + * @returns {Scale} The calling Scale. + */ + public range(values: any[]): Scale; + /** + * Creates a copy of the Scale with the same domain and range but without any registered listeners. + * + * @returns {Scale} A copy of the calling Scale. + */ + public copy(): Scale; + /** + * When a renderer determines that the extent of a projector has changed, + * it will call this function. This function should ensure that + * the scale has a domain at least large enough to include extent. + * + * @param {number} rendererID A unique indentifier of the renderer sending + * the new extent. + * @param {string} attr The attribute being projected, e.g. "x", "y0", "r" + * @param {any[]} extent The new extent to be included in the scale. + */ + public updateExtent(rendererID: number, attr: string, extent: any[]): Scale; + public removeExtent(rendererID: number, attr: string): Scale; } } } @@ -335,19 +922,55 @@ declare module Plottable { [attrToSet: string]: IAppliedAccessor; } class Plot extends Component { - renderArea: D3.Selection; - element: D3.Selection; + public renderArea: D3.Selection; + public element: D3.Selection; + /** + * Creates a Plot. + * + * @constructor + * @param {any[]|DataSource} [dataset] The data or DataSource to be associated with this Plot. + */ constructor(); constructor(dataset: any[]); constructor(dataset: DataSource); - remove(): void; - dataSource(): DataSource; - dataSource(source: DataSource): Plot; - project(attrToSet: string, accessor: any, scale?: Scale): Plot; - animate(enabled: boolean): Plot; - detach(): Plot; - animator(animatorKey: string): Plottable.Animator.IPlotAnimator; - animator(animatorKey: string, animator: Plottable.Animator.IPlotAnimator): Plot; + public remove(): void; + /** + * Gets the Plot's DataSource. + * + * @return {DataSource} The current DataSource. + */ + public dataSource(): DataSource; + /** + * Sets the Plot's DataSource. + * + * @param {DataSource} source The DataSource the Plot should use. + * @return {Plot} The calling Plot. + */ + public dataSource(source: DataSource): Plot; + public project(attrToSet: string, accessor: any, scale?: Scale): Plot; + /** + * Enables or disables animation. + * + * @param {boolean} enabled Whether or not to animate. + */ + public animate(enabled: boolean): Plot; + public detach(): Plot; + /** + * Gets the animator associated with the specified Animator key. + * + * @param {string} animatorKey The key for the Animator. + * @return {Animator.IPlotAnimator} The Animator for the specified key. + */ + public animator(animatorKey: string): Animator.IPlotAnimator; + /** + * Sets the animator associated with the specified Animator key. + * + * @param {string} animatorKey The key for the Animator. + * @param {Animator.IPlotAnimator} animator An Animator to be assigned to + * the specified key. + * @return {Plot} The calling Plot. + */ + public animator(animatorKey: string, animator: Animator.IPlotAnimator): Plot; } } } @@ -361,13 +984,13 @@ declare module Plottable { render(): any; } class Immediate implements IRenderPolicy { - render(): void; + public render(): void; } class AnimationFrame implements IRenderPolicy { - render(): void; + public render(): void; } class Timeout implements IRenderPolicy { - render(): void; + public render(): void; } } } @@ -377,11 +1000,33 @@ declare module Plottable { declare module Plottable { module Core { + /** + * The RenderController is responsible for enqueueing and synchronizing + * layout and render calls for Plottable components. + * + * Layouts and renders occur inside an animation callback + * (window.requestAnimationFrame if available). + * + * If you require immediate rendering, call RenderController.flush() to + * perform enqueued layout and rendering serially. + */ module RenderController { var _renderPolicy: RenderPolicy.IRenderPolicy; function setRenderPolicy(policy: RenderPolicy.IRenderPolicy): any; - function registerToRender(c: Plottable.Abstract.Component): void; - function registerToComputeLayout(c: Plottable.Abstract.Component): void; + /** + * If the RenderController is enabled, we enqueue the component for + * render. Otherwise, it is rendered immediately. + * + * @param {Abstract.Component} component Any Plottable component. + */ + function registerToRender(c: Abstract.Component): void; + /** + * If the RenderController is enabled, we enqueue the component for + * layout and render. Otherwise, it is rendered immediately. + * + * @param {Abstract.Component} component Any Plottable component. + */ + function registerToComputeLayout(c: Abstract.Component): void; function flush(): void; } } @@ -390,11 +1035,41 @@ declare module Plottable { declare module Plottable { module Core { + /** + * The ResizeBroadcaster will broadcast a notification to any registered + * components when the window is resized. + * + * The broadcaster and single event listener are lazily constructed. + * + * Upon resize, the _resized flag will be set to true until after the next + * flush of the RenderController. This is used, for example, to disable + * animations during resize. + */ module ResizeBroadcaster { + /** + * Returns true if the window has been resized and the RenderController + * has not yet been flushed. + */ function resizing(): boolean; function clearResizing(): any; - function register(c: Plottable.Abstract.Component): void; - function deregister(c: Plottable.Abstract.Component): void; + /** + * Registers a component. + * + * When the window is resized, we invoke ._invalidateLayout() on the + * component, which will enqueue the component for layout and rendering + * with the RenderController. + * + * @param {Abstract.Component} component Any Plottable component. + */ + function register(c: Abstract.Component): void; + /** + * Deregisters the components. + * + * The component will no longer receive updates on window resize. + * + * @param {Abstract.Component} component Any Plottable component. + */ + function deregister(c: Abstract.Component): void; } } } @@ -403,7 +1078,18 @@ declare module Plottable { declare module Plottable { module Animator { interface IPlotAnimator { - animate(selection: any, attrToProjector: Plottable.Abstract.IAttributeToProjector, plot: Plottable.Abstract.Plot): any; + /** + * Applies the supplied attributes to a D3.Selection with some animation. + * + * @param {D3.Selection} selection The update selection or transition selection that we wish to animate. + * @param {Abstract.IAttributeToProjector} attrToProjector The set of + * IAccessors that we will use to set attributes on the selection. + * @param {Abstract.Plot} plot The plot being animated. + * @return {D3.Selection} Animators should return the selection or + * transition object so that plots may chain the transitions between + * animators. + */ + animate(selection: any, attrToProjector: Abstract.IAttributeToProjector, plot: Abstract.Plot): any; } interface IPlotAnimatorMap { [animatorKey: string]: IPlotAnimator; @@ -461,14 +1147,94 @@ declare module Plottable { declare module Plottable { class Domainer { + /** + * @param {(extents: any[][]) => any[]} combineExtents + * If present, this function will be used by the Domainer to merge + * all the extents that are present on a scale. + * + * A plot may draw multiple things relative to a scale, e.g. + * different stocks over time. The plot computes their extents, + * which are a [min, max] pair. combineExtents is responsible for + * merging them all into one [min, max] pair. It defaults to taking + * the min of the first elements and the max of the second arguments. + */ constructor(combineExtents?: (extents: any[][]) => any[]); - computeDomain(extents: any[][], scale: Plottable.Abstract.QuantitativeScale): any[]; - pad(padProportion?: number): Domainer; - addPaddingException(exception: any, key?: string): Domainer; - removePaddingException(keyOrException: any): Domainer; - addIncludedValue(value: any, key?: string): Domainer; - removeIncludedValue(valueOrKey: any): Domainer; - nice(count?: number): Domainer; + /** + * @param {any[][]} extents The list of extents to be reduced to a single + * extent. + * @param {Abstract.QuantitativeScale} scale + * Since nice() must do different things depending on Linear, Log, + * or Time scale, the scale must be passed in for nice() to work. + * @return {any[]} The domain, as a merging of all exents, as a [min, max] + * pair. + */ + public computeDomain(extents: any[][], scale: Abstract.QuantitativeScale): any[]; + /** + * Sets the Domainer to pad by a given ratio. + * + * @param {number} [padProportion] Proportionally how much bigger the + * new domain should be (0.05 = 5% larger). + * + * A domainer will pad equal visual amounts on each side. + * On a linear scale, this means both sides are padded the same + * amount: [10, 20] will be padded to [5, 25]. + * On a log scale, the top will be padded more than the bottom, so + * [10, 100] will be padded to [1, 1000]. + * + * @return {Domainer} The calling Domainer. + */ + public pad(padProportion?: number): Domainer; + /** + * Add a padding exception, a value that will not be padded at either end of the domain. + * + * Eg, if a padding exception is added at x=0, then [0, 100] will pad to [0, 105] instead of [-2.5, 102.5]. + * If a key is provided, it will be registered under that key with standard map semantics. (Overwrite / remove by key) + * If a key is not provided, it will be added with set semantics (Can be removed by value) + * + * @param {any} exception The padding exception to add. + * @param string [key] The key to register the exception under. + * @return Domainer The calling domainer + */ + public addPaddingException(exception: any, key?: string): Domainer; + /** + * Remove a padding exception, allowing the domain to pad out that value again. + * + * If a string is provided, it is assumed to be a key and the exception associated with that key is removed. + * If a non-string is provdied, it is assumed to be an unkeyed exception and that exception is removed. + * + * @param {any} keyOrException The key for the value to remove, or the value to remove + * @return Domainer The calling domainer + */ + public removePaddingException(keyOrException: any): Domainer; + /** + * Add an included value, a value that must be included inside the domain. + * + * Eg, if a value exception is added at x=0, then [50, 100] will expand to [0, 100] rather than [50, 100]. + * If a key is provided, it will be registered under that key with standard map semantics. (Overwrite / remove by key) + * If a key is not provided, it will be added with set semantics (Can be removed by value) + * + * @param {any} value The included value to add. + * @param string [key] The key to register the value under. + * @return Domainer The calling domainer + */ + public addIncludedValue(value: any, key?: string): Domainer; + /** + * Remove an included value, allowing the domain to not include that value gain again. + * + * If a string is provided, it is assumed to be a key and the value associated with that key is removed. + * If a non-string is provdied, it is assumed to be an unkeyed value and that value is removed. + * + * @param {any} keyOrException The key for the value to remove, or the value to remove + * @return Domainer The calling domainer + */ + public removeIncludedValue(valueOrKey: any): Domainer; + /** + * Extends the scale's domain so it starts and ends with "nice" values. + * + * @param {number} [count] The number of ticks that should fit inside the new domain. + * @return {Domainer} The calling Domainer. + */ + public nice(count?: number): Domainer; } } @@ -476,20 +1242,89 @@ declare module Plottable { declare module Plottable { module Abstract { class QuantitativeScale extends Scale { + /** + * Creates a new QuantitativeScale. + * + * @constructor + * @param {D3.Scale.QuantitativeScale} scale The D3 QuantitativeScale backing the QuantitativeScale. + */ constructor(scale: D3.Scale.QuantitativeScale); - invert(value: number): number; - copy(): QuantitativeScale; - domain(): any[]; - domain(values: any[]): QuantitativeScale; - interpolate(): D3.Transition.Interpolate; - interpolate(factory: D3.Transition.Interpolate): QuantitativeScale; - rangeRound(values: number[]): QuantitativeScale; - clamp(): boolean; - clamp(clamp: boolean): QuantitativeScale; - ticks(count?: number): any[]; - tickFormat(count: number, format?: string): (n: number) => string; - domainer(): Domainer; - domainer(domainer: Domainer): QuantitativeScale; + /** + * Retrieves the domain value corresponding to a supplied range value. + * + * @param {number} value: A value from the Scale's range. + * @returns {number} The domain value corresponding to the supplied range value. + */ + public invert(value: number): number; + /** + * Creates a copy of the QuantitativeScale with the same domain and range but without any registered listeners. + * + * @returns {QuantitativeScale} A copy of the calling QuantitativeScale. + */ + public copy(): QuantitativeScale; + public domain(): any[]; + public domain(values: any[]): QuantitativeScale; + /** + * Sets or gets the QuantitativeScale's output interpolator + * + * @param {D3.Transition.Interpolate} [factory] The output interpolator to use. + * @returns {D3.Transition.Interpolate|QuantitativeScale} The current output interpolator, or the calling QuantitativeScale. + */ + public interpolate(): D3.Transition.Interpolate; + public interpolate(factory: D3.Transition.Interpolate): QuantitativeScale; + /** + * Sets the range of the QuantitativeScale and sets the interpolator to d3.interpolateRound. + * + * @param {number[]} values The new range value for the range. + */ + public rangeRound(values: number[]): QuantitativeScale; + /** + * Gets the clamp status of the QuantitativeScale (whether to cut off values outside the ouput range). + * + * @returns {boolean} The current clamp status. + */ + public clamp(): boolean; + /** + * Sets the clamp status of the QuantitativeScale (whether to cut off values outside the ouput range). + * + * @param {boolean} clamp Whether or not to clamp the QuantitativeScale. + * @returns {QuantitativeScale} The calling QuantitativeScale. + */ + public clamp(clamp: boolean): QuantitativeScale; + /** + * Generates tick values. + * + * @param {number} [count] The number of ticks to generate. + * @returns {any[]} The generated ticks. + */ + public ticks(count?: number): any[]; + /** + * Gets a tick formatting function for displaying tick values. + * + * @param {number} count The number of ticks to be displayed + * @param {string} [format] A format specifier string. + * @returns {(n: number) => string} A formatting function. + */ + public tickFormat(count: number, format?: string): (n: number) => string; + /** + * Retrieve a Domainer of a scale. A Domainer is responsible for combining + * multiple extents into a single domain. + * + * @return {QuantitativeScale} The scale's current domainer. + */ + public domainer(): Domainer; + /** + * Sets a Domainer of a scale. A Domainer is responsible for combining + * multiple extents into a single domain. + * + * When you set domainer, we assume that you know what you want the domain + * to look like better that we do. Ensuring that the domain is padded, + * includes 0, etc., will be the responsability of the new domainer. + * + * @param {Domainer} domainer The domainer to be set. + * @return {QuantitativeScale} The calling scale. + */ + public domainer(domainer: Domainer): QuantitativeScale; } } } @@ -497,10 +1332,21 @@ declare module Plottable { declare module Plottable { module Scale { - class Linear extends Plottable.Abstract.QuantitativeScale { + class Linear extends Abstract.QuantitativeScale { + /** + * Creates a new LinearScale. + * + * @constructor + * @param {D3.Scale.LinearScale} [scale] The D3 LinearScale backing the LinearScale. If not supplied, uses a default scale. + */ constructor(); constructor(scale: D3.Scale.LinearScale); - copy(): Linear; + /** + * Creates a copy of the LinearScale with the same domain and range but without any registered listeners. + * + * @returns {LinearScale} A copy of the calling LinearScale. + */ + public copy(): Linear; } } } @@ -508,10 +1354,27 @@ declare module Plottable { declare module Plottable { module Scale { - class Log extends Plottable.Abstract.QuantitativeScale { + class Log extends Abstract.QuantitativeScale { + /** + * Creates a new Scale.Log. + * + * Warning: Log is deprecated; if possible, use ModifiedLog. Log scales are + * very unstable due to the fact that they can't handle 0 or negative + * numbers. The only time when you would want to use a Log scale over a + * ModifiedLog scale is if you're plotting very small data, such as all + * data < 1. + * + * @constructor + * @param {D3.Scale.LogScale} [scale] The D3 Scale.Log backing the Scale.Log. If not supplied, uses a default scale. + */ constructor(); constructor(scale: D3.Scale.LogScale); - copy(): Log; + /** + * Creates a copy of the Scale.Log with the same domain and range but without any registered listeners. + * + * @returns {Scale.Log} A copy of the calling Scale.Log. + */ + public copy(): Log; } } } @@ -519,14 +1382,51 @@ declare module Plottable { declare module Plottable { module Scale { - class ModifiedLog extends Plottable.Abstract.QuantitativeScale { + class ModifiedLog extends Abstract.QuantitativeScale { + /** + * Creates a new Scale.ModifiedLog. + * + * A ModifiedLog scale acts as a regular log scale for large numbers. + * As it approaches 0, it gradually becomes linear. This means that the + * scale won't freak out if you give it 0 or a negative number, where an + * ordinary Log scale would. + * + * However, it does mean that scale will be effectively linear as values + * approach 0. If you want very small values on a log scale, you should use + * an ordinary Scale.Log instead. + * + * @constructor + * @param {number} [base] + * The base of the log. Defaults to 10, and must be > 1. + * + * For base <= x, 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). + */ constructor(base?: number); - scale(x: number): number; - invert(x: number): number; - ticks(count?: number): number[]; - copy(): ModifiedLog; - showIntermediateTicks(): boolean; - showIntermediateTicks(show: boolean): ModifiedLog; + public scale(x: number): number; + public invert(x: number): number; + public ticks(count?: number): number[]; + public copy(): ModifiedLog; + /** + * @returns {boolean} + * Whether or not to return tick values other than powers of base. + * + * This defaults to false, so you'll normally only see ticks like + * [10, 100, 1000]. If you turn it on, you might see ticks values + * like [10, 50, 100, 500, 1000]. + */ + public showIntermediateTicks(): boolean; + /** + * @param {boolean} show + * Whether or not to return ticks values other than powers of the base. + */ + public showIntermediateTicks(show: boolean): ModifiedLog; } } } @@ -534,18 +1434,72 @@ declare module Plottable { declare module Plottable { module Scale { - class Ordinal extends Plottable.Abstract.Scale { + class Ordinal extends Abstract.Scale { + /** + * Creates a new OrdinalScale. Domain and Range are set later. + * + * @constructor + */ constructor(scale?: D3.Scale.OrdinalScale); - domain(): any[]; - domain(values: any[]): Ordinal; - range(): number[]; - range(values: number[]): Ordinal; - rangeBand(): number; - innerPadding(): number; - fullBandStartAndWidth(v: any): number[]; - rangeType(): string; - rangeType(rangeType: string, outerPadding?: number, innerPadding?: number): Ordinal; - copy(): Ordinal; + /** + * Gets the domain. + * + * @returns {any[]} The current domain. + */ + public domain(): any[]; + /** + * Sets the domain. + * + * @param {any[]} values The new values for the domain. This array may contain more than 2 values. + * @returns {Ordinal} The calling Ordinal Scale. + */ + public domain(values: any[]): Ordinal; + /** + * Gets the range of pixels spanned by the Ordinal Scale. + * + * @returns {number[]} The pixel range. + */ + public range(): number[]; + /** + * Sets the range of pixels spanned by the Ordinal Scale. + * + * @param {number[]} values The pixel range to to be spanend by the scale. + * @returns {Ordinal} The calling Ordinal Scale. + */ + public range(values: number[]): Ordinal; + /** + * Returns the width of the range band. Only valid when rangeType is set to "bands". + * + * @returns {number} The range band width or 0 if rangeType isn't "bands". + */ + public rangeBand(): number; + public innerPadding(): number; + public fullBandStartAndWidth(v: any): number[]; + /** + * Gets the range type. + * + * @returns {string} The current range type. + */ + public rangeType(): string; + /** + * Sets the range type. + * + * @param {string} rangeType Either "points" or "bands" indicating the + * d3 method used to generate range bounds. + * @param {number} [outerPadding] The padding outside the range, + * proportional to the range step. + * @param {number} [innerPadding] The padding between bands in the range, + * proportional to the range step. This parameter is only used in + * "bands" type ranges. + * @returns {Ordinal} The calling Ordinal Scale. + */ + public rangeType(rangeType: string, outerPadding?: number, innerPadding?: number): Ordinal; + /** + * Creates a copy of the Scale with the same domain and range but without any registered listeners. + * + * @returns {Ordinal} A copy of the calling Scale. + */ + public copy(): Ordinal; } } } @@ -553,7 +1507,15 @@ declare module Plottable { declare module Plottable { module Scale { - class Color extends Plottable.Abstract.Scale { + class Color extends Abstract.Scale { + /** + * Creates a ColorScale. + * + * @constructor + * @param {string} [scaleType] the type of color scale to create + * (Category10/Category20/Category20b/Category20c). + * See https://github.com/mbostock/d3/wiki/Ordinal-Scales#categorical-colors + */ constructor(scaleType?: string); } } @@ -562,13 +1524,24 @@ declare module Plottable { declare module Plottable { module Scale { - class Time extends Plottable.Abstract.QuantitativeScale { + class Time extends Abstract.QuantitativeScale { + /** + * Creates a new Time Scale. + * + * @constructor + * @param {D3.Scale.Time} [scale] The D3 LinearScale backing the TimeScale. If not supplied, uses a default scale. + */ constructor(); constructor(scale: D3.Scale.LinearScale); - tickInterval(interval: D3.Time.Interval, step?: number): any[]; - domain(): any[]; - domain(values: any[]): Time; - copy(): Time; + public tickInterval(interval: D3.Time.Interval, step?: number): any[]; + public domain(): any[]; + public domain(values: any[]): Time; + /** + * Creates a copy of the TimeScale with the same domain and range but without any registered listeners. + * + * @returns {TimeScale} A copy of the calling TimeScale. + */ + public copy(): Time; } } } @@ -576,13 +1549,58 @@ declare module Plottable { declare module Plottable { module Scale { - class InterpolatedColor extends Plottable.Abstract.QuantitativeScale { + /** + * This class implements a color scale that takes quantitive input and + * interpolates between a list of color values. It returns a hex string + * representing the interpolated color. + * + * By default it generates a linear scale internally. + */ + class InterpolatedColor extends Abstract.QuantitativeScale { + /** + * Creates a InterpolatedColorScale. + * + * @constructor + * @param {string|string[]} [colorRange] the type of color scale to + * create. Default is "reds". @see {@link colorRange} for further + * options. + * @param {string} [scaleType] the type of underlying scale to use + * (linear/pow/log/sqrt). Default is "linear". @see {@link scaleType} + * for further options. + */ constructor(colorRange?: any, scaleType?: string); - colorRange(): string[]; - colorRange(colorRange: any): InterpolatedColor; - scaleType(): string; - scaleType(scaleType: string): InterpolatedColor; - autoDomain(): InterpolatedColor; + /** + * Gets the color range. + * + * @returns {string[]} the current color values for the range as strings. + */ + public colorRange(): string[]; + /** + * Sets the color range. + * + * @param {string|string[]} colorRange. If colorRange is one of + * (reds/blues/posneg), uses the built-in color groups. If colorRange + * is an array of strings with at least 2 values + * (e.g. ["#FF00FF", "red", "dodgerblue"], the resulting scale + * will interpolate between the color values across the domain. + * @returns {InterpolatedColor} The calling InterpolatedColor Scale. + */ + public colorRange(colorRange: any): InterpolatedColor; + /** + * Gets the internal scale type. + * + * @returns {string} The current scale type. + */ + public scaleType(): string; + /** + * Sets the internal scale type. + * + * @param {string} scaleType. The type of d3 scale to use internally. + * (linear/log/sqrt/pow). + * @returns {InterpolatedColor} The calling InterpolatedColor Scale. + */ + public scaleType(scaleType: string): InterpolatedColor; + public autoDomain(): InterpolatedColor; } } } @@ -591,8 +1609,14 @@ declare module Plottable { declare module Plottable { module Util { class ScaleDomainCoordinator { - constructor(scales: Plottable.Abstract.Scale[]); - rescale(scale: Plottable.Abstract.Scale): void; + /** + * Creates a ScaleDomainCoordinator. + * + * @constructor + * @param {Scale[]} scales A list of scales whose domains should be linked. + */ + constructor(scales: Abstract.Scale[]); + public rescale(scale: Abstract.Scale): void; } } } @@ -601,29 +1625,138 @@ declare module Plottable { declare module Plottable { module Abstract { class Axis extends Component { + /** + * The css class applied to each end tick mark (the line on the end tick). + */ static END_TICK_MARK_CLASS: string; + /** + * The css class applied to each tick mark (the line on the tick). + */ static TICK_MARK_CLASS: string; + /** + * The css class applied to each tick label (the text associated with the tick). + */ static TICK_LABEL_CLASS: string; constructor(scale: Scale, orientation: string, formatter?: (d: any) => string); - remove(): void; - width(): number; - width(w: any): Axis; - height(): number; - height(h: any): Axis; - formatter(): Formatter; - formatter(formatter: Formatter): Axis; - tickLength(): number; - tickLength(length: number): Axis; - endTickLength(): number; - endTickLength(length: number): Axis; - tickLabelPadding(): number; - tickLabelPadding(padding: number): Axis; - gutter(): number; - gutter(size: number): Axis; - orient(): string; - orient(newOrientation: string): Axis; - showEndTickLabels(): boolean; - showEndTickLabels(show: boolean): Axis; + public remove(): void; + /** + * Gets the current width. + * + * @returns {number} The current width. + */ + public width(): number; + /** + * Sets a user-specified width. + * + * @param {number|String} w A fixed width for the Axis, or "auto" for automatic mode. + * @returns {Axis} The calling Axis. + */ + public width(w: any): Axis; + /** + * Gets the current height. + * + * @returns {number} The current height. + */ + public height(): number; + /** + * Sets a user-specified height. + * + * @param {number|String} h A fixed height for the Axis, or "auto" for automatic mode. + * @returns {Axis} The calling Axis. + */ + public height(h: any): Axis; + /** + * Get the current formatter on the axis. + * + * @returns {Formatter} the axis formatter + */ + public formatter(): Formatter; + /** + * Sets a new tick formatter. + * + * @param {Formatter} formatter + * @returns {Abstract.Axis} The calling Axis. + */ + public formatter(formatter: Formatter): Axis; + /** + * Gets the current tick mark length. + * + * @returns {number} The current tick mark length. + */ + public tickLength(): number; + /** + * Sets the tick mark length. + * + * @param {number} length The length of each tick. + * @returns {BaseAxis} The calling Axis. + */ + public tickLength(length: number): Axis; + /** + * Gets the current end tick mark length. + * + * @returns {number} The current end tick mark length. + */ + public endTickLength(): number; + /** + * Sets the end tick mark length. + * + * @param {number} length The length of the end ticks. + * @returns {BaseAxis} The calling Axis. + */ + public endTickLength(length: number): Axis; + /** + * Gets the padding between each tick mark and its associated label. + * + * @returns {number} The current padding, in pixels. + */ + public tickLabelPadding(): number; + /** + * Sets the padding between each tick mark and its associated label. + * + * @param {number} padding The desired padding, in pixels. + * @returns {Axis} The calling Axis. + */ + public tickLabelPadding(padding: number): Axis; + /** + * Gets the size of the gutter (the extra space between the tick labels and the outer edge of the axis). + * + * @returns {number} The current size of the gutter, in pixels. + */ + public gutter(): number; + /** + * Sets the size of the gutter (the extra space between the tick labels and the outer edge of the axis). + * + * @param {number} size The desired size of the gutter, in pixels. + * @returns {Axis} The calling Axis. + */ + public gutter(size: number): Axis; + /** + * Gets the orientation of the Axis. + * + * @returns {string} The current orientation. + */ + public orient(): string; + /** + * Sets the orientation of the Axis. + * + * @param {string} newOrientation The desired orientation (top/bottom/left/right). + * @returns {Axis} The calling Axis. + */ + public orient(newOrientation: string): Axis; + /** + * Checks whether the Axis is currently set to show the first and last + * tick labels. + * + * @returns {boolean} + */ + public showEndTickLabels(): boolean; + /** + * Set whether or not to show the first and last tick labels. + * + * @param {boolean} show Whether or not to show the first and last labels. + * @returns {Axis} The calling Axis. + */ + public showEndTickLabels(show: boolean): Axis; } } } @@ -636,13 +1769,20 @@ declare module Plottable { step: number; formatString: string; } - class Time extends Plottable.Abstract.Axis { + class Time extends Abstract.Axis { static minorIntervals: ITimeInterval[]; static majorIntervals: ITimeInterval[]; - constructor(scale: Plottable.Scale.Time, orientation: string); - calculateWorstWidth(container: D3.Selection, format: string): number; - getIntervalLength(interval: ITimeInterval): number; - isEnoughSpace(container: D3.Selection, interval: ITimeInterval): boolean; + /** + * Creates a TimeAxis + * + * @constructor + * @param {TimeScale} scale The scale to base the Axis on. + * @param {string} orientation The orientation of the Axis (top/bottom) + */ + constructor(scale: Scale.Time, orientation: string); + public calculateWorstWidth(container: D3.Selection, format: string): number; + public getIntervalLength(interval: ITimeInterval): number; + public isEnoughSpace(container: D3.Selection, interval: ITimeInterval): boolean; } } } @@ -650,12 +1790,54 @@ declare module Plottable { declare module Plottable { module Axis { - class Numeric extends Plottable.Abstract.Axis { - constructor(scale: Plottable.Abstract.QuantitativeScale, orientation: string, formatter?: (d: any) => string); - tickLabelPosition(): string; - tickLabelPosition(position: string): Numeric; - showEndTickLabel(orientation: string): boolean; - showEndTickLabel(orientation: string, show: boolean): Numeric; + class Numeric extends Abstract.Axis { + /** + * Creates a NumericAxis. + * + * @constructor + * @param {QuantitativeScale} scale The QuantitativeScale to base the NumericAxis on. + * @param {string} orientation The orientation of the QuantitativeScale (top/bottom/left/right) + * @param {Formatter} [formatter] A function to format tick labels (default Formatters.general(3, false)). + */ + constructor(scale: Abstract.QuantitativeScale, orientation: string, formatter?: (d: any) => string); + /** + * Gets the tick label position relative to the tick marks. + * + * @returns {string} The current tick label position. + */ + public tickLabelPosition(): string; + /** + * Sets the tick label position relative to the tick marks. + * + * @param {string} position The relative position of the tick label. + * [top/center/bottom] for a vertical NumericAxis, + * [left/center/right] for a horizontal NumericAxis. + * @returns {NumericAxis} The calling NumericAxis. + */ + public tickLabelPosition(position: string): Numeric; + /** + * Return whether or not the tick labels at the end of the graph are + * displayed when partially cut off. + * + * @param {string} orientation Where on the scale to change tick labels. + * On a "top" or "bottom" axis, this can be "left" or + * "right". On a "left" or "right" axis, this can be "top" + * or "bottom". + * @returns {boolean} The current setting. + */ + public showEndTickLabel(orientation: string): boolean; + /** + * Control whether or not the tick labels at the end of the graph are + * displayed when partially cut off. + * + * @param {string} orientation Where on the scale to change tick labels. + * On a "top" or "bottom" axis, this can be "left" or + * "right". On a "left" or "right" axis, this can be "top" + * or "bottom". + * @param {boolean} show Whether or not the given tick should be displayed. + * @returns {Numeric} The calling Numeric. + */ + public showEndTickLabel(orientation: string, show: boolean): Numeric; } } } @@ -663,8 +1845,19 @@ declare module Plottable { declare module Plottable { module Axis { - class Category extends Plottable.Abstract.Axis { - constructor(scale: Plottable.Scale.Ordinal, orientation?: string, formatter?: (d: any) => string); + class Category extends Abstract.Axis { + /** + * Creates a CategoryAxis. + * + * A CategoryAxis takes an OrdinalScale and includes word-wrapping algorithms and advanced layout logic to try to + * display the scale as efficiently as possible. + * + * @constructor + * @param {OrdinalScale} scale The scale to base the Axis on. + * @param {string} orientation The orientation of the Axis (top/bottom/left/right) + * @param {Formatter} [formatter] The Formatter for the Axis (default Formatters.identity()) + */ + constructor(scale: Scale.Ordinal, orientation?: string, formatter?: (d: any) => string); } } } @@ -672,12 +1865,30 @@ declare module Plottable { declare module Plottable { module Component { - class Label extends Plottable.Abstract.Component { + class Label extends Abstract.Component { + /** + * Creates a Label. + * + * @constructor + * @param {string} [displayText] The text of the Label. + * @param {string} [orientation] The orientation of the Label (horizontal/vertical-left/vertical-right). + */ constructor(displayText?: string, orientation?: string); - xAlign(alignment: string): Label; - yAlign(alignment: string): Label; - text(): string; - text(displayText: string): Label; + public xAlign(alignment: string): Label; + public yAlign(alignment: string): Label; + /** + * Retrieve the current text on the Label. + * + * @returns {string} The text on the label. + */ + public text(): string; + /** + * Sets the text on the Label. + * + * @param {string} displayText The new text for the Label. + * @returns {Label} The calling Label. + */ + public text(displayText: string): Label; } class TitleLabel extends Label { constructor(text?: string, orientation?: string); @@ -697,16 +1908,55 @@ declare module Plottable { interface HoverCallback { (datum?: string): any; } - class Legend extends Plottable.Abstract.Component { + class Legend extends Abstract.Component { + /** + * The css class applied to each legend row + */ static SUBELEMENT_CLASS: string; - constructor(colorScale?: Plottable.Scale.Color); - remove(): void; - toggleCallback(callback: ToggleCallback): Legend; - toggleCallback(): ToggleCallback; - hoverCallback(callback: HoverCallback): Legend; - hoverCallback(): HoverCallback; - scale(scale: Plottable.Scale.Color): Legend; - scale(): Plottable.Scale.Color; + /** + * Creates a Legend. + * + * A legend consists of a series of legend rows, each with a color and label taken from the `colorScale`. + * The rows will be displayed in the order of the `colorScale` domain. + * This legend also allows interactions, through the functions `toggleCallback` and `hoverCallback` + * Setting a callback will also put classes on the individual rows. + * + * @constructor + * @param {Scale.Color} colorScale + */ + constructor(colorScale?: Scale.Color); + public remove(): void; + /** + * Assigns or gets the callback to the Legend + * + * This callback is associated with toggle events, which trigger when a legend row is clicked. + * Internally, this will change the state of of the row from "toggled-on" to "toggled-off" and vice versa. + * Setting a callback will also set a class to each individual legend row as "toggled-on" or "toggled-off". + * Call with argument of null to remove the callback. This will also remove the above classes to legend rows. + * + * @param {ToggleCallback} callback The new callback function + */ + public toggleCallback(callback: ToggleCallback): Legend; + public toggleCallback(): ToggleCallback; + /** + * Assigns or gets the callback to the Legend + * This callback is associated with hover events, which trigger when the mouse enters or leaves a legend row + * Setting a callback will also set the class "hover" to all legend row, + * as well as the class "focus" to the legend row being hovered over. + * Call with argument of null to remove the callback. This will also remove the above classes to legend rows. + * + * @param{HoverCallback} callback The new callback function + */ + public hoverCallback(callback: HoverCallback): Legend; + public hoverCallback(): HoverCallback; + /** + * Assigns a new ColorScale to the Legend. + * + * @param {ColorScale} scale + * @returns {Legend} The calling Legend. + */ + public scale(scale: Scale.Color): Legend; + public scale(): Scale.Color; } } } @@ -714,9 +1964,16 @@ declare module Plottable { declare module Plottable { module Component { - class Gridlines extends Plottable.Abstract.Component { - constructor(xScale: Plottable.Abstract.QuantitativeScale, yScale: Plottable.Abstract.QuantitativeScale); - remove(): Gridlines; + class Gridlines extends Abstract.Component { + /** + * Creates a set of Gridlines. + * @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. + */ + constructor(xScale: Abstract.QuantitativeScale, yScale: Abstract.QuantitativeScale); + public remove(): Gridlines; } } } @@ -725,10 +1982,18 @@ declare module Plottable { declare module Plottable { module Abstract { class XYPlot extends Plot { - xScale: Scale; - yScale: Scale; + public xScale: Scale; + public yScale: Scale; + /** + * Creates an XYPlot. + * + * @constructor + * @param {any[]|DataSource} [dataset] The data or DataSource to be associated with this Renderer. + * @param {Scale} xScale The x scale to use. + * @param {Scale} yScale The y scale to use. + */ constructor(dataset: any, xScale: Scale, yScale: Scale); - project(attrToSet: string, accessor: any, scale?: Scale): XYPlot; + public project(attrToSet: string, accessor: any, scale?: Scale): XYPlot; } } } @@ -736,9 +2001,17 @@ declare module Plottable { declare module Plottable { module Plot { - class Scatter extends Plottable.Abstract.XYPlot { - constructor(dataset: any, xScale: Plottable.Abstract.Scale, yScale: Plottable.Abstract.Scale); - project(attrToSet: string, accessor: any, scale?: Plottable.Abstract.Scale): Scatter; + class Scatter extends Abstract.XYPlot { + /** + * Creates a ScatterPlot. + * + * @constructor + * @param {IDataset} dataset The dataset to render. + * @param {Scale} xScale The x scale to use. + * @param {Scale} yScale The y scale to use. + */ + constructor(dataset: any, xScale: Abstract.Scale, yScale: Abstract.Scale); + public project(attrToSet: string, accessor: any, scale?: Abstract.Scale): Scatter; } } } @@ -746,12 +2019,22 @@ declare module Plottable { declare module Plottable { module Plot { - class Grid extends Plottable.Abstract.XYPlot { - colorScale: Plottable.Abstract.Scale; - xScale: Plottable.Scale.Ordinal; - yScale: Plottable.Scale.Ordinal; - constructor(dataset: any, xScale: Plottable.Scale.Ordinal, yScale: Plottable.Scale.Ordinal, colorScale: Plottable.Abstract.Scale); - project(attrToSet: string, accessor: any, scale?: Plottable.Abstract.Scale): Grid; + class Grid extends Abstract.XYPlot { + public colorScale: Abstract.Scale; + public xScale: Scale.Ordinal; + public yScale: Scale.Ordinal; + /** + * Creates a GridPlot. + * + * @constructor + * @param {IDataset} dataset The dataset to render. + * @param {OrdinalScale} xScale The x scale to use. + * @param {OrdinalScale} yScale The y scale to use. + * @param {ColorScale|InterpolatedColorScale} colorScale The color scale to use for each grid + * cell. + */ + constructor(dataset: any, xScale: Scale.Ordinal, yScale: Scale.Ordinal, colorScale: Abstract.Scale); + public project(attrToSet: string, accessor: any, scale?: Abstract.Scale): Grid; } } } @@ -761,16 +2044,53 @@ declare module Plottable { module Abstract { class BarPlot extends XYPlot { static _BarAlignmentToFactor: { - [x: string]: number; + [alignment: string]: number; }; + /** + * Creates an AbstractBarPlot. + * + * @constructor + * @param {IDataset} dataset The dataset to render. + * @param {Scale} xScale The x scale to use. + * @param {Scale} yScale The y scale to use. + */ constructor(dataset: any, xScale: Scale, yScale: Scale); - baseline(value: number): BarPlot; - barAlignment(alignment: string): BarPlot; - selectBar(xValOrExtent: IExtent, yValOrExtent: IExtent, select?: boolean): D3.Selection; - selectBar(xValOrExtent: number, yValOrExtent: IExtent, select?: boolean): D3.Selection; - selectBar(xValOrExtent: IExtent, yValOrExtent: number, select?: boolean): D3.Selection; - selectBar(xValOrExtent: number, yValOrExtent: number, select?: boolean): D3.Selection; - deselectAll(): BarPlot; + /** + * Sets the baseline for the bars to the specified value. + * + * @param {number} value The value to position the baseline at. + * @return {AbstractBarPlot} The calling AbstractBarPlot. + */ + public baseline(value: number): BarPlot; + /** + * Sets the bar alignment relative to the independent axis. + * VerticalBarPlot supports "left", "center", "right" + * HorizontalBarPlot supports "top", "center", "bottom" + * + * @param {string} alignment The desired alignment. + * @return {AbstractBarPlot} The calling AbstractBarPlot. + */ + public barAlignment(alignment: string): BarPlot; + /** + * Selects the bar under the given pixel position (if [xValOrExtent] + * and [yValOrExtent] are {number}s), under a given line (if only one + * of [xValOrExtent] or [yValOrExtent] are {IExtent}s) or are under a + * 2D area (if [xValOrExtent] and [yValOrExtent] are both {IExtent}s). + * + * @param {any} xValOrExtent The pixel x position, or range of x values. + * @param {any} yValOrExtent The pixel y position, or range of y values. + * @param {boolean} [select] Whether or not to select the bar (by classing it "selected"); + * @return {D3.Selection} The selected bar, or null if no bar was selected. + */ + public selectBar(xValOrExtent: IExtent, yValOrExtent: IExtent, select?: boolean): D3.Selection; + public selectBar(xValOrExtent: number, yValOrExtent: IExtent, select?: boolean): D3.Selection; + public selectBar(xValOrExtent: IExtent, yValOrExtent: number, select?: boolean): D3.Selection; + public selectBar(xValOrExtent: number, yValOrExtent: number, select?: boolean): D3.Selection; + /** + * Deselects all bars. + * @return {AbstractBarPlot} The calling AbstractBarPlot. + */ + public deselectAll(): BarPlot; } } } @@ -778,11 +2098,28 @@ declare module Plottable { declare module Plottable { module Plot { - class VerticalBar extends Plottable.Abstract.BarPlot { + /** + * A VerticalBarPlot draws bars vertically. + * Key projected attributes: + * - "width" - the horizontal width of a bar. + * - if an ordinal scale is attached, this defaults to ordinalScale.rangeBand() + * - if a quantitative scale is attached, this defaults to 10 + * - "x" - the horizontal position of a bar + * - "y" - the vertical height of a bar + */ + class VerticalBar extends Abstract.BarPlot { static _BarAlignmentToFactor: { - [x: string]: number; + [alignment: string]: number; }; - constructor(dataset: any, xScale: Plottable.Abstract.Scale, yScale: Plottable.Abstract.QuantitativeScale); + /** + * Creates a VerticalBarPlot. + * + * @constructor + * @param {IDataset} dataset The dataset to render. + * @param {Scale} xScale The x scale to use. + * @param {QuantitativeScale} yScale The y scale to use. + */ + constructor(dataset: any, xScale: Abstract.Scale, yScale: Abstract.QuantitativeScale); } } } @@ -790,12 +2127,29 @@ declare module Plottable { declare module Plottable { module Plot { - class HorizontalBar extends Plottable.Abstract.BarPlot { + /** + * A HorizontalBarPlot draws bars horizontally. + * Key projected attributes: + * - "width" - the vertical height of a bar (since the bar is rotated horizontally) + * - if an ordinal scale is attached, this defaults to ordinalScale.rangeBand() + * - if a quantitative scale is attached, this defaults to 10 + * - "x" - the horizontal length of a bar + * - "y" - the vertical position of a bar + */ + class HorizontalBar extends Abstract.BarPlot { static _BarAlignmentToFactor: { - [x: string]: number; + [alignment: string]: number; }; - isVertical: boolean; - constructor(dataset: any, xScale: Plottable.Abstract.QuantitativeScale, yScale: Plottable.Abstract.Scale); + public isVertical: boolean; + /** + * Creates a HorizontalBarPlot. + * + * @constructor + * @param {IDataset} dataset The dataset to render. + * @param {QuantitativeScale} xScale The x scale to use. + * @param {Scale} yScale The y scale to use. + */ + constructor(dataset: any, xScale: Abstract.QuantitativeScale, yScale: Abstract.Scale); } } } @@ -803,8 +2157,16 @@ declare module Plottable { declare module Plottable { module Plot { - class Line extends Plottable.Abstract.XYPlot { - constructor(dataset: any, xScale: Plottable.Abstract.Scale, yScale: Plottable.Abstract.Scale); + class Line extends Abstract.XYPlot { + /** + * Creates a LinePlot. + * + * @constructor + * @param {IDataset} dataset The dataset to render. + * @param {Scale} xScale The x scale to use. + * @param {Scale} yScale The y scale to use. + */ + constructor(dataset: any, xScale: Abstract.Scale, yScale: Abstract.Scale); } } } @@ -812,9 +2174,20 @@ declare module Plottable { declare module Plottable { module Plot { + /** + * An AreaPlot draws a filled region (area) between the plot's projected "y" and projected "y0" values. + */ class Area extends Line { - constructor(dataset: any, xScale: Plottable.Abstract.Scale, yScale: Plottable.Abstract.Scale); - project(attrToSet: string, accessor: any, scale?: Plottable.Abstract.Scale): Area; + /** + * Creates an AreaPlot. + * + * @constructor + * @param {IDataset} dataset The dataset to render. + * @param {Scale} xScale The x scale to use. + * @param {Scale} yScale The y scale to use. + */ + constructor(dataset: any, xScale: Abstract.Scale, yScale: Abstract.Scale); + public project(attrToSet: string, accessor: any, scale?: Abstract.Scale): Area; } } } @@ -822,8 +2195,12 @@ declare module Plottable { declare module Plottable { module Animator { + /** + * An animator implementation with no animation. The attributes are + * immediately set on the selection. + */ class Null implements IPlotAnimator { - animate(selection: any, attrToProjector: Plottable.Abstract.IAttributeToProjector, plot: Plottable.Abstract.Plot): any; + public animate(selection: any, attrToProjector: Abstract.IAttributeToProjector, plot: Abstract.Plot): any; } } } @@ -831,14 +2208,50 @@ declare module Plottable { declare module Plottable { module Animator { + /** + * The default animator implementation with easing, duration, and delay. + */ class Default implements IPlotAnimator { - animate(selection: any, attrToProjector: Plottable.Abstract.IAttributeToProjector, plot: Plottable.Abstract.Plot): any; - duration(): Number; - duration(duration: Number): Default; - delay(): Number; - delay(delay: Number): Default; - easing(): string; - easing(easing: string): Default; + public animate(selection: any, attrToProjector: Abstract.IAttributeToProjector, plot: Abstract.Plot): any; + /** + * Gets the duration of the animation in milliseconds. + * + * @returns {Number} The current duration. + */ + public duration(): Number; + /** + * Sets the duration of the animation in milliseconds. + * + * @param {Number} duration The duration in milliseconds. + * @returns {Default} The calling Default Animator. + */ + public duration(duration: Number): Default; + /** + * Gets the delay of the animation in milliseconds. + * + * @returns {Number} The current delay. + */ + public delay(): Number; + /** + * Sets the delay of the animation in milliseconds. + * + * @param {Number} delay The delay in milliseconds. + * @returns {Default} The calling Default Animator. + */ + public delay(delay: Number): Default; + /** + * Gets the current easing of the animation. + * + * @returns {string} the current easing mode. + */ + public easing(): string; + /** + * Sets the easing mode of the animation. + * + * @param {string} easing The desired easing mode. + * @returns {Default} The calling Default Animator. + */ + public easing(easing: string): Default; } } } @@ -846,8 +2259,14 @@ declare module Plottable { declare module Plottable { module Animator { + /** + * An animator that delays the animation of the attributes using the index + * of the selection data. + * + * The delay between animations can be configured with the .delay getter/setter. + */ class IterativeDelay extends Default { - animate(selection: any, attrToProjector: Plottable.Abstract.IAttributeToProjector, plot: Plottable.Abstract.Plot): any; + public animate(selection: any, attrToProjector: Abstract.IAttributeToProjector, plot: Abstract.Plot): any; } } } @@ -869,10 +2288,20 @@ declare module Plottable { declare module Plottable { module Abstract { class Interaction { - hitBox: D3.Selection; - componentToListenTo: Component; + public hitBox: D3.Selection; + public componentToListenTo: Component; + /** + * Creates an Interaction. + * + * @constructor + * @param {Component} componentToListenTo The component to listen for interactions on. + */ constructor(componentToListenTo: Component); - registerWithComponent(): Interaction; + /** + * Registers the Interaction on the Component it's listening to. + * This needs to be called to activate the interaction. + */ + public registerWithComponent(): Interaction; } } } @@ -880,12 +2309,29 @@ declare module Plottable { declare module Plottable { module Interaction { - class Click extends Plottable.Abstract.Interaction { - constructor(componentToListenTo: Plottable.Abstract.Component); - callback(cb: (x: number, y: number) => any): Click; + class Click extends Abstract.Interaction { + /** + * Creates a ClickInteraction. + * + * @constructor + * @param {Component} componentToListenTo The component to listen for clicks on. + */ + constructor(componentToListenTo: Abstract.Component); + /** + * Sets an callback to be called when a click is received. + * + * @param {(x: number, y: number) => any} cb: Callback to be called. Takes click x and y in pixels. + */ + public callback(cb: (x: number, y: number) => any): Click; } class DoubleClick extends Click { - constructor(componentToListenTo: Plottable.Abstract.Component); + /** + * Creates a DoubleClickInteraction. + * + * @constructor + * @param {Component} componentToListenTo The component to listen for clicks on. + */ + constructor(componentToListenTo: Abstract.Component); } } } @@ -893,9 +2339,9 @@ declare module Plottable { declare module Plottable { module Interaction { - class Mousemove extends Plottable.Abstract.Interaction { - constructor(componentToListenTo: Plottable.Abstract.Component); - mousemove(x: number, y: number): void; + class Mousemove extends Abstract.Interaction { + constructor(componentToListenTo: Abstract.Component); + public mousemove(x: number, y: number): void; } } } @@ -903,9 +2349,21 @@ declare module Plottable { declare module Plottable { module Interaction { - class Key extends Plottable.Abstract.Interaction { - constructor(componentToListenTo: Plottable.Abstract.Component, keyCode: number); - callback(cb: () => any): Key; + class Key extends Abstract.Interaction { + /** + * Creates a KeyInteraction. + * + * @constructor + * @param {Component} componentToListenTo The component to listen for keypresses on. + * @param {number} keyCode The key code to listen for. + */ + constructor(componentToListenTo: Abstract.Component, keyCode: number); + /** + * Sets an callback to be called when the designated key is pressed. + * + * @param {() => any} cb: Callback to be called. + */ + public callback(cb: () => any): Key; } } } @@ -913,11 +2371,19 @@ declare module Plottable { declare module Plottable { module Interaction { - class PanZoom extends Plottable.Abstract.Interaction { - xScale: Plottable.Abstract.QuantitativeScale; - yScale: Plottable.Abstract.QuantitativeScale; - constructor(componentToListenTo: Plottable.Abstract.Component, xScale?: Plottable.Abstract.QuantitativeScale, yScale?: Plottable.Abstract.QuantitativeScale); - resetZoom(): void; + class PanZoom extends Abstract.Interaction { + public xScale: Abstract.QuantitativeScale; + public yScale: Abstract.QuantitativeScale; + /** + * Creates a PanZoomInteraction. + * + * @constructor + * @param {Component} componentToListenTo The component to listen for interactions on. + * @param {QuantitativeScale} [xScale] The X scale to update on panning/zooming. + * @param {QuantitativeScale} [yScale] The Y scale to update on panning/zooming. + */ + constructor(componentToListenTo: Abstract.Component, xScale?: Abstract.QuantitativeScale, yScale?: Abstract.QuantitativeScale); + public resetZoom(): void; } } } @@ -925,13 +2391,24 @@ declare module Plottable { declare module Plottable { module Interaction { - class Drag extends Plottable.Abstract.Interaction { - origin: number[]; - location: number[]; - callbackToCall: (dragInfo: any) => any; - constructor(componentToListenTo: Plottable.Abstract.Component); - callback(cb?: (a: any) => any): Drag; - setupZoomCallback(xScale?: Plottable.Abstract.QuantitativeScale, yScale?: Plottable.Abstract.QuantitativeScale): Drag; + class Drag extends Abstract.Interaction { + public origin: number[]; + public location: number[]; + public callbackToCall: (dragInfo: any) => any; + /** + * Creates a Drag. + * + * @param {Component} componentToListenTo The component to listen for interactions on. + */ + constructor(componentToListenTo: Abstract.Component); + /** + * Adds a callback to be called when the AreaInteraction triggers. + * + * @param {(a: SelectionArea) => any} cb The function to be called. Takes in a SelectionArea in pixels. + * @returns {AreaInteraction} The calling AreaInteraction. + */ + public callback(cb?: (a: any) => any): Drag; + public setupZoomCallback(xScale?: Abstract.QuantitativeScale, yScale?: Abstract.QuantitativeScale): Drag; } } } @@ -940,10 +2417,15 @@ declare module Plottable { declare module Plottable { module Interaction { class DragBox extends Drag { - dragBox: D3.Selection; - boxIsDrawn: boolean; - clearBox(): DragBox; - setBox(x0: number, x1: number, y0: number, y1: number): DragBox; + public dragBox: D3.Selection; + public boxIsDrawn: boolean; + /** + * Clears the highlighted drag-selection box drawn by the AreaInteraction. + * + * @returns {AreaInteraction} The calling AreaInteraction. + */ + public clearBox(): DragBox; + public setBox(x0: number, x1: number, y0: number, y1: number): DragBox; } } } @@ -952,7 +2434,7 @@ declare module Plottable { declare module Plottable { module Interaction { class XDragBox extends DragBox { - setBox(x0: number, x1: number): XDragBox; + public setBox(x0: number, x1: number): XDragBox; } } } @@ -969,7 +2451,7 @@ declare module Plottable { declare module Plottable { module Interaction { class YDragBox extends DragBox { - setBox(y0: number, y1: number): YDragBox; + public setBox(y0: number, y1: number): YDragBox; } } } @@ -978,11 +2460,37 @@ declare module Plottable { declare module Plottable { module Abstract { class Dispatcher extends PlottableObject { + /** + * Creates a Dispatcher with the specified target. + * + * @param {D3.Selection} target The selection to listen for events on. + */ constructor(target: D3.Selection); - target(): D3.Selection; - target(targetElement: D3.Selection): Dispatcher; - connect(): Dispatcher; - disconnect(): Dispatcher; + /** + * Gets the target of the Dispatcher. + * + * @returns {D3.Selection} The Dispatcher's current target. + */ + public target(): D3.Selection; + /** + * Sets the target of the Dispatcher. + * + * @param {D3.Selection} target The element to listen for updates on. + * @returns {Dispatcher} The calling Dispatcher. + */ + public target(targetElement: D3.Selection): Dispatcher; + /** + * Attaches the Dispatcher's listeners to the Dispatcher's target element. + * + * @returns {Dispatcher} The calling Dispatcher. + */ + public connect(): Dispatcher; + /** + * Detaches the Dispatcher's listeners from the Dispatchers' target element. + * + * @returns {Dispatcher} The calling Dispatcher. + */ + public disconnect(): Dispatcher; } } } @@ -990,14 +2498,55 @@ declare module Plottable { declare module Plottable { module Dispatcher { - class Mouse extends Plottable.Abstract.Dispatcher { + class Mouse extends Abstract.Dispatcher { + /** + * Creates a Mouse Dispatcher with the specified target. + * + * @param {D3.Selection} target The selection to listen for events on. + */ constructor(target: D3.Selection); - mouseover(): (location: Point) => any; - mouseover(callback: (location: Point) => any): Mouse; - mousemove(): (location: Point) => any; - mousemove(callback: (location: Point) => any): Mouse; - mouseout(): (location: Point) => any; - mouseout(callback: (location: Point) => any): Mouse; + /** + * Gets the current callback to be called on mouseover. + * + * @return {(location: Point) => any} The current mouseover callback. + */ + public mouseover(): (location: Point) => any; + /** + * Attaches a callback to be called on mouseover. + * + * @param {(location: Point) => any} callback A function that takes the pixel position of the mouse event. + * Pass in null to remove the callback. + * @return {Mouse} The calling Mouse Handler. + */ + public mouseover(callback: (location: Point) => any): Mouse; + /** + * Gets the current callback to be called on mousemove. + * + * @return {(location: Point) => any} The current mousemove callback. + */ + public mousemove(): (location: Point) => any; + /** + * Attaches a callback to be called on mousemove. + * + * @param {(location: Point) => any} callback A function that takes the pixel position of the mouse event. + * Pass in null to remove the callback. + * @return {Mouse} The calling Mouse Handler. + */ + public mousemove(callback: (location: Point) => any): Mouse; + /** + * Gets the current callback to be called on mouseout. + * + * @return {(location: Point) => any} The current mouseout callback. + */ + public mouseout(): (location: Point) => any; + /** + * Attaches a callback to be called on mouseout. + * + * @param {(location: Point) => any} callback A function that takes the pixel position of the mouse event. + * Pass in null to remove the callback. + * @return {Mouse} The calling Mouse Handler. + */ + public mouseout(callback: (location: Point) => any): Mouse; } } } @@ -1005,22 +2554,22 @@ declare module Plottable { declare module Plottable { module Template { - class StandardChart extends Plottable.Component.Table { + class StandardChart extends Component.Table { constructor(); - yAxis(y: Plottable.Abstract.Axis): StandardChart; - yAxis(): Plottable.Abstract.Axis; - xAxis(x: Plottable.Abstract.Axis): StandardChart; - xAxis(): Plottable.Abstract.Axis; - yLabel(y: Plottable.Component.AxisLabel): StandardChart; - yLabel(y: string): StandardChart; - yLabel(): Plottable.Component.AxisLabel; - xLabel(x: Plottable.Component.AxisLabel): StandardChart; - xLabel(x: string): StandardChart; - xLabel(): Plottable.Component.AxisLabel; - titleLabel(x: Plottable.Component.TitleLabel): StandardChart; - titleLabel(x: string): StandardChart; - titleLabel(): Plottable.Component.TitleLabel; - center(c: Plottable.Abstract.Component): StandardChart; + public yAxis(y: Abstract.Axis): StandardChart; + public yAxis(): Abstract.Axis; + public xAxis(x: Abstract.Axis): StandardChart; + public xAxis(): Abstract.Axis; + public yLabel(y: Component.AxisLabel): StandardChart; + public yLabel(y: string): StandardChart; + public yLabel(): Component.AxisLabel; + public xLabel(x: Component.AxisLabel): StandardChart; + public xLabel(x: string): StandardChart; + public xLabel(): Component.AxisLabel; + public titleLabel(x: Component.TitleLabel): StandardChart; + public titleLabel(x: string): StandardChart; + public titleLabel(): Component.TitleLabel; + public center(c: Abstract.Component): StandardChart; } } } diff --git a/plottable.js b/plottable.js index 32a48b42cc..09011dbe49 100644 --- a/plottable.js +++ b/plottable.js @@ -1,35 +1,68 @@ /*! -Plottable 0.23.2 (https://github.com/palantir/plottable) +Plottable 0.24.0 (https://github.com/palantir/plottable) Copyright 2014 Palantir Technologies Licensed under MIT (https://github.com/palantir/plottable/blob/master/LICENSE) */ +/// var Plottable; (function (Plottable) { (function (Util) { (function (Methods) { + /** + * 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 (Math.min(a, b) <= x && x <= Math.max(a, b)); } Methods.inRange = inRange; + + /** Print a warning message to the console, if it is available. + * + * @param {string} The warnings to print + */ function warn(warning) { + /* tslint:disable:no-console */ if (window.console != null) { if (window.console.warn != null) { console.warn(warning); - } - else if (window.console.log != null) { + } else if (window.console.log != null) { console.log(warning); } } + /* tslint:enable:no-console */ } Methods.warn = warn; + + /** + * 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 addArrays(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]; }); + return alist.map(function (_, i) { + return alist[i] + blist[i]; + }); } Methods.addArrays = addArrays; + + /** + * Takes two sets and returns the intersection + * + * @param {D3.Set} set1 The first set + * @param {D3.Set} set2 The second set + * @return {D3.Set} A set that contains elements that appear in both set1 and set2 + */ function intersection(set1, set2) { var set = d3.set(); set1.forEach(function (v) { @@ -40,37 +73,66 @@ var Plottable; return set; } Methods.intersection = intersection; + + /** + * Take an accessor object (may be a string to be made into a key, or a value, or a color code) + * and "activate" it by turning it into a function in (datum, index, metadata) + */ function _accessorize(accessor) { if (typeof (accessor) === "function") { return accessor; - } - else if (typeof (accessor) === "string" && accessor[0] !== "#") { - return function (d, i, s) { return d[accessor]; }; - } - else { - return function (d, i, s) { return accessor; }; + } else if (typeof (accessor) === "string" && accessor[0] !== "#") { + return function (d, i, s) { + return d[accessor]; + }; + } else { + return function (d, i, s) { + return accessor; + }; } ; } Methods._accessorize = _accessorize; + + /** + * Takes two sets and returns the union + * + * @param{D3.Set} set1 The first set + * @param{D3.Set} set2 The second set + * @return{D3.Set} A set that contains elements that appear in either set1 or set2 + */ function union(set1, set2) { var set = d3.set(); - set1.forEach(function (v) { return set.add(v); }); - set2.forEach(function (v) { return set.add(v); }); + set1.forEach(function (v) { + return set.add(v); + }); + set2.forEach(function (v) { + return set.add(v); + }); return set; } Methods.union = union; + + /** + * Take an accessor object, activate it, and partially apply it to a Plot's datasource's metadata + */ function _applyAccessor(accessor, plot) { var activatedAccessor = _accessorize(accessor); - return function (d, i) { return activatedAccessor(d, i, plot.dataSource().metadata()); }; + return function (d, i) { + return activatedAccessor(d, i, plot.dataSource().metadata()); + }; } Methods._applyAccessor = _applyAccessor; + function uniq(strings) { var seen = {}; - strings.forEach(function (s) { return seen[s] = true; }); + strings.forEach(function (s) { + return seen[s] = true; + }); return d3.keys(seen); } Methods.uniq = uniq; + function uniqNumbers(a) { var seen = d3.set(); var result = []; @@ -83,6 +145,14 @@ var Plottable; return result; } Methods.uniqNumbers = uniqNumbers; + + /** + * Creates an array of length `count`, filled with value or (if value is a function), value() + * + * @param {any} value The value to fill the array with, or, if a function, a generator for values + * @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++) { @@ -91,11 +161,21 @@ var Plottable; return out; } Methods.createFilledArray = createFilledArray; + + /** + * @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 Array.prototype.concat.apply([], a); } Methods.flatten = flatten; + + /** + * 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; } @@ -110,14 +190,27 @@ var Plottable; 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]; }); + 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; @@ -127,20 +220,26 @@ var Plottable; var Util = Plottable.Util; })(Plottable || (Plottable = {})); +/// +// This file contains open source utilities, along with their copyright notices var Plottable; (function (Plottable) { (function (Util) { (function (OpenSource) { + + function sortedIndex(val, arr, accessor) { var low = 0; var high = arr.length; while (low < high) { + /* tslint:disable:no-bitwise */ var mid = (low + high) >>> 1; + + /* tslint:enable:no-bitwise */ var x = accessor == null ? arr[mid] : accessor(arr[mid]); if (x < val) { low = mid + 1; - } - else { + } else { high = mid; } } @@ -154,6 +253,7 @@ var Plottable; var Util = Plottable.Util; })(Plottable || (Plottable = {})); +/// var Plottable; (function (Plottable) { (function (Util) { @@ -166,14 +266,17 @@ var Plottable; this.counter[id] = 0; } }; + IDCounter.prototype.increment = function (id) { this.setDefault(id); return ++this.counter[id]; }; + IDCounter.prototype.decrement = function (id) { this.setDefault(id); return --this.counter[id]; }; + IDCounter.prototype.get = function (id) { this.setDefault(id); return this.counter[id]; @@ -185,13 +288,26 @@ var Plottable; var Util = Plottable.Util; })(Plottable || (Plottable = {})); +/// var Plottable; (function (Plottable) { (function (Util) { + /** + * An associative array that can be keyed by anything (inc objects). + * Uses pointer equality checks which is why this works. + * This power has a price: everything is linear time since it is actually backed by an array... + */ var StrictEqualityAssociativeArray = (function () { function StrictEqualityAssociativeArray() { this.keyValuePairs = []; } + /** + * Set a new key/value pair in the store. + * + * @param {any} key Key to set in the store + * @param {any} value Value to set in the store + * @return {boolean} True if key already in store, false otherwise + */ StrictEqualityAssociativeArray.prototype.set = function (key, value) { if (key !== key) { throw new Error("NaN may not be used as a key to the StrictEqualityAssociativeArray"); @@ -205,6 +321,13 @@ var Plottable; this.keyValuePairs.push([key, value]); return false; }; + + /** + * Get a value from the store, given a key. + * + * @param {any} key Key associated with value to retrieve + * @return {any} Value if found, undefined otherwise + */ StrictEqualityAssociativeArray.prototype.get = function (key) { for (var i = 0; i < this.keyValuePairs.length; i++) { if (this.keyValuePairs[i][0] === key) { @@ -213,6 +336,16 @@ var Plottable; } return undefined; }; + + /** + * Test whether store has a value associated with given key. + * + * Will return true if there is a key/value entry, + * even if the value is explicitly `undefined`. + * + * @param {any} key Key to test for presence of an entry + * @return {boolean} Whether there was a matching entry for that key + */ StrictEqualityAssociativeArray.prototype.has = function (key) { for (var i = 0; i < this.keyValuePairs.length; i++) { if (this.keyValuePairs[i][0] === key) { @@ -221,17 +354,47 @@ var Plottable; } return false; }; + + /** + * Return an array of the values in the key-value store + * + * @return {any[]} The values in the store + */ StrictEqualityAssociativeArray.prototype.values = function () { - return this.keyValuePairs.map(function (x) { return x[1]; }); + return this.keyValuePairs.map(function (x) { + return x[1]; + }); }; + + /** + * Return an array of keys in the key-value store + * + * @return {any[]} The keys in the store + */ StrictEqualityAssociativeArray.prototype.keys = function () { - return this.keyValuePairs.map(function (x) { return x[0]; }); + return this.keyValuePairs.map(function (x) { + return x[0]; + }); }; + + /** + * Execute a callback for each entry in the array. + * + * @param {(key: any, val?: any, index?: number) => any} callback The callback to eecute + * @return {any[]} The results of mapping the callback over the entries + */ StrictEqualityAssociativeArray.prototype.map = function (cb) { return this.keyValuePairs.map(function (kv, index) { return cb(kv[0], kv[1], index); }); }; + + /** + * Delete a key from the key-value store. Return whether the key was present. + * + * @param {any} The key to remove + * @return {boolean} Whether a matching entry was found and removed + */ StrictEqualityAssociativeArray.prototype.delete = function (key) { for (var i = 0; i < this.keyValuePairs.length; i++) { if (this.keyValuePairs[i][0] === key) { @@ -248,12 +411,26 @@ var Plottable; var Util = Plottable.Util; })(Plottable || (Plottable = {})); +/// var Plottable; (function (Plottable) { (function (Util) { var Cache = (function () { + /** + * @constructor + * + * @param {string} compute The function whose results will be cached. + * @param {string} [canonicalKey] If present, when clear() is called, + * this key will be re-computed. If its result hasn't been changed, + * the cache will not be cleared. + * @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, canonicalKey, valueEq) { - if (valueEq === void 0) { valueEq = function (v, w) { return v === w; }; } + if (typeof valueEq === "undefined") { valueEq = function (v, w) { + return v === w; + }; } this.cache = d3.map(); this.canonicalKey = null; this.compute = compute; @@ -263,12 +440,29 @@ var Plottable; this.cache.set(this.canonicalKey, this.compute(this.canonicalKey)); } } + /** + * 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. + * + * If canonicalKey was provided at construction, compute(canonicalKey) + * will be re-run. If the result matches what is already in the cache, + * it will not clear the cache. + * + * @return {Cache} The calling Cache. + */ Cache.prototype.clear = function () { if (this.canonicalKey === undefined || !this.valueEq(this.cache.get(this.canonicalKey), this.compute(this.canonicalKey))) { this.cache = d3.map(); @@ -282,12 +476,21 @@ var Plottable; var Util = Plottable.Util; })(Plottable || (Plottable = {})); +/// var Plottable; (function (Plottable) { (function (Util) { (function (Text) { ; + ; + + /** + * Returns a quasi-pure function of typesignature (t: string) => Dimensions which measures height and width of text + * + * @param {D3.Selection} selection: The selection in which text will be drawn and measured + * @returns {Dimensions} width and height of the text + */ function getTextMeasure(selection) { return function (s) { if (s.trim() === "") { @@ -300,8 +503,7 @@ var Plottable; bb = Util.DOM.getBBox(selection); selection.text(originalText); return { width: bb.width, height: bb.height }; - } - else { + } else { var t = selection.append("text").text(s); bb = Util.DOM.getBBox(t); t.remove(); @@ -310,19 +512,45 @@ var Plottable; }; } Text.getTextMeasure = getTextMeasure; + + /** + * @return {TextMeasurer} A test measurer that will treat all sequences + * of consecutive whitespace as a single " ". + */ function combineWhitespace(tm) { - return function (s) { return tm(s.replace(/\s+/g, " ")); }; + return function (s) { + return tm(s.replace(/\s+/g, " ")); + }; } + + /** + * Returns a text measure that measures each individual character of the + * string with tm, then combines all the individual measurements. + */ function measureByCharacter(tm) { return function (s) { var whs = s.trim().split("").map(tm); return { - width: d3.sum(whs, function (wh) { return wh.width; }), - height: d3.max(whs, function (wh) { return wh.height; }) + width: d3.sum(whs, function (wh) { + return wh.width; + }), + height: d3.max(whs, function (wh) { + return wh.height; + }) }; }; } + var CANONICAL_CHR = "a"; + + /** + * Some TextMeasurers get confused when measuring something that's only + * whitespace: only whitespace in a dom node takes up 0 x 0 space. + * + * @return {TextMeasurer} A function that if its argument is all + * whitespace, it will wrap its argument in CANONICAL_CHR before + * measuring in order to get a non-zero size of the whitespace. + */ function wrapWhitespace(tm) { return function (s) { if (/^\s*$/.test(s)) { @@ -335,21 +563,40 @@ var Plottable; }; }); return { - width: d3.sum(whs, function (x) { return x.width; }), - height: d3.max(whs, function (x) { return x.height; }) + width: d3.sum(whs, function (x) { + return x.width; + }), + height: d3.max(whs, function (x) { + return x.height; + }) }; - } - else { + } else { return tm(s); } }; } + + /** + * This class will measure text by measuring each character individually, + * then adding up the dimensions. It will also cache the dimensions of each + * letter. + */ var CachingCharacterMeasurer = (function () { + /** + * @param {D3.Selection} g The element that will have text inserted into + * it in order to measure text. The styles present for text in + * this element will to the text being measured. + */ function CachingCharacterMeasurer(g) { var _this = this; this.cache = new Util.Cache(getTextMeasure(g), CANONICAL_CHR, Util.Methods.objEq); - this.measure = combineWhitespace(measureByCharacter(wrapWhitespace(function (s) { return _this.cache.get(s); }))); + this.measure = combineWhitespace(measureByCharacter(wrapWhitespace(function (s) { + return _this.cache.get(s); + }))); } + /** + * Clear the cache, if it seems that the text has changed size. + */ CachingCharacterMeasurer.prototype.clear = function () { this.cache.clear(); return this; @@ -357,26 +604,55 @@ var Plottable; return CachingCharacterMeasurer; })(); Text.CachingCharacterMeasurer = CachingCharacterMeasurer; + + /** + * Gets a truncated version of a sting that fits in the available space, given the element in which to draw the text + * + * @param {string} text: The string to be truncated + * @param {number} availableWidth: The available width, in pixels + * @param {D3.Selection} element: The text element used to measure the text + * @returns {string} text - the shortened text + */ function getTruncatedText(text, availableWidth, measurer) { if (measurer(text).width <= availableWidth) { return text; - } - else { + } else { return _addEllipsesToLine(text, availableWidth, measurer); } } Text.getTruncatedText = getTruncatedText; + + /** + * Gets the height of a text element, as rendered. + * + * @param {D3.Selection} textElement + * @return {number} The height of the text element, in pixels. + */ function getTextHeight(selection) { return getTextMeasure(selection)("bqpdl").height; } Text.getTextHeight = getTextHeight; + + /** + * Gets the width of a text element, as rendered. + * + * @param {D3.Selection} textElement + * @return {number} The width of the text element, in pixels. + */ function getTextWidth(textElement, text) { return getTextMeasure(textElement)(text).width; } Text.getTextWidth = getTextWidth; + + /** + * Takes a line, a width to fit it in, and a text measurer. Will attempt to add ellipses to the end of the line, + * shortening the line as required to ensure that it fits within width. + */ function _addEllipsesToLine(line, width, measureText) { var mutatedLine = line.trim(); - var widthMeasure = function (s) { return measureText(s).width; }; + var widthMeasure = function (s) { + return measureText(s).width; + }; var lineWidth = widthMeasure(line); var ellipsesWidth = widthMeasure("..."); if (width < ellipsesWidth) { @@ -394,9 +670,10 @@ var Plottable; return mutatedLine + "..."; } Text._addEllipsesToLine = _addEllipsesToLine; + function writeLineHorizontally(line, g, width, height, xAlign, yAlign) { - if (xAlign === void 0) { xAlign = "left"; } - if (yAlign === void 0) { yAlign = "top"; } + if (typeof xAlign === "undefined") { xAlign = "left"; } + if (typeof yAlign === "undefined") { yAlign = "top"; } var xOffsetFactor = { left: 0, center: 0.5, right: 1 }; var yOffsetFactor = { top: 0, center: 0.5, bottom: 1 }; if (xOffsetFactor[xAlign] === undefined || yOffsetFactor[yAlign] === undefined) { @@ -423,10 +700,11 @@ var Plottable; return { width: w, height: h }; } Text.writeLineHorizontally = writeLineHorizontally; + function writeLineVertically(line, g, width, height, xAlign, yAlign, rotation) { - if (xAlign === void 0) { xAlign = "left"; } - if (yAlign === void 0) { yAlign = "top"; } - if (rotation === void 0) { rotation = "right"; } + if (typeof xAlign === "undefined") { xAlign = "left"; } + if (typeof yAlign === "undefined") { yAlign = "top"; } + if (typeof rotation === "undefined") { rotation = "right"; } if (rotation !== "right" && rotation !== "left") { throw new Error("unrecognized rotation: " + rotation); } @@ -440,12 +718,14 @@ var Plottable; xForm.rotate = rotation === "right" ? 90 : -90; xForm.translate = [isRight ? width : 0, isRight ? 0 : height]; innerG.attr("transform", xForm.toString()); + return wh; } Text.writeLineVertically = writeLineVertically; + function writeTextHorizontally(brokenText, g, width, height, xAlign, yAlign) { - if (xAlign === void 0) { xAlign = "left"; } - if (yAlign === void 0) { yAlign = "top"; } + if (typeof xAlign === "undefined") { xAlign = "left"; } + if (typeof yAlign === "undefined") { yAlign = "top"; } var h = getTextHeight(g); var maxWidth = 0; var blockG = g.append("g"); @@ -464,10 +744,11 @@ var Plottable; return { width: maxWidth, height: usedSpace }; } Text.writeTextHorizontally = writeTextHorizontally; + function writeTextVertically(brokenText, g, width, height, xAlign, yAlign, rotation) { - if (xAlign === void 0) { xAlign = "left"; } - if (yAlign === void 0) { yAlign = "top"; } - if (rotation === void 0) { rotation = "left"; } + if (typeof xAlign === "undefined") { xAlign = "left"; } + if (typeof yAlign === "undefined") { yAlign = "top"; } + if (typeof rotation === "undefined") { rotation = "left"; } var h = getTextHeight(g); var maxHeight = 0; var blockG = g.append("g"); @@ -483,32 +764,50 @@ var Plottable; var freeSpace = width - usedSpace; var translator = { center: 0.5, left: 0, right: 1 }; Util.DOM.translate(blockG, freeSpace * translator[xAlign], 0); + return { width: usedSpace, height: maxHeight }; } Text.writeTextVertically = writeTextVertically; + ; + + /** + * @param {write} [IWriteOptions] If supplied, the text will be written + * To the given g. Will align the text vertically if it seems like + * that is appropriate. + * Returns an IWriteTextResult with info on whether the text fit, and how much width/height was used. + */ function writeText(text, width, height, tm, horizontally, write) { var orientHorizontally = (horizontally != null) ? horizontally : width * 1.1 > height; var primaryDimension = orientHorizontally ? width : height; var secondaryDimension = orientHorizontally ? height : width; var wrappedText = Util.WordWrap.breakTextToFitRect(text, primaryDimension, secondaryDimension, tm); + if (wrappedText.lines.length === 0) { return { textFits: wrappedText.textFits, usedWidth: 0, usedHeight: 0 }; } + var usedWidth, usedHeight; if (write == null) { var widthFn = orientHorizontally ? d3.max : d3.sum; var heightFn = orientHorizontally ? d3.sum : d3.max; - usedWidth = widthFn(wrappedText.lines, function (line) { return tm(line).width; }); - usedHeight = heightFn(wrappedText.lines, function (line) { return tm(line).height; }); - } - else { + usedWidth = widthFn(wrappedText.lines, function (line) { + return tm(line).width; + }); + usedHeight = heightFn(wrappedText.lines, function (line) { + return tm(line).height; + }); + } else { var innerG = write.g.append("g").classed("writeText-inner-g", true); + + // the outerG contains general transforms for positining the whole block, the inner g + // will contain transforms specific to orienting the text properly within the block. var writeTextFn = orientHorizontally ? writeTextHorizontally : writeTextVertically; var wh = writeTextFn(wrappedText.lines, innerG, width, height, write.xAlign, write.yAlign); usedWidth = wh.width; usedHeight = wh.height; } + return { textFits: wrappedText.textFits, usedWidth: usedWidth, usedHeight: usedHeight }; } Text.writeText = writeText; @@ -518,6 +817,7 @@ var Plottable; var Util = Plottable.Util; })(Plottable || (Plottable = {})); +/// var Plottable; (function (Plottable) { (function (Util) { @@ -525,9 +825,17 @@ var Plottable; var LINE_BREAKS_BEFORE = /[{\[]/; var LINE_BREAKS_AFTER = /[!"%),-.:;?\]}]/; var SPACES = /^\s+$/; + ; + + /** + * Takes a block of text, a width and height to fit it in, and a 2-d text measurement function. + * Wraps words and fits as much of the text as possible into the given width and height. + */ function breakTextToFitRect(text, width, height, measureText) { - var widthMeasure = function (s) { return measureText(s).width; }; + var widthMeasure = function (s) { + return measureText(s).width; + }; var lines = breakTextToFitWidth(text, width, widthMeasure); var textHeight = measureText("hello world").height; var nLinesThatFit = Math.floor(height / textHeight); @@ -535,12 +843,19 @@ var Plottable; if (!textFit) { lines = lines.splice(0, nLinesThatFit); if (nLinesThatFit > 0) { + // Overwrite the last line to one that has had a ... appended to the end lines[nLinesThatFit - 1] = Util.Text._addEllipsesToLine(lines[nLinesThatFit - 1], width, measureText); } } return { originalText: text, lines: lines, textFits: textFit }; } WordWrap.breakTextToFitRect = breakTextToFitRect; + + /** + * Splits up the text so that it will fit in width (or splits into a list of single characters if it is impossible + * to fit in width). Tries to avoid breaking words on non-linebreak-or-space characters, and will only break a word if + * the word is too big to fit within width on its own. + */ function breakTextToFitWidth(text, width, widthMeasure) { var ret = []; var paragraphs = text.split("\n"); @@ -548,13 +863,18 @@ var Plottable; var paragraph = paragraphs[i]; if (paragraph !== null) { ret = ret.concat(breakParagraphToFitWidth(paragraph, width, widthMeasure)); - } - else { + } else { ret.push(""); } } return ret; } + + /** + * Determines if it is possible to fit a given text within width without breaking any of the words. + * Simple algorithm, split the text up into tokens, and make sure that the widest token doesn't exceed + * allowed width. + */ function canWrapWithoutBreakingWords(text, width, widthMeasure) { var tokens = tokenize(text); var widths = tokens.map(widthMeasure); @@ -562,6 +882,13 @@ var Plottable; return maxWidth <= width; } WordWrap.canWrapWithoutBreakingWords = canWrapWithoutBreakingWords; + + /** + * A paragraph is a string of text containing no newlines. + * Given a paragraph, break it up into lines that are no + * wider than width. widthMeasure is a function that takes + * text as input, and returns the width of the text in pixels. + */ function breakParagraphToFitWidth(text, width, widthMeasure) { var lines = []; var tokens = tokenize(text); @@ -573,8 +900,10 @@ var Plottable; nextToken = tokens[i++]; } var brokenToken = breakNextTokenToFitInWidth(curLine, nextToken, width, widthMeasure); + var canAdd = brokenToken[0]; var leftOver = brokenToken[1]; + if (canAdd !== null) { curLine += canAdd; } @@ -589,6 +918,15 @@ var Plottable; } return lines; } + + /** + * Breaks up the next token and so that some part of it can be + * added to curLine and fits in the width. the return value + * is an array with 2 elements, the part that can be added + * and the left over part of the token + * widthMeasure is a function that takes text as input, + * and returns the width of the text in pixels. + */ function breakNextTokenToFitInWidth(curLine, nextToken, width, widthMeasure) { if (isBlank(nextToken)) { return [nextToken, null]; @@ -603,8 +941,7 @@ var Plottable; while (i < nextToken.length) { if (widthMeasure(curLine + nextToken[i] + "-") <= width) { curLine += nextToken[i++]; - } - else { + } else { break; } } @@ -615,6 +952,15 @@ var Plottable; } return [nextToken.substring(0, i) + append, nextToken.substring(i)]; } + + /** + * Breaks up into tokens for word wrapping + * Each token is comprised of either: + * 1) Only word and non line break characters + * 2) Only spaces characters + * 3) Line break characters such as ":" or ";" or "," + * (will be single character token, unless there is a repeated linebreak character) + */ function tokenize(text) { var ret = []; var token = ""; @@ -623,8 +969,7 @@ var Plottable; var curChar = text[i]; if (token === "" || isTokenizedTogether(token[0], curChar, lastChar)) { token += curChar; - } - else { + } else { ret.push(token); token = curChar; } @@ -635,17 +980,31 @@ var Plottable; } return ret; } + + /** + * Returns whether a string is blank. + * + * @param {string} str: The string to test for blank-ness + * @returns {boolean} Whether the string is blank + */ function isBlank(text) { return text == null ? true : text.trim() === ""; } + + /** + * Given a token (ie a string of characters that are similar and shouldn't be broken up) and a character, determine + * whether that character should be added to the token. Groups of characters that don't match the space or line break + * regex are always tokenzied together. Spaces are always tokenized together. Line break characters are almost always + * split into their own token, except that two subsequent identical line break characters are put into the same token. + * For isTokenizedTogether(":", ",") == False but isTokenizedTogether("::") == True. + */ function isTokenizedTogether(text, nextChar, lastChar) { if (!(text && nextChar)) { false; } if (SPACES.test(text) && SPACES.test(nextChar)) { return true; - } - else if (SPACES.test(text) || SPACES.test(nextChar)) { + } else if (SPACES.test(text) || SPACES.test(nextChar)) { return false; } if (LINE_BREAKS_AFTER.test(lastChar) || LINE_BREAKS_BEFORE.test(nextChar)) { @@ -663,20 +1022,26 @@ var Plottable; (function (Plottable) { (function (Util) { (function (DOM) { + /** + * Gets the bounding box of an element. + * @param {D3.Selection} element + * @returns {SVGRed} The bounding box. + */ function getBBox(element) { return element.node().getBBox(); } DOM.getBBox = getBBox; + DOM.POLYFILL_TIMEOUT_MSEC = 1000 / 60; function requestAnimationFramePolyfill(fn) { if (window.requestAnimationFrame != null) { window.requestAnimationFrame(fn); - } - else { + } else { setTimeout(fn, DOM.POLYFILL_TIMEOUT_MSEC); } } DOM.requestAnimationFramePolyfill = requestAnimationFramePolyfill; + function _getParsedStyleValue(style, prop) { var value = style.getPropertyValue(prop); var parsedValue = parseFloat(value); @@ -685,6 +1050,8 @@ var Plottable; } return parsedValue; } + + // function isSelectionRemovedFromSVG(selection) { var n = selection.node(); while (n !== null && n.nodeName !== "svg") { @@ -693,20 +1060,25 @@ var Plottable; return (n == null); } DOM.isSelectionRemovedFromSVG = isSelectionRemovedFromSVG; + function getElementWidth(elem) { var style = window.getComputedStyle(elem); return _getParsedStyleValue(style, "width") + _getParsedStyleValue(style, "padding-left") + _getParsedStyleValue(style, "padding-right") + _getParsedStyleValue(style, "border-left-width") + _getParsedStyleValue(style, "border-right-width"); } DOM.getElementWidth = getElementWidth; + function getElementHeight(elem) { var style = window.getComputedStyle(elem); return _getParsedStyleValue(style, "height") + _getParsedStyleValue(style, "padding-top") + _getParsedStyleValue(style, "padding-bottom") + _getParsedStyleValue(style, "border-top-width") + _getParsedStyleValue(style, "border-bottom-width"); } DOM.getElementHeight = getElementHeight; + function getSVGPixelWidth(svg) { var width = svg.node().clientWidth; + if (width === 0) { var widthAttr = svg.attr("width"); + if (widthAttr.indexOf("%") !== -1) { var ancestorNode = svg.node().parentNode; while (ancestorNode != null && ancestorNode.clientWidth === 0) { @@ -716,20 +1088,20 @@ var Plottable; throw new Error("Could not compute width of element"); } width = ancestorNode.clientWidth * parseFloat(widthAttr) / 100; - } - else { + } else { width = parseFloat(widthAttr); } } + return width; } DOM.getSVGPixelWidth = getSVGPixelWidth; + function translate(s, x, y) { var xform = d3.transform(s.attr("transform")); if (x == null) { return xform.translate; - } - else { + } else { y = (y == null) ? 0 : y; xform.translate[0] = x; xform.translate[1] = y; @@ -738,6 +1110,7 @@ var Plottable; } } DOM.translate = translate; + function boxesOverlap(boxA, boxB) { if (boxA.right < boxB.left) { return false; @@ -760,17 +1133,29 @@ var Plottable; var Util = Plottable.Util; })(Plottable || (Plottable = {})); +/// var Plottable; (function (Plottable) { Plottable.MILLISECONDS_IN_ONE_DAY = 24 * 60 * 60 * 1000; + var Formatters = (function () { 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. + */ Formatters.currency = function (precision, symbol, prefix, onlyShowUnchanged) { - if (precision === void 0) { precision = 2; } - if (symbol === void 0) { symbol = "$"; } - if (prefix === void 0) { prefix = true; } - if (onlyShowUnchanged === void 0) { onlyShowUnchanged = true; } + if (typeof precision === "undefined") { precision = 2; } + if (typeof symbol === "undefined") { symbol = "$"; } + if (typeof prefix === "undefined") { prefix = true; } + if (typeof onlyShowUnchanged === "undefined") { onlyShowUnchanged = true; } var fixedFormatter = Formatters.fixed(precision); return function (d) { var formattedValue = fixedFormatter(Math.abs(d)); @@ -780,10 +1165,10 @@ var Plottable; if (formattedValue !== "") { if (prefix) { formattedValue = symbol + formattedValue; - } - else { + } else { formattedValue += symbol; } + if (d < 0) { formattedValue = "-" + formattedValue; } @@ -791,9 +1176,18 @@ var Plottable; return formattedValue; }; }; + + /** + * 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. + */ Formatters.fixed = function (precision, onlyShowUnchanged) { - if (precision === void 0) { precision = 3; } - if (onlyShowUnchanged === void 0) { onlyShowUnchanged = true; } + if (typeof precision === "undefined") { precision = 3; } + if (typeof onlyShowUnchanged === "undefined") { onlyShowUnchanged = true; } Formatters.verifyPrecision(precision); return function (d) { var formattedValue = d.toFixed(precision); @@ -803,9 +1197,19 @@ var Plottable; return formattedValue; }; }; + + /** + * 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. + */ Formatters.general = function (precision, onlyShowUnchanged) { - if (precision === void 0) { precision = 3; } - if (onlyShowUnchanged === void 0) { onlyShowUnchanged = true; } + if (typeof precision === "undefined") { precision = 3; } + if (typeof onlyShowUnchanged === "undefined") { onlyShowUnchanged = true; } Formatters.verifyPrecision(precision); return function (d) { if (typeof d === "number") { @@ -815,20 +1219,35 @@ var Plottable; return ""; } return formattedValue; - } - else { + } else { return String(d); } }; }; + + /** + * Creates a formatter that stringifies its input. + * + * @returns {Formatter} A formatter that stringifies its input. + */ Formatters.identity = function () { return function (d) { return String(d); }; }; + + /** + * 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. + */ Formatters.percentage = function (precision, onlyShowUnchanged) { - if (precision === void 0) { precision = 0; } - if (onlyShowUnchanged === void 0) { onlyShowUnchanged = true; } + if (typeof precision === "undefined") { precision = 0; } + if (typeof onlyShowUnchanged === "undefined") { onlyShowUnchanged = true; } var fixedFormatter = Formatters.fixed(precision); return function (d) { var formattedValue = fixedFormatter(d * 100); @@ -841,48 +1260,84 @@ var Plottable; return formattedValue; }; }; + + /** + * 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. + */ Formatters.siSuffix = function (precision) { - if (precision === void 0) { precision = 3; } + if (typeof precision === "undefined") { precision = 3; } Formatters.verifyPrecision(precision); return function (d) { return d3.format("." + precision + "s")(d); }; }; + + /** + * Creates a formatter that displays dates. + * + * @returns {Formatter} A formatter for time/date values. + */ Formatters.time = function () { 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; } + filter: function (d) { + return d.getMilliseconds() !== 0; + } }; timeFormat[1] = { format: ":%S", - filter: function (d) { return d.getSeconds() !== 0; } + filter: function (d) { + return d.getSeconds() !== 0; + } }; timeFormat[2] = { format: "%I:%M", - filter: function (d) { return d.getMinutes() !== 0; } + filter: function (d) { + return d.getMinutes() !== 0; + } }; timeFormat[3] = { format: "%I %p", - filter: function (d) { return d.getHours() !== 0; } + filter: function (d) { + return d.getHours() !== 0; + } }; timeFormat[4] = { format: "%a %d", - filter: function (d) { return d.getDay() !== 0 && d.getDate() !== 1; } + filter: function (d) { + return d.getDay() !== 0 && d.getDate() !== 1; + } }; timeFormat[5] = { format: "%b %d", - filter: function (d) { return d.getDate() !== 1; } + filter: function (d) { + return d.getDate() !== 1; + } }; timeFormat[6] = { format: "%b", - filter: function (d) { return d.getMonth() !== 0; } + filter: function (d) { + return d.getMonth() !== 0; + } }; timeFormat[7] = { format: "%Y", - filter: function () { return true; } + filter: function () { + return true; + } }; + return function (d) { for (var i = 0; i < numFormats; i++) { if (timeFormat[i].filter(d)) { @@ -891,20 +1346,32 @@ var Plottable; } }; }; + + /** + * 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. + */ Formatters.relativeDate = function (baseValue, increment, label) { - if (baseValue === void 0) { baseValue = 0; } - if (increment === void 0) { increment = Plottable.MILLISECONDS_IN_ONE_DAY; } - if (label === void 0) { label = ""; } + if (typeof baseValue === "undefined") { baseValue = 0; } + if (typeof increment === "undefined") { increment = Plottable.MILLISECONDS_IN_ONE_DAY; } + if (typeof label === "undefined") { label = ""; } return function (d) { var relativeDate = Math.round((d.valueOf() - baseValue) / increment); return relativeDate.toString() + label; }; }; + Formatters.verifyPrecision = function (precision) { if (precision < 0 || precision > 20) { throw new RangeError("Formatter precision must be between 0 and 20"); } }; + Formatters._valueChanged = function (d, formattedValue) { return d !== parseFloat(formattedValue); }; @@ -913,11 +1380,13 @@ var Plottable; Plottable.Formatters = Formatters; })(Plottable || (Plottable = {})); +/// var Plottable; (function (Plottable) { - Plottable.version = "0.23.2"; + Plottable.version = "0.24.0"; })(Plottable || (Plottable = {})); +/// var Plottable; (function (Plottable) { (function (Core) { @@ -934,6 +1403,7 @@ var Plottable; Colors.CERISE_RED = "#db2e65"; Colors.BRIGHT_SUN = "#ffe43d"; Colors.JACARTA = "#2c2b6f"; + Colors.PLOTTABLE_COLORS = [ Colors.CORAL_RED, Colors.INDIGO, @@ -953,6 +1423,7 @@ var Plottable; var Core = Plottable.Core; })(Plottable || (Plottable = {})); +/// var Plottable; (function (Plottable) { (function (Abstract) { @@ -968,6 +1439,7 @@ var Plottable; var Abstract = Plottable.Abstract; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -977,30 +1449,79 @@ var __extends = this.__extends || function (d, b) { var Plottable; (function (Plottable) { (function (Core) { + + + + + /** + * The Broadcaster class is owned by an IListenable. Third parties can register and deregister listeners + * from the broadcaster. When the broadcaster.broadcast method is activated, all registered callbacks are + * called. The registered callbacks are called with the registered Listenable that the broadcaster is attached + * to, along with optional arguments passed to the `broadcast` method. + * + * The listeners are called synchronously. + */ var Broadcaster = (function (_super) { __extends(Broadcaster, _super); + /** + * Construct a broadcaster, taking the Listenable that the broadcaster will be attached to. + * + * @constructor + * @param {IListenable} listenable The Listenable-object that this broadcaster is attached to. + */ function Broadcaster(listenable) { _super.call(this); this.key2callback = new Plottable.Util.StrictEqualityAssociativeArray(); this.listenable = listenable; } + /** + * Registers a callback to be called when the broadcast method is called. Also takes a key which + * is used to support deregistering the same callback later, by passing in the same key. + * If there is already a callback associated with that key, then the callback will be replaced. + * + * @param key The key associated with the callback. Key uniqueness is determined by deep equality. + * @param {IBroadcasterCallback} callback A callback to be called when the Scale's domain changes. + * @returns {Broadcaster} this object + */ Broadcaster.prototype.registerListener = function (key, callback) { this.key2callback.set(key, callback); return this; }; + + /** + * Call all listening callbacks, optionally with arguments passed through. + * + * @param ...args A variable number of optional arguments + * @returns {Broadcaster} this object + */ Broadcaster.prototype.broadcast = function () { var _this = this; var args = []; - for (var _i = 0; _i < arguments.length; _i++) { - args[_i - 0] = arguments[_i]; + for (var _i = 0; _i < (arguments.length - 0); _i++) { + args[_i] = arguments[_i + 0]; } - this.key2callback.values().forEach(function (callback) { return callback(_this.listenable, args); }); + this.key2callback.values().forEach(function (callback) { + return callback(_this.listenable, args); + }); return this; }; + + /** + * Deregisters the callback associated with a key. + * + * @param key The key to deregister. + * @returns {Broadcaster} this object + */ Broadcaster.prototype.deregisterListener = function (key) { this.key2callback.delete(key); return this; }; + + /** + * Deregisters all listeners and callbacks associated with the broadcaster. + * + * @returns {Broadcaster} this object + */ Broadcaster.prototype.deregisterAllListeners = function () { this.key2callback = new Plottable.Util.StrictEqualityAssociativeArray(); }; @@ -1011,6 +1532,7 @@ var Plottable; var Core = Plottable.Core; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -1021,9 +1543,16 @@ var Plottable; (function (Plottable) { var DataSource = (function (_super) { __extends(DataSource, _super); + /** + * Creates a new DataSource. + * + * @constructor + * @param {any[]} data + * @param {any} metadata An object containing additional information. + */ function DataSource(data, metadata) { - if (data === void 0) { data = []; } - if (metadata === void 0) { metadata = {}; } + if (typeof data === "undefined") { data = []; } + if (typeof metadata === "undefined") { metadata = {}; } _super.call(this); this.broadcaster = new Plottable.Core.Broadcaster(this); this._data = data; @@ -1033,25 +1562,25 @@ var Plottable; DataSource.prototype.data = function (data) { if (data == null) { return this._data; - } - else { + } else { this._data = data; this.accessor2cachedExtent = new Plottable.Util.StrictEqualityAssociativeArray(); this.broadcaster.broadcast(); return this; } }; + DataSource.prototype.metadata = function (metadata) { if (metadata == null) { return this._metadata; - } - else { + } else { this._metadata = metadata; this.accessor2cachedExtent = new Plottable.Util.StrictEqualityAssociativeArray(); this.broadcaster.broadcast(); return this; } }; + DataSource.prototype._getExtent = function (accessor) { var cachedExtent = this.accessor2cachedExtent.get(accessor); if (cachedExtent === undefined) { @@ -1060,20 +1589,18 @@ var Plottable; } return cachedExtent; }; + DataSource.prototype.computeExtent = function (accessor) { var mappedData = this._data.map(accessor); if (mappedData.length === 0) { return []; - } - else if (typeof (mappedData[0]) === "string") { + } else if (typeof (mappedData[0]) === "string") { return Plottable.Util.Methods.uniq(mappedData); - } - else { + } else { var extent = d3.extent(mappedData); if (extent[0] == null || extent[1] == null) { return []; - } - else { + } else { return extent; } } @@ -1083,6 +1610,7 @@ var Plottable; Plottable.DataSource = DataSource; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -1111,25 +1639,41 @@ var Plottable; this._isAnchored = false; this.removed = false; } + /** + * Attaches the Component as a child of a given a DOM element. Usually only directly invoked on root-level Components. + * + * @param {D3.Selection} element A D3 selection consisting of the element to anchor under. + */ Component.prototype._anchor = function (element) { if (this.removed) { throw new Error("Can't reuse remove()-ed components!"); } + if (element.node().nodeName === "svg") { + // svg node gets the "plottable" CSS class this.rootSVG = element; 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 element.node().appendChild(this.element.node()); - } - else { + } else { this.element = element.append("g"); this._setup(); } this._isAnchored = true; }; + + /** + * 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) { @@ -1139,45 +1683,67 @@ var Plottable; _this.element.classed(cssClass, true); }); this.cssClasses = null; + this.backgroundContainer = this.element.append("g").classed("background-container", true); 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.addBox("bounding-box"); - this.interactionsToRegister.forEach(function (r) { return _this.registerInteraction(r); }); + + this.interactionsToRegister.forEach(function (r) { + return _this.registerInteraction(r); + }); this.interactionsToRegister = null; if (this.isTopLevelComponent) { this.autoResize(Component.AUTORESIZE_BY_DEFAULT); } this._isSetup = true; }; + Component.prototype._requestedSpace = function (availableWidth, availableHeight) { return { width: 0, height: 0, wantsWidth: false, wantsHeight: false }; }; + + /** + * Computes the size, position, and alignment 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 {number} xOrigin + * @param {number} yOrigin + * @param {number} availableWidth + * @param {number} availableHeight + */ Component.prototype._computeLayout = function (xOrigin, yOrigin, availableWidth, availableHeight) { var _this = this; if (xOrigin == null || yOrigin == null || availableWidth == null || availableHeight == null) { if (this.element == null) { throw new Error("anchor must be called before computeLayout"); - } - else if (this.isTopLevelComponent) { + } else if (this.isTopLevelComponent) { + // we are the root node, retrieve height/width from root SVG xOrigin = 0; yOrigin = 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.Util.DOM.getElementWidth(elem); availableHeight = Plottable.Util.DOM.getElementHeight(elem); - } - else { + } else { throw new Error("null arguments cannot be passed to _computeLayout() on a non-root node"); } } @@ -1185,51 +1751,71 @@ var Plottable; this.yOrigin = yOrigin; var xPosition = this.xOrigin; var yPosition = this.yOrigin; + var requestedSpace = this._requestedSpace(availableWidth, availableHeight); + xPosition += (availableWidth - requestedSpace.width) * this._xAlignProportion; xPosition += this._xOffset; if (this._isFixedWidth()) { + // Decrease size so hitbox / bounding box and children are sized correctly availableWidth = Math.min(availableWidth, requestedSpace.width); } + yPosition += (availableHeight - requestedSpace.height) * this._yAlignProportion; yPosition += this._yOffset; if (this._isFixedHeight()) { availableHeight = Math.min(availableHeight, requestedSpace.height); } + this.availableWidth = availableWidth; this.availableHeight = availableHeight; this.element.attr("transform", "translate(" + xPosition + "," + yPosition + ")"); - this.boxes.forEach(function (b) { return b.attr("width", _this.availableWidth).attr("height", _this.availableHeight); }); + this.boxes.forEach(function (b) { + return b.attr("width", _this.availableWidth).attr("height", _this.availableHeight); + }); }; + + /** + * Renders the component. + */ Component.prototype._render = function () { if (this._isAnchored && this._isSetup) { Plottable.Core.RenderController.registerToRender(this); } }; + Component.prototype._scheduleComputeLayout = function () { if (this._isAnchored && this._isSetup) { Plottable.Core.RenderController.registerToComputeLayout(this); } }; + Component.prototype._doRender = function () { + //no-op }; + Component.prototype._invalidateLayout = function () { if (this._isAnchored && this._isSetup) { if (this.isTopLevelComponent) { this._scheduleComputeLayout(); - } - else { + } else { this._parent._invalidateLayout(); } } }; + + /** + * Renders the Component into a given DOM element. + * + * @param {String|D3.Selection} element A D3 selection or a selector for getting the element to render into. + * @return {Component} The calling component. + */ Component.prototype.renderTo = function (element) { if (element != null) { var selection; if (typeof (element.node) === "function") { selection = element; - } - else { + } else { selection = d3.select(element); } this._anchor(selection); @@ -1238,6 +1824,13 @@ var Plottable; this._render(); return this; }; + + /** + * Cause the Component to recompute layout and redraw. If passed arguments, will resize the root SVG it lives in. + * + * @param {number} [availableWidth] - the width of the container element + * @param {number} [availableHeight] - the height of the container element + */ Component.prototype.resize = function (width, height) { if (!this.isTopLevelComponent) { throw new Error("Cannot resize on non top-level component"); @@ -1248,59 +1841,91 @@ var Plottable; this._invalidateLayout(); return this; }; + + /** + * Enables and disables auto-resize. + * + * If enabled, window resizes will enqueue this component for a re-layout + * and re-render. Animations are disabled during window resizes when auto- + * resize is enabled. + * + * @param {boolean} flag - Enables (true) or disables (false) auto-resize. + */ Component.prototype.autoResize = function (flag) { if (flag) { Plottable.Core.ResizeBroadcaster.register(this); - } - else { + } else { Plottable.Core.ResizeBroadcaster.deregister(this); } return this; }; + + /** + * Sets the x alignment of the Component. + * + * @param {string} alignment The x alignment of the Component (one of LEFT/CENTER/RIGHT). + * @returns {Component} The calling Component. + */ Component.prototype.xAlign = function (alignment) { alignment = alignment.toLowerCase(); if (alignment === "left") { this._xAlignProportion = 0; - } - else if (alignment === "center") { + } else if (alignment === "center") { this._xAlignProportion = 0.5; - } - else if (alignment === "right") { + } else if (alignment === "right") { this._xAlignProportion = 1; - } - else { + } else { throw new Error("Unsupported alignment"); } this._invalidateLayout(); return this; }; + + /** + * Sets the y alignment of the Component. + * + * @param {string} alignment The y alignment of the Component (one of TOP/CENTER/BOTTOM). + * @returns {Component} The calling Component. + */ Component.prototype.yAlign = function (alignment) { alignment = alignment.toLowerCase(); if (alignment === "top") { this._yAlignProportion = 0; - } - else if (alignment === "center") { + } else if (alignment === "center") { this._yAlignProportion = 0.5; - } - else if (alignment === "bottom") { + } else if (alignment === "bottom") { this._yAlignProportion = 1; - } - else { + } else { throw new Error("Unsupported alignment"); } this._invalidateLayout(); return this; }; + + /** + * Sets the x offset of the Component. + * + * @param {number} offset The desired x offset, in pixels. + * @returns {Component} The calling Component. + */ Component.prototype.xOffset = function (offset) { this._xOffset = offset; this._invalidateLayout(); return this; }; + + /** + * Sets the y offset of the Component. + * + * @param {number} offset The desired y offset, in pixels. + * @returns {Component} The calling Component. + */ Component.prototype.yOffset = function (offset) { this._yOffset = offset; this._invalidateLayout(); return this; }; + Component.prototype.addBox = function (className, parentElement) { if (this.element == null) { throw new Error("Adding boxes before anchoring is currently disallowed"); @@ -1317,37 +1942,46 @@ var Plottable; } return box; }; + Component.prototype.generateClipPath = function () { + // The clip path will prevent content from overflowing its component space. this.element.attr("clip-path", "url(#clipPath" + this._plottableID + ")"); var clipPathParent = this.boxContainer.append("clipPath").attr("id", "clipPath" + this._plottableID); this.addBox("clip-rect", clipPathParent); }; + + /** + * Attaches an Interaction to the Component, so that the Interaction will listen for events on the Component. + * + * @param {Interaction} interaction The Interaction to attach to the Component. + * @return {Component} The calling Component. + */ Component.prototype.registerInteraction = function (interaction) { + // Interactions can be registered before or after anchoring. If registered before, they are + // pushed to this.interactionsToRegister and registered during anchoring. If after, they are + // registered immediately if (this.element != null) { if (this.hitBox == null) { this.hitBox = this.addBox("hit-box"); - this.hitBox.style("fill", "#ffffff").style("opacity", 0); + this.hitBox.style("fill", "#ffffff").style("opacity", 0); // We need to set these so Chrome will register events } interaction._anchor(this.hitBox); - } - else { + } else { this.interactionsToRegister.push(interaction); } return this; }; + Component.prototype.classed = function (cssClass, addClass) { if (addClass == null) { if (cssClass == null) { return false; - } - else if (this.element == null) { + } else if (this.element == null) { return (this.cssClasses.indexOf(cssClass) !== -1); - } - else { + } else { return this.element.classed(cssClass); } - } - else { + } else { if (cssClass == null) { return this; } @@ -1355,23 +1989,47 @@ var Plottable; var classIndex = this.cssClasses.indexOf(cssClass); if (addClass && classIndex === -1) { this.cssClasses.push(cssClass); - } - else if (!addClass && classIndex !== -1) { + } else if (!addClass && classIndex !== -1) { this.cssClasses.splice(classIndex, 1); } - } - else { + } else { this.element.classed(cssClass, addClass); } return this; } }; + + /** + * Checks if the Component has a fixed width or false if it grows to fill available space. + * Returns false by default on the base Component class. + * + * @return {boolean} Whether the component has a fixed width. + */ Component.prototype._isFixedWidth = function () { return this._fixedWidthFlag; }; + + /** + * Checks if the Component has a fixed height or false if it grows to fill available space. + * Returns false by default on the base Component class. + * + * @return {boolean} Whether the component has a fixed height. + */ Component.prototype._isFixedHeight = function () { return this._fixedHeightFlag; }; + + /** + * Merges this Component with another Component, returning a ComponentGroup. + * There are four cases: + * Component + Component: Returns a ComponentGroup with both components inside it. + * ComponentGroup + Component: Returns the ComponentGroup with the Component appended. + * Component + ComponentGroup: Returns the ComponentGroup with the Component prepended. + * ComponentGroup + ComponentGroup: Returns a new ComponentGroup with two ComponentGroups inside it. + * + * @param {Component} c The component to merge in. + * @return {ComponentGroup} + */ Component.prototype.merge = function (c) { var cg; if (this._isSetup || this._isAnchored) { @@ -1381,12 +2039,17 @@ var Plottable; cg = c; cg._addComponent(this, true); return cg; - } - else { + } else { cg = new Plottable.Component.Group([this, c]); return cg; } }; + + /** + * Detaches a Component from the DOM. The component can be reused. + * + * @returns The calling Component. + */ Component.prototype.detach = function () { if (this._isAnchored) { this.element.remove(); @@ -1398,6 +2061,11 @@ var Plottable; this._parent = null; return this; }; + + /** + * Removes a Component from the DOM and disconnects it from everything it's + * listening to (effectively destroying it). + */ Component.prototype.remove = function () { this.removed = true; this.detach(); @@ -1411,6 +2079,7 @@ var Plottable; var Abstract = Plottable.Abstract; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -1424,16 +2093,26 @@ var Plottable; __extends(ComponentContainer, _super); function ComponentContainer() { _super.apply(this, arguments); + /* + * An abstract ComponentContainer class to encapsulate Table and ComponentGroup's shared functionality. + * It will not do anything if instantiated directly. + */ this._components = []; } ComponentContainer.prototype._anchor = function (element) { var _this = this; _super.prototype._anchor.call(this, element); - this._components.forEach(function (c) { return c._anchor(_this.content); }); + this._components.forEach(function (c) { + return c._anchor(_this.content); + }); }; + ComponentContainer.prototype._render = function () { - this._components.forEach(function (c) { return c._render(); }); + this._components.forEach(function (c) { + return c._render(); + }); }; + ComponentContainer.prototype._removeComponent = function (c) { var removeIndex = this._components.indexOf(c); if (removeIndex >= 0) { @@ -1441,15 +2120,16 @@ var Plottable; this._invalidateLayout(); } }; + ComponentContainer.prototype._addComponent = function (c, prepend) { - if (prepend === void 0) { prepend = false; } + if (typeof prepend === "undefined") { prepend = false; } if (c == null || this._components.indexOf(c) >= 0) { return false; } + if (prepend) { this._components.unshift(c); - } - else { + } else { this._components.push(c); } c._parent = this; @@ -1459,19 +2139,45 @@ var Plottable; this._invalidateLayout(); return true; }; + + /** + * Returns a list of components in the ComponentContainer + * + * @returns{Component[]} the contained Components + */ ComponentContainer.prototype.components = function () { return this._components.slice(); }; + + /** + * Returns true iff the ComponentContainer is empty. + * + * @returns {boolean} Whether the calling ComponentContainer is empty. + */ ComponentContainer.prototype.empty = function () { return this._components.length === 0; }; + + /** + * Detaches all components contained in the ComponentContainer, and + * empties the ComponentContainer. + * + * @returns {ComponentContainer} The calling ComponentContainer + */ ComponentContainer.prototype.detachAll = function () { - this._components.slice().forEach(function (c) { return c.detach(); }); + // Calling c.remove() will mutate this._components because the component will call this._parent._removeComponent(this) + // Since mutating an array while iterating over it is dangerous, we instead iterate over a copy generated by Arr.slice() + this._components.slice().forEach(function (c) { + return c.detach(); + }); return this; }; + ComponentContainer.prototype.remove = function () { _super.prototype.remove.call(this); - this._components.slice().forEach(function (c) { return c.remove(); }); + this._components.slice().forEach(function (c) { + return c.remove(); + }); }; return ComponentContainer; })(Abstract.Component); @@ -1480,6 +2186,7 @@ var Plottable; var Abstract = Plottable.Abstract; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -1491,27 +2198,51 @@ var Plottable; (function (Component) { var Group = (function (_super) { __extends(Group, _super); + /** + * Creates a ComponentGroup. + * + * @constructor + * @param {Component[]} [components] The Components in the Group. + */ function Group(components) { - if (components === void 0) { components = []; } - _super.call(this); + if (typeof components === "undefined") { components = []; } var _this = this; + _super.call(this); this.classed("component-group", true); - components.forEach(function (c) { return _this._addComponent(c); }); + components.forEach(function (c) { + return _this._addComponent(c); + }); } Group.prototype._requestedSpace = function (offeredWidth, offeredHeight) { - var requests = this._components.map(function (c) { return c._requestedSpace(offeredWidth, offeredHeight); }); + var requests = this._components.map(function (c) { + return c._requestedSpace(offeredWidth, offeredHeight); + }); var isEmpty = this.empty(); return { - width: isEmpty ? 0 : d3.max(requests, function (request) { return request.width; }), - height: isEmpty ? 0 : d3.max(requests, function (request) { return request.height; }), - wantsWidth: isEmpty ? false : requests.map(function (r) { return r.wantsWidth; }).some(function (x) { return x; }), - wantsHeight: isEmpty ? false : requests.map(function (r) { return r.wantsHeight; }).some(function (x) { return x; }) + width: isEmpty ? 0 : d3.max(requests, function (request) { + return request.width; + }), + height: isEmpty ? 0 : d3.max(requests, function (request) { + return request.height; + }), + wantsWidth: isEmpty ? false : requests.map(function (r) { + return r.wantsWidth; + }).some(function (x) { + return x; + }), + wantsHeight: isEmpty ? false : requests.map(function (r) { + return r.wantsHeight; + }).some(function (x) { + return x; + }) }; }; + Group.prototype.merge = function (c) { this._addComponent(c); return this; }; + Group.prototype._computeLayout = function (xOrigin, yOrigin, availableWidth, availableHeight) { var _this = this; _super.prototype._computeLayout.call(this, xOrigin, yOrigin, availableWidth, availableHeight); @@ -1520,11 +2251,17 @@ var Plottable; }); return this; }; + Group.prototype._isFixedWidth = function () { - return this._components.every(function (c) { return c._isFixedWidth(); }); + return this._components.every(function (c) { + return c._isFixedWidth(); + }); }; + Group.prototype._isFixedHeight = function () { - return this._components.every(function (c) { return c._isFixedHeight(); }); + return this._components.every(function (c) { + return c._isFixedHeight(); + }); }; return Group; })(Plottable.Abstract.ComponentContainer); @@ -1533,6 +2270,7 @@ var Plottable; var Component = Plottable.Component; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -1543,12 +2281,20 @@ var Plottable; (function (Plottable) { (function (Component) { ; + var Table = (function (_super) { __extends(Table, _super); + /** + * Creates a Table. + * + * @constructor + * @param {Component[][]} [rows] A 2-D array of the Components to place in the table. + * null can be used if a cell is empty. + */ function Table(rows) { - if (rows === void 0) { rows = []; } - _super.call(this); + if (typeof rows === "undefined") { rows = []; } var _this = this; + _super.call(this); this.rowPadding = 0; this.colPadding = 0; this.rows = []; @@ -1563,24 +2309,35 @@ var Plottable; }); }); } + /** + * Adds a Component in the specified cell. + * + * @param {number} row The row in which to add the Component. + * @param {number} col The column in which to add the Component. + * @param {Component} component The Component to be added. + */ Table.prototype.addComponent = function (row, col, component) { if (this._addComponent(component)) { this.nRows = Math.max(row + 1, this.nRows); this.nCols = Math.max(col + 1, this.nCols); this.padTableToSize(this.nRows, this.nCols); + var currentComponent = this.rows[row][col]; if (currentComponent != null) { throw new Error("Table.addComponent cannot be called on a cell where a component already exists (for the moment)"); } + this.rows[row][col] = component; } return this; }; + Table.prototype._removeComponent = function (component) { _super.prototype._removeComponent.call(this, component); var rowpos; var colpos; - outer: for (var i = 0; i < this.nRows; i++) { + outer: + for (var i = 0; i < this.nRows; i++) { for (var j = 0; j < this.nCols; j++) { if (this.rows[i][j] === component) { rowpos = i; @@ -1589,24 +2346,63 @@ var Plottable; } } } + if (rowpos !== undefined) { this.rows[rowpos][colpos] = null; } }; + Table.prototype.iterateLayout = function (availableWidth, availableHeight) { + /* + * 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 cols = d3.transpose(this.rows); var availableWidthAfterPadding = availableWidth - this.colPadding * (this.nCols - 1); var availableHeightAfterPadding = availableHeight - this.rowPadding * (this.nRows - 1); - var rowWeights = Table.calcComponentWeights(this.rowWeights, this.rows, function (c) { return (c == null) || c._isFixedHeight(); }); - var colWeights = Table.calcComponentWeights(this.colWeights, cols, function (c) { return (c == null) || c._isFixedWidth(); }); - 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 rowWeights = Table.calcComponentWeights(this.rowWeights, this.rows, function (c) { + return (c == null) || c._isFixedHeight(); + }); + var colWeights = Table.calcComponentWeights(this.colWeights, cols, function (c) { + return (c == null) || c._isFixedWidth(); + }); + + // 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.Util.Methods.createFilledArray(0, this.nCols); var guaranteedHeights = Plottable.Util.Methods.createFilledArray(0, this.nRows); + var freeWidth; var freeHeight; + var nIterations = 0; while (true) { var offeredHeights = Plottable.Util.Methods.addArrays(guaranteedHeights, rowProportionalSpace); @@ -1614,46 +2410,68 @@ var Plottable; var guarantees = this.determineGuarantees(offeredWidths, offeredHeights); 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 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 = guarantees.wantsWidthArr.map(function (x) { + return x ? 0.1 : 0; + }); xWeights = Plottable.Util.Methods.addArrays(xWeights, colWeights); - } - else { + } else { xWeights = colWeights; } + var yWeights; if (wantsHeight) { - yWeights = guarantees.wantsHeightArr.map(function (x) { return x ? 0.1 : 0; }); + yWeights = guarantees.wantsHeightArr.map(function (x) { + return x ? 0.1 : 0; + }); yWeights = Plottable.Util.Methods.addArrays(yWeights, rowWeights); - } - else { + } else { yWeights = rowWeights; } + colProportionalSpace = Table.calcProportionalSpace(xWeights, freeWidth); rowProportionalSpace = Table.calcProportionalSpace(yWeights, freeHeight); nIterations++; + var canImproveWidthAllocation = freeWidth > 0 && wantsWidth && freeWidth !== lastFreeWidth; var canImproveHeightAllocation = freeHeight > 0 && wantsHeight && 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 }; + + return { + colProportionalSpace: colProportionalSpace, + rowProportionalSpace: rowProportionalSpace, + guaranteedWidths: guarantees.guaranteedWidths, + guaranteedHeights: guarantees.guaranteedHeights, + wantsWidth: wantsWidth, + wantsHeight: wantsHeight }; }; + Table.prototype.determineGuarantees = function (offeredWidths, offeredHeights) { var requestedWidths = Plottable.Util.Methods.createFilledArray(0, this.nCols); var requestedHeights = Plottable.Util.Methods.createFilledArray(0, this.nRows); @@ -1664,35 +2482,51 @@ var Plottable; var spaceRequest; if (component != null) { spaceRequest = component._requestedSpace(offeredWidths[colIndex], offeredHeights[rowIndex]); - } - else { + } else { spaceRequest = { width: 0, height: 0, wantsWidth: false, wantsHeight: false }; } + var allocatedWidth = Math.min(spaceRequest.width, offeredWidths[colIndex]); var allocatedHeight = Math.min(spaceRequest.height, offeredHeights[rowIndex]); + requestedWidths[colIndex] = Math.max(requestedWidths[colIndex], allocatedWidth); requestedHeights[rowIndex] = Math.max(requestedHeights[rowIndex], allocatedHeight); layoutWantsWidth[colIndex] = layoutWantsWidth[colIndex] || spaceRequest.wantsWidth; layoutWantsHeight[rowIndex] = layoutWantsHeight[rowIndex] || spaceRequest.wantsHeight; }); }); - return { guaranteedWidths: requestedWidths, guaranteedHeights: requestedHeights, wantsWidthArr: layoutWantsWidth, wantsHeightArr: layoutWantsHeight }; + return { + guaranteedWidths: requestedWidths, + guaranteedHeights: requestedHeights, + wantsWidthArr: layoutWantsWidth, + wantsHeightArr: layoutWantsHeight }; }; + Table.prototype._requestedSpace = function (offeredWidth, offeredHeight) { var layout = this.iterateLayout(offeredWidth, offeredHeight); - return { width: d3.sum(layout.guaranteedWidths), height: d3.sum(layout.guaranteedHeights), wantsWidth: layout.wantsWidth, wantsHeight: layout.wantsHeight }; + return { + width: d3.sum(layout.guaranteedWidths), + height: d3.sum(layout.guaranteedHeights), + wantsWidth: layout.wantsWidth, + wantsHeight: layout.wantsHeight }; }; + + // xOffset is relative to parent element, not absolute Table.prototype._computeLayout = function (xOffset, yOffset, availableWidth, availableHeight) { var _this = this; _super.prototype._computeLayout.call(this, xOffset, yOffset, availableWidth, availableHeight); var layout = this.iterateLayout(this.availableWidth, this.availableHeight); - var sumPair = function (p) { return p[0] + p[1]; }; + + var sumPair = function (p) { + return p[0] + p[1]; + }; var rowHeights = Plottable.Util.Methods.addArrays(layout.rowProportionalSpace, layout.guaranteedHeights); var colWidths = Plottable.Util.Methods.addArrays(layout.colProportionalSpace, layout.guaranteedWidths); var childYOffset = 0; this.rows.forEach(function (row, rowIndex) { var childXOffset = 0; row.forEach(function (component, colIndex) { + // recursively compute layout if (component != null) { component._computeLayout(childXOffset, childYOffset, colWidths[colIndex], rowHeights[rowIndex]); } @@ -1701,29 +2535,62 @@ var Plottable; childYOffset += rowHeights[rowIndex] + _this.rowPadding; }); }; + + /** + * Sets the row and column padding on the Table. + * + * @param {number} rowPadding The padding above and below each row, in pixels. + * @param {number} colPadding the padding to the left and right of each column, in pixels. + * @returns {Table} The calling Table. + */ Table.prototype.padding = function (rowPadding, colPadding) { this.rowPadding = rowPadding; this.colPadding = colPadding; this._invalidateLayout(); return this; }; + + /** + * Sets the layout weight of a particular row. + * Space is allocated to rows based on their weight. Rows with higher weights receive proportionally more space. + * + * @param {number} index The index of the row. + * @param {number} weight The weight to be set on the row. + * @returns {Table} The calling Table. + */ Table.prototype.rowWeight = function (index, weight) { this.rowWeights[index] = weight; this._invalidateLayout(); return this; }; + + /** + * Sets the layout weight of a particular column. + * Space is allocated to columns based on their weight. Columns with higher weights receive proportionally more space. + * + * @param {number} index The index of the column. + * @param {number} weight The weight to be set on the column. + * @returns {Table} The calling Table. + */ Table.prototype.colWeight = function (index, weight) { this.colWeights[index] = weight; this._invalidateLayout(); return this; }; + Table.prototype._isFixedWidth = function () { var cols = d3.transpose(this.rows); - return Table.fixedSpace(cols, function (c) { return (c == null) || c._isFixedWidth(); }); + return Table.fixedSpace(cols, function (c) { + return (c == null) || c._isFixedWidth(); + }); }; + Table.prototype._isFixedHeight = function () { - return Table.fixedSpace(this.rows, function (c) { return (c == null) || c._isFixedHeight(); }); + return Table.fixedSpace(this.rows, function (c) { + return (c == null) || c._isFixedHeight(); + }); }; + Table.prototype.padTableToSize = function (nRows, nCols) { for (var i = 0; i < nRows; i++) { if (this.rows[i] === undefined) { @@ -1742,28 +2609,43 @@ var Plottable; } } }; + 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); + 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.Util.Methods.createFilledArray(0, weights.length); - } - else { - return weights.map(function (w) { return freeSpace * w / weightSum; }); + } 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 group_isFixed = function (components) { return all(components.map(fixityAccessor)); }; + var all = function (bools) { + return bools.reduce(function (a, b) { + return a && b; + }, true); + }; + var group_isFixed = function (components) { + return all(components.map(fixityAccessor)); + }; return all(componentGroup.map(group_isFixed)); }; return Table; @@ -1773,6 +2655,7 @@ var Plottable; var Component = Plottable.Component; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -1784,6 +2667,12 @@ var Plottable; (function (Abstract) { var Scale = (function (_super) { __extends(Scale, _super); + /** + * Creates a new Scale. + * + * @constructor + * @param {D3.Scale.Scale} scale The D3 scale backing the Scale. + */ function Scale(scale) { _super.call(this); this.autoDomainAutomatically = true; @@ -1794,56 +2683,93 @@ var Plottable; Scale.prototype._getAllExtents = function () { return d3.values(this._rendererAttrID2Extent); }; + Scale.prototype._getExtent = function () { return []; }; + + /** + * Modify the domain on the scale so that it includes the extent of all + * perspectives it depends on. Extent: The (min, max) pair for a + * QuantitiativeScale, all covered strings for an OrdinalScale. + * Perspective: A combination of a DataSource and an Accessor that + * represents a view in to the data. + */ Scale.prototype.autoDomain = function () { this.autoDomainAutomatically = true; this._setDomain(this._getExtent()); return this; }; + Scale.prototype._autoDomainIfAutomaticMode = function () { if (this.autoDomainAutomatically) { this.autoDomain(); } }; + + /** + * Returns the range value corresponding to a given domain value. + * + * @param value {any} A domain value to be scaled. + * @returns {any} The range value corresponding to the supplied domain value. + */ Scale.prototype.scale = function (value) { return this._d3Scale(value); }; + Scale.prototype.domain = function (values) { if (values == null) { return this._getDomain(); - } - else { + } else { this.autoDomainAutomatically = false; this._setDomain(values); return this; } }; + Scale.prototype._getDomain = function () { return this._d3Scale.domain(); }; + Scale.prototype._setDomain = function (values) { this._d3Scale.domain(values); this.broadcaster.broadcast(); }; + Scale.prototype.range = function (values) { if (values == null) { return this._d3Scale.range(); - } - else { + } else { this._d3Scale.range(values); return this; } }; + + /** + * Creates a copy of the Scale with the same domain and range but without any registered listeners. + * + * @returns {Scale} A copy of the calling Scale. + */ Scale.prototype.copy = function () { return new Scale(this._d3Scale.copy()); }; + + /** + * When a renderer determines that the extent of a projector has changed, + * it will call this function. This function should ensure that + * the scale has a domain at least large enough to include extent. + * + * @param {number} rendererID A unique indentifier of the renderer sending + * the new extent. + * @param {string} attr The attribute being projected, e.g. "x", "y0", "r" + * @param {any[]} extent The new extent to be included in the scale. + */ Scale.prototype.updateExtent = function (rendererID, attr, extent) { this._rendererAttrID2Extent[rendererID + attr] = extent; this._autoDomainIfAutomaticMode(); return this; }; + Scale.prototype.removeExtent = function (rendererID, attr) { delete this._rendererAttrID2Extent[rendererID + attr]; this._autoDomainIfAutomaticMode(); @@ -1856,6 +2782,7 @@ var Plottable; var Abstract = Plottable.Abstract; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -1877,16 +2804,15 @@ var Plottable; this.animateOnNextRender = true; this.clipPathEnabled = true; this.classed("plot", true); + var dataSource; if (dataset != null) { if (typeof dataset.data === "function") { dataSource = dataset; - } - else { + } else { dataSource = dataSource = new Plottable.DataSource(dataset); } - } - else { + } else { dataSource = new Plottable.DataSource(); } this.dataSource(dataSource); @@ -1897,10 +2823,13 @@ var Plottable; this._dataChanged = true; this.updateAllProjectors(); }; + Plot.prototype.remove = function () { var _this = this; _super.prototype.remove.call(this); this._dataSource.broadcaster.deregisterListener(this); + + // deregister from all scales var properties = Object.keys(this._projectors); properties.forEach(function (property) { var projector = _this._projectors[property]; @@ -1909,6 +2838,7 @@ var Plottable; } }); }; + Plot.prototype.dataSource = function (source) { var _this = this; if (source == null) { @@ -1919,34 +2849,43 @@ var Plottable; this._dataSource.broadcaster.deregisterListener(this); } this._dataSource = source; - this._dataSource.broadcaster.registerListener(this, function () { return _this._onDataSourceUpdate(); }); + this._dataSource.broadcaster.registerListener(this, function () { + return _this._onDataSourceUpdate(); + }); this._onDataSourceUpdate(); return this; }; + Plot.prototype._onDataSourceUpdate = function () { this.updateAllProjectors(); this.animateOnNextRender = true; this._dataChanged = true; this._render(); }; + Plot.prototype.project = function (attrToSet, accessor, scale) { var _this = this; attrToSet = attrToSet.toLowerCase(); var currentProjection = this._projectors[attrToSet]; var existingScale = (currentProjection != null) ? currentProjection.scale : null; + if (existingScale != null) { existingScale.removeExtent(this._plottableID, attrToSet); existingScale.broadcaster.deregisterListener(this); } + if (scale != null) { - scale.broadcaster.registerListener(this, function () { return _this._render(); }); + scale.broadcaster.registerListener(this, function () { + return _this._render(); + }); } var activatedAccessor = Plottable.Util.Methods._applyAccessor(accessor, this); this._projectors[attrToSet] = { accessor: activatedAccessor, scale: scale }; this.updateProjector(attrToSet); - this._render(); + this._render(); // queue a re-render upon changing projector return this; }; + Plot.prototype._generateAttrToProjector = function () { var _this = this; var h = {}; @@ -1954,11 +2893,14 @@ var Plottable; var projector = _this._projectors[a]; var accessor = projector.accessor; var scale = projector.scale; - var fn = scale == null ? accessor : function (d, i) { return scale.scale(accessor(d, i)); }; + var fn = scale == null ? accessor : function (d, i) { + return scale.scale(accessor(d, i)); + }; h[a] = fn; }); return h; }; + Plot.prototype._doRender = function () { if (this._isAnchored) { this._paint(); @@ -1966,52 +2908,85 @@ var Plottable; this.animateOnNextRender = false; } }; + Plot.prototype._paint = function () { + // no-op }; + Plot.prototype._setup = function () { _super.prototype._setup.call(this); this.renderArea = this.content.append("g").classed("render-area", true); }; + + /** + * Enables or disables animation. + * + * @param {boolean} enabled Whether or not to animate. + */ Plot.prototype.animate = function (enabled) { this._animate = enabled; return this; }; + Plot.prototype.detach = function () { _super.prototype.detach.call(this); + + // make the domain resize this.updateAllProjectors(); return this; }; + + /** + * This function makes sure that all of the scales in this._projectors + * have an extent that includes all the data that is projected onto them. + */ Plot.prototype.updateAllProjectors = function () { var _this = this; - d3.keys(this._projectors).forEach(function (attr) { return _this.updateProjector(attr); }); + d3.keys(this._projectors).forEach(function (attr) { + return _this.updateProjector(attr); + }); return this; }; + Plot.prototype.updateProjector = function (attr) { var projector = this._projectors[attr]; if (projector.scale != null) { var extent = this.dataSource()._getExtent(projector.accessor); if (extent.length === 0 || !this._isAnchored) { projector.scale.removeExtent(this._plottableID, attr); - } - else { + } else { projector.scale.updateExtent(this._plottableID, attr, extent); } } return this; }; + + /** + * Apply attributes to the selection. + * + * If animation is enabled and a valid animator's key is specified, the + * attributes are applied with the animator. Otherwise, they are applied + * immediately to the selection. + * + * The animation will not animate during auto-resize renders. + * + * @param {D3.Selection} selection The selection of elements to update. + * @param {string} animatorKey The key for the animator. + * @param {Abstract.IAttributeToProjector} attrToProjector The set of attributes to set on the selection. + * @return {D3.Selection} The resulting selection (potentially after the transition) + */ Plot.prototype._applyAnimatedAttributes = function (selection, animatorKey, attrToProjector) { if (this._animate && this.animateOnNextRender && this._animators[animatorKey] != null) { return this._animators[animatorKey].animate(selection, attrToProjector, this); - } - else { + } else { return selection.attr(attrToProjector); } }; + Plot.prototype.animator = function (animatorKey, animator) { if (animator === undefined) { return this._animators[animatorKey]; - } - else { + } else { this._animators[animatorKey] = animator; return this; } @@ -2023,6 +2998,7 @@ var Plottable; var Abstract = Plottable.Abstract; })(Plottable || (Plottable = {})); +/// var Plottable; (function (Plottable) { (function (Core) { @@ -2037,6 +3013,7 @@ var Plottable; return Immediate; })(); RenderPolicy.Immediate = Immediate; + var AnimationFrame = (function () { function AnimationFrame() { } @@ -2046,6 +3023,7 @@ var Plottable; return AnimationFrame; })(); RenderPolicy.AnimationFrame = AnimationFrame; + var Timeout = (function () { function Timeout() { this._timeoutMsec = Plottable.Util.DOM.POLYFILL_TIMEOUT_MSEC; @@ -2064,57 +3042,101 @@ var Plottable; var Core = Plottable.Core; })(Plottable || (Plottable = {})); +/// var Plottable; (function (Plottable) { (function (Core) { + /** + * The RenderController is responsible for enqueueing and synchronizing + * layout and render calls for Plottable components. + * + * Layouts and renders occur inside an animation callback + * (window.requestAnimationFrame if available). + * + * If you require immediate rendering, call RenderController.flush() to + * perform enqueued layout and rendering serially. + */ (function (RenderController) { var _componentsNeedingRender = {}; var _componentsNeedingComputeLayout = {}; var _animationRequested = false; RenderController._renderPolicy = new RenderController.RenderPolicy.AnimationFrame(); + function setRenderPolicy(policy) { RenderController._renderPolicy = policy; } RenderController.setRenderPolicy = setRenderPolicy; + + /** + * If the RenderController is enabled, we enqueue the component for + * render. Otherwise, it is rendered immediately. + * + * @param {Abstract.Component} component Any Plottable component. + */ function registerToRender(c) { _componentsNeedingRender[c._plottableID] = c; requestRender(); } RenderController.registerToRender = registerToRender; + + /** + * If the RenderController is enabled, we enqueue the component for + * layout and render. Otherwise, it is rendered immediately. + * + * @param {Abstract.Component} component Any Plottable component. + */ function registerToComputeLayout(c) { _componentsNeedingComputeLayout[c._plottableID] = c; _componentsNeedingRender[c._plottableID] = c; requestRender(); } RenderController.registerToComputeLayout = registerToComputeLayout; + function requestRender() { + // Only run or enqueue flush on first request. if (!_animationRequested) { _animationRequested = true; RenderController._renderPolicy.render(); } } + function flush() { if (_animationRequested) { + // Layout var toCompute = d3.values(_componentsNeedingComputeLayout); - toCompute.forEach(function (c) { return c._computeLayout(); }); + toCompute.forEach(function (c) { + return c._computeLayout(); + }); + + // Top level render. + // Containers will put their children in the toRender queue var toRender = d3.values(_componentsNeedingRender); - toRender.forEach(function (c) { return c._render(); }); + toRender.forEach(function (c) { + return c._render(); + }); + + // Finally, perform render of all components var failed = {}; Object.keys(_componentsNeedingRender).forEach(function (k) { - try { + try { _componentsNeedingRender[k]._doRender(); - } - catch (err) { + } catch (err) { + // using setTimeout instead of console.log, we get the familiar red + // stack trace setTimeout(function () { throw err; }, 0); failed[k] = _componentsNeedingRender[k]; } }); + + // Reset queues _componentsNeedingComputeLayout = {}; _componentsNeedingRender = failed; _animationRequested = false; } + + // Reset resize flag regardless of queue'd components Core.ResizeBroadcaster.clearResizing(); } RenderController.flush = flush; @@ -2124,35 +3146,74 @@ var Plottable; var Core = Plottable.Core; })(Plottable || (Plottable = {})); +/// var Plottable; (function (Plottable) { (function (Core) { + /** + * The ResizeBroadcaster will broadcast a notification to any registered + * components when the window is resized. + * + * The broadcaster and single event listener are lazily constructed. + * + * Upon resize, the _resized flag will be set to true until after the next + * flush of the RenderController. This is used, for example, to disable + * animations during resize. + */ (function (ResizeBroadcaster) { var broadcaster; var _resizing = false; + function _lazyInitialize() { if (broadcaster === undefined) { broadcaster = new Core.Broadcaster(ResizeBroadcaster); window.addEventListener("resize", _onResize); } } + function _onResize() { _resizing = true; broadcaster.broadcast(); } + + /** + * Returns true if the window has been resized and the RenderController + * has not yet been flushed. + */ function resizing() { return _resizing; } ResizeBroadcaster.resizing = resizing; + function clearResizing() { _resizing = false; } ResizeBroadcaster.clearResizing = clearResizing; + + /** + * Registers a component. + * + * When the window is resized, we invoke ._invalidateLayout() on the + * component, which will enqueue the component for layout and rendering + * with the RenderController. + * + * @param {Abstract.Component} component Any Plottable component. + */ function register(c) { _lazyInitialize(); - broadcaster.registerListener(c._plottableID, function () { return c._invalidateLayout(); }); + broadcaster.registerListener(c._plottableID, function () { + return c._invalidateLayout(); + }); } ResizeBroadcaster.register = register; + + /** + * Deregisters the components. + * + * The component will no longer receive updates on window resize. + * + * @param {Abstract.Component} component Any Plottable component. + */ function deregister(c) { if (broadcaster) { broadcaster.deregisterListener(c._plottableID); @@ -2165,94 +3226,186 @@ var Plottable; var Core = Plottable.Core; })(Plottable || (Plottable = {})); +/// var Plottable; (function (Plottable) { ; })(Plottable || (Plottable = {})); +/// var Plottable; (function (Plottable) { var Domainer = (function () { + /** + * @param {(extents: any[][]) => any[]} combineExtents + * If present, this function will be used by the Domainer to merge + * all the extents that are present on a scale. + * + * A plot may draw multiple things relative to a scale, e.g. + * different stocks over time. The plot computes their extents, + * which are a [min, max] pair. combineExtents is responsible for + * merging them all into one [min, max] pair. It defaults to taking + * the min of the first elements and the max of the second arguments. + */ function Domainer(combineExtents) { this.doNice = false; this.padProportion = 0.0; this.paddingExceptions = d3.map(); this.unregisteredPaddingExceptions = d3.set(); this.includedValues = d3.map(); + // includedValues needs to be a map, even unregistered, to support getting un-stringified values back out this.unregisteredIncludedValues = d3.map(); this.combineExtents = combineExtents; } + /** + * @param {any[][]} extents The list of extents to be reduced to a single + * extent. + * @param {Abstract.QuantitativeScale} scale + * Since nice() must do different things depending on Linear, Log, + * or Time scale, the scale must be passed in for nice() to work. + * @return {any[]} The domain, as a merging of all exents, as a [min, max] + * pair. + */ Domainer.prototype.computeDomain = function (extents, scale) { var domain; if (this.combineExtents != null) { domain = this.combineExtents(extents); - } - else if (extents.length === 0) { + } else if (extents.length === 0) { domain = scale._defaultExtent(); - } - else { - domain = [d3.min(extents, function (e) { return e[0]; }), d3.max(extents, function (e) { return e[1]; })]; + } else { + domain = [d3.min(extents, function (e) { + return e[0]; + }), d3.max(extents, function (e) { + return e[1]; + })]; } domain = this.includeDomain(domain); domain = this.padDomain(scale, domain); domain = this.niceDomain(scale, domain); return domain; }; + + /** + * Sets the Domainer to pad by a given ratio. + * + * @param {number} [padProportion] Proportionally how much bigger the + * new domain should be (0.05 = 5% larger). + * + * A domainer will pad equal visual amounts on each side. + * On a linear scale, this means both sides are padded the same + * amount: [10, 20] will be padded to [5, 25]. + * On a log scale, the top will be padded more than the bottom, so + * [10, 100] will be padded to [1, 1000]. + * + * @return {Domainer} The calling Domainer. + */ Domainer.prototype.pad = function (padProportion) { - if (padProportion === void 0) { padProportion = 0.05; } + if (typeof padProportion === "undefined") { padProportion = 0.05; } this.padProportion = padProportion; return this; }; + + /** + * Add a padding exception, a value that will not be padded at either end of the domain. + * + * Eg, if a padding exception is added at x=0, then [0, 100] will pad to [0, 105] instead of [-2.5, 102.5]. + * If a key is provided, it will be registered under that key with standard map semantics. (Overwrite / remove by key) + * If a key is not provided, it will be added with set semantics (Can be removed by value) + * + * @param {any} exception The padding exception to add. + * @param string [key] The key to register the exception under. + * @return Domainer The calling domainer + */ Domainer.prototype.addPaddingException = function (exception, key) { if (key != null) { this.paddingExceptions.set(key, exception); - } - else { + } else { this.unregisteredPaddingExceptions.add(exception); } return this; }; + + /** + * Remove a padding exception, allowing the domain to pad out that value again. + * + * If a string is provided, it is assumed to be a key and the exception associated with that key is removed. + * If a non-string is provdied, it is assumed to be an unkeyed exception and that exception is removed. + * + * @param {any} keyOrException The key for the value to remove, or the value to remove + * @return Domainer The calling domainer + */ Domainer.prototype.removePaddingException = function (keyOrException) { if (typeof (keyOrException) === "string") { this.paddingExceptions.remove(keyOrException); - } - else { + } else { this.unregisteredPaddingExceptions.remove(keyOrException); } return this; }; + + /** + * Add an included value, a value that must be included inside the domain. + * + * Eg, if a value exception is added at x=0, then [50, 100] will expand to [0, 100] rather than [50, 100]. + * If a key is provided, it will be registered under that key with standard map semantics. (Overwrite / remove by key) + * If a key is not provided, it will be added with set semantics (Can be removed by value) + * + * @param {any} value The included value to add. + * @param string [key] The key to register the value under. + * @return Domainer The calling domainer + */ Domainer.prototype.addIncludedValue = function (value, key) { if (key != null) { this.includedValues.set(key, value); - } - else { + } else { this.unregisteredIncludedValues.set(value, value); } return this; }; + + /** + * Remove an included value, allowing the domain to not include that value gain again. + * + * If a string is provided, it is assumed to be a key and the value associated with that key is removed. + * If a non-string is provdied, it is assumed to be an unkeyed value and that value is removed. + * + * @param {any} keyOrException The key for the value to remove, or the value to remove + * @return Domainer The calling domainer + */ Domainer.prototype.removeIncludedValue = function (valueOrKey) { if (typeof (valueOrKey) === "string") { this.includedValues.remove(valueOrKey); - } - else { + } else { this.unregisteredIncludedValues.remove(valueOrKey); } return this; }; + + /** + * Extends the scale's domain so it starts and ends with "nice" values. + * + * @param {number} [count] The number of ticks that should fit inside the new domain. + * @return {Domainer} The calling Domainer. + */ Domainer.prototype.nice = function (count) { this.doNice = true; this.niceCount = count; return this; }; + Domainer.defaultCombineExtents = function (extents) { if (extents.length === 0) { return [0, 1]; - } - else { - return [d3.min(extents, function (e) { return e[0]; }), d3.max(extents, function (e) { return e[1]; })]; + } else { + return [d3.min(extents, function (e) { + return e[0]; + }), d3.max(extents, function (e) { + return e[1]; + })]; } }; + Domainer.prototype.padDomain = function (scale, domain) { var min = domain[0]; var max = domain[1]; @@ -2260,15 +3413,20 @@ var Plottable; var d = min.valueOf(); if (min instanceof Date) { return [d - Domainer.ONE_DAY, d + Domainer.ONE_DAY]; - } - else { - return [d - Domainer.PADDING_FOR_IDENTICAL_DOMAIN, d + Domainer.PADDING_FOR_IDENTICAL_DOMAIN]; + } else { + return [ + d - Domainer.PADDING_FOR_IDENTICAL_DOMAIN, + d + Domainer.PADDING_FOR_IDENTICAL_DOMAIN]; } } + if (scale.domain()[0] === scale.domain()[1]) { return domain; } var p = this.padProportion / 2; + + // This scaling is done to account for log scales and other non-linear + // scales. A log scale should be padded more on the max than on the min. var newMin = scale.invert(scale.scale(min) - (scale.scale(max) - scale.scale(min)) * p); var newMax = scale.invert(scale.scale(max) + (scale.scale(max) - scale.scale(min)) * p); var exceptionValues = this.paddingExceptions.values().concat(this.unregisteredPaddingExceptions.values()); @@ -2281,17 +3439,20 @@ var Plottable; } return [newMin, newMax]; }; + Domainer.prototype.niceDomain = function (scale, domain) { if (this.doNice) { return scale._niceDomain(domain, this.niceCount); - } - else { + } else { return domain; } }; + Domainer.prototype.includeDomain = function (domain) { var includedValues = this.includedValues.values().concat(this.unregisteredIncludedValues.values()); - return includedValues.reduce(function (domain, value) { return [Math.min(domain[0], value), Math.max(domain[1], value)]; }, domain); + return includedValues.reduce(function (domain, value) { + return [Math.min(domain[0], value), Math.max(domain[1], value)]; + }, domain); }; Domainer.PADDING_FOR_IDENTICAL_DOMAIN = 1; Domainer.ONE_DAY = 1000 * 60 * 60 * 24; @@ -2300,6 +3461,7 @@ var Plottable; Plottable.Domainer = Domainer; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -2311,6 +3473,12 @@ var Plottable; (function (Abstract) { var QuantitativeScale = (function (_super) { __extends(QuantitativeScale, _super); + /** + * Creates a new QuantitativeScale. + * + * @constructor + * @param {D3.Scale.QuantitativeScale} scale The D3 QuantitativeScale backing the QuantitativeScale. + */ function QuantitativeScale(scale) { _super.call(this, scale); this._lastRequestedTickCount = 10; @@ -2321,23 +3489,41 @@ var Plottable; QuantitativeScale.prototype._getExtent = function () { return this._domainer.computeDomain(this._getAllExtents(), this); }; + + /** + * Retrieves the domain value corresponding to a supplied range value. + * + * @param {number} value: A value from the Scale's range. + * @returns {number} The domain value corresponding to the supplied range value. + */ QuantitativeScale.prototype.invert = function (value) { return this._d3Scale.invert(value); }; + + /** + * Creates a copy of the QuantitativeScale with the same domain and range but without any registered listeners. + * + * @returns {QuantitativeScale} A copy of the calling QuantitativeScale. + */ QuantitativeScale.prototype.copy = function () { return new QuantitativeScale(this._d3Scale.copy()); }; + QuantitativeScale.prototype.domain = function (values) { return _super.prototype.domain.call(this, values); }; + QuantitativeScale.prototype._setDomain = function (values) { - var isNaNOrInfinity = function (x) { return x !== x || x === Infinity || x === -Infinity; }; + var isNaNOrInfinity = function (x) { + return x !== x || x === Infinity || x === -Infinity; + }; if (isNaNOrInfinity(values[0]) || isNaNOrInfinity(values[1])) { Plottable.Util.Methods.warn("Warning: QuantitativeScales cannot take NaN or Infinity as a domain value. Ignoring."); return; } _super.prototype._setDomain.call(this, values); }; + QuantitativeScale.prototype.interpolate = function (factory) { if (factory == null) { return this._d3Scale.interpolate(); @@ -2345,10 +3531,17 @@ var Plottable; this._d3Scale.interpolate(factory); return this; }; + + /** + * Sets the range of the QuantitativeScale and sets the interpolator to d3.interpolateRound. + * + * @param {number[]} values The new range value for the range. + */ QuantitativeScale.prototype.rangeRound = function (values) { this._d3Scale.rangeRound(values); return this; }; + QuantitativeScale.prototype.clamp = function (clamp) { if (clamp == null) { return this._d3Scale.clamp(); @@ -2356,29 +3549,50 @@ var Plottable; this._d3Scale.clamp(clamp); return this; }; + + /** + * Generates tick values. + * + * @param {number} [count] The number of ticks to generate. + * @returns {any[]} The generated ticks. + */ QuantitativeScale.prototype.ticks = function (count) { if (count != null) { this._lastRequestedTickCount = count; } return this._d3Scale.ticks(this._lastRequestedTickCount); }; + + /** + * Gets a tick formatting function for displaying tick values. + * + * @param {number} count The number of ticks to be displayed + * @param {string} [format] A format specifier string. + * @returns {(n: number) => string} A formatting function. + */ QuantitativeScale.prototype.tickFormat = function (count, format) { return this._d3Scale.tickFormat(count, format); }; + + /** + * Given a domain, expands its domain onto "nice" values, e.g. whole + * numbers. + */ QuantitativeScale.prototype._niceDomain = function (domain, count) { return this._d3Scale.copy().domain(domain).nice(count).domain(); }; + QuantitativeScale.prototype.domainer = function (domainer) { if (domainer == null) { return this._domainer; - } - else { + } else { this._domainer = domainer; this._userSetDomainer = true; this._autoDomainIfAutomaticMode(); return this; } }; + QuantitativeScale.prototype._defaultExtent = function () { return [0, 1]; }; @@ -2389,6 +3603,7 @@ var Plottable; var Abstract = Plottable.Abstract; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -2403,6 +3618,11 @@ var Plottable; function Linear(scale) { _super.call(this, scale == null ? d3.scale.linear() : scale); } + /** + * Creates a copy of the LinearScale with the same domain and range but without any registered listeners. + * + * @returns {LinearScale} A copy of the calling LinearScale. + */ Linear.prototype.copy = function () { return new Linear(this._d3Scale.copy()); }; @@ -2413,6 +3633,7 @@ var Plottable; var Scale = Plottable.Scale; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -2431,9 +3652,15 @@ var Plottable; Plottable.Util.Methods.warn("Plottable.Scale.Log is deprecated. If possible, use Plottable.Scale.ModifiedLog instead."); } } + /** + * Creates a copy of the Scale.Log with the same domain and range but without any registered listeners. + * + * @returns {Scale.Log} A copy of the calling Scale.Log. + */ Log.prototype.copy = function () { return new Log(this._d3Scale.copy()); }; + Log.prototype._defaultExtent = function () { return [1, 10]; }; @@ -2445,6 +3672,7 @@ var Plottable; var Scale = Plottable.Scale; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -2456,8 +3684,33 @@ var Plottable; (function (Scale) { var ModifiedLog = (function (_super) { __extends(ModifiedLog, _super); + /** + * Creates a new Scale.ModifiedLog. + * + * A ModifiedLog scale acts as a regular log scale for large numbers. + * As it approaches 0, it gradually becomes linear. This means that the + * scale won't freak out if you give it 0 or a negative number, where an + * ordinary Log scale would. + * + * However, it does mean that scale will be effectively linear as values + * approach 0. If you want very small values on a log scale, you should use + * an ordinary Scale.Log instead. + * + * @constructor + * @param {number} [base] + * The base of the log. Defaults to 10, and must be > 1. + * + * For base <= x, 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; } + if (typeof base === "undefined") { base = 10; } _super.call(this, d3.scale.linear()); this._showIntermediateTicks = false; this.base = base; @@ -2468,61 +3721,111 @@ var Plottable; 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])]; this._d3Scale.domain(transformedDomain); this.broadcaster.broadcast(); }; + ModifiedLog.prototype.ticks = function (count) { if (count != null) { _super.prototype.ticks.call(this, count); } - var middle = function (x, y, z) { return [x, y, z].sort(function (a, b) { return a - b; })[1]; }; + + // 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 = d3.min(this.untransformedDomain); var max = d3.max(this.untransformedDomain); 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 negativeLogTicks = this.logTicks(-negativeUpper, -negativeLower).map(function (x) { + return -x; + }).reverse(); var positiveLogTicks = this.logTicks(positiveLower, positiveUpper); - var linearTicks = this._showIntermediateTicks ? d3.scale.linear().domain([negativeUpper, positiveLower]).ticks(this.howManyTicks(negativeUpper, positiveLower)) : [-this.pivot, 0, this.pivot].filter(function (x) { return min <= x && x <= max; }); + var linearTicks = this._showIntermediateTicks ? d3.scale.linear().domain([negativeUpper, positiveLower]).ticks(this.howManyTicks(negativeUpper, positiveLower)) : [-this.pivot, 0, this.pivot].filter(function (x) { + return min <= x && x <= max; + }); + 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(this._lastRequestedTickCount); } 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); @@ -2535,12 +3838,28 @@ var Plottable; var nMultiples = this._showIntermediateTicks ? Math.floor(nTicks / bases.length) : 1; var multiples = d3.range(this.base, 1, -(this.base - 1) / nMultiples).map(Math.floor); var uniqMultiples = Plottable.Util.Methods.uniqNumbers(multiples); - var clusters = bases.map(function (b) { return uniqMultiples.map(function (x) { return Math.pow(_this.base, b - 1) * x; }); }); + var clusters = bases.map(function (b) { + return uniqMultiples.map(function (x) { + return Math.pow(_this.base, b - 1) * x; + }); + }); var flattened = Plottable.Util.Methods.flatten(clusters); - var filtered = flattened.filter(function (x) { return lower <= x && x <= upper; }); - var sorted = filtered.sort(function (x, y) { return x - y; }); + 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(d3.min(this.untransformedDomain)); var adjustedMax = this.adjustedLog(d3.max(this.untransformedDomain)); @@ -2550,17 +3869,19 @@ var Plottable; var ticks = Math.ceil(proportion * this._lastRequestedTickCount); return ticks; }; + ModifiedLog.prototype.copy = function () { return new ModifiedLog(this.base); }; + ModifiedLog.prototype._niceDomain = function (domain, count) { return domain; }; + ModifiedLog.prototype.showIntermediateTicks = function (show) { if (show == null) { return this._showIntermediateTicks; - } - else { + } else { this._showIntermediateTicks = show; } }; @@ -2571,6 +3892,7 @@ var Plottable; var Scale = Plottable.Scale; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -2582,10 +3904,16 @@ var Plottable; (function (Scale) { var Ordinal = (function (_super) { __extends(Ordinal, _super); + /** + * Creates a new OrdinalScale. Domain and Range are set later. + * + * @constructor + */ function Ordinal(scale) { _super.call(this, scale == null ? d3.scale.ordinal() : scale); this._range = [0, 1]; this._rangeType = "bands"; + // Padding as a proportion of the spacing between domain values this._innerPadding = 0.3; this._outerPadding = 0.5; if (this._innerPadding > this._outerPadding) { @@ -2596,31 +3924,39 @@ var Plottable; var extents = this._getAllExtents(); return Plottable.Util.Methods.uniq(Plottable.Util.Methods.flatten(extents)); }; + Ordinal.prototype.domain = function (values) { return _super.prototype.domain.call(this, values); }; + Ordinal.prototype._setDomain = function (values) { _super.prototype._setDomain.call(this, values); - this.range(this.range()); + this.range(this.range()); // update range }; + Ordinal.prototype.range = function (values) { if (values == null) { return this._range; - } - else { + } else { this._range = values; if (this._rangeType === "points") { - this._d3Scale.rangePoints(values, 2 * this._outerPadding); - } - else if (this._rangeType === "bands") { + this._d3Scale.rangePoints(values, 2 * this._outerPadding); // d3 scale takes total padding + } else if (this._rangeType === "bands") { this._d3Scale.rangeBands(values, this._innerPadding, this._outerPadding); } return this; } }; + + /** + * Returns the width of the range band. Only valid when rangeType is set to "bands". + * + * @returns {number} The range band width or 0 if rangeType isn't "bands". + */ Ordinal.prototype.rangeBand = function () { return this._d3Scale.rangeBand(); }; + Ordinal.prototype.innerPadding = function () { var d = this.domain(); if (d.length < 2) { @@ -2629,16 +3965,17 @@ var Plottable; var step = Math.abs(this.scale(d[1]) - this.scale(d[0])); return step - this.rangeBand(); }; + Ordinal.prototype.fullBandStartAndWidth = function (v) { var start = this.scale(v) - this.innerPadding() / 2; var width = this.rangeBand() + this.innerPadding(); return [start, width]; }; + Ordinal.prototype.rangeType = function (rangeType, outerPadding, innerPadding) { if (rangeType == null) { return this._rangeType; - } - else { + } else { if (!(rangeType === "points" || rangeType === "bands")) { throw new Error("Unsupported range type: " + rangeType); } @@ -2653,6 +3990,12 @@ var Plottable; return this; } }; + + /** + * Creates a copy of the Scale with the same domain and range but without any registered listeners. + * + * @returns {Ordinal} A copy of the calling Scale. + */ Ordinal.prototype.copy = function () { return new Ordinal(this._d3Scale.copy()); }; @@ -2663,6 +4006,7 @@ var Plottable; var Scale = Plottable.Scale; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -2674,6 +4018,14 @@ var Plottable; (function (Scale) { var Color = (function (_super) { __extends(Color, _super); + /** + * Creates a ColorScale. + * + * @constructor + * @param {string} [scaleType] the type of color scale to create + * (Category10/Category20/Category20b/Category20c). + * See https://github.com/mbostock/d3/wiki/Ordinal-Scales#categorical-colors + */ function Color(scaleType) { var scale; switch (scaleType) { @@ -2706,6 +4058,7 @@ var Plottable; } _super.call(this, scale); } + // Duplicated from OrdinalScale._getExtent - should be removed in #388 Color.prototype._getExtent = function () { var extents = this._getAllExtents(); var concatenatedExtents = []; @@ -2721,6 +4074,7 @@ var Plottable; var Scale = Plottable.Scale; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -2733,26 +4087,37 @@ var Plottable; var Time = (function (_super) { __extends(Time, _super); function Time(scale) { + // need to cast since d3 time scales do not descend from Quantitative scales _super.call(this, scale == null ? d3.time.scale() : scale); this._PADDING_FOR_IDENTICAL_DOMAIN = 1000 * 60 * 60 * 24; } 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(); tempScale.domain(this.domain()); tempScale.range(this.range()); return tempScale.ticks(interval.range, step); }; + Time.prototype.domain = function (values) { if (values == null) { return _super.prototype.domain.call(this); - } - else { + } else { + // attempt to parse dates if (typeof (values[0]) === "string") { - values = values.map(function (d) { return new Date(d); }); + values = values.map(function (d) { + return new Date(d); + }); } return _super.prototype.domain.call(this, values); } }; + + /** + * Creates a copy of the TimeScale with the same domain and range but without any registered listeners. + * + * @returns {TimeScale} A copy of the calling TimeScale. + */ Time.prototype.copy = function () { return new Time(this._d3Scale.copy()); }; @@ -2763,6 +4128,7 @@ var Plottable; var Scale = Plottable.Scale; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -2773,15 +4139,43 @@ var Plottable; (function (Plottable) { (function (Scale) { ; + + /** + * This class implements a color scale that takes quantitive input and + * interpolates between a list of color values. It returns a hex string + * representing the interpolated color. + * + * By default it generates a linear scale internally. + */ var InterpolatedColor = (function (_super) { __extends(InterpolatedColor, _super); + /** + * Creates a InterpolatedColorScale. + * + * @constructor + * @param {string|string[]} [colorRange] the type of color scale to + * create. Default is "reds". @see {@link colorRange} for further + * options. + * @param {string} [scaleType] the type of underlying scale to use + * (linear/pow/log/sqrt). Default is "linear". @see {@link scaleType} + * for further options. + */ function InterpolatedColor(colorRange, scaleType) { - if (colorRange === void 0) { colorRange = "reds"; } - if (scaleType === void 0) { scaleType = "linear"; } + if (typeof colorRange === "undefined") { colorRange = "reds"; } + if (typeof scaleType === "undefined") { scaleType = "linear"; } this._colorRange = this._resolveColorValues(colorRange); this._scaleType = scaleType; _super.call(this, InterpolatedColor.getD3InterpolatedScale(this._colorRange, this._scaleType)); } + /** + * Converts the string array into a d3 scale. + * + * @param {string[]} colors an array of strings representing color + * values in hex ("#FFFFFF") or keywords ("white"). + * @param {string} scaleType a string representing the underlying scale + * type ("linear"/"log"/"sqrt"/"pow") + * @returns a Quantitative d3 scale. + */ InterpolatedColor.getD3InterpolatedScale = function (colors, scaleType) { var scale; switch (scaleType) { @@ -2803,6 +4197,18 @@ var Plottable; } return scale.range([0, 1]).interpolate(InterpolatedColor.interpolateColors(colors)); }; + + /** + * Creates a d3 interpolator given the color array. + * + * d3 doesn't accept more than 2 range values unless we use a ordinal + * scale. So, in order to interpolate smoothly between the full color + * range, we must override the interpolator and compute the color values + * manually. + * + * @param {string[]} colors an array of strings representing color + * values in hex ("#FFFFFF") or keywords ("white"). + */ InterpolatedColor.interpolateColors = function (colors) { if (colors.length < 2) { throw new Error("Color scale arrays must have at least two elements."); @@ -2810,15 +4216,21 @@ var Plottable; ; return function (ignored) { 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.colorRange = function (colorRange) { if (colorRange == null) { return this._colorRange; @@ -2827,6 +4239,7 @@ var Plottable; this._resetScale(); return this; }; + InterpolatedColor.prototype.scaleType = function (scaleType) { if (scaleType == null) { return this._scaleType; @@ -2835,26 +4248,32 @@ var Plottable; this._resetScale(); return this; }; + InterpolatedColor.prototype._resetScale = function () { this._d3Scale = InterpolatedColor.getD3InterpolatedScale(this._colorRange, this._scaleType); this._autoDomainIfAutomaticMode(); this.broadcaster.broadcast(); }; + InterpolatedColor.prototype._resolveColorValues = function (colorRange) { if (colorRange instanceof Array) { return colorRange; - } - else if (InterpolatedColor.COLOR_SCALES[colorRange] != null) { + } else if (InterpolatedColor.COLOR_SCALES[colorRange] != null) { return InterpolatedColor.COLOR_SCALES[colorRange]; - } - else { + } else { return InterpolatedColor.COLOR_SCALES["reds"]; } }; + InterpolatedColor.prototype.autoDomain = function () { + // unlike other QuantitativeScales, interpolatedColorScale ignores its domainer var extents = this._getAllExtents(); if (extents.length > 0) { - this._setDomain([d3.min(extents, function (x) { return x[0]; }), d3.max(extents, function (x) { return x[1]; })]); + this._setDomain([d3.min(extents, function (x) { + return x[0]; + }), d3.max(extents, function (x) { + return x[1]; + })]); } return this; }; @@ -2908,18 +4327,33 @@ var Plottable; var Scale = Plottable.Scale; })(Plottable || (Plottable = {})); +/// var Plottable; (function (Plottable) { (function (Util) { var ScaleDomainCoordinator = (function () { + /** + * Creates a ScaleDomainCoordinator. + * + * @constructor + * @param {Scale[]} scales A list of scales whose domains should be linked. + */ function ScaleDomainCoordinator(scales) { var _this = this; + /* This class is responsible for maintaining coordination between linked scales. + It registers event listeners for when one of its scales changes its domain. When the scale + does change its domain, it re-propogates the change to every linked scale. + */ this.rescaleInProgress = false; if (scales == null) { throw new Error("ScaleDomainCoordinator requires scales to coordinate"); } this.scales = scales; - this.scales.forEach(function (s) { return s.broadcaster.registerListener(_this, function (sx) { return _this.rescale(sx); }); }); + this.scales.forEach(function (s) { + return s.broadcaster.registerListener(_this, function (sx) { + return _this.rescale(sx); + }); + }); } ScaleDomainCoordinator.prototype.rescale = function (scale) { if (this.rescaleInProgress) { @@ -2927,7 +4361,9 @@ var Plottable; } this.rescaleInProgress = true; var newDomain = scale.domain(); - this.scales.forEach(function (s) { return s.domain(newDomain); }); + this.scales.forEach(function (s) { + return s.domain(newDomain); + }); this.rescaleInProgress = false; }; return ScaleDomainCoordinator; @@ -2937,6 +4373,7 @@ var Plottable; var Util = Plottable.Util; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -2949,9 +4386,9 @@ var Plottable; var Axis = (function (_super) { __extends(Axis, _super); function Axis(scale, orientation, formatter) { - if (formatter === void 0) { formatter = Plottable.Formatters.identity(); } - _super.call(this); + if (typeof formatter === "undefined") { formatter = Plottable.Formatters.identity(); } var _this = this; + _super.call(this); this._width = "auto"; this._height = "auto"; this._endTickLength = 5; @@ -2964,34 +4401,45 @@ var Plottable; } this._scale = scale; this.orient(orientation); + this.classed("axis", true); if (this._isHorizontal()) { this.classed("x-axis", true); - } - else { + } else { this.classed("y-axis", true); } + this.formatter(formatter); - this._scale.broadcaster.registerListener(this, function () { return _this.rescale(); }); + + this._scale.broadcaster.registerListener(this, function () { + return _this.rescale(); + }); } Axis.prototype.remove = function () { _super.prototype.remove.call(this); this._scale.broadcaster.deregisterListener(this); }; + 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 = this._width; var requestedHeight = this._height; + if (this._isHorizontal()) { if (this._height === "auto") { if (this._computedHeight == null) { @@ -3000,8 +4448,7 @@ var Plottable; requestedHeight = this._computedHeight + this._gutter; } requestedWidth = 0; - } - else { + } else { if (this._width === "auto") { if (this._computedWidth == null) { this._computeWidth(); @@ -3010,6 +4457,7 @@ var Plottable; } requestedHeight = 0; } + return { width: requestedWidth, height: requestedHeight, @@ -3017,30 +4465,39 @@ var Plottable; wantsHeight: this._isHorizontal() && offeredHeight < requestedHeight }; }; + Axis.prototype._isFixedHeight = function () { return this._isHorizontal(); }; + Axis.prototype._isFixedWidth = function () { return !this._isHorizontal(); }; + Axis.prototype._computeLayout = function (xOffset, yOffset, availableWidth, availableHeight) { _super.prototype._computeLayout.call(this, xOffset, yOffset, availableWidth, availableHeight); if (this._isHorizontal()) { this._scale.range([0, this.availableWidth]); - } - else { + } else { this._scale.range([this.availableHeight, 0]); } }; + 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._doRender = function () { var tickMarkValues = this._getTickValues(); var tickMarks = this._tickMarkContainer.selectAll("." + Axis.TICK_MARK_CLASS).data(tickMarkValues); @@ -3051,6 +4508,7 @@ var Plottable; tickMarks.exit().remove(); this._baseline.attr(this._generateBaselineAttrHash()); }; + Axis.prototype._generateBaselineAttrHash = function () { var baselineAttrHash = { x1: 0, @@ -3058,76 +4516,92 @@ var Plottable; x2: 0, y2: 0 }; + switch (this._orientation) { case "bottom": baselineAttrHash.x2 = this.availableWidth; break; + case "top": baselineAttrHash.x2 = this.availableWidth; baselineAttrHash.y1 = this.availableHeight; baselineAttrHash.y2 = this.availableHeight; break; + case "left": baselineAttrHash.x1 = this.availableWidth; baselineAttrHash.x2 = this.availableWidth; baselineAttrHash.y2 = this.availableHeight; break; + case "right": baselineAttrHash.y2 = this.availableHeight; break; } + return baselineAttrHash; }; + Axis.prototype._generateTickMarkAttrHash = function (isEndTickMark) { var _this = this; - if (isEndTickMark === void 0) { isEndTickMark = false; } + if (typeof isEndTickMark === "undefined") { isEndTickMark = false; } var tickMarkAttrHash = { x1: 0, y1: 0, x2: 0, y2: 0 }; - var scalingFunction = function (d) { return _this._scale.scale(d); }; + + var scalingFunction = function (d) { + return _this._scale.scale(d); + }; if (this._isHorizontal()) { tickMarkAttrHash["x1"] = scalingFunction; tickMarkAttrHash["x2"] = scalingFunction; - } - else { + } else { tickMarkAttrHash["y1"] = scalingFunction; tickMarkAttrHash["y2"] = scalingFunction; } + var tickLength = isEndTickMark ? this._endTickLength : this._tickLength; + switch (this._orientation) { case "bottom": tickMarkAttrHash["y2"] = tickLength; break; + case "top": tickMarkAttrHash["y1"] = this.availableHeight; tickMarkAttrHash["y2"] = this.availableHeight - tickLength; break; + case "left": tickMarkAttrHash["x1"] = this.availableWidth; tickMarkAttrHash["x2"] = this.availableWidth - tickLength; break; + case "right": tickMarkAttrHash["x2"] = tickLength; break; } + return tickMarkAttrHash; }; + Axis.prototype.rescale = function () { return (this.element != null) ? this._render() : null; }; + Axis.prototype._invalidateLayout = function () { this._computedWidth = null; this._computedHeight = null; _super.prototype._invalidateLayout.call(this); }; + Axis.prototype.width = function (w) { if (w == null) { return this.availableWidth; - } - else { + } else { if (this._isHorizontal()) { throw new Error("width cannot be set on a horizontal Axis"); } @@ -3139,11 +4613,11 @@ var Plottable; return this; } }; + Axis.prototype.height = function (h) { if (h == null) { return this.availableHeight; - } - else { + } else { if (!this._isHorizontal()) { throw new Error("height cannot be set on a vertical Axis"); } @@ -3155,6 +4629,7 @@ var Plottable; return this; } }; + Axis.prototype.formatter = function (formatter) { if (formatter === undefined) { return this._formatter; @@ -3163,11 +4638,11 @@ var Plottable; this._invalidateLayout(); return this; }; + Axis.prototype.tickLength = function (length) { if (length == null) { return this._tickLength; - } - else { + } else { if (length < 0) { throw new Error("tick length must be positive"); } @@ -3176,11 +4651,11 @@ var Plottable; return this; } }; + Axis.prototype.endTickLength = function (length) { if (length == null) { return this._endTickLength; - } - else { + } else { if (length < 0) { throw new Error("end tick length must be positive"); } @@ -3189,19 +4664,19 @@ var Plottable; return this; } }; + Axis.prototype._maxLabelTickLength = function () { if (this.showEndTickLabels()) { return Math.max(this.tickLength(), this.endTickLength()); - } - else { + } else { return this.tickLength(); } }; + Axis.prototype.tickLabelPadding = function (padding) { if (padding == null) { return this._tickLabelPadding; - } - else { + } else { if (padding < 0) { throw new Error("tick label padding must be positive"); } @@ -3210,11 +4685,11 @@ var Plottable; return this; } }; + Axis.prototype.gutter = function (size) { if (size == null) { return this._gutter; - } - else { + } else { if (size < 0) { throw new Error("gutter size must be positive"); } @@ -3223,11 +4698,11 @@ var Plottable; return this; } }; + Axis.prototype.orient = function (newOrientation) { if (newOrientation == null) { return this._orientation; - } - else { + } else { var newOrientationLC = newOrientation.toLowerCase(); if (newOrientationLC !== "top" && newOrientationLC !== "bottom" && newOrientationLC !== "left" && newOrientationLC !== "right") { throw new Error("unsupported orientation"); @@ -3237,6 +4712,7 @@ var Plottable; return this; } }; + Axis.prototype.showEndTickLabels = function (show) { if (show == null) { return this._showEndTickLabels; @@ -3245,12 +4721,15 @@ var Plottable; this._render(); return this; }; + Axis.prototype._hideEndTickLabels = function () { var _this = this; var boundingBox = this.element.select(".bounding-box")[0][0].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.availableWidth) && Math.floor(tickBox.bottom) <= Math.ceil(boundingBox.top + _this.availableHeight)); }; + var tickLabels = this._tickLabelContainer.selectAll("." + Abstract.Axis.TICK_LABEL_CLASS); if (tickLabels[0].length === 0) { return; @@ -3264,25 +4743,28 @@ var Plottable; d3.select(lastTickLabel).style("visibility", "hidden"); } }; + Axis.prototype._hideOverlappingTickLabels = function () { var visibleTickLabels = this._tickLabelContainer.selectAll("." + Abstract.Axis.TICK_LABEL_CLASS).filter(function (d, i) { return d3.select(this).style("visibility") === "visible"; }); var lastLabelClientRect; + visibleTickLabels.each(function (d) { var clientRect = this.getBoundingClientRect(); var tickLabel = d3.select(this); if (lastLabelClientRect != null && Plottable.Util.DOM.boxesOverlap(clientRect, lastLabelClientRect)) { tickLabel.style("visibility", "hidden"); - } - else { + } else { lastLabelClientRect = clientRect; tickLabel.style("visibility", "visible"); } }); }; Axis.END_TICK_MARK_CLASS = "end-tick-mark"; + Axis.TICK_MARK_CLASS = "tick-mark"; + Axis.TICK_LABEL_CLASS = "tick-label"; return Axis; })(Abstract.Component); @@ -3291,6 +4773,7 @@ var Plottable; var Abstract = Plottable.Abstract; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -3301,8 +4784,16 @@ var Plottable; (function (Plottable) { (function (Axis) { ; + var Time = (function (_super) { __extends(Time, _super); + /** + * Creates a TimeAxis + * + * @constructor + * @param {TimeScale} scale The scale to base the Axis on. + * @param {string} orientation The orientation of the Axis (top/bottom) + */ function Time(scale, orientation) { orientation = orientation.toLowerCase(); if (orientation !== "top" && orientation !== "bottom") { @@ -3324,31 +4815,46 @@ var Plottable; this._computedHeight = this._maxLabelTickLength() + 2 * this.tickLabelPadding(); return this._computedHeight; }; + Time.prototype.calculateWorstWidth = function (container, format) { + // returns the worst case width for a format + // September 29, 9999 at 12:59.9999 PM Wednesday var longDate = new Date(9999, 8, 29, 12, 59, 9999); return Plottable.Util.Text.getTextWidth(container, d3.time.format(format)(longDate)); }; + Time.prototype.getIntervalLength = function (interval) { var testDate = this._scale.domain()[0]; + + // meausre how much space one date can get var stepLength = Math.abs(this._scale.scale(interval.timeUnit.offset(testDate, interval.step)) - this._scale.scale(testDate)); return stepLength; }; + Time.prototype.isEnoughSpace = function (container, interval) { + // compute number of ticks + // if less than a certain threshold var worst = this.calculateWorstWidth(container, interval.formatString) + 2 * this.tickLabelPadding(); var stepLength = Math.min(this.getIntervalLength(interval), this.availableWidth); return worst < stepLength; }; + Time.prototype._setup = function () { _super.prototype._setup.call(this); this._majorTickLabels = this.content.append("g").classed(Plottable.Abstract.Axis.TICK_LABEL_CLASS, true); this._minorTickLabels = this.content.append("g").classed(Plottable.Abstract.Axis.TICK_LABEL_CLASS, true); }; + + // returns a number to index into the major/minor intervals Time.prototype.getTickLevel = function () { + // for zooming, don't start search all the way from beginning. var startingPoint = Time.minorIntervals.length - 1; var curSpan = Math.abs(this._scale.domain()[1] - this._scale.domain()[0]); if (curSpan <= this.previousSpan + 1) { startingPoint = this.previousIndex; } + + // find lowest granularity that will fit var i = startingPoint; while (i >= 0) { if (!(this.isEnoughSpace(this._minorTickLabels, Time.minorIntervals[i]) && this.isEnoughSpace(this._majorTickLabels, Time.majorIntervals[i]))) { @@ -3364,23 +4870,28 @@ var Plottable; } this.previousIndex = Math.max(0, i - 1); this.previousSpan = curSpan; + return i; }; + Time.prototype._getTickIntervalValues = function (interval) { return this._scale.tickInterval(interval.timeUnit, interval.step); }; + Time.prototype._getTickValues = function () { var index = this.getTickLevel(); var minorTicks = this._getTickIntervalValues(Time.minorIntervals[index]); var majorTicks = this._getTickIntervalValues(Time.majorIntervals[index]); return minorTicks.concat(majorTicks); }; + Time.prototype._measureTextHeight = function (container) { var fakeTickLabel = container.append("g").classed(Plottable.Abstract.Axis.TICK_LABEL_CLASS, true); var textHeight = Plottable.Util.Text.getTextHeight(fakeTickLabel.append("text")); fakeTickLabel.remove(); return textHeight; }; + Time.prototype.renderTickLabels = function (container, interval, height) { var _this = this; container.selectAll("." + Plottable.Abstract.Axis.TICK_LABEL_CLASS).remove(); @@ -3388,6 +4899,8 @@ var Plottable; tickPos.splice(0, 0, this._scale.domain()[0]); tickPos.push(this._scale.domain()[1]); var shouldCenterText = interval.step === 1; + + // only center when the label should span the whole interval var labelPos = []; if (shouldCenterText) { tickPos.map(function (datum, index) { @@ -3396,12 +4909,15 @@ var Plottable; } labelPos.push(new Date((tickPos[index + 1].valueOf() - tickPos[index].valueOf()) / 2 + tickPos[index].valueOf())); }); - } - else { + } else { labelPos = tickPos; } - labelPos = labelPos.filter(function (d) { return _this.canFitLabelFilter(container, d, d3.time.format(interval.formatString)(d), shouldCenterText); }); - var tickLabels = container.selectAll("." + Plottable.Abstract.Axis.TICK_LABEL_CLASS).data(labelPos, function (d) { return d.valueOf(); }); + labelPos = labelPos.filter(function (d) { + return _this.canFitLabelFilter(container, d, d3.time.format(interval.formatString)(d), shouldCenterText); + }); + var tickLabels = container.selectAll("." + Plottable.Abstract.Axis.TICK_LABEL_CLASS).data(labelPos, function (d) { + return d.valueOf(); + }); var tickLabelsEnter = tickLabels.enter().append("g").classed(Plottable.Abstract.Axis.TICK_LABEL_CLASS, true); tickLabelsEnter.append("text"); var xTranslate = shouldCenterText ? 0 : this.tickLabelPadding(); @@ -3411,10 +4927,15 @@ var Plottable; Plottable.Util.DOM.translate(textSelection, xTranslate, yTranslate); } tickLabels.exit().remove(); - tickLabels.attr("transform", function (d) { return "translate(" + _this._scale.scale(d) + ",0)"; }); + tickLabels.attr("transform", function (d) { + return "translate(" + _this._scale.scale(d) + ",0)"; + }); var anchor = shouldCenterText ? "middle" : "start"; - tickLabels.selectAll("text").text(function (d) { return d3.time.format(interval.formatString)(d); }).style("text-anchor", anchor); + tickLabels.selectAll("text").text(function (d) { + return d3.time.format(interval.formatString)(d); + }).style("text-anchor", anchor); }; + Time.prototype.canFitLabelFilter = function (container, position, label, isCentered) { var endPosition; var startPosition; @@ -3422,33 +4943,42 @@ var Plottable; if (isCentered) { endPosition = this._scale.scale(position) + width / 2; startPosition = this._scale.scale(position) - width / 2; - } - else { + } else { endPosition = this._scale.scale(position) + width; startPosition = this._scale.scale(position); } + return endPosition < this.availableWidth && startPosition > 0; }; + Time.prototype.adjustTickLength = function (height, interval) { var tickValues = this._getTickIntervalValues(interval); - var selection = this._tickMarkContainer.selectAll("." + Plottable.Abstract.Axis.TICK_MARK_CLASS).filter(function (d) { return tickValues.map(function (x) { return x.valueOf(); }).indexOf(d.valueOf()) >= 0; }); + var selection = this._tickMarkContainer.selectAll("." + Plottable.Abstract.Axis.TICK_MARK_CLASS).filter(function (d) { + return tickValues.map(function (x) { + return x.valueOf(); + }).indexOf(d.valueOf()) >= 0; + }); if (this._orientation === "top") { height = this.availableHeight - height; } selection.attr("y2", height); }; + Time.prototype.generateLabellessTicks = function (index) { if (index < 0) { return; } + var smallTicks = this._getTickIntervalValues(Time.minorIntervals[index]); var allTicks = this._getTickValues().concat(smallTicks); + var tickMarks = this._tickMarkContainer.selectAll("." + Plottable.Abstract.Axis.TICK_MARK_CLASS).data(allTicks); tickMarks.enter().append("line").classed(Plottable.Abstract.Axis.TICK_MARK_CLASS, true); tickMarks.attr(this._generateTickMarkAttrHash()); tickMarks.exit().remove(); this.adjustTickLength(this.tickLabelPadding(), Time.minorIntervals[index]); }; + Time.prototype._doRender = function () { _super.prototype._doRender.call(this); var index = this.getTickLevel(); @@ -3459,7 +4989,11 @@ var Plottable; if (this.getIntervalLength(Time.minorIntervals[index]) * 1.5 >= totalLength) { this.generateLabellessTicks(index - 1); } + + // make minor ticks shorter this.adjustTickLength(this._maxLabelTickLength() / 2, Time.minorIntervals[index]); + + // however, we need to make major ticks longer, since they may have overlapped with some minor ticks this.adjustTickLength(this._maxLabelTickLength(), Time.majorIntervals[index]); }; Time.minorIntervals = [ @@ -3493,6 +5027,7 @@ var Plottable; { timeUnit: d3.time.year, step: 500, formatString: "%Y" }, { timeUnit: d3.time.year, step: 1000, formatString: "%Y" } ]; + Time.majorIntervals = [ { timeUnit: d3.time.day, step: 1, formatString: "%B %e, %Y" }, { timeUnit: d3.time.day, step: 1, formatString: "%B %e, %Y" }, @@ -3531,6 +5066,7 @@ var Plottable; var Axis = Plottable.Axis; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -3542,10 +5078,20 @@ var Plottable; (function (Axis) { var Numeric = (function (_super) { __extends(Numeric, _super); + /** + * Creates a NumericAxis. + * + * @constructor + * @param {QuantitativeScale} scale The QuantitativeScale to base the NumericAxis on. + * @param {string} orientation The orientation of the QuantitativeScale (top/bottom/left/right) + * @param {Formatter} [formatter] A function to format tick labels (default Formatters.general(3, false)). + */ function Numeric(scale, orientation, formatter) { - if (formatter === void 0) { formatter = Plottable.Formatters.general(3, false); } + if (typeof formatter === "undefined") { formatter = Plottable.Formatters.general(3, false); } _super.call(this, scale, orientation, formatter); this.tickLabelPositioning = "center"; + // Whether or not first/last tick label will still be displayed even if + // the label is cut off. this.showFirstTickLabel = false; this.showLastTickLabel = false; } @@ -3553,48 +5099,62 @@ var Plottable; var _this = this; var tickValues = this._getTickValues(); var testTextEl = this._tickLabelContainer.append("text").classed(Plottable.Abstract.Axis.TICK_LABEL_CLASS, true); + + // create a new text measurerer every time; see issue #643 var measurer = Plottable.Util.Text.getTextMeasure(testTextEl); var textLengths = tickValues.map(function (v) { var formattedValue = _this._formatter(v); return measurer(formattedValue).width; }); testTextEl.remove(); + var maxTextLength = d3.max(textLengths); + if (this.tickLabelPositioning === "center") { this._computedWidth = this._maxLabelTickLength() + this.tickLabelPadding() + maxTextLength; - } - else { + } else { this._computedWidth = Math.max(this._maxLabelTickLength(), this.tickLabelPadding() + maxTextLength); } + return this._computedWidth; }; + Numeric.prototype._computeHeight = function () { var testTextEl = this._tickLabelContainer.append("text").classed(Plottable.Abstract.Axis.TICK_LABEL_CLASS, true); + + // create a new text measurerer every time; see issue #643 var measurer = Plottable.Util.Text.getTextMeasure(testTextEl); var textHeight = measurer("test").height; testTextEl.remove(); + if (this.tickLabelPositioning === "center") { this._computedHeight = this._maxLabelTickLength() + this.tickLabelPadding() + textHeight; - } - else { + } else { this._computedHeight = Math.max(this._maxLabelTickLength(), this.tickLabelPadding() + textHeight); } + return this._computedHeight; }; + Numeric.prototype._getTickValues = function () { return this._scale.ticks(); }; + Numeric.prototype._doRender = function () { _super.prototype._doRender.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; @@ -3615,8 +5175,7 @@ var Plottable; labelGroupShiftY = tickLabelPadding; break; } - } - else { + } else { switch (this.tickLabelPositioning) { case "top": tickLabelAttrHash["dy"] = "-0.3em"; @@ -3633,6 +5192,7 @@ var Plottable; break; } } + var tickMarkAttrHash = this._generateTickMarkAttrHash(); switch (this._orientation) { case "bottom": @@ -3640,46 +5200,53 @@ var Plottable; 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.Abstract.Axis.TICK_LABEL_CLASS).data(tickLabelValues); tickLabels.enter().append("text").classed(Plottable.Abstract.Axis.TICK_LABEL_CLASS, true); tickLabels.exit().remove(); + tickLabels.style("text-anchor", tickLabelTextAnchor).style("visibility", "visible").attr(tickLabelAttrHash).text(this._formatter); + var labelGroupTransform = "translate(" + labelGroupTransformX + ", " + labelGroupTransformY + ")"; this._tickLabelContainer.attr("transform", labelGroupTransform); + if (!this.showEndTickLabels()) { this._hideEndTickLabels(); } + this._hideOverlappingTickLabels(); }; + Numeric.prototype.tickLabelPosition = function (position) { if (position == null) { return this.tickLabelPositioning; - } - else { + } 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 { + } else { if (!(positionLC === "top" || positionLC === "center" || positionLC === "bottom")) { throw new Error(positionLC + " is not a valid tick label position for a vertical NumericAxis"); } @@ -3689,28 +5256,25 @@ var Plottable; return this; } }; + Numeric.prototype.showEndTickLabel = function (orientation, show) { if ((this._isHorizontal() && orientation === "left") || (!this._isHorizontal() && orientation === "bottom")) { if (show === undefined) { return this.showFirstTickLabel; - } - else { + } else { this.showFirstTickLabel = show; this._render(); return this; } - } - else if ((this._isHorizontal() && orientation === "right") || (!this._isHorizontal() && orientation === "top")) { + } else if ((this._isHorizontal() && orientation === "right") || (!this._isHorizontal() && orientation === "top")) { if (show === undefined) { return this.showLastTickLabel; - } - else { + } else { this.showLastTickLabel = show; this._render(); return this; } - } - else { + } else { throw new Error("Attempt to show " + orientation + " tick label on a " + (this._isHorizontal() ? "horizontal" : "vertical") + " axis"); } }; @@ -3721,6 +5285,7 @@ var Plottable; var Axis = Plottable.Axis; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -3732,35 +5297,51 @@ var Plottable; (function (Axis) { var Category = (function (_super) { __extends(Category, _super); + /** + * Creates a CategoryAxis. + * + * A CategoryAxis takes an OrdinalScale and includes word-wrapping algorithms and advanced layout logic to try to + * display the scale as efficiently as possible. + * + * @constructor + * @param {OrdinalScale} scale The scale to base the Axis on. + * @param {string} orientation The orientation of the Axis (top/bottom/left/right) + * @param {Formatter} [formatter] The Formatter for the Axis (default Formatters.identity()) + */ function Category(scale, orientation, formatter) { - if (orientation === void 0) { orientation = "bottom"; } - if (formatter === void 0) { formatter = Plottable.Formatters.identity(); } - _super.call(this, scale, orientation, formatter); + if (typeof orientation === "undefined") { orientation = "bottom"; } + if (typeof formatter === "undefined") { formatter = Plottable.Formatters.identity(); } var _this = this; + _super.call(this, scale, orientation, formatter); this.classed("category-axis", true); if (scale.rangeType() !== "bands") { throw new Error("Only rangeBands category axes are implemented"); } - this._scale.broadcaster.registerListener(this, function () { return _this._invalidateLayout(); }); + this._scale.broadcaster.registerListener(this, function () { + return _this._invalidateLayout(); + }); } Category.prototype._setup = function () { _super.prototype._setup.call(this); this.measurer = new Plottable.Util.Text.CachingCharacterMeasurer(this._tickLabelContainer); }; + Category.prototype._requestedSpace = function (offeredWidth, offeredHeight) { var widthRequiredByTicks = this._isHorizontal() ? 0 : this._maxLabelTickLength() + this.tickLabelPadding(); var heightRequiredByTicks = this._isHorizontal() ? this._maxLabelTickLength() + this.tickLabelPadding() : 0; + if (this._scale.domain().length === 0) { return { width: 0, height: 0, wantsWidth: false, wantsHeight: false }; } + var fakeScale = this._scale.copy(); if (this._isHorizontal()) { fakeScale.range([0, offeredWidth]); - } - else { + } else { fakeScale.range([offeredHeight, 0]); } var textResult = this.measureTicks(offeredWidth, offeredHeight, fakeScale, this._scale.domain()); + return { width: textResult.usedWidth + widthRequiredByTicks, height: textResult.usedHeight + heightRequiredByTicks, @@ -3768,19 +5349,29 @@ var Plottable; wantsHeight: !textResult.textFits }; }; + Category.prototype._getTickValues = function () { return this._scale.domain(); }; + Category.prototype.measureTicks = function (axisWidth, axisHeight, scale, dataOrTicks) { var draw = typeof dataOrTicks[0] !== "string"; var self = this; var textWriteResults = []; - var tm = function (s) { return self.measurer.measure(s); }; - var iterator = draw ? function (f) { return dataOrTicks.each(f); } : function (f) { return dataOrTicks.forEach(f); }; + var tm = function (s) { + return self.measurer.measure(s); + }; + var iterator = draw ? function (f) { + return dataOrTicks.each(f); + } : function (f) { + return dataOrTicks.forEach(f); + }; + iterator(function (d) { var bandWidth = scale.fullBandStartAndWidth(d)[1]; var width = self._isHorizontal() ? bandWidth : axisWidth - self._maxLabelTickLength() - self.tickLabelPadding(); var height = self._isHorizontal() ? axisHeight - self._maxLabelTickLength() - self.tickLabelPadding() : bandWidth; + var textWriteResult; var formatter = self._formatter; if (draw) { @@ -3792,24 +5383,35 @@ var Plottable; xAlign: xAlign[self._orientation], yAlign: yAlign[self._orientation] }); - } - else { + } else { textWriteResult = Plottable.Util.Text.writeText(formatter(d), width, height, tm, true); } + textWriteResults.push(textWriteResult); }); + var widthFn = this._isHorizontal() ? d3.sum : d3.max; var heightFn = this._isHorizontal() ? d3.max : d3.sum; return { - textFits: textWriteResults.every(function (t) { return t.textFits; }), - usedWidth: widthFn(textWriteResults, function (t) { return t.usedWidth; }), - usedHeight: heightFn(textWriteResults, function (t) { return t.usedHeight; }) + textFits: textWriteResults.every(function (t) { + return t.textFits; + }), + usedWidth: widthFn(textWriteResults, function (t) { + return t.usedWidth; + }), + usedHeight: heightFn(textWriteResults, function (t) { + return t.usedHeight; + }) }; }; + Category.prototype._doRender = function () { var _this = this; _super.prototype._doRender.call(this); - var tickLabels = this._tickLabelContainer.selectAll("." + Plottable.Abstract.Axis.TICK_LABEL_CLASS).data(this._scale.domain(), function (d) { return d; }); + var tickLabels = this._tickLabelContainer.selectAll("." + Plottable.Abstract.Axis.TICK_LABEL_CLASS).data(this._scale.domain(), function (d) { + return d; + }); + var getTickLabelTransform = function (d, i) { var startAndWidth = _this._scale.fullBandStartAndWidth(d); var bandStartPosition = startAndWidth[0]; @@ -3820,15 +5422,22 @@ var Plottable; tickLabels.enter().append("g").classed(Plottable.Abstract.Axis.TICK_LABEL_CLASS, true); tickLabels.exit().remove(); tickLabels.attr("transform", getTickLabelTransform); + + // erase all text first, then rewrite tickLabels.text(""); this.measureTicks(this.availableWidth, this.availableHeight, this._scale, tickLabels); var translate = this._isHorizontal() ? [this._scale.rangeBand() / 2, 0] : [0, this._scale.rangeBand() / 2]; + var xTranslate = this._orientation === "right" ? this._maxLabelTickLength() + this.tickLabelPadding() : 0; var yTranslate = this._orientation === "bottom" ? this._maxLabelTickLength() + this.tickLabelPadding() : 0; Plottable.Util.DOM.translate(this._tickLabelContainer, xTranslate, yTranslate); Plottable.Util.DOM.translate(this._tickMarkContainer, translate[0], translate[1]); }; + Category.prototype._computeLayout = function (xOrigin, yOrigin, availableWidth, availableHeight) { + // When anyone calls _invalidateLayout, _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.clear(); return _super.prototype._computeLayout.call(this, xOrigin, yOrigin, availableWidth, availableHeight); }; @@ -3839,6 +5448,7 @@ var Plottable; var Axis = Plottable.Axis; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -3850,9 +5460,16 @@ var Plottable; (function (Component) { var Label = (function (_super) { __extends(Label, _super); + /** + * Creates a Label. + * + * @constructor + * @param {string} [displayText] The text of the Label. + * @param {string} [orientation] The orientation of the Label (horizontal/vertical-left/vertical-right). + */ function Label(displayText, orientation) { - if (displayText === void 0) { displayText = ""; } - if (orientation === void 0) { orientation = "horizontal"; } + if (typeof displayText === "undefined") { displayText = ""; } + if (typeof orientation === "undefined") { orientation = "horizontal"; } _super.call(this); this.classed("label", true); this.text(displayText); @@ -3865,8 +5482,7 @@ var Plottable; } if (orientation === "horizontal" || orientation === "left" || orientation === "right") { this.orientation = orientation; - } - else { + } else { throw new Error(orientation + " is not a valid orientation for LabelComponent"); } this.xAlign("center").yAlign("center"); @@ -3885,10 +5501,12 @@ var Plottable; this.yAlignment = alignmentLC; return this; }; + Label.prototype._requestedSpace = function (offeredWidth, offeredHeight) { var desiredWH = this.measurer(this._text); var desiredWidth = (this.orientation === "horizontal" ? desiredWH.width : desiredWH.height); var desiredHeight = (this.orientation === "horizontal" ? desiredWH.height : desiredWH.width); + return { width: desiredWidth, height: desiredHeight, @@ -3896,22 +5514,24 @@ var Plottable; wantsHeight: desiredHeight > offeredHeight }; }; + Label.prototype._setup = function () { _super.prototype._setup.call(this); this.textContainer = this.content.append("g"); this.measurer = Plottable.Util.Text.getTextMeasure(this.textContainer); this.text(this._text); }; + Label.prototype.text = function (displayText) { if (displayText === undefined) { return this._text; - } - else { + } else { this._text = displayText; this._invalidateLayout(); return this; } }; + Label.prototype._doRender = function () { _super.prototype._doRender.call(this); this.textContainer.text(""); @@ -3919,19 +5539,20 @@ var Plottable; var truncatedText = Plottable.Util.Text.getTruncatedText(this._text, dimension, this.measurer); if (this.orientation === "horizontal") { Plottable.Util.Text.writeLineHorizontally(truncatedText, this.textContainer, this.availableWidth, this.availableHeight, this.xAlignment, this.yAlignment); - } - else { + } else { Plottable.Util.Text.writeLineVertically(truncatedText, this.textContainer, this.availableWidth, this.availableHeight, this.xAlignment, this.yAlignment, this.orientation); } }; + Label.prototype._computeLayout = function (xOffset, yOffset, availableWidth, availableHeight) { _super.prototype._computeLayout.call(this, xOffset, yOffset, availableWidth, availableHeight); - this.measurer = Plottable.Util.Text.getTextMeasure(this.textContainer); + this.measurer = Plottable.Util.Text.getTextMeasure(this.textContainer); // reset it in case fonts have changed return this; }; return Label; })(Plottable.Abstract.Component); Component.Label = Label; + var TitleLabel = (function (_super) { __extends(TitleLabel, _super); function TitleLabel(text, orientation) { @@ -3941,6 +5562,7 @@ var Plottable; return TitleLabel; })(Label); Component.TitleLabel = TitleLabel; + var AxisLabel = (function (_super) { __extends(AxisLabel, _super); function AxisLabel(text, orientation) { @@ -3954,6 +5576,7 @@ var Plottable; var Component = Plottable.Component; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -3965,6 +5588,17 @@ var Plottable; (function (Component) { var Legend = (function (_super) { __extends(Legend, _super); + /** + * Creates a Legend. + * + * A legend consists of a series of legend rows, each with a color and label taken from the `colorScale`. + * The rows will be displayed in the order of the `colorScale` domain. + * This legend also allows interactions, through the functions `toggleCallback` and `hoverCallback` + * Setting a callback will also put classes on the individual rows. + * + * @constructor + * @param {Scale.Color} colorScale + */ function Legend(colorScale) { _super.call(this); this.classed("legend", true); @@ -3980,6 +5614,7 @@ var Plottable; this.colorScale.broadcaster.deregisterListener(this); } }; + Legend.prototype.toggleCallback = function (callback) { if (callback !== undefined) { this._toggleCallback = callback; @@ -3987,11 +5622,11 @@ var Plottable; this.updateListeners(); this.updateClasses(); return this; - } - else { + } else { return this._toggleCallback; } }; + Legend.prototype.hoverCallback = function (callback) { if (callback !== undefined) { this._hoverCallback = callback; @@ -3999,11 +5634,11 @@ var Plottable; this.updateListeners(); this.updateClasses(); return this; - } - else { + } else { return this._hoverCallback; } }; + Legend.prototype.scale = function (scale) { var _this = this; if (scale != null) { @@ -4011,14 +5646,16 @@ var Plottable; this.colorScale.broadcaster.deregisterListener(this); } this.colorScale = scale; - this.colorScale.broadcaster.registerListener(this, function () { return _this.updateDomain(); }); + this.colorScale.broadcaster.registerListener(this, function () { + return _this.updateDomain(); + }); this.updateDomain(); return this; - } - else { + } else { return this.colorScale; } }; + Legend.prototype.updateDomain = function () { if (this._toggleCallback != null) { this.isOff = Plottable.Util.Methods.intersection(this.isOff, d3.set(this.scale().domain())); @@ -4028,19 +5665,23 @@ var Plottable; } this._invalidateLayout(); }; + Legend.prototype._computeLayout = function (xOrigin, yOrigin, availableWidth, availableHeight) { _super.prototype._computeLayout.call(this, xOrigin, yOrigin, availableWidth, availableHeight); var textHeight = this.measureTextHeight(); var totalNumRows = this.colorScale.domain().length; this.nRowsDrawn = Math.min(totalNumRows, Math.floor(this.availableHeight / textHeight)); }; + Legend.prototype._requestedSpace = function (offeredWidth, offeredHeight) { var textHeight = this.measureTextHeight(); var totalNumRows = this.colorScale.domain().length; var rowsICanFit = Math.min(totalNumRows, Math.floor((offeredHeight - 2 * Legend.MARGIN) / textHeight)); var fakeLegendEl = this.content.append("g").classed(Legend.SUBELEMENT_CLASS, true); var fakeText = fakeLegendEl.append("text"); - var maxWidth = d3.max(this.colorScale.domain(), function (d) { return Plottable.Util.Text.getTextWidth(fakeText, d); }); + var maxWidth = d3.max(this.colorScale.domain(), function (d) { + return Plottable.Util.Text.getTextWidth(fakeText, d); + }); fakeLegendEl.remove(); maxWidth = maxWidth === undefined ? 0 : maxWidth; var desiredWidth = rowsICanFit === 0 ? 0 : maxWidth + textHeight + 2 * Legend.MARGIN; @@ -4052,26 +5693,36 @@ var Plottable; wantsHeight: offeredHeight < desiredHeight }; }; + Legend.prototype.measureTextHeight = function () { + // note: can't be called before anchoring atm var fakeLegendEl = this.content.append("g").classed(Legend.SUBELEMENT_CLASS, true); var textHeight = Plottable.Util.Text.getTextHeight(fakeLegendEl.append("text")); + + // HACKHACK if (textHeight === 0) { textHeight = 1; } fakeLegendEl.remove(); return textHeight; }; + Legend.prototype._doRender = function () { _super.prototype._doRender.call(this); var domain = this.colorScale.domain().slice(0, this.nRowsDrawn); var textHeight = this.measureTextHeight(); var availableWidth = this.availableWidth - textHeight - Legend.MARGIN; var r = textHeight * 0.3; - var legend = this.content.selectAll("." + Legend.SUBELEMENT_CLASS).data(domain, function (d) { return d; }); + var legend = this.content.selectAll("." + Legend.SUBELEMENT_CLASS).data(domain, function (d) { + return d; + }); var legendEnter = legend.enter().append("g").classed(Legend.SUBELEMENT_CLASS, true); + legendEnter.append("circle"); legendEnter.append("g").classed("text-container", true); + legend.exit().remove(); + legend.selectAll("circle").attr("cx", textHeight / 2).attr("cy", textHeight / 2).attr("r", r).attr("fill", this.colorScale._d3Scale); legend.selectAll("g.text-container").text("").attr("transform", "translate(" + textHeight + ", 0)").each(function (d) { var d3this = d3.select(this); @@ -4080,12 +5731,15 @@ var Plottable; var writeLineMeasure = measure(writeLine); Plottable.Util.Text.writeLineHorizontally(writeLine, d3this, writeLineMeasure.width, writeLineMeasure.height); }); + legend.attr("transform", function (d) { return "translate(" + Legend.MARGIN + "," + (domain.indexOf(d) * textHeight + Legend.MARGIN) + ")"; }); + this.updateClasses(); this.updateListeners(); }; + Legend.prototype.updateListeners = function () { var _this = this; if (!this._isSetup) { @@ -4093,35 +5747,40 @@ var Plottable; } var dataSelection = this.content.selectAll("." + Legend.SUBELEMENT_CLASS); if (this._hoverCallback != null) { - var hoverRow = function (mouseover) { return function (datum) { - _this.datumCurrentlyFocusedOn = mouseover ? datum : undefined; - _this._hoverCallback(_this.datumCurrentlyFocusedOn); - _this.updateClasses(); - }; }; + // tag the element that is being hovered over with the class "focus" + // this callback will trigger with the specific element being hovered over. + var hoverRow = function (mouseover) { + return function (datum) { + _this.datumCurrentlyFocusedOn = mouseover ? datum : undefined; + _this._hoverCallback(_this.datumCurrentlyFocusedOn); + _this.updateClasses(); + }; + }; dataSelection.on("mouseover", hoverRow(true)); dataSelection.on("mouseout", hoverRow(false)); - } - else { + } else { + // remove all mouseover/mouseout listeners dataSelection.on("mouseover", null); dataSelection.on("mouseout", null); } + if (this._toggleCallback != null) { dataSelection.on("click", function (datum) { var turningOn = _this.isOff.has(datum); if (turningOn) { _this.isOff.remove(datum); - } - else { + } else { _this.isOff.add(datum); } _this._toggleCallback(datum, turningOn); _this.updateClasses(); }); - } - else { + } else { + // remove all click listeners dataSelection.on("click", null); } }; + Legend.prototype.updateClasses = function () { var _this = this; if (!this._isSetup) { @@ -4129,18 +5788,22 @@ var Plottable; } var dataSelection = this.content.selectAll("." + Legend.SUBELEMENT_CLASS); if (this._hoverCallback != null) { - dataSelection.classed("focus", function (d) { return _this.datumCurrentlyFocusedOn === d; }); + dataSelection.classed("focus", function (d) { + return _this.datumCurrentlyFocusedOn === d; + }); dataSelection.classed("hover", this.datumCurrentlyFocusedOn !== undefined); - } - else { + } else { dataSelection.classed("hover", false); dataSelection.classed("focus", false); } if (this._toggleCallback != null) { - dataSelection.classed("toggled-on", function (d) { return !_this.isOff.has(d); }); - dataSelection.classed("toggled-off", function (d) { return _this.isOff.has(d); }); - } - else { + dataSelection.classed("toggled-on", function (d) { + return !_this.isOff.has(d); + }); + dataSelection.classed("toggled-off", function (d) { + return _this.isOff.has(d); + }); + } else { dataSelection.classed("toggled-on", false); dataSelection.classed("toggled-off", false); } @@ -4154,6 +5817,7 @@ var Plottable; var Component = Plottable.Component; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -4165,9 +5829,16 @@ var Plottable; (function (Component) { var Gridlines = (function (_super) { __extends(Gridlines, _super); + /** + * Creates a set of Gridlines. + * @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) { - _super.call(this); var _this = this; + _super.call(this); if (xScale == null && yScale == null) { throw new Error("Gridlines must have at least one scale"); } @@ -4175,10 +5846,14 @@ var Plottable; this.xScale = xScale; this.yScale = yScale; if (this.xScale != null) { - this.xScale.broadcaster.registerListener(this, function () { return _this._render(); }); + this.xScale.broadcaster.registerListener(this, function () { + return _this._render(); + }); } if (this.yScale != null) { - this.yScale.broadcaster.registerListener(this, function () { return _this._render(); }); + this.yScale.broadcaster.registerListener(this, function () { + return _this._render(); + }); } } Gridlines.prototype.remove = function () { @@ -4191,35 +5866,47 @@ var Plottable; } 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._doRender = function () { _super.prototype._doRender.call(this); this.redrawXLines(); this.redrawYLines(); }; + Gridlines.prototype.redrawXLines = function () { var _this = this; if (this.xScale != null) { var xTicks = this.xScale.ticks(); - var getScaledXValue = function (tickVal) { return _this.xScale.scale(tickVal); }; + 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.availableHeight).classed("zeroline", function (t) { return t === 0; }); + xLines.attr("x1", getScaledXValue).attr("y1", 0).attr("x2", getScaledXValue).attr("y2", this.availableHeight).classed("zeroline", function (t) { + return t === 0; + }); xLines.exit().remove(); } }; + Gridlines.prototype.redrawYLines = function () { var _this = this; if (this.yScale != null) { var yTicks = this.yScale.ticks(); - var getScaledYValue = function (tickVal) { return _this.yScale.scale(tickVal); }; + 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.availableWidth).attr("y2", getScaledYValue).classed("zeroline", function (t) { return t === 0; }); + yLines.attr("x1", 0).attr("y1", getScaledYValue).attr("x2", this.availableWidth).attr("y2", getScaledYValue).classed("zeroline", function (t) { + return t === 0; + }); yLines.exit().remove(); } }; @@ -4230,6 +5917,7 @@ var Plottable; var Component = Plottable.Component; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -4241,32 +5929,48 @@ var Plottable; (function (Abstract) { var XYPlot = (function (_super) { __extends(XYPlot, _super); + /** + * Creates an XYPlot. + * + * @constructor + * @param {any[]|DataSource} [dataset] The data or DataSource to be associated with this Renderer. + * @param {Scale} xScale The x scale to use. + * @param {Scale} yScale The y scale to use. + */ function XYPlot(dataset, xScale, yScale) { _super.call(this, dataset); if (xScale == null || yScale == null) { throw new Error("XYPlots require an xScale and yScale"); } this.classed("xy-plot", true); - this.project("x", "x", xScale); - this.project("y", "y", yScale); + + this.project("x", "x", xScale); // default accessor + this.project("y", "y", yScale); // default accessor } XYPlot.prototype.project = function (attrToSet, accessor, scale) { + // We only want padding and nice-ing on scales that will correspond to axes / pixel layout. + // So when we get an "x" or "y" scale, enable autoNiceing and autoPadding. if (attrToSet === "x" && scale != null) { this.xScale = scale; this._updateXDomainer(); } + if (attrToSet === "y" && scale != null) { this.yScale = scale; this._updateYDomainer(); } + _super.prototype.project.call(this, attrToSet, accessor, scale); + return this; }; + XYPlot.prototype._computeLayout = function (xOffset, yOffset, availableWidth, availableHeight) { _super.prototype._computeLayout.call(this, xOffset, yOffset, availableWidth, availableHeight); this.xScale.range([0, this.availableWidth]); this.yScale.range([this.availableHeight, 0]); }; + XYPlot.prototype._updateXDomainer = function () { if (this.xScale instanceof Abstract.QuantitativeScale) { var scale = this.xScale; @@ -4275,6 +5979,7 @@ var Plottable; } } }; + XYPlot.prototype._updateYDomainer = function () { if (this.yScale instanceof Abstract.QuantitativeScale) { var scale = this.yScale; @@ -4290,6 +5995,7 @@ var Plottable; var Abstract = Plottable.Abstract; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -4301,6 +6007,14 @@ var Plottable; (function (Plot) { var Scatter = (function (_super) { __extends(Scatter, _super); + /** + * Creates a ScatterPlot. + * + * @constructor + * @param {IDataset} dataset The dataset to render. + * @param {Scale} xScale The x scale to use. + * @param {Scale} yScale The y scale to use. + */ function Scatter(dataset, xScale, yScale) { _super.call(this, dataset, xScale, yScale); this._animators = { @@ -4308,9 +6022,11 @@ var Plottable; "circles": new Plottable.Animator.IterativeDelay().duration(250).delay(5) }; this.classed("scatter-plot", true); - this.project("r", 3); - this.project("opacity", 0.6); - this.project("fill", function () { return Plottable.Core.Colors.INDIGO; }); + this.project("r", 3); // default + this.project("opacity", 0.6); // default + this.project("fill", function () { + return Plottable.Core.Colors.INDIGO; + }); // default } Scatter.prototype.project = function (attrToSet, accessor, scale) { attrToSet = attrToSet === "cx" ? "x" : attrToSet; @@ -4318,21 +6034,28 @@ var Plottable; _super.prototype.project.call(this, attrToSet, accessor, scale); return this; }; + Scatter.prototype._paint = function () { _super.prototype._paint.call(this); + var attrToProjector = this._generateAttrToProjector(); attrToProjector["cx"] = attrToProjector["x"]; attrToProjector["cy"] = attrToProjector["y"]; delete attrToProjector["x"]; delete attrToProjector["y"]; + var circles = this.renderArea.selectAll("circle").data(this._dataSource.data()); circles.enter().append("circle"); + if (this._dataChanged) { var rFunction = attrToProjector["r"]; - attrToProjector["r"] = function () { return 0; }; + attrToProjector["r"] = function () { + return 0; + }; this._applyAnimatedAttributes(circles, "circles-reset", attrToProjector); attrToProjector["r"] = rFunction; } + this._applyAnimatedAttributes(circles, "circles", attrToProjector); circles.exit().remove(); }; @@ -4343,6 +6066,7 @@ var Plottable; var Plot = Plottable.Plot; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -4354,16 +6078,29 @@ var Plottable; (function (Plot) { var Grid = (function (_super) { __extends(Grid, _super); + /** + * Creates a GridPlot. + * + * @constructor + * @param {IDataset} dataset The dataset to render. + * @param {OrdinalScale} xScale The x scale to use. + * @param {OrdinalScale} yScale The y scale to use. + * @param {ColorScale|InterpolatedColorScale} colorScale The color scale to use for each grid + * cell. + */ function Grid(dataset, xScale, yScale, colorScale) { _super.call(this, dataset, xScale, yScale); this._animators = { "cells": new Plottable.Animator.Null() }; this.classed("grid-plot", true); + + // The x and y scales should render in bands with no padding this.xScale.rangeType("bands", 0, 0); this.yScale.rangeType("bands", 0, 0); + this.colorScale = colorScale; - this.project("fill", "value", colorScale); + this.project("fill", "value", colorScale); // default } Grid.prototype.project = function (attrToSet, accessor, scale) { _super.prototype.project.call(this, attrToSet, accessor, scale); @@ -4372,15 +6109,24 @@ var Plottable; } return this; }; + Grid.prototype._paint = function () { _super.prototype._paint.call(this); + var cells = this.renderArea.selectAll("rect").data(this._dataSource.data()); cells.enter().append("rect"); + var xStep = this.xScale.rangeBand(); var yStep = this.yScale.rangeBand(); + var attrToProjector = this._generateAttrToProjector(); - attrToProjector["width"] = function () { return xStep; }; - attrToProjector["height"] = function () { return yStep; }; + attrToProjector["width"] = function () { + return xStep; + }; + attrToProjector["height"] = function () { + return yStep; + }; + this._applyAnimatedAttributes(cells, "cells", attrToProjector); cells.exit().remove(); }; @@ -4391,6 +6137,7 @@ var Plottable; var Plot = Plottable.Plot; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -4400,8 +6147,20 @@ var __extends = this.__extends || function (d, b) { var Plottable; (function (Plottable) { (function (Abstract) { + /* + * An Abstract.BarPlot is the base implementation for HorizontalBarPlot and + * VerticalBarPlot. It should not be used on its own. + */ var BarPlot = (function (_super) { __extends(BarPlot, _super); + /** + * Creates an AbstractBarPlot. + * + * @constructor + * @param {IDataset} dataset The dataset to render. + * @param {Scale} xScale The x scale to use. + * @param {Scale} yScale The y scale to use. + */ function BarPlot(dataset, xScale, yScale) { _super.call(this, dataset, xScale, yScale); this._baselineValue = 0; @@ -4412,7 +6171,13 @@ var Plottable; "baseline": new Plottable.Animator.Null() }; this.classed("bar-plot", true); - this.project("fill", function () { return Plottable.Core.Colors.INDIGO; }); + this.project("fill", function () { + return Plottable.Core.Colors.INDIGO; + }); + + // because this._baselineValue was not initialized during the super() + // call, we must call this in order to get this._baselineValue + // to be used by the Domainer. this.baseline(this._baselineValue); } BarPlot.prototype._setup = function () { @@ -4420,34 +6185,52 @@ var Plottable; this._baseline = this.renderArea.append("line").classed("baseline", true); this._bars = this.renderArea.selectAll("rect").data([]); }; + BarPlot.prototype._paint = function () { _super.prototype._paint.call(this); this._bars = this.renderArea.selectAll("rect").data(this._dataSource.data()); this._bars.enter().append("rect"); + var primaryScale = this._isVertical ? this.yScale : this.xScale; var scaledBaseline = primaryScale.scale(this._baselineValue); var positionAttr = this._isVertical ? "y" : "x"; var dimensionAttr = this._isVertical ? "height" : "width"; + if (this._dataChanged && this._animate) { var resetAttrToProjector = this._generateAttrToProjector(); - resetAttrToProjector[positionAttr] = function () { return scaledBaseline; }; - resetAttrToProjector[dimensionAttr] = function () { return 0; }; + resetAttrToProjector[positionAttr] = function () { + return scaledBaseline; + }; + resetAttrToProjector[dimensionAttr] = function () { + return 0; + }; this._applyAnimatedAttributes(this._bars, "bars-reset", resetAttrToProjector); } + var attrToProjector = this._generateAttrToProjector(); if (attrToProjector["fill"] != null) { - this._bars.attr("fill", attrToProjector["fill"]); + this._bars.attr("fill", attrToProjector["fill"]); // so colors don't animate } this._applyAnimatedAttributes(this._bars, "bars", attrToProjector); + this._bars.exit().remove(); + var baselineAttr = { "x1": this._isVertical ? 0 : scaledBaseline, "y1": this._isVertical ? scaledBaseline : 0, "x2": this._isVertical ? this.availableWidth : scaledBaseline, "y2": this._isVertical ? scaledBaseline : this.availableHeight }; + this._applyAnimatedAttributes(this._baseline, "baseline", baselineAttr); }; + + /** + * Sets the baseline for the bars to the specified value. + * + * @param {number} value The value to position the baseline at. + * @return {AbstractBarPlot} The calling AbstractBarPlot. + */ BarPlot.prototype.baseline = function (value) { this._baselineValue = value; this._updateXDomainer(); @@ -4455,6 +6238,15 @@ var Plottable; this._render(); return this; }; + + /** + * Sets the bar alignment relative to the independent axis. + * VerticalBarPlot supports "left", "center", "right" + * HorizontalBarPlot supports "top", "center", "bottom" + * + * @param {string} alignment The desired alignment. + * @return {AbstractBarPlot} The calling AbstractBarPlot. + */ BarPlot.prototype.barAlignment = function (alignment) { var alignmentLC = alignment.toLowerCase(); var align2factor = this.constructor._BarAlignmentToFactor; @@ -4462,67 +6254,87 @@ var Plottable; throw new Error("unsupported bar alignment"); } this._barAlignmentFactor = align2factor[alignmentLC]; + this._render(); return this; }; + BarPlot.prototype.parseExtent = function (input) { if (typeof (input) === "number") { return { min: input, max: input }; - } - else if (input instanceof Object && "min" in input && "max" in input) { + } else if (input instanceof Object && "min" in input && "max" in input) { return input; - } - else { + } else { throw new Error("input '" + input + "' can't be parsed as an IExtent"); } }; + BarPlot.prototype.selectBar = function (xValOrExtent, yValOrExtent, select) { - if (select === void 0) { select = true; } + if (typeof select === "undefined") { select = true; } if (!this._isSetup) { return null; } + var selectedBars = []; + var xExtent = this.parseExtent(xValOrExtent); var yExtent = this.parseExtent(yValOrExtent); + + // the 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: var tolerance = 0.5; + + // currently, linear scan the bars. If inversion is implemented on non-numeric scales we might be able to do better. this._bars.each(function (d) { var bbox = this.getBBox(); if (bbox.x + bbox.width >= xExtent.min - tolerance && bbox.x <= xExtent.max + tolerance && bbox.y + bbox.height >= yExtent.min - tolerance && bbox.y <= yExtent.max + tolerance) { selectedBars.push(this); } }); + if (selectedBars.length > 0) { var selection = d3.selectAll(selectedBars); selection.classed("selected", select); return selection; - } - else { + } else { return null; } }; + + /** + * Deselects all bars. + * @return {AbstractBarPlot} The calling AbstractBarPlot. + */ BarPlot.prototype.deselectAll = function () { if (this._isSetup) { this._bars.classed("selected", false); } return this; }; + BarPlot.prototype._updateDomainer = function (scale) { if (scale instanceof Abstract.QuantitativeScale) { var qscale = scale; if (!qscale._userSetDomainer) { if (this._baselineValue != null) { qscale.domainer().addPaddingException(this._baselineValue, "BAR_PLOT+" + this._plottableID).addIncludedValue(this._baselineValue, "BAR_PLOT+" + this._plottableID); - } - else { + } else { qscale.domainer().removePaddingException("BAR_PLOT+" + this._plottableID).removeIncludedValue("BAR_PLOT+" + this._plottableID); } qscale.domainer().pad(); } + + // prepending "BAR_PLOT" is unnecessary but reduces likely of user accidentally creating collisions qscale._autoDomainIfAutomaticMode(); } }; + BarPlot.prototype._generateAttrToProjector = function () { var _this = this; + // 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.yScale : this.xScale; var secondaryScale = this._isVertical ? this.xScale : this.yScale; @@ -4532,28 +6344,42 @@ var Plottable; var scaledBaseline = primaryScale.scale(this._baselineValue); if (attrToProjector["width"] == null) { var constantWidth = bandsMode ? secondaryScale.rangeBand() : BarPlot.DEFAULT_WIDTH; - attrToProjector["width"] = function (d, i) { return constantWidth; }; + attrToProjector["width"] = function (d, i) { + return constantWidth; + }; } + var positionF = attrToProjector[secondaryAttr]; var widthF = attrToProjector["width"]; if (!bandsMode) { - attrToProjector[secondaryAttr] = function (d, i) { return positionF(d, i) - widthF(d, i) * _this._barAlignmentFactor; }; - } - else { + attrToProjector[secondaryAttr] = function (d, i) { + return positionF(d, i) - widthF(d, i) * _this._barAlignmentFactor; + }; + } else { var bandWidth = secondaryScale.rangeBand(); - attrToProjector[secondaryAttr] = function (d, i) { return positionF(d, i) - widthF(d, i) / 2 + bandWidth / 2; }; + attrToProjector[secondaryAttr] = function (d, i) { + return positionF(d, i) - widthF(d, i) / 2 + bandWidth / 2; + }; } + var originalPositionFn = attrToProjector[primaryAttr]; attrToProjector[primaryAttr] = function (d, i) { var originalPos = originalPositionFn(d, i); + + // 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; }; + attrToProjector["height"] = function (d, i) { return Math.abs(scaledBaseline - originalPositionFn(d, i)); }; + return attrToProjector; }; BarPlot.DEFAULT_WIDTH = 10; + BarPlot._BarAlignmentToFactor = {}; return BarPlot; })(Abstract.XYPlot); @@ -4562,6 +6388,7 @@ var Plottable; var Abstract = Plottable.Abstract; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -4571,8 +6398,25 @@ var __extends = this.__extends || function (d, b) { var Plottable; (function (Plottable) { (function (Plot) { + /** + * A VerticalBarPlot draws bars vertically. + * Key projected attributes: + * - "width" - the horizontal width of a bar. + * - if an ordinal scale is attached, this defaults to ordinalScale.rangeBand() + * - if a quantitative scale is attached, this defaults to 10 + * - "x" - the horizontal position of a bar + * - "y" - the vertical height of a bar + */ var VerticalBar = (function (_super) { __extends(VerticalBar, _super); + /** + * Creates a VerticalBarPlot. + * + * @constructor + * @param {IDataset} dataset The dataset to render. + * @param {Scale} xScale The x scale to use. + * @param {QuantitativeScale} yScale The y scale to use. + */ function VerticalBar(dataset, xScale, yScale) { _super.call(this, dataset, xScale, yScale); this._isVertical = true; @@ -4588,6 +6432,7 @@ var Plottable; var Plot = Plottable.Plot; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -4597,8 +6442,25 @@ var __extends = this.__extends || function (d, b) { var Plottable; (function (Plottable) { (function (Plot) { + /** + * A HorizontalBarPlot draws bars horizontally. + * Key projected attributes: + * - "width" - the vertical height of a bar (since the bar is rotated horizontally) + * - if an ordinal scale is attached, this defaults to ordinalScale.rangeBand() + * - if a quantitative scale is attached, this defaults to 10 + * - "x" - the horizontal length of a bar + * - "y" - the vertical position of a bar + */ var HorizontalBar = (function (_super) { __extends(HorizontalBar, _super); + /** + * Creates a HorizontalBarPlot. + * + * @constructor + * @param {IDataset} dataset The dataset to render. + * @param {QuantitativeScale} xScale The x scale to use. + * @param {Scale} yScale The y scale to use. + */ function HorizontalBar(dataset, xScale, yScale) { _super.call(this, dataset, xScale, yScale); this.isVertical = false; @@ -4606,8 +6468,12 @@ var Plottable; HorizontalBar.prototype._updateXDomainer = function () { this._updateDomainer(this.xScale); }; + HorizontalBar.prototype._generateAttrToProjector = function () { var attrToProjector = _super.prototype._generateAttrToProjector.call(this); + + // by convention, for API users the 2ndary dimension of a bar is always called its "width", so + // the "width" of a horziontal bar plot is actually its "height" from the perspective of a svg rect var widthF = attrToProjector["width"]; attrToProjector["width"] = attrToProjector["height"]; attrToProjector["height"] = widthF; @@ -4621,6 +6487,7 @@ var Plottable; var Plot = Plottable.Plot; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -4632,6 +6499,14 @@ var Plottable; (function (Plot) { var Line = (function (_super) { __extends(Line, _super); + /** + * Creates a LinePlot. + * + * @constructor + * @param {IDataset} dataset The dataset to render. + * @param {Scale} xScale The x scale to use. + * @param {Scale} yScale The y scale to use. + */ function Line(dataset, xScale, yScale) { _super.call(this, dataset, xScale, yScale); this._animators = { @@ -4639,27 +6514,38 @@ var Plottable; "line": new Plottable.Animator.Default().duration(600).easing("exp-in-out") }; this.classed("line-plot", true); - this.project("stroke", function () { return Plottable.Core.Colors.INDIGO; }); - this.project("stroke-width", function () { return "2px"; }); + this.project("stroke", function () { + return Plottable.Core.Colors.INDIGO; + }); // default + this.project("stroke-width", function () { + return "2px"; + }); // default } Line.prototype._setup = function () { _super.prototype._setup.call(this); this.linePath = this.renderArea.append("path").classed("line", true); }; + Line.prototype._getResetYFunction = function () { + // gets the y-value generator for the animation start point var yDomain = this.yScale.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 = 0; if (domainMax < 0) { startValue = domainMax; - } - else if (domainMin > 0) { + } else if (domainMin > 0) { startValue = domainMin; } var scaledStartValue = this.yScale.scale(startValue); - return function (d, i) { return scaledStartValue; }; + return function (d, i) { + return scaledStartValue; + }; }; + Line.prototype._generateAttrToProjector = function () { var attrToProjector = _super.prototype._generateAttrToProjector.call(this); var wholeDatumAttributes = this._wholeDatumAttributes(); @@ -4672,14 +6558,14 @@ var Plottable; attrToProjector[attribute] = function (data, i) { if (data.length > 0) { return projector(data[0], i); - } - else { + } else { return null; } }; }); return attrToProjector; }; + Line.prototype._paint = function () { _super.prototype._paint.call(this); var attrToProjector = this._generateAttrToProjector(); @@ -4687,14 +6573,18 @@ var Plottable; var yFunction = attrToProjector["y"]; delete attrToProjector["x"]; delete attrToProjector["y"]; + this.linePath.datum(this._dataSource.data()); + if (this._dataChanged) { attrToProjector["d"] = d3.svg.line().x(xFunction).y(this._getResetYFunction()); this._applyAnimatedAttributes(this.linePath, "line-reset", attrToProjector); } + attrToProjector["d"] = d3.svg.line().x(xFunction).y(yFunction); this._applyAnimatedAttributes(this.linePath, "line", attrToProjector); }; + Line.prototype._wholeDatumAttributes = function () { return ["x", "y"]; }; @@ -4705,6 +6595,7 @@ var Plottable; var Plot = Plottable.Plot; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -4714,15 +6605,32 @@ var __extends = this.__extends || function (d, b) { var Plottable; (function (Plottable) { (function (Plot) { + /** + * An AreaPlot draws a filled region (area) between the plot's projected "y" and projected "y0" values. + */ var Area = (function (_super) { __extends(Area, _super); + /** + * Creates an AreaPlot. + * + * @constructor + * @param {IDataset} dataset The dataset to render. + * @param {Scale} xScale The x scale to use. + * @param {Scale} yScale The y scale to use. + */ function Area(dataset, xScale, yScale) { _super.call(this, dataset, xScale, yScale); this.classed("area-plot", true); - this.project("y0", 0, yScale); - this.project("fill", function () { return Plottable.Core.Colors.INDIGO; }); - this.project("fill-opacity", function () { return 0.25; }); - this.project("stroke", function () { return Plottable.Core.Colors.INDIGO; }); + this.project("y0", 0, yScale); // default + this.project("fill", function () { + return Plottable.Core.Colors.INDIGO; + }); // default + this.project("fill-opacity", function () { + return 0.25; + }); // default + this.project("stroke", function () { + return Plottable.Core.Colors.INDIGO; + }); // default this._animators["area-reset"] = new Plottable.Animator.Null(); this._animators["area"] = new Plottable.Animator.Default().duration(600).easing("exp-in-out"); } @@ -4730,29 +6638,35 @@ var Plottable; _super.prototype._setup.call(this); this.areaPath = this.renderArea.append("path").classed("area", true); }; + Area.prototype._onDataSourceUpdate = function () { _super.prototype._onDataSourceUpdate.call(this); if (this.yScale != null) { this._updateYDomainer(); } }; + Area.prototype._updateYDomainer = function () { _super.prototype._updateYDomainer.call(this); var scale = this.yScale; + var y0Projector = this._projectors["y0"]; var y0Accessor = y0Projector != null ? y0Projector.accessor : null; var extent = y0Accessor != null ? this.dataSource()._getExtent(y0Accessor) : []; var constantBaseline = (extent.length === 2 && extent[0] === extent[1]) ? extent[0] : null; + if (!scale._userSetDomainer) { if (constantBaseline != null) { scale.domainer().addPaddingException(constantBaseline, "AREA_PLOT+" + this._plottableID); - } - else { + } else { scale.domainer().removePaddingException("AREA_PLOT+" + this._plottableID); } + + // prepending "AREA_PLOT" is unnecessary but reduces likely of user accidentally creating collisions scale._autoDomainIfAutomaticMode(); } }; + Area.prototype.project = function (attrToSet, accessor, scale) { _super.prototype.project.call(this, attrToSet, accessor, scale); if (attrToSet === "y0") { @@ -4760,9 +6674,11 @@ var Plottable; } return this; }; + Area.prototype._getResetYFunction = function () { return this._generateAttrToProjector()["y0"]; }; + Area.prototype._paint = function () { _super.prototype._paint.call(this); var attrToProjector = this._generateAttrToProjector(); @@ -4772,14 +6688,18 @@ var Plottable; delete attrToProjector["x"]; delete attrToProjector["y0"]; delete attrToProjector["y"]; + this.areaPath.datum(this._dataSource.data()); + if (this._dataChanged) { attrToProjector["d"] = d3.svg.area().x(xFunction).y0(y0Function).y1(this._getResetYFunction()); this._applyAnimatedAttributes(this.areaPath, "area-reset", attrToProjector); } + attrToProjector["d"] = d3.svg.area().x(xFunction).y0(y0Function).y1(yFunction); this._applyAnimatedAttributes(this.areaPath, "area", attrToProjector); }; + Area.prototype._wholeDatumAttributes = function () { var wholeDatumAttributes = _super.prototype._wholeDatumAttributes.call(this); wholeDatumAttributes.push("y0"); @@ -4792,9 +6712,14 @@ var Plottable; var Plot = Plottable.Plot; })(Plottable || (Plottable = {})); +/// var Plottable; (function (Plottable) { (function (Animator) { + /** + * An animator implementation with no animation. The attributes are + * immediately set on the selection. + */ var Null = (function () { function Null() { } @@ -4808,9 +6733,13 @@ var Plottable; var Animator = Plottable.Animator; })(Plottable || (Plottable = {})); +/// var Plottable; (function (Plottable) { (function (Animator) { + /** + * The default animator implementation with easing, duration, and delay. + */ var Default = (function () { function Default() { this._durationMsec = 300; @@ -4820,29 +6749,29 @@ var Plottable; Default.prototype.animate = function (selection, attrToProjector, plot) { return selection.transition().ease(this._easing).duration(this._durationMsec).delay(this._delayMsec).attr(attrToProjector); }; + Default.prototype.duration = function (duration) { if (duration === undefined) { return this._durationMsec; - } - else { + } else { this._durationMsec = duration; return this; } }; + Default.prototype.delay = function (delay) { if (delay === undefined) { return this._delayMsec; - } - else { + } else { this._delayMsec = delay; return this; } }; + Default.prototype.easing = function (easing) { if (easing === undefined) { return this._easing; - } - else { + } else { this._easing = easing; return this; } @@ -4854,6 +6783,7 @@ var Plottable; var Animator = Plottable.Animator; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -4863,6 +6793,12 @@ var __extends = this.__extends || function (d, b) { var Plottable; (function (Plottable) { (function (Animator) { + /** + * An animator that delays the animation of the attributes using the index + * of the selection data. + * + * The delay between animations can be configured with the .delay getter/setter. + */ var IterativeDelay = (function (_super) { __extends(IterativeDelay, _super); function IterativeDelay() { @@ -4871,7 +6807,9 @@ var Plottable; } IterativeDelay.prototype.animate = function (selection, attrToProjector, plot) { var _this = this; - return selection.transition().ease(this._easing).duration(this._durationMsec).delay(function (d, i) { return i * _this._delayMsec; }).attr(attrToProjector); + return selection.transition().ease(this._easing).duration(this._durationMsec).delay(function (d, i) { + return i * _this._delayMsec; + }).attr(attrToProjector); }; return IterativeDelay; })(Animator.Default); @@ -4880,12 +6818,14 @@ var Plottable; var Animator = Plottable.Animator; })(Plottable || (Plottable = {})); +/// var Plottable; (function (Plottable) { (function (Core) { (function (KeyEventListener) { var _initialized = false; var _callbacks = []; + function initialize() { if (_initialized) { return; @@ -4894,20 +6834,25 @@ var Plottable; _initialized = true; } KeyEventListener.initialize = initialize; + function addCallback(keyCode, cb) { if (!_initialized) { initialize(); } + if (_callbacks[keyCode] == null) { _callbacks[keyCode] = []; } + _callbacks[keyCode].push(cb); } KeyEventListener.addCallback = addCallback; + function processEvent() { if (_callbacks[d3.event.keyCode] == null) { return; } + _callbacks[d3.event.keyCode].forEach(function (cb) { cb(d3.event); }); @@ -4918,10 +6863,17 @@ var Plottable; var Core = Plottable.Core; })(Plottable || (Plottable = {})); +/// var Plottable; (function (Plottable) { (function (Abstract) { var Interaction = (function () { + /** + * Creates an Interaction. + * + * @constructor + * @param {Component} componentToListenTo The component to listen for interactions on. + */ function Interaction(componentToListenTo) { if (componentToListenTo == null) { throw new Error("Interactions require a component to listen to"); @@ -4931,6 +6883,11 @@ var Plottable; Interaction.prototype._anchor = function (hitBox) { this.hitBox = hitBox; }; + + /** + * Registers the Interaction on the Component it's listening to. + * This needs to be called to activate the interaction. + */ Interaction.prototype.registerWithComponent = function () { this.componentToListenTo.registerInteraction(this); return this; @@ -4942,6 +6899,7 @@ var Plottable; var Abstract = Plottable.Abstract; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -4953,6 +6911,12 @@ var Plottable; (function (Interaction) { var Click = (function (_super) { __extends(Click, _super); + /** + * Creates a ClickInteraction. + * + * @constructor + * @param {Component} componentToListenTo The component to listen for clicks on. + */ function Click(componentToListenTo) { _super.call(this, componentToListenTo); } @@ -4966,9 +6930,16 @@ var Plottable; _this._callback(x, y); }); }; + Click.prototype._listenTo = function () { return "click"; }; + + /** + * Sets an callback to be called when a click is received. + * + * @param {(x: number, y: number) => any} cb: Callback to be called. Takes click x and y in pixels. + */ Click.prototype.callback = function (cb) { this._callback = cb; return this; @@ -4976,8 +6947,15 @@ var Plottable; return Click; })(Plottable.Abstract.Interaction); Interaction.Click = Click; + var DoubleClick = (function (_super) { __extends(DoubleClick, _super); + /** + * Creates a DoubleClickInteraction. + * + * @constructor + * @param {Component} componentToListenTo The component to listen for clicks on. + */ function DoubleClick(componentToListenTo) { _super.call(this, componentToListenTo); } @@ -4991,6 +6969,7 @@ var Plottable; var Interaction = Plottable.Interaction; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -5015,6 +6994,7 @@ var Plottable; _this.mousemove(x, y); }); }; + Mousemove.prototype.mousemove = function (x, y) { return; }; @@ -5025,6 +7005,7 @@ var Plottable; var Interaction = Plottable.Interaction; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -5036,6 +7017,13 @@ var Plottable; (function (Interaction) { var Key = (function (_super) { __extends(Key, _super); + /** + * Creates a KeyInteraction. + * + * @constructor + * @param {Component} componentToListenTo The component to listen for keypresses on. + * @param {number} keyCode The key code to listen for. + */ function Key(componentToListenTo, keyCode) { _super.call(this, componentToListenTo); this.activated = false; @@ -5050,12 +7038,19 @@ var Plottable; hitBox.on("mouseout", function () { _this.activated = false; }); + Plottable.Core.KeyEventListener.addCallback(this.keyCode, function (e) { if (_this.activated && _this._callback != null) { _this._callback(); } }); }; + + /** + * Sets an callback to be called when the designated key is pressed. + * + * @param {() => any} cb: Callback to be called. + */ Key.prototype.callback = function (cb) { this._callback = cb; return this; @@ -5067,6 +7062,7 @@ var Plottable; var Interaction = Plottable.Interaction; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -5078,9 +7074,17 @@ var Plottable; (function (Interaction) { var PanZoom = (function (_super) { __extends(PanZoom, _super); + /** + * Creates a PanZoomInteraction. + * + * @constructor + * @param {Component} componentToListenTo The component to listen for interactions on. + * @param {QuantitativeScale} [xScale] The X scale to update on panning/zooming. + * @param {QuantitativeScale} [yScale] The Y scale to update on panning/zooming. + */ function PanZoom(componentToListenTo, xScale, yScale) { - _super.call(this, componentToListenTo); var _this = this; + _super.call(this, componentToListenTo); if (xScale == null) { xScale = new Plottable.Scale.Linear(); } @@ -5092,21 +7096,30 @@ var Plottable; this.zoom = d3.behavior.zoom(); this.zoom.x(this.xScale._d3Scale); this.zoom.y(this.yScale._d3Scale); - this.zoom.on("zoom", function () { return _this.rerenderZoomed(); }); + this.zoom.on("zoom", function () { + return _this.rerenderZoomed(); + }); } PanZoom.prototype.resetZoom = function () { var _this = this; + // HACKHACK #254 this.zoom = d3.behavior.zoom(); this.zoom.x(this.xScale._d3Scale); this.zoom.y(this.yScale._d3Scale); - this.zoom.on("zoom", function () { return _this.rerenderZoomed(); }); + this.zoom.on("zoom", function () { + return _this.rerenderZoomed(); + }); this.zoom(this.hitBox); }; + PanZoom.prototype._anchor = function (hitBox) { _super.prototype._anchor.call(this, hitBox); this.zoom(hitBox); }; + PanZoom.prototype.rerenderZoomed = function () { + // HACKHACK since the d3.zoom.x modifies d3 scales and not our TS scales, and the TS scales have the + // event listener machinery, let's grab the domain out of the d3 scale and pipe it back into the TS scale var xDomain = this.xScale._d3Scale.domain(); var yDomain = this.yScale._d3Scale.domain(); this.xScale.domain(xDomain); @@ -5119,6 +7132,7 @@ var Plottable; var Interaction = Plottable.Interaction; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -5130,35 +7144,62 @@ var Plottable; (function (Interaction) { var Drag = (function (_super) { __extends(Drag, _super); + /** + * Creates a Drag. + * + * @param {Component} componentToListenTo The component to listen for interactions on. + */ function Drag(componentToListenTo) { - _super.call(this, componentToListenTo); var _this = this; + _super.call(this, componentToListenTo); this.dragInitialized = false; this.origin = [0, 0]; this.location = [0, 0]; this.dragBehavior = d3.behavior.drag(); - this.dragBehavior.on("dragstart", function () { return _this._dragstart(); }); - this.dragBehavior.on("drag", function () { return _this._drag(); }); - this.dragBehavior.on("dragend", function () { return _this._dragend(); }); + this.dragBehavior.on("dragstart", function () { + return _this._dragstart(); + }); + this.dragBehavior.on("drag", function () { + return _this._drag(); + }); + this.dragBehavior.on("dragend", function () { + return _this._dragend(); + }); } + /** + * Adds a callback to be called when the AreaInteraction triggers. + * + * @param {(a: SelectionArea) => any} cb The function to be called. Takes in a SelectionArea in pixels. + * @returns {AreaInteraction} The calling AreaInteraction. + */ Drag.prototype.callback = function (cb) { this.callbackToCall = cb; return this; }; + Drag.prototype._dragstart = function () { var availableWidth = this.componentToListenTo.availableWidth; var availableHeight = this.componentToListenTo.availableHeight; - var constraintFunction = function (min, max) { return function (x) { return Math.min(Math.max(x, min), max); }; }; + + // the constraint functions ensure that the selection rectangle will not exceed the hit box + var constraintFunction = function (min, max) { + return function (x) { + return Math.min(Math.max(x, min), max); + }; + }; this.constrainX = constraintFunction(0, availableWidth); this.constrainY = constraintFunction(0, availableHeight); }; + Drag.prototype._drag = function () { if (!this.dragInitialized) { this.origin = [d3.event.x, d3.event.y]; this.dragInitialized = true; } + this.location = [this.constrainX(d3.event.x), this.constrainY(d3.event.y)]; }; + Drag.prototype._dragend = function () { if (!this.dragInitialized) { return; @@ -5166,16 +7207,21 @@ var Plottable; this.dragInitialized = false; this._doDragend(); }; + Drag.prototype._doDragend = function () { + // seperated out so it can be over-ridden by dragInteractions that want to pass out diff information + // eg just x values for an xSelectionInteraction if (this.callbackToCall != null) { this.callbackToCall([this.origin, this.location]); } }; + Drag.prototype._anchor = function (hitBox) { _super.prototype._anchor.call(this, hitBox); hitBox.call(this.dragBehavior); return this; }; + Drag.prototype.setupZoomCallback = function (xScale, yScale) { var xDomainOriginal = xScale != null ? xScale.domain() : null; var yDomainOriginal = yScale != null ? yScale.domain() : null; @@ -5213,6 +7259,7 @@ var Plottable; var Interaction = Plottable.Interaction; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -5235,6 +7282,12 @@ var Plottable; } this.clearBox(); }; + + /** + * Clears the highlighted drag-selection box drawn by the AreaInteraction. + * + * @returns {AreaInteraction} The calling AreaInteraction. + */ DragBox.prototype.clearBox = function () { if (this.dragBox == null) { return; @@ -5243,6 +7296,7 @@ var Plottable; this.boxIsDrawn = false; return this; }; + DragBox.prototype.setBox = function (x0, x1, y0, y1) { if (this.dragBox == null) { return; @@ -5255,6 +7309,7 @@ var Plottable; this.boxIsDrawn = (w > 0 && h > 0); return this; }; + DragBox.prototype._anchor = function (hitBox) { _super.prototype._anchor.call(this, hitBox); var cname = DragBox.CLASS_DRAG_BOX; @@ -5270,6 +7325,7 @@ var Plottable; var Interaction = Plottable.Interaction; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -5288,6 +7344,7 @@ var Plottable; _super.prototype._drag.call(this); this.setBox(this.origin[0], this.location[0]); }; + XDragBox.prototype._doDragend = function () { if (this.callbackToCall == null) { return; @@ -5297,6 +7354,7 @@ var Plottable; var pixelArea = { xMin: xMin, xMax: xMax }; this.callbackToCall(pixelArea); }; + XDragBox.prototype.setBox = function (x0, x1) { _super.prototype.setBox.call(this, x0, x1, 0, this.componentToListenTo.availableHeight); return this; @@ -5308,6 +7366,7 @@ var Plottable; var Interaction = Plottable.Interaction; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -5326,6 +7385,7 @@ var Plottable; _super.prototype._drag.call(this); this.setBox(this.origin[0], this.location[0], this.origin[1], this.location[1]); }; + XYDragBox.prototype._doDragend = function () { if (this.callbackToCall == null) { return; @@ -5344,6 +7404,7 @@ var Plottable; var Interaction = Plottable.Interaction; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -5362,6 +7423,7 @@ var Plottable; _super.prototype._drag.call(this); this.setBox(this.origin[1], this.location[1]); }; + YDragBox.prototype._doDragend = function () { if (this.callbackToCall == null) { return; @@ -5371,6 +7433,7 @@ var Plottable; var pixelArea = { yMin: yMin, yMax: yMax }; this.callbackToCall(pixelArea); }; + YDragBox.prototype.setBox = function (y0, y1) { _super.prototype.setBox.call(this, 0, this.componentToListenTo.availableWidth, y0, y1); return this; @@ -5382,6 +7445,7 @@ var Plottable; var Interaction = Plottable.Interaction; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -5393,6 +7457,11 @@ var Plottable; (function (Abstract) { var Dispatcher = (function (_super) { __extends(Dispatcher, _super); + /** + * Creates a Dispatcher with the specified target. + * + * @param {D3.Selection} target The selection to listen for events on. + */ function Dispatcher(target) { _super.call(this); this._event2Callback = {}; @@ -5407,13 +7476,24 @@ var Plottable; this.disconnect(); this._target = targetElement; if (wasConnected) { + // re-connect to the new target this.connect(); } return this; }; + + /** + * Gets a namespaced version of the event name. + */ Dispatcher.prototype.getEventString = function (eventName) { return eventName + ".dispatcher" + this._plottableID; }; + + /** + * Attaches the Dispatcher's listeners to the Dispatcher's target element. + * + * @returns {Dispatcher} The calling Dispatcher. + */ Dispatcher.prototype.connect = function () { var _this = this; if (this.connected) { @@ -5424,8 +7504,15 @@ var Plottable; var callback = _this._event2Callback[event]; _this._target.on(_this.getEventString(event), callback); }); + return this; }; + + /** + * Detaches the Dispatcher's listeners from the Dispatchers' target element. + * + * @returns {Dispatcher} The calling Dispatcher. + */ Dispatcher.prototype.disconnect = function () { var _this = this; this.connected = false; @@ -5441,6 +7528,7 @@ var Plottable; var Abstract = Plottable.Abstract; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -5452,19 +7540,27 @@ var Plottable; (function (Dispatcher) { var Mouse = (function (_super) { __extends(Mouse, _super); + /** + * Creates a Mouse Dispatcher with the specified target. + * + * @param {D3.Selection} target The selection to listen for events on. + */ function Mouse(target) { - _super.call(this, target); var _this = this; + _super.call(this, target); + this._event2Callback["mouseover"] = function () { if (_this._mouseover != null) { _this._mouseover(_this.getMousePosition()); } }; + this._event2Callback["mousemove"] = function () { if (_this._mousemove != null) { _this._mousemove(_this.getMousePosition()); } }; + this._event2Callback["mouseout"] = function () { if (_this._mouseout != null) { _this._mouseout(_this.getMousePosition()); @@ -5478,6 +7574,7 @@ var Plottable; y: xy[1] }; }; + Mouse.prototype.mouseover = function (callback) { if (callback === undefined) { return this._mouseover; @@ -5485,6 +7582,7 @@ var Plottable; this._mouseover = callback; return this; }; + Mouse.prototype.mousemove = function (callback) { if (callback === undefined) { return this._mousemove; @@ -5492,6 +7590,7 @@ var Plottable; this._mousemove = callback; return this; }; + Mouse.prototype.mouseout = function (callback) { if (callback === undefined) { return this._mouseout; @@ -5506,6 +7605,7 @@ var Plottable; var Dispatcher = Plottable.Dispatcher; })(Plottable || (Plottable = {})); +/// var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } @@ -5533,11 +7633,11 @@ var Plottable; this._yAxis = y; this.yTable.addComponent(0, 1, this._yAxis); return this; - } - else { + } else { return this._yAxis; } }; + StandardChart.prototype.xAxis = function (x) { if (x != null) { if (this._xAxis != null) { @@ -5546,19 +7646,18 @@ var Plottable; this._xAxis = x; this.xTable.addComponent(0, 0, this._xAxis); return this; - } - else { + } else { return this._xAxis; } }; + StandardChart.prototype.yLabel = function (y) { if (y != null) { if (this._yLabel != null) { if (typeof (y) === "string") { this._yLabel.text(y); return this; - } - else { + } else { throw new Error("yLabel already assigned!"); } } @@ -5568,19 +7667,18 @@ var Plottable; this._yLabel = y; this.yTable.addComponent(0, 0, this._yLabel); return this; - } - else { + } else { return this._yLabel; } }; + StandardChart.prototype.xLabel = function (x) { if (x != null) { if (this._xLabel != null) { if (typeof (x) === "string") { this._xLabel.text(x); return this; - } - else { + } else { throw new Error("xLabel already assigned!"); } } @@ -5590,19 +7688,18 @@ var Plottable; this._xLabel = x; this.xTable.addComponent(1, 0, this._xLabel); return this; - } - else { + } else { return this._xLabel; } }; + StandardChart.prototype.titleLabel = function (x) { if (x != null) { if (this._titleLabel != null) { if (typeof (x) === "string") { this._titleLabel.text(x); return this; - } - else { + } else { throw new Error("titleLabel already assigned!"); } } @@ -5612,11 +7709,11 @@ var Plottable; this._titleLabel = x; this.addComponent(0, 0, this._titleLabel); return this; - } - else { + } else { return this._titleLabel; } }; + StandardChart.prototype.center = function (c) { this.centerComponent.merge(c); return this; diff --git a/plottable.min.js b/plottable.min.js index 6b2604621e..4fce561909 100644 --- a/plottable.min.js +++ b/plottable.min.js @@ -1,4 +1,4 @@ -var Plottable;!function(a){!function(a){!function(a){function b(a,b,c){return Math.min(b,c)<=a&&a<=Math.max(b,c)}function c(a){null!=window.console&&(null!=window.console.warn?console.warn(a):null!=window.console.log&&console.log(a))}function d(a,b){if(a.length!==b.length)throw new Error("attempted to add arrays of unequal length");return a.map(function(c,d){return a[d]+b[d]})}function e(a,b){var c=d3.set();return a.forEach(function(a){b.has(a)&&c.add(a)}),c}function f(a,b){var c=d3.set();return a.forEach(function(a){return c.add(a)}),b.forEach(function(a){return c.add(a)}),c}function g(a){return"function"==typeof a?a:"string"==typeof a&&"#"!==a[0]?function(b){return b[a]}:function(){return a}}function h(a,b){var c=g(a);return function(a,d){return c(a,d,b.metadata())}}function i(a){var b={};return a.forEach(function(a){return b[a]=!0}),d3.keys(b)}function j(a){var b=d3.set(),c=[];return a.forEach(function(a){b.has(a)||(b.add(a),c.push(a))}),c}function k(a,b){for(var c=[],d=0;b>d;d++)c[d]="function"==typeof a?a(d):a;return c}function l(a){return Array.prototype.concat.apply([],a)}function m(a,b){if(null==a||null==b)return a===b;if(a.length!==b.length)return!1;for(var c=0;cd;){var f=d+e>>>1,g=null==c?b[f]:c(b[f]);a>g?d=f+1:e=f}return d}a.sortedIndex=b}(a.OpenSource||(a.OpenSource={}));a.OpenSource}(a.Util||(a.Util={}));a.Util}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){var b=function(){function a(){this.counter={}}return a.prototype.setDefault=function(a){null==this.counter[a]&&(this.counter[a]=0)},a.prototype.increment=function(a){return this.setDefault(a),++this.counter[a]},a.prototype.decrement=function(a){return this.setDefault(a),--this.counter[a]},a.prototype.get=function(a){return this.setDefault(a),this.counter[a]},a}();a.IDCounter=b}(a.Util||(a.Util={}));a.Util}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){var b=function(){function a(){this.keyValuePairs=[]}return a.prototype.set=function(a,b){if(a!==a)throw new Error("NaN may not be used as a key to the StrictEqualityAssociativeArray");for(var c=0;cb){var h=e("."),i=Math.floor(b/h);return"...".substr(0,i)}for(;f+g>b;)d=d.substr(0,d.length-1).trim(),f=e(d);if(e(d+"...")>b)throw new Error("_addEllipsesToLine failed :(");return d+"..."}function k(b,c,d,e,f,g){"undefined"==typeof f&&(f="left"),"undefined"==typeof g&&(g="top");var h={left:0,center:.5,right:1},i={top:0,center:.5,bottom:1};if(void 0===h[f]||void 0===i[g])throw new Error("unrecognized alignment x:"+f+", y:"+g);var j=c.append("g"),k=j.append("text");k.text(b);var l=a.Util.DOM.getBBox(k),m=l.height,n=l.width;if(n>d||m>e)return a.Util.Methods.warn("Insufficient space to fit text"),{width:0,height:0};var o={left:"start",center:"middle",right:"end"},p=o[f],q=d*h[f],r=e*i[g]+m*(1-i[g]),s=-.4*(1-i[g]);return k.attr("text-anchor",p).attr("y",s+"em"),a.Util.DOM.translate(j,q,r),{width:n,height:m}}function l(a,b,c,d,e,f,g){if("undefined"==typeof e&&(e="left"),"undefined"==typeof f&&(f="top"),"undefined"==typeof g&&(g="right"),"right"!==g&&"left"!==g)throw new Error("unrecognized rotation: "+g);var h="right"===g,i={left:"bottom",right:"top",center:"center",top:"left",bottom:"right"},j={left:"top",right:"bottom",center:"center",top:"right",bottom:"left"},l=h?i:j,m=b.append("g"),n=k(a,m,d,c,l[f],l[e]),o=d3.transform("");return o.rotate="right"===g?90:-90,o.translate=[h?c:0,h?0:d],m.attr("transform",o.toString()),n}function m(b,c,d,e,f,g){"undefined"==typeof f&&(f="left"),"undefined"==typeof g&&(g="top");var i=h(c),j=0,l=c.append("g");b.forEach(function(b,c){var e=l.append("g");a.Util.DOM.translate(e,0,c*i);var h=k(b,e,d,i,f,g);h.width>j&&(j=h.width)});var m=i*b.length,n=e-m,o={center:.5,top:0,bottom:1};return a.Util.DOM.translate(l,0,n*o[g]),{width:j,height:m}}function n(b,c,d,e,f,g,i){"undefined"==typeof f&&(f="left"),"undefined"==typeof g&&(g="top"),"undefined"==typeof i&&(i="left");var j=h(c),k=0,m=c.append("g");b.forEach(function(b,c){var d=m.append("g");a.Util.DOM.translate(d,c*j,0);var h=l(b,d,j,e,f,g,i);h.height>k&&(k=h.height)});var n=j*b.length,o=d-n,p={center:.5,left:0,right:1};return a.Util.DOM.translate(m,o*p[f],0),{width:n,height:k}}function o(b,c,d,e,f,g){var h=null!=f?f:1.1*c>d,i=h?c:d,j=h?d:c,k=a.Util.WordWrap.breakTextToFitRect(b,i,j,e);if(0===k.lines.length)return{textFits:k.textFits,usedWidth:0,usedHeight:0};var l,o;if(null==g){var p=h?d3.max:d3.sum,q=h?d3.sum:d3.max;l=p(k.lines,function(a){return e(a).width}),o=q(k.lines,function(a){return e(a).height})}else{var r=g.g.append("g").classed("writeText-inner-g",!0),s=h?m:n,t=s(k.lines,r,c,d,g.xAlign,g.yAlign);l=t.width,o=t.height}return{textFits:k.textFits,usedWidth:l,usedHeight:o}}b.getTextMeasure=c;var p="a",q=function(){function b(b){var g=this;this.cache=new a.Util.Cache(c(b),p,a.Util.Methods.objEq),this.measure=d(e(f(function(a){return g.cache.get(a)})))}return b.prototype.clear=function(){return this.cache.clear(),this},b}();b.CachingCharacterMeasurer=q,b.getTruncatedText=g,b.getTextHeight=h,b.getTextWidth=i,b._addEllipsesToLine=j,b.writeLineHorizontally=k,b.writeLineVertically=l,b.writeTextHorizontally=m,b.writeTextVertically=n,b.writeText=o}(b.Text||(b.Text={}));b.Text}(a.Util||(a.Util={}));a.Util}(Plottable||(Plottable={}));var Plottable;!function(a){!function(b){!function(b){function c(b,c,e,f){var g=function(a){return f(a).width},h=d(b,c,g),i=f("hello world").height,j=Math.floor(e/i),k=j>=h.length;return k||(h=h.splice(0,j),j>0&&(h[j-1]=a.Util.Text._addEllipsesToLine(h[j-1],c,f))),{originalText:b,lines:h,textFits:k}}function d(a,b,c){for(var d=[],e=a.split("\n"),g=0,h=e.length;h>g;g++){var i=e[g];null!==i?d=d.concat(f(i,b,c)):d.push("")}return d}function e(a,b,c){var d=h(a),e=d.map(c),f=d3.max(e);return b>=f}function f(a,b,c){for(var d,e=[],f=h(a),i="",j=0;d||je;e++){var g=a[e];""===c||j(c[0],g,d)?c+=g:(b.push(c),c=g),d=g}return c&&b.push(c),b}function i(a){return null==a?!0:""===a.trim()}function j(a,b,c){return m.test(a)&&m.test(b)?!0:m.test(a)||m.test(b)?!1:l.test(c)||k.test(b)?!1:!0}var k=/[{\[]/,l=/[!"%),-.:;?\]}]/,m=/^\s+$/;b.breakTextToFitRect=c,b.canWrapWithoutBreakingWords=e}(b.WordWrap||(b.WordWrap={}));b.WordWrap}(a.Util||(a.Util={}));a.Util}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){!function(a){function b(a){return a.node().getBBox()}function c(b){null!=window.requestAnimationFrame?window.requestAnimationFrame(b):setTimeout(b,a.POLYFILL_TIMEOUT_MSEC)}function d(a,b){var c=a.getPropertyValue(b),d=parseFloat(c);return d!==d?0:d}function e(a){for(var b=a.node();null!==b&&"svg"!==b.nodeName;)b=b.parentNode;return null==b}function f(a){var b=window.getComputedStyle(a);return d(b,"width")+d(b,"padding-left")+d(b,"padding-right")+d(b,"border-left-width")+d(b,"border-right-width")}function g(a){var b=window.getComputedStyle(a);return d(b,"height")+d(b,"padding-top")+d(b,"padding-bottom")+d(b,"border-top-width")+d(b,"border-bottom-width")}function h(a){var b=a.node().clientWidth;if(0===b){var c=a.attr("width");if(-1!==c.indexOf("%")){for(var d=a.node().parentNode;null!=d&&0===d.clientWidth;)d=d.parentNode;if(null==d)throw new Error("Could not compute width of element");b=d.clientWidth*parseFloat(c)/100}else b=parseFloat(c)}return b}function i(a,b,c){var d=d3.transform(a.attr("transform"));return null==b?d.translate:(c=null==c?0:c,d.translate[0]=b,d.translate[1]=c,a.attr("transform",d.toString()),a)}function j(a,b){return a.rightb.right?!1:a.bottomb.bottom?!1:!0}a.getBBox=b,a.POLYFILL_TIMEOUT_MSEC=1e3/60,a.requestAnimationFramePolyfill=c,a.isSelectionRemovedFromSVG=e,a.getElementWidth=f,a.getElementHeight=g,a.getSVGPixelWidth=h,a.translate=i,a.boxesOverlap=j}(a.DOM||(a.DOM={}));a.DOM}(a.Util||(a.Util={}));a.Util}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){var b=function(){function a(a){this._onlyShowUnchanged=!0,this.precision(a)}return a.prototype.format=function(a){var b=this._formatFunction(a);return this._onlyShowUnchanged&&this._valueChanged(a,b)?"":b},a.prototype._valueChanged=function(a,b){return a!==parseFloat(b)},a.prototype.precision=function(a){if(void 0===a)return this._precision;if(0>a||a>20)throw new RangeError("Formatter precision must be between 0 and 20");return this._precision=a,this},a.prototype.showOnlyUnchangedValues=function(a){return void 0===a?this._onlyShowUnchanged:(this._onlyShowUnchanged=a,this)},a}();a.Formatter=b}(a.Abstract||(a.Abstract={}));a.Abstract}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(){a.call(this,null),this.showOnlyUnchangedValues(!1),this._formatFunction=function(a){return String(a)}}return __extends(b,a),b}(a.Abstract.Formatter);b.Identity=c}(a.Formatter||(a.Formatter={}));a.Formatter}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b){"undefined"==typeof b&&(b=3),a.call(this,b),this._formatFunction=function(a){if("number"==typeof a){var b=Math.pow(10,this._precision);return String(Math.round(a*b)/b)}return String(a)}}return __extends(b,a),b.prototype._valueChanged=function(a,b){return"number"==typeof a?a!==parseFloat(b):!1},b}(a.Abstract.Formatter);b.General=c}(a.Formatter||(a.Formatter={}));a.Formatter}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b){"undefined"==typeof b&&(b=3),a.call(this,b),this._formatFunction=function(a){return a.toFixed(this._precision)}}return __extends(b,a),b}(a.Abstract.Formatter);b.Fixed=c}(a.Formatter||(a.Formatter={}));a.Formatter}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b,c,d){"undefined"==typeof b&&(b=2),"undefined"==typeof c&&(c="$"),"undefined"==typeof d&&(d=!0),a.call(this,b),this.symbol=c,this.prefix=d}return __extends(b,a),b.prototype.format=function(b){var c=a.prototype.format.call(this,Math.abs(b));return""!==c&&(this.prefix?c=this.symbol+c:c+=this.symbol,0>b&&(c="-"+c)),c},b}(a.Formatter.Fixed);b.Currency=c}(a.Formatter||(a.Formatter={}));a.Formatter}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b){"undefined"==typeof b&&(b=0),a.call(this,b)}return __extends(b,a),b.prototype.format=function(b){var c=a.prototype.format.call(this,100*b);return""!==c&&(c+="%"),c},b}(a.Formatter.Fixed);b.Percentage=c}(a.Formatter||(a.Formatter={}));a.Formatter}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b){"undefined"==typeof b&&(b=3),a.call(this,b),this.showOnlyUnchangedValues(!1)}return __extends(b,a),b.prototype.precision=function(b){var c=a.prototype.precision.call(this,b);return this._formatFunction=d3.format("."+this._precision+"s"),c},b}(a.Abstract.Formatter);b.SISuffix=c}(a.Formatter||(a.Formatter={}));a.Formatter}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b,c){if("undefined"==typeof c&&(c=0),a.call(this,c),null==b)throw new Error("Custom Formatters require a formatting function");this._onlyShowUnchanged=!1,this._formatFunction=function(a){return b(a,this)}}return __extends(b,a),b}(a.Abstract.Formatter);b.Custom=c}(a.Formatter||(a.Formatter={}));a.Formatter}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(){a.call(this,null);var b=8,c={};c[0]={format:".%L",filter:function(a){return 0!==a.getMilliseconds()}},c[1]={format:":%S",filter:function(a){return 0!==a.getSeconds()}},c[2]={format:"%I:%M",filter:function(a){return 0!==a.getMinutes()}},c[3]={format:"%I %p",filter:function(a){return 0!==a.getHours()}},c[4]={format:"%a %d",filter:function(a){return 0!==a.getDay()&&1!==a.getDate()}},c[5]={format:"%b %d",filter:function(a){return 1!==a.getDate()}},c[6]={format:"%b",filter:function(a){return 0!==a.getMonth()}},c[7]={format:"%Y",filter:function(){return!0}},this._formatFunction=function(a){for(var d=0;b>d;d++)if(c[d].filter(a))return d3.time.format(c[d].format)(a)},this.showOnlyUnchangedValues(!1)}return __extends(b,a),b}(a.Abstract.Formatter);b.Time=c}(a.Formatter||(a.Formatter={}));a.Formatter}(Plottable||(Plottable={}));var Plottable;!function(a){a.version="0.23.2"}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){var b=function(){function a(){this._plottableID=a.nextID++}return a.nextID=0,a}();a.PlottableObject=b}(a.Abstract||(a.Abstract={}));a.Abstract}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(c){b.call(this),this.listener2Callback=new a.Util.StrictEqualityAssociativeArray,this.listenable=c}return __extends(c,b),c.prototype.registerListener=function(a,b){return this.listener2Callback.set(a,b),this},c.prototype.broadcast=function(){for(var a=this,b=[],c=0;c=0&&(this._components.splice(b,1),this._invalidateLayout()),this},b.prototype._addComponent=function(a,b){return"undefined"==typeof b&&(b=!1),null==a||this._components.indexOf(a)>=0?!1:(b?this._components.unshift(a):this._components.push(a),a._parent=this,this._isAnchored&&a._anchor(this.content),this._invalidateLayout(),!0)},b.prototype.components=function(){return this._components.slice()},b.prototype.empty=function(){return 0===this._components.length},b.prototype.detachAll=function(){return this._components.slice().forEach(function(a){return a.detach()}),this},b.prototype.remove=function(){a.prototype.remove.call(this),this._components.slice().forEach(function(a){return a.remove()})},b}(a.Abstract.Component);b.ComponentContainer=c}(a.Abstract||(a.Abstract={}));a.Abstract}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b){"undefined"==typeof b&&(b=[]);var c=this;a.call(this),this.classed("component-group",!0),b.forEach(function(a){return c._addComponent(a)})}return __extends(b,a),b.prototype._requestedSpace=function(a,b){var c=this._components.map(function(c){return c._requestedSpace(a,b)}),d=this.empty(),e=d?0:d3.max(c,function(a){return a.width}),f=d?0:d3.max(c,function(a){return a.height});return{width:Math.min(e,a),height:Math.min(f,b),wantsWidth:d?!1:c.map(function(a){return a.wantsWidth}).some(function(a){return a}),wantsHeight:d?!1:c.map(function(a){return a.wantsHeight}).some(function(a){return a})}},b.prototype.merge=function(a){return this._addComponent(a),this},b.prototype._computeLayout=function(b,c,d,e){var f=this;return a.prototype._computeLayout.call(this,b,c,d,e),this._components.forEach(function(a){a._computeLayout(0,0,f.availableWidth,f.availableHeight)}),this},b.prototype._isFixedWidth=function(){return this._components.every(function(a){return a._isFixedWidth()})},b.prototype._isFixedHeight=function(){return this._components.every(function(a){return a._isFixedHeight()})},b}(a.Abstract.ComponentContainer);b.Group=c}(a.Component||(a.Component={}));a.Component}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(a){"undefined"==typeof a&&(a=[]);var c=this;b.call(this),this.rowPadding=0,this.colPadding=0,this.rows=[],this.rowWeights=[],this.colWeights=[],this.nRows=0,this.nCols=0,this.classed("table",!0),a.forEach(function(a,b){a.forEach(function(a,d){c.addComponent(b,d,a)})})}return __extends(c,b),c.prototype.addComponent=function(a,b,c){if(this._addComponent(c)){this.nRows=Math.max(a+1,this.nRows),this.nCols=Math.max(b+1,this.nCols),this.padTableToSize(this.nRows,this.nCols);var d=this.rows[a][b];if(null!=d)throw new Error("Table.addComponent cannot be called on a cell where a component already exists (for the moment)");this.rows[a][b]=c}return this},c.prototype._removeComponent=function(a){b.prototype._removeComponent.call(this,a);var c,d;a:for(var e=0;e0&&v&&e!==x,C=f>0&&w&&f!==y;if(!B&&!C)break;if(r>5)break}return e=h-d3.sum(u.guaranteedWidths),f=i-d3.sum(u.guaranteedHeights),n=c.calcProportionalSpace(k,e),o=c.calcProportionalSpace(j,f),{colProportionalSpace:n,rowProportionalSpace:o,guaranteedWidths:u.guaranteedWidths,guaranteedHeights:u.guaranteedHeights,wantsWidth:v,wantsHeight:w}},c.prototype.determineGuarantees=function(b,c){var d=a.Util.Methods.createFilledArray(0,this.nCols),e=a.Util.Methods.createFilledArray(0,this.nRows),f=a.Util.Methods.createFilledArray(!1,this.nCols),g=a.Util.Methods.createFilledArray(!1,this.nRows);return this.rows.forEach(function(h,i){h.forEach(function(h,j){var k; -k=null!=h?h._requestedSpace(b[j],c[i]):{width:0,height:0,wantsWidth:!1,wantsHeight:!1};var l=.001,m=function(a,b){return a-b-l>0};(m(k.width,b[j])||m(k.height,c[i]))&&a.Util.Methods.warn("Invariant Violation: Abstract.Component cannot request more space than is offered"),d[j]=Math.max(d[j],k.width),e[i]=Math.max(e[i],k.height),f[j]=f[j]||k.wantsWidth,g[i]=g[i]||k.wantsHeight})}),{guaranteedWidths:d,guaranteedHeights:e,wantsWidthArr:f,wantsHeightArr:g}},c.prototype._requestedSpace=function(a,b){var c=this.iterateLayout(a,b);return{width:d3.sum(c.guaranteedWidths),height:d3.sum(c.guaranteedHeights),wantsWidth:c.wantsWidth,wantsHeight:c.wantsHeight}},c.prototype._computeLayout=function(c,d,e,f){var g=this;b.prototype._computeLayout.call(this,c,d,e,f);var h=this.iterateLayout(this.availableWidth,this.availableHeight),i=a.Util.Methods.addArrays(h.rowProportionalSpace,h.guaranteedHeights),j=a.Util.Methods.addArrays(h.colProportionalSpace,h.guaranteedWidths),k=0;return this.rows.forEach(function(a,b){var c=0;a.forEach(function(a,d){null!=a&&a._computeLayout(c,k,j[d],i[b]),c+=j[d]+g.colPadding}),k+=i[b]+g.rowPadding}),this},c.prototype.padding=function(a,b){return this.rowPadding=a,this.colPadding=b,this._invalidateLayout(),this},c.prototype.rowWeight=function(a,b){return this.rowWeights[a]=b,this._invalidateLayout(),this},c.prototype.colWeight=function(a,b){return this.colWeights[a]=b,this._invalidateLayout(),this},c.prototype._isFixedWidth=function(){var a=d3.transpose(this.rows);return c.fixedSpace(a,function(a){return null==a||a._isFixedWidth()})},c.prototype._isFixedHeight=function(){return c.fixedSpace(this.rows,function(a){return null==a||a._isFixedHeight()})},c.prototype.padTableToSize=function(a,b){for(var c=0;a>c;c++){void 0===this.rows[c]&&(this.rows[c]=[],this.rowWeights[c]=null);for(var d=0;b>d;d++)void 0===this.rows[c][d]&&(this.rows[c][d]=null)}for(d=0;b>d;d++)void 0===this.colWeights[d]&&(this.colWeights[d]=null)},c.calcComponentWeights=function(a,b,c){return a.map(function(a,d){if(null!=a)return a;var e=b[d].map(c),f=e.reduce(function(a,b){return a&&b},!0);return f?0:1})},c.calcProportionalSpace=function(b,c){var d=d3.sum(b);return 0===d?a.Util.Methods.createFilledArray(0,b.length):b.map(function(a){return c*a/d})},c.fixedSpace=function(a,b){var c=function(a){return a.reduce(function(a,b){return a&&b},!0)},d=function(a){return c(a.map(b))};return c(a.map(d))},c}(a.Abstract.ComponentContainer);b.Table=c}(a.Component||(a.Component={}));a.Component}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(c){b.call(this),this.autoDomainAutomatically=!0,this.broadcaster=new a.Core.Broadcaster(this),this._rendererAttrID2Extent={},this._d3Scale=c}return __extends(c,b),c.prototype._getAllExtents=function(){return d3.values(this._rendererAttrID2Extent)},c.prototype._getExtent=function(){return[]},c.prototype.autoDomain=function(){return this.autoDomainAutomatically=!0,this._setDomain(this._getExtent()),this},c.prototype._autoDomainIfAutomaticMode=function(){this.autoDomainAutomatically&&this.autoDomain()},c.prototype.scale=function(a){return this._d3Scale(a)},c.prototype.domain=function(a){return null==a?this._getDomain():(this.autoDomainAutomatically=!1,this._setDomain(a),this)},c.prototype._getDomain=function(){return this._d3Scale.domain()},c.prototype._setDomain=function(a){this._d3Scale.domain(a),this.broadcaster.broadcast()},c.prototype.range=function(a){return null==a?this._d3Scale.range():(this._d3Scale.range(a),this)},c.prototype.copy=function(){return new c(this._d3Scale.copy())},c.prototype.updateExtent=function(a,b,c){return this._rendererAttrID2Extent[a+b]=c,this._autoDomainIfAutomaticMode(),this},c.prototype.removeExtent=function(a,b){return delete this._rendererAttrID2Extent[a+b],this._autoDomainIfAutomaticMode(),this},c}(a.Abstract.PlottableObject);b.Scale=c}(a.Abstract||(a.Abstract={}));a.Abstract}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(c){b.call(this),this._dataChanged=!1,this._animate=!1,this._animators={},this._ANIMATION_DURATION=250,this._projectors={},this.animateOnNextRender=!0,this.clipPathEnabled=!0,this.classed("renderer",!0);var d;d=null!=c?"function"==typeof c.data?c:d=new a.DataSource(c):new a.DataSource,this.dataSource(d)}return __extends(c,b),c.prototype._anchor=function(a){return b.prototype._anchor.call(this,a),this.animateOnNextRender=!0,this._dataChanged=!0,this.updateAllProjectors(),this},c.prototype.remove=function(){var a=this;b.prototype.remove.call(this),this._dataSource.broadcaster.deregisterListener(this);var c=Object.keys(this._projectors);c.forEach(function(b){var c=a._projectors[b];null!=c.scale&&c.scale.broadcaster.deregisterListener(a)})},c.prototype.dataSource=function(a){var b=this;if(null==a)return this._dataSource;var c=this._dataSource;return null!=c&&this._dataSource.broadcaster.deregisterListener(this),this._dataSource=a,this._dataSource.broadcaster.registerListener(this,function(){return b._onDataSourceUpdate()}),this._onDataSourceUpdate(),this},c.prototype._onDataSourceUpdate=function(){this.updateAllProjectors(),this.animateOnNextRender=!0,this._dataChanged=!0,this._render()},c.prototype.project=function(a,b,c){var d=this;a=a.toLowerCase();var e=this._projectors[a],f=null!=e?e.scale:null;return null!=f&&(f.removeExtent(this._plottableID,a),f.broadcaster.deregisterListener(this)),null!=c&&c.broadcaster.registerListener(this,function(){return d._render()}),this._projectors[a]={accessor:b,scale:c},this.updateProjector(a),this._render(),this},c.prototype._generateAttrToProjector=function(){var b=this,c={};return d3.keys(this._projectors).forEach(function(d){var e=b._projectors[d],f=a.Util.Methods.applyAccessor(e.accessor,b.dataSource()),g=e.scale,h=null==g?f:function(a,b){return g.scale(f(a,b))};c[d]=h}),c},c.prototype._doRender=function(){return null!=this.element&&(this._paint(),this._dataChanged=!1,this.animateOnNextRender=!1),this},c.prototype._paint=function(){},c.prototype._setup=function(){return b.prototype._setup.call(this),this.renderArea=this.content.append("g").classed("render-area",!0),this},c.prototype.animate=function(a){return this._animate=a,this},c.prototype.detach=function(){return b.prototype.detach.call(this),this.updateAllProjectors(),this},c.prototype.updateAllProjectors=function(){var a=this;return d3.keys(this._projectors).forEach(function(b){return a.updateProjector(b)}),this},c.prototype.updateProjector=function(a){var b=this._projectors[a];if(null!=b.scale){var c=this.dataSource()._getExtent(b.accessor);0!==c.length&&this._isAnchored?b.scale.updateExtent(this._plottableID,a,c):b.scale.removeExtent(this._plottableID,a)}return this},c.prototype._applyAnimatedAttributes=function(a,b,c){return this._animate&&this.animateOnNextRender&&null!=this._animators[b]?this._animators[b].animate(a,c,this):a.attr(c)},c.prototype.animator=function(a,b){return void 0===b?this._animators[a]:(this._animators[a]=b,this)},c}(a.Abstract.Component);b.Plot=c}(a.Abstract||(a.Abstract={}));a.Abstract}(Plottable||(Plottable={}));var Plottable;!function(a){!function(b){!function(b){!function(b){var c=function(){function b(){}return b.prototype.render=function(){a.Core.RenderController.flush()},b}();b.Immediate=c;var d=function(){function b(){}return b.prototype.render=function(){a.Util.DOM.requestAnimationFramePolyfill(a.Core.RenderController.flush)},b}();b.AnimationFrame=d;var e=function(){function b(){this._timeoutMsec=a.Util.DOM.POLYFILL_TIMEOUT_MSEC}return b.prototype.render=function(){setTimeout(a.Core.RenderController.flush,this._timeoutMsec)},b}();b.Timeout=e}(b.RenderPolicy||(b.RenderPolicy={}));b.RenderPolicy}(b.RenderController||(b.RenderController={}));b.RenderController}(a.Core||(a.Core={}));a.Core}(Plottable||(Plottable={}));var Plottable;!function(a){!function(b){!function(b){function c(a){b._renderPolicy=a}function d(a){h[a._plottableID]=a,f()}function e(a){i[a._plottableID]=a,h[a._plottableID]=a,f()}function f(){j||(j=!0,b._renderPolicy.render())}function g(){if(j){var b=d3.values(i);b.forEach(function(a){return a._computeLayout()});var c=d3.values(h);c.forEach(function(a){return a._render()}),c=d3.values(h),c.forEach(function(a){return a._doRender()}),i={},h={},j=!1}a.Core.ResizeBroadcaster.clearResizing()}var h={},i={},j=!1;b._renderPolicy=new a.Core.RenderController.RenderPolicy.AnimationFrame,b.setRenderPolicy=c,b.registerToRender=d,b.registerToComputeLayout=e,b.flush=g}(b.RenderController||(b.RenderController={}));b.RenderController}(a.Core||(a.Core={}));a.Core}(Plottable||(Plottable={}));var Plottable;!function(a){!function(b){!function(b){function c(){void 0===i&&(i=new a.Core.Broadcaster(b),window.addEventListener("resize",d))}function d(){j=!0,i.broadcast()}function e(){return j}function f(){j=!1}function g(a){c(),i.registerListener(a._plottableID,function(){return a._invalidateLayout()})}function h(a){i&&i.deregisterListener(a._plottableID)}var i,j=!1;b.resizing=e,b.clearResizing=f,b.register=g,b.deregister=h}(b.ResizeBroadcaster||(b.ResizeBroadcaster={}));b.ResizeBroadcaster}(a.Core||(a.Core={}));a.Core}(Plottable||(Plottable={}));var Plottable;!function(){}(Plottable||(Plottable={}));var Plottable;!function(a){var b=function(){function a(a){this.doNice=!1,this.padProportion=0,this.paddingExceptions=d3.map(),this.unregisteredPaddingExceptions=d3.set(),this.includedValues=d3.map(),this.unregisteredIncludedValues=d3.map(),this.combineExtents=a}return a.prototype.computeDomain=function(a,b){var c;return c=null!=this.combineExtents?this.combineExtents(a):0===a.length?b._defaultExtent():[d3.min(a,function(a){return a[0]}),d3.max(a,function(a){return a[1]})],c=this.includeDomain(c),c=this.padDomain(b,c),c=this.niceDomain(b,c)},a.prototype.pad=function(a){return"undefined"==typeof a&&(a=.05),this.padProportion=a,this},a.prototype.addPaddingException=function(a,b){return null!=b?this.paddingExceptions.set(b,a):this.unregisteredPaddingExceptions.add(a),this},a.prototype.removePaddingException=function(a){return"string"==typeof a?this.paddingExceptions.remove(a):this.unregisteredPaddingExceptions.remove(a),this},a.prototype.addIncludedValue=function(a,b){return null!=b?this.includedValues.set(b,a):this.unregisteredIncludedValues.set(a,a),this},a.prototype.removeIncludedValue=function(a){return"string"==typeof a?this.includedValues.remove(a):this.unregisteredIncludedValues.remove(a),this},a.prototype.nice=function(a){return this.doNice=!0,this.niceCount=a,this},a.defaultCombineExtents=function(a){return 0===a.length?[0,1]:[d3.min(a,function(a){return a[0]}),d3.max(a,function(a){return a[1]})]},a.prototype.padDomain=function(b,c){var d=c[0],e=c[1];if(d===e&&this.padProportion>0){var f=d.valueOf();return d instanceof Date?[f-a.ONE_DAY,f+a.ONE_DAY]:[f-a.PADDING_FOR_IDENTICAL_DOMAIN,f+a.PADDING_FOR_IDENTICAL_DOMAIN]}var g=this.padProportion/2,h=b.invert(b.scale(d)-(b.scale(e)-b.scale(d))*g),i=b.invert(b.scale(e)+(b.scale(e)-b.scale(d))*g),j=this.paddingExceptions.values().concat(this.unregisteredPaddingExceptions.values()),k=d3.set(j);return k.has(d)&&(h=d),k.has(e)&&(i=e),[h,i]},a.prototype.niceDomain=function(a,b){return this.doNice?a._niceDomain(b,this.niceCount):b},a.prototype.includeDomain=function(a){var b=this.includedValues.values().concat(this.unregisteredIncludedValues.values());return b.reduce(function(a,b){return[Math.min(a[0],b),Math.max(a[1],b)]},a)},a.PADDING_FOR_IDENTICAL_DOMAIN=1,a.ONE_DAY=864e5,a}();a.Domainer=b}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(c){b.call(this,c),this._lastRequestedTickCount=10,this._PADDING_FOR_IDENTICAL_DOMAIN=1,this._userSetDomainer=!1,this._domainer=new a.Domainer}return __extends(c,b),c.prototype._getExtent=function(){return this._domainer.computeDomain(this._getAllExtents(),this)},c.prototype.invert=function(a){return this._d3Scale.invert(a)},c.prototype.copy=function(){return new c(this._d3Scale.copy())},c.prototype.domain=function(a){return b.prototype.domain.call(this,a)},c.prototype._setDomain=function(c){var d=function(a){return a!==a||1/0===a||a===-1/0};return d(c[0])||d(c[1])?void a.Util.Methods.warn("Warning: QuantitativeScales cannot take NaN or Infinity as a domain value. Ignoring."):void b.prototype._setDomain.call(this,c)},c.prototype.interpolate=function(a){return null==a?this._d3Scale.interpolate():(this._d3Scale.interpolate(a),this)},c.prototype.rangeRound=function(a){return this._d3Scale.rangeRound(a),this},c.prototype.clamp=function(a){return null==a?this._d3Scale.clamp():(this._d3Scale.clamp(a),this)},c.prototype.ticks=function(a){return null!=a&&(this._lastRequestedTickCount=a),this._d3Scale.ticks(this._lastRequestedTickCount)},c.prototype.tickFormat=function(a,b){return this._d3Scale.tickFormat(a,b)},c.prototype._niceDomain=function(a,b){return this._d3Scale.copy().domain(a).nice(b).domain()},c.prototype.domainer=function(a){return null==a?this._domainer:(this._domainer=a,this._userSetDomainer=!0,this._autoDomainIfAutomaticMode(),this)},c.prototype._defaultExtent=function(){return[0,1]},c}(a.Abstract.Scale);b.QuantitativeScale=c}(a.Abstract||(a.Abstract={}));a.Abstract}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b){a.call(this,null==b?d3.scale.linear():b)}return __extends(b,a),b.prototype.copy=function(){return new b(this._d3Scale.copy())},b}(a.Abstract.QuantitativeScale);b.Linear=c}(a.Scale||(a.Scale={}));a.Scale}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b){a.call(this,null==b?d3.scale.log():b)}return __extends(b,a),b.prototype.copy=function(){return new b(this._d3Scale.copy())},b.prototype._defaultExtent=function(){return[1,10]},b}(a.Abstract.QuantitativeScale);b.Log=c}(a.Scale||(a.Scale={}));a.Scale}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(a){if("undefined"==typeof a&&(a=10),b.call(this,d3.scale.linear()),this._showIntermediateTicks=!1,this.base=a,this.pivot=this.base,this.untransformedDomain=this._defaultExtent(),this._lastRequestedTickCount=10,1>=a)throw new Error("ModifiedLogScale: The base must be > 1")}return __extends(c,b),c.prototype.adjustedLog=function(a){var b=0>a?-1:1;return a*=b,aa?-1:1;return a*=b,a=Math.pow(this.base,a),a=d&&e>=a});return j.concat(l).concat(k)},c.prototype.logTicks=function(b,c){var d=this,e=this.howManyTicks(b,c);if(0===e)return[];var f=Math.floor(Math.log(b)/Math.log(this.base)),g=Math.ceil(Math.log(c)/Math.log(this.base)),h=d3.range(g,f,-Math.ceil((g-f)/e)),i=this._showIntermediateTicks?Math.floor(e/h.length):1,j=d3.range(this.base,1,-(this.base-1)/i).map(Math.floor),k=a.Util.Methods.uniqNumbers(j),l=h.map(function(a){return k.map(function(b){return Math.pow(d.base,a-1)*b})}),m=a.Util.Methods.flatten(l),n=m.filter(function(a){return a>=b&&c>=a}),o=n.sort(function(a,b){return a-b});return o},c.prototype.howManyTicks=function(a,b){var c=this.adjustedLog(d3.min(this.untransformedDomain)),d=this.adjustedLog(d3.max(this.untransformedDomain)),e=this.adjustedLog(a),f=this.adjustedLog(b),g=(f-e)/(d-c),h=Math.ceil(g*this._lastRequestedTickCount);return h},c.prototype.copy=function(){return new c(this.base)},c.prototype._niceDomain=function(a){return a},c.prototype.showIntermediateTicks=function(a){return null==a?this._showIntermediateTicks:void(this._showIntermediateTicks=a)},c}(a.Abstract.QuantitativeScale);b.ModifiedLog=c}(a.Scale||(a.Scale={}));a.Scale}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(a){if(b.call(this,null==a?d3.scale.ordinal():a),this._range=[0,1],this._rangeType="bands",this._innerPadding=.3,this._outerPadding=.5,this._innerPadding>this._outerPadding)throw new Error("outerPadding must be >= innerPadding so cat axis bands work out reasonably")}return __extends(c,b),c.prototype._getExtent=function(){var b=this._getAllExtents();return a.Util.Methods.uniq(a.Util.Methods.flatten(b))},c.prototype.domain=function(a){return b.prototype.domain.call(this,a)},c.prototype._setDomain=function(a){b.prototype._setDomain.call(this,a),this.range(this.range())},c.prototype.range=function(a){return null==a?this._range:(this._range=a,"points"===this._rangeType?this._d3Scale.rangePoints(a,2*this._outerPadding):"bands"===this._rangeType&&this._d3Scale.rangeBands(a,this._innerPadding,this._outerPadding),this)},c.prototype.rangeBand=function(){return this._d3Scale.rangeBand()},c.prototype.innerPadding=function(){var a=this.domain();if(a.length<2)return 0;var b=Math.abs(this.scale(a[1])-this.scale(a[0]));return b-this.rangeBand()},c.prototype.fullBandStartAndWidth=function(a){var b=this.scale(a)-this.innerPadding()/2,c=this.rangeBand()+this.innerPadding();return[b,c]},c.prototype.rangeType=function(a,b,c){if(null==a)return this._rangeType;if("points"!==a&&"bands"!==a)throw new Error("Unsupported range type: "+a);return this._rangeType=a,null!=b&&(this._outerPadding=b),null!=c&&(this._innerPadding=c),this.broadcaster.broadcast(),this},c.prototype.copy=function(){return new c(this._d3Scale.copy())},c}(a.Abstract.Scale);b.Ordinal=c}(a.Scale||(a.Scale={}));a.Scale}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(a){var c;switch(a){case"Category10":case"category10":case"10":c=d3.scale.category10();break;case"Category20":case"category20":case"20":c=d3.scale.category20();break;case"Category20b":case"category20b":case"20b":c=d3.scale.category20b();break;case"Category20c":case"category20c":case"20c":c=d3.scale.category20c();break;case null:case void 0:c=d3.scale.ordinal();break;default:throw new Error("Unsupported ColorScale type")}b.call(this,c)}return __extends(c,b),c.prototype._getExtent=function(){var b=this._getAllExtents(),c=[];return b.forEach(function(a){c=c.concat(a)}),a.Util.Methods.uniq(c)},c}(a.Abstract.Scale);b.Color=c}(a.Scale||(a.Scale={}));a.Scale}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b){a.call(this,null==b?d3.time.scale():b),this._PADDING_FOR_IDENTICAL_DOMAIN=864e5}return __extends(b,a),b.prototype.tickInterval=function(a,b){var c=d3.time.scale();return c.domain(this.domain()),c.range(this.range()),c.ticks(a.range,b)},b.prototype.domain=function(b){return null==b?a.prototype.domain.call(this):("string"==typeof b[0]&&(b=b.map(function(a){return new Date(a)})),a.prototype.domain.call(this,b))},b.prototype.copy=function(){return new b(this._d3Scale.copy())},b}(a.Abstract.QuantitativeScale);b.Time=c}(a.Scale||(a.Scale={}));a.Scale}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(c,d){"undefined"==typeof c&&(c="reds"),"undefined"==typeof d&&(d="linear"),this._colorRange=this._resolveColorValues(c),this._scaleType=d,a.call(this,b.getD3InterpolatedScale(this._colorRange,this._scaleType))}return __extends(b,a),b.getD3InterpolatedScale=function(a,c){var d;switch(c){case"linear":d=d3.scale.linear();break;case"log":d=d3.scale.log();break;case"sqrt":d=d3.scale.sqrt();break;case"pow":d=d3.scale.pow()}if(null==d)throw new Error("unknown Quantitative scale type "+c);return d.range([0,1]).interpolate(b.interpolateColors(a))},b.interpolateColors=function(a){if(a.length<2)throw new Error("Color scale arrays must have at least two elements.");return function(){return function(b){b=Math.max(0,Math.min(1,b));var c=b*(a.length-1),d=Math.floor(c),e=Math.ceil(c),f=c-d;return d3.interpolateLab(a[d],a[e])(f)}}},b.prototype.colorRange=function(a){return null==a?this._colorRange:(this._colorRange=this._resolveColorValues(a),void this._resetScale())},b.prototype.scaleType=function(a){return null==a?this._scaleType:(this._scaleType=a,void this._resetScale())},b.prototype._resetScale=function(){this._d3Scale=b.getD3InterpolatedScale(this._colorRange,this._scaleType),this._autoDomainIfAutomaticMode(),this.broadcaster.broadcast()},b.prototype._resolveColorValues=function(a){return a instanceof Array?a:null!=b.COLOR_SCALES[a]?b.COLOR_SCALES[a]:b.COLOR_SCALES.reds},b.prototype.autoDomain=function(){var a=this._getAllExtents();return a.length>0&&this._setDomain([d3.min(a,function(a){return a[0]}),d3.max(a,function(a){return a[1]})]),this},b.COLOR_SCALES={reds:["#FFFFFF","#FFF6E1","#FEF4C0","#FED976","#FEB24C","#FD8D3C","#FC4E2A","#E31A1C","#B10026"],blues:["#FFFFFF","#CCFFFF","#A5FFFD","#85F7FB","#6ED3EF","#55A7E0","#417FD0","#2545D3","#0B02E1"],posneg:["#0B02E1","#2545D3","#417FD0","#55A7E0","#6ED3EF","#85F7FB","#A5FFFD","#CCFFFF","#FFFFFF","#FFF6E1","#FEF4C0","#FED976","#FEB24C","#FD8D3C","#FC4E2A","#E31A1C","#B10026"]},b}(a.Abstract.QuantitativeScale);b.InterpolatedColor=c}(a.Scale||(a.Scale={}));a.Scale}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){var b=function(){function a(a){var b=this;if(this.rescaleInProgress=!1,null==a)throw new Error("ScaleDomainCoordinator requires scales to coordinate");this.scales=a,this.scales.forEach(function(a){return a.broadcaster.registerListener(b,function(a){return b.rescale(a)})})}return a.prototype.rescale=function(a){if(!this.rescaleInProgress){this.rescaleInProgress=!0;var b=a.domain();this.scales.forEach(function(a){return a.domain(b)}),this.rescaleInProgress=!1}},a}();a.ScaleDomainCoordinator=b}(a.Util||(a.Util={}));a.Util}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(c,d,e){var f=this;if(b.call(this),this._width="auto",this._height="auto",this._tickLength=5,this._tickLabelPadding=3,this._showEndTickLabels=!1,null==c||null==d)throw new Error("Axis requires a scale and orientation");this._scale=c,this.orient(d),this.classed("axis",!0),this._isHorizontal()?this.classed("x-axis",!0):this.classed("y-axis",!0),null==e&&(e=new a.Formatter.General,e.showOnlyUnchangedValues(!1)),this.formatter(e),this._scale.broadcaster.registerListener(this,function(){return f.rescale()})}return __extends(c,b),c.prototype.remove=function(){b.prototype.remove.call(this),this._scale.broadcaster.deregisterListener(this)},c.prototype._isHorizontal=function(){return"top"===this._orientation||"bottom"===this._orientation},c.prototype._computeWidth=function(){return this._computedWidth=this._tickLength,this._computedWidth},c.prototype._computeHeight=function(){return this._computedHeight=this._tickLength,this._computedHeight},c.prototype._requestedSpace=function(a,b){var c=this._width,d=this._height;return this._isHorizontal()?("auto"===this._height&&(null==this._computedHeight&&this._computeHeight(),d=this._computedHeight),c=0):("auto"===this._width&&(null==this._computedWidth&&this._computeWidth(),c=this._computedWidth),d=0),{width:Math.min(a,c),height:Math.min(b,d),wantsWidth:!this._isHorizontal()&&c>a,wantsHeight:this._isHorizontal()&&d>b}},c.prototype._computeLayout=function(a,c,d,e){return b.prototype._computeLayout.call(this,a,c,d,e),this._scale.range(this._isHorizontal()?[0,this.availableWidth]:[this.availableHeight,0]),this},c.prototype._setup=function(){return b.prototype._setup.call(this),this._tickMarkContainer=this.content.append("g").classed(c.TICK_MARK_CLASS+"-container",!0),this._tickLabelContainer=this.content.append("g").classed(c.TICK_LABEL_CLASS+"-container",!0),this._baseline=this.content.append("line").classed("baseline",!0),this},c.prototype._getTickValues=function(){return[]},c.prototype._doRender=function(){var a=this._getTickValues(),b=this._tickMarkContainer.selectAll("."+c.TICK_MARK_CLASS).data(a);return b.enter().append("line").classed(c.TICK_MARK_CLASS,!0),b.attr(this._generateTickMarkAttrHash()),b.exit().remove(),this._baseline.attr(this._generateBaselineAttrHash()),this},c.prototype._generateBaselineAttrHash=function(){var a={x1:0,y1:0,x2:0,y2:0};switch(this._orientation){case"bottom":a.x2=this.availableWidth;break;case"top":a.x2=this.availableWidth,a.y1=this.availableHeight,a.y2=this.availableHeight;break;case"left":a.x1=this.availableWidth,a.x2=this.availableWidth,a.y2=this.availableHeight;break;case"right":a.y2=this.availableHeight}return a},c.prototype._generateTickMarkAttrHash=function(){var a=this,b={x1:0,y1:0,x2:0,y2:0},c=function(b){return a._scale.scale(b)};switch(this._isHorizontal()?(b.x1=c,b.x2=c):(b.y1=c,b.y2=c),this._orientation){case"bottom":b.y2=this._tickLength;break;case"top":b.y1=this.availableHeight,b.y2=this.availableHeight-this._tickLength;break;case"left":b.x1=this.availableWidth,b.x2=this.availableWidth-this._tickLength;break;case"right":b.x2=this._tickLength}return b},c.prototype.rescale=function(){return null!=this.element?this._render():null},c.prototype._invalidateLayout=function(){b.prototype._invalidateLayout.call(this),this._computedWidth=null,this._computedHeight=null},c.prototype.width=function(a){if(null==a)return this.availableWidth;if(this._isHorizontal())throw new Error("width cannot be set on a horizontal Axis");if("auto"!==a&&0>a)throw new Error("invalid value for width");return this._width=a,this._invalidateLayout(),this},c.prototype.height=function(a){if(null==a)return this.availableHeight;if(!this._isHorizontal())throw new Error("height cannot be set on a vertical Axis");if("auto"!==a&&0>a)throw new Error("invalid value for height");return this._height=a,this._invalidateLayout(),this},c.prototype.formatter=function(b){return void 0===b?this._formatter:("function"==typeof b&&(b=new a.Formatter.Custom(b),b.showOnlyUnchangedValues(!1)),this._formatter=b,this._invalidateLayout(),this)},c.prototype.tickLength=function(a){if(null==a)return this._tickLength;if(0>a)throw new Error("tick length must be positive");return this._tickLength=a,this._invalidateLayout(),this},c.prototype.tickLabelPadding=function(a){if(null==a)return this._tickLabelPadding;if(0>a)throw new Error("tick label padding must be positive");return this._tickLabelPadding=a,this._invalidateLayout(),this},c.prototype.orient=function(a){if(null==a)return this._orientation;var b=a.toLowerCase();if("top"!==b&&"bottom"!==b&&"left"!==b&&"right"!==b)throw new Error("unsupported orientation");return this._orientation=b,this._invalidateLayout(),this},c.prototype.showEndTickLabels=function(a){return null==a?this._showEndTickLabels:(this._showEndTickLabels=a,this._render(),this)},c.prototype._hideEndTickLabels=function(){var b=this,c=this.element.select(".bounding-box")[0][0].getBoundingClientRect(),d=function(a){return Math.floor(c.left)<=Math.ceil(a.left)&&Math.floor(c.top)<=Math.ceil(a.top)&&Math.floor(a.right)<=Math.ceil(c.left+b.availableWidth)&&Math.floor(a.bottom)<=Math.ceil(c.top+b.availableHeight)},e=this._tickLabelContainer.selectAll("."+a.Abstract.Axis.TICK_LABEL_CLASS);if(0!==e[0].length){var f=e[0][0];d(f.getBoundingClientRect())||d3.select(f).style("visibility","hidden");var g=e[0][e[0].length-1];d(g.getBoundingClientRect())||d3.select(g).style("visibility","hidden")}},c.prototype._hideOverlappingTickLabels=function(){var b,c=this._tickLabelContainer.selectAll("."+a.Abstract.Axis.TICK_LABEL_CLASS).filter(function(){return"visible"===d3.select(this).style("visibility")});c.each(function(){var c=this.getBoundingClientRect(),d=d3.select(this);null!=b&&a.Util.DOM.boxesOverlap(c,b)?d.style("visibility","hidden"):(b=c,d.style("visibility","visible"))})},c.TICK_MARK_CLASS="tick-mark",c.TICK_LABEL_CLASS="tick-label",c}(a.Abstract.Component);b.Axis=c}(a.Abstract||(a.Abstract={}));a.Abstract}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(a,d){if(d=d.toLowerCase(),"top"!==d&&"bottom"!==d)throw new Error("unsupported orientation: "+d);b.call(this,a,d),this.classed("time-axis",!0),this.previousSpan=0,this.previousIndex=c.minorIntervals.length-1,this.tickLabelPadding(5)}return __extends(c,b),c.prototype._computeHeight=function(){if(null!==this._computedHeight)return this._computedHeight;var a=this._measureTextHeight(this._majorTickLabels)+this._measureTextHeight(this._minorTickLabels);return this.tickLength(a),this._computedHeight=a+2*this.tickLabelPadding(),this._computedHeight},c.prototype.calculateWorstWidth=function(b,c){var d=new Date(9999,8,29,12,59,9999);return a.Util.Text.getTextWidth(b,d3.time.format(c)(d))},c.prototype.getIntervalLength=function(a){var b=this._scale.domain()[0],c=Math.abs(this._scale.scale(a.timeUnit.offset(b,a.step))-this._scale.scale(b));return c},c.prototype.isEnoughSpace=function(a,b){var c=this.calculateWorstWidth(a,b.formatString)+2*this.tickLabelPadding(),d=Math.min(this.getIntervalLength(b),this.availableWidth);return d>c},c.prototype._setup=function(){return b.prototype._setup.call(this),this._majorTickLabels=this.content.append("g").classed(a.Abstract.Axis.TICK_LABEL_CLASS,!0),this._minorTickLabels=this.content.append("g").classed(a.Abstract.Axis.TICK_LABEL_CLASS,!0),this},c.prototype.getTickLevel=function(){var b=c.minorIntervals.length-1,d=Math.abs(this._scale.domain()[1]-this._scale.domain()[0]);d<=this.previousSpan+1&&(b=this.previousIndex);for(var e=b;e>=0;){if(!this.isEnoughSpace(this._minorTickLabels,c.minorIntervals[e])||!this.isEnoughSpace(this._majorTickLabels,c.majorIntervals[e])){e++; -break}e--}return e=Math.min(e,c.minorIntervals.length-1),0>e&&(e=0,a.Util.Methods.warn("could not find suitable interval to display labels")),this.previousIndex=Math.max(0,e-1),this.previousSpan=d,e},c.prototype._getTickIntervalValues=function(a){return this._scale.tickInterval(a.timeUnit,a.step)},c.prototype._getTickValues=function(){var a=this.getTickLevel(),b=this._getTickIntervalValues(c.minorIntervals[a]),d=this._getTickIntervalValues(c.majorIntervals[a]);return b.concat(d)},c.prototype._measureTextHeight=function(b){var c=b.append("g").classed(a.Abstract.Axis.TICK_LABEL_CLASS,!0),d=a.Util.Text.getTextHeight(c.append("text"));return c.remove(),d},c.prototype.renderTickLabels=function(b,c,d){var e=this;b.selectAll("."+a.Abstract.Axis.TICK_LABEL_CLASS).remove();var f=this._scale.tickInterval(c.timeUnit,c.step);f.splice(0,0,this._scale.domain()[0]),f.push(this._scale.domain()[1]);var g=1===c.step,h=[];g?f.map(function(a,b){b+1>=f.length||h.push(new Date((f[b+1].valueOf()-f[b].valueOf())/2+f[b].valueOf()))}):h=f,h=h.filter(function(a){return e.canFitLabelFilter(b,a,d3.time.format(c.formatString)(a),g)});var i=b.selectAll("."+a.Abstract.Axis.TICK_LABEL_CLASS).data(h,function(a){return a.valueOf()}),j=i.enter().append("g").classed(a.Abstract.Axis.TICK_LABEL_CLASS,!0);j.append("text");var k=g?0:this.tickLabelPadding(),l="bottom"===this._orientation?this.tickLength()/2*d:this.availableHeight-this.tickLength()/2*d+2*this.tickLabelPadding(),m=i.selectAll("text");m.size()>0&&a.Util.DOM.translate(m,k,l),i.exit().remove(),i.attr("transform",function(a){return"translate("+e._scale.scale(a)+",0)"});var n=g?"middle":"left";i.selectAll("text").text(function(a){return d3.time.format(c.formatString)(a)}).style("text-anchor",n)},c.prototype.canFitLabelFilter=function(b,c,d,e){var f,g,h=a.Util.Text.getTextWidth(b,d)+this.tickLabelPadding();return e?(f=this._scale.scale(c)+h/2,g=this._scale.scale(c)-h/2):(f=this._scale.scale(c)+h,g=this._scale.scale(c)),f0},c.prototype.adjustTickLength=function(b,c){var d=this._getTickIntervalValues(c),e=this._tickMarkContainer.selectAll("."+a.Abstract.Axis.TICK_MARK_CLASS).filter(function(a){return d.map(function(a){return a.valueOf()}).indexOf(a.valueOf())>=0});"top"===this._orientation&&(b=this.availableHeight-b),e.attr("y2",b)},c.prototype.generateLabellessTicks=function(b){if(!(0>b)){var d=this._getTickIntervalValues(c.minorIntervals[b]),e=this._getTickValues().concat(d),f=this._tickMarkContainer.selectAll("."+a.Abstract.Axis.TICK_MARK_CLASS).data(e);f.enter().append("line").classed(a.Abstract.Axis.TICK_MARK_CLASS,!0),f.attr(this._generateTickMarkAttrHash()),f.exit().remove(),this.adjustTickLength(this.tickLabelPadding(),c.minorIntervals[b])}},c.prototype._doRender=function(){b.prototype._doRender.call(this);var a=this.getTickLevel();this.renderTickLabels(this._minorTickLabels,c.minorIntervals[a],1),this.renderTickLabels(this._majorTickLabels,c.majorIntervals[a],2);var d=this._scale.domain(),e=this._scale.scale(d[1])-this._scale.scale(d[0]);return 1.5*this.getIntervalLength(c.minorIntervals[a])>=e&&this.generateLabellessTicks(a-1),this.adjustTickLength(this.tickLength()/2,c.minorIntervals[a]),this.adjustTickLength(this.tickLength(),c.majorIntervals[a]),this},c.minorIntervals=[{timeUnit:d3.time.second,step:1,formatString:"%I:%M:%S %p"},{timeUnit:d3.time.second,step:5,formatString:"%I:%M:%S %p"},{timeUnit:d3.time.second,step:10,formatString:"%I:%M:%S %p"},{timeUnit:d3.time.second,step:15,formatString:"%I:%M:%S %p"},{timeUnit:d3.time.second,step:30,formatString:"%I:%M:%S %p"},{timeUnit:d3.time.minute,step:1,formatString:"%I:%M %p"},{timeUnit:d3.time.minute,step:5,formatString:"%I:%M %p"},{timeUnit:d3.time.minute,step:10,formatString:"%I:%M %p"},{timeUnit:d3.time.minute,step:15,formatString:"%I:%M %p"},{timeUnit:d3.time.minute,step:30,formatString:"%I:%M %p"},{timeUnit:d3.time.hour,step:1,formatString:"%I %p"},{timeUnit:d3.time.hour,step:3,formatString:"%I %p"},{timeUnit:d3.time.hour,step:6,formatString:"%I %p"},{timeUnit:d3.time.hour,step:12,formatString:"%I %p"},{timeUnit:d3.time.day,step:1,formatString:"%a %e"},{timeUnit:d3.time.day,step:1,formatString:"%e"},{timeUnit:d3.time.month,step:1,formatString:"%B"},{timeUnit:d3.time.month,step:1,formatString:"%b"},{timeUnit:d3.time.month,step:3,formatString:"%B"},{timeUnit:d3.time.month,step:6,formatString:"%B"},{timeUnit:d3.time.year,step:1,formatString:"%Y"},{timeUnit:d3.time.year,step:1,formatString:"%y"},{timeUnit:d3.time.year,step:5,formatString:"%Y"},{timeUnit:d3.time.year,step:25,formatString:"%Y"},{timeUnit:d3.time.year,step:50,formatString:"%Y"},{timeUnit:d3.time.year,step:100,formatString:"%Y"},{timeUnit:d3.time.year,step:200,formatString:"%Y"},{timeUnit:d3.time.year,step:500,formatString:"%Y"},{timeUnit:d3.time.year,step:1e3,formatString:"%Y"}],c.majorIntervals=[{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.month,step:1,formatString:"%B %Y"},{timeUnit:d3.time.month,step:1,formatString:"%B %Y"},{timeUnit:d3.time.year,step:1,formatString:"%Y"},{timeUnit:d3.time.year,step:1,formatString:"%Y"},{timeUnit:d3.time.year,step:1,formatString:"%Y"},{timeUnit:d3.time.year,step:1,formatString:"%Y"},{timeUnit:d3.time.year,step:1e5,formatString:""},{timeUnit:d3.time.year,step:1e5,formatString:""},{timeUnit:d3.time.year,step:1e5,formatString:""},{timeUnit:d3.time.year,step:1e5,formatString:""},{timeUnit:d3.time.year,step:1e5,formatString:""},{timeUnit:d3.time.year,step:1e5,formatString:""},{timeUnit:d3.time.year,step:1e5,formatString:""},{timeUnit:d3.time.year,step:1e5,formatString:""},{timeUnit:d3.time.year,step:1e5,formatString:""}],c}(a.Abstract.Axis);b.Time=c}(a.Axis||(a.Axis={}));a.Axis}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(a,c,d){b.call(this,a,c,d),this.tickLabelPositioning="center",this.showFirstTickLabel=!1,this.showLastTickLabel=!1}return __extends(c,b),c.prototype._computeWidth=function(){var b=this._getTickValues(),c=function(a){var b=Math.floor(Math.log(Math.abs(a))/Math.LN10);return b>0?b:1},d=Math.max.apply(null,b.map(c)),e=this._formatter.precision(),f=-(Math.pow(10,d)+Math.pow(10,-e)),g=this._tickLabelContainer.append("text").classed(a.Abstract.Axis.TICK_LABEL_CLASS,!0),h=this._formatter.format(f),i=g.text(h).node().getComputedTextLength();return g.remove(),this._computedWidth="center"===this.tickLabelPositioning?this.tickLength()+this.tickLabelPadding()+i:Math.max(this.tickLength(),this.tickLabelPadding()+i),this._computedWidth},c.prototype._computeHeight=function(){var b=this._tickLabelContainer.append("text").classed(a.Abstract.Axis.TICK_LABEL_CLASS,!0),c=a.Util.DOM.getBBox(b.text("test")).height;return b.remove(),this._computedHeight="center"===this.tickLabelPositioning?this.tickLength()+this.tickLabelPadding()+c:Math.max(this.tickLength(),this.tickLabelPadding()+c),this._computedHeight},c.prototype._getTickValues=function(){return this._scale.ticks()},c.prototype._doRender=function(){var c=this;b.prototype._doRender.call(this);var d={x:0,y:0,dx:"0em",dy:"0.3em"},e=this.tickLength(),f=this.tickLabelPadding(),g="middle",h=0,i=0,j=0,k=0;if(this._isHorizontal())switch(this.tickLabelPositioning){case"left":g="end",h=-f,k=f;break;case"center":k=e+f;break;case"right":g="start",h=f,k=f}else switch(this.tickLabelPositioning){case"top":d.dy="-0.3em",j=f,i=-f;break;case"center":j=e+f;break;case"bottom":d.dy="1em",j=f,i=f}var l=this._generateTickMarkAttrHash();switch(this._orientation){case"bottom":d.x=l.x1,d.dy="0.95em",i=l.y1+k;break;case"top":d.x=l.x1,d.dy="-.25em",i=l.y1-k;break;case"left":g="end",h=l.x1-j,d.y=l.y1;break;case"right":g="start",h=l.x1+j,d.y=l.y1}var m=this._getTickValues(),n=this._tickLabelContainer.selectAll("."+a.Abstract.Axis.TICK_LABEL_CLASS).data(m);n.enter().append("text").classed(a.Abstract.Axis.TICK_LABEL_CLASS,!0),n.exit().remove();var o=function(a){return c._formatter.format(a)};n.style("text-anchor",g).style("visibility","visible").attr(d).text(o);var p="translate("+h+", "+i+")";return this._tickLabelContainer.attr("transform",p),this.showEndTickLabels()||this._hideEndTickLabels(),this._hideOverlappingTickLabels(),this},c.prototype.tickLabelPosition=function(a){if(null==a)return this.tickLabelPositioning;var b=a.toLowerCase();if(this._isHorizontal()){if("left"!==b&&"center"!==b&&"right"!==b)throw new Error(b+" is not a valid tick label position for a horizontal NumericAxis")}else if("top"!==b&&"center"!==b&&"bottom"!==b)throw new Error(b+" is not a valid tick label position for a vertical NumericAxis");return this.tickLabelPositioning=b,this._invalidateLayout(),this},c.prototype.showEndTickLabel=function(a,b){if(this._isHorizontal()&&"left"===a||!this._isHorizontal()&&"bottom"===a)return void 0===b?this.showFirstTickLabel:(this.showFirstTickLabel=b,this._render());if(this._isHorizontal()&&"right"===a||!this._isHorizontal()&&"top"===a)return void 0===b?this.showLastTickLabel:(this.showLastTickLabel=b,this._render());throw new Error("Attempt to show "+a+" tick label on a "+(this._isHorizontal()?"horizontal":"vertical")+" axis")},c}(a.Abstract.Axis);b.Numeric=c}(a.Axis||(a.Axis={}));a.Axis}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(c,d,e){"undefined"==typeof d&&(d="bottom"),"undefined"==typeof e&&(e=new a.Formatter.Identity);var f=this;if(b.call(this,c,d,e),this.classed("category-axis",!0),"bands"!==c.rangeType())throw new Error("Only rangeBands category axes are implemented");this._scale.broadcaster.registerListener(this,function(){return f._invalidateLayout()})}return __extends(c,b),c.prototype._setup=function(){return b.prototype._setup.call(this),this.measurer=new a.Util.Text.CachingCharacterMeasurer(this._tickLabelContainer),this},c.prototype._requestedSpace=function(a,b){var c=this._isHorizontal()?0:this.tickLength()+this.tickLabelPadding(),d=this._isHorizontal()?this.tickLength()+this.tickLabelPadding():0;if(0>a||0>b)return{width:a,height:b,wantsWidth:!this._isHorizontal(),wantsHeight:this._isHorizontal()};if(0===this._scale.domain().length)return{width:0,height:0,wantsWidth:!1,wantsHeight:!1};var e=this._scale.copy();e.range(this._isHorizontal()?[0,a]:[b,0]);var f=this.measureTicks(a,b,e,this._scale.domain());return{width:f.usedWidth+c,height:f.usedHeight+d,wantsWidth:!f.textFits,wantsHeight:!f.textFits}},c.prototype._getTickValues=function(){return this._scale.domain()},c.prototype.measureTicks=function(b,c,d,e){var f="string"!=typeof e[0],g=this,h=[],i=function(a){return g.measurer.measure(a)},j=f?function(a){return e.each(a)}:function(a){return e.forEach(a)};j(function(e){var j,k=d.fullBandStartAndWidth(e)[1],l=g._isHorizontal()?k:b-g.tickLength()-g.tickLabelPadding(),m=g._isHorizontal()?c-g.tickLength()-g.tickLabelPadding():k,n=g._formatter;if(f){var o=d3.select(this),p={left:"right",right:"left",top:"center",bottom:"center"},q={left:"center",right:"center",top:"bottom",bottom:"top"};j=a.Util.Text.writeText(n.format(e),l,m,i,!0,{g:o,xAlign:p[g._orientation],yAlign:q[g._orientation]})}else j=a.Util.Text.writeText(n.format(e),l,m,i,!0);h.push(j)});var k=this._isHorizontal()?d3.sum:d3.max,l=this._isHorizontal()?d3.max:d3.sum;return{textFits:h.every(function(a){return a.textFits}),usedWidth:k(h,function(a){return a.usedWidth}),usedHeight:l(h,function(a){return a.usedHeight})}},c.prototype._doRender=function(){var c=this;b.prototype._doRender.call(this);var d=this._tickLabelContainer.selectAll("."+a.Abstract.Axis.TICK_LABEL_CLASS).data(this._scale.domain(),function(a){return a}),e=function(a){var b=c._scale.fullBandStartAndWidth(a),d=b[0],e=c._isHorizontal()?d:0,f=c._isHorizontal()?0:d;return"translate("+e+","+f+")"};d.enter().append("g").classed(a.Abstract.Axis.TICK_LABEL_CLASS,!0),d.exit().remove(),d.attr("transform",e),d.text(""),this.measureTicks(this.availableWidth,this.availableHeight,this._scale,d);var f=this._isHorizontal()?[this._scale.rangeBand()/2,0]:[0,this._scale.rangeBand()/2],g="right"===this._orientation?this.tickLength()+this.tickLabelPadding():0,h="bottom"===this._orientation?this.tickLength()+this.tickLabelPadding():0;return a.Util.DOM.translate(this._tickLabelContainer,g,h),a.Util.DOM.translate(this._tickMarkContainer,f[0],f[1]),this},c.prototype._computeLayout=function(a,c,d,e){return this.measurer.clear(),b.prototype._computeLayout.call(this,a,c,d,e)},c}(a.Abstract.Axis);b.Category=c}(a.Axis||(a.Axis={}));a.Axis}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(a,c){if("undefined"==typeof a&&(a=""),"undefined"==typeof c&&(c="horizontal"),b.call(this),this.classed("label",!0),this.text(a),c=c.toLowerCase(),"vertical-left"===c&&(c="left"),"vertical-right"===c&&(c="right"),"horizontal"!==c&&"left"!==c&&"right"!==c)throw new Error(c+" is not a valid orientation for LabelComponent");this.orientation=c,this.xAlign("center").yAlign("center")}return __extends(c,b),c.prototype.xAlign=function(a){var c=a.toLowerCase();return b.prototype.xAlign.call(this,c),this.xAlignment=c,this},c.prototype.yAlign=function(a){var c=a.toLowerCase();return b.prototype.yAlign.call(this,c),this.yAlignment=c,this},c.prototype._requestedSpace=function(a,b){var c=this.measurer(this._text),d="horizontal"===this.orientation?c.width:c.height,e="horizontal"===this.orientation?c.height:c.width;return{width:Math.min(d,a),height:Math.min(e,b),wantsWidth:d>a,wantsHeight:e>b}},c.prototype._setup=function(){return b.prototype._setup.call(this),this.textContainer=this.content.append("g"),this.measurer=a.Util.Text.getTextMeasure(this.textContainer),this.text(this._text),this},c.prototype.text=function(a){return void 0===a?this._text:(this._text=a,this._invalidateLayout(),this)},c.prototype._doRender=function(){b.prototype._doRender.call(this),this.textContainer.selectAll("text").remove();var c="horizontal"===this.orientation?this.availableWidth:this.availableHeight,d=a.Util.Text.getTruncatedText(this._text,c,this.measurer);return"horizontal"===this.orientation?a.Util.Text.writeLineHorizontally(d,this.textContainer,this.availableWidth,this.availableHeight,this.xAlignment,this.yAlignment):a.Util.Text.writeLineVertically(d,this.textContainer,this.availableWidth,this.availableHeight,this.xAlignment,this.yAlignment,this.orientation),this},c.prototype._computeLayout=function(c,d,e,f){return b.prototype._computeLayout.call(this,c,d,e,f),this.measurer=a.Util.Text.getTextMeasure(this.textContainer),this},c}(a.Abstract.Component);b.Label=c;var d=function(a){function b(b,c){a.call(this,b,c),this.classed("title-label",!0)}return __extends(b,a),b}(c);b.TitleLabel=d;var e=function(a){function b(b,c){a.call(this,b,c),this.classed("axis-label",!0)}return __extends(b,a),b}(c);b.AxisLabel=e}(a.Component||(a.Component={}));a.Component}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(a){b.call(this),this.classed("legend",!0),this.scale(a),this.xAlign("RIGHT").yAlign("TOP"),this.xOffset(5).yOffset(5)}return __extends(c,b),c.prototype.remove=function(){b.prototype.remove.call(this),null!=this.colorScale&&this.colorScale.broadcaster.deregisterListener(this)},c.prototype.toggleCallback=function(a){return void 0!==a?(this._toggleCallback=a,this.isOff=d3.set(),this.updateListeners(),this.updateClasses(),this):this._toggleCallback},c.prototype.hoverCallback=function(a){return void 0!==a?(this._hoverCallback=a,this.datumCurrentlyFocusedOn=void 0,this.updateListeners(),this.updateClasses(),this):this._hoverCallback},c.prototype.scale=function(a){var b=this;return null!=a?(null!=this.colorScale&&this.colorScale.broadcaster.deregisterListener(this),this.colorScale=a,this.colorScale.broadcaster.registerListener(this,function(){return b.updateDomain()}),this.updateDomain(),this):this.colorScale},c.prototype.updateDomain=function(){null!=this._toggleCallback&&(this.isOff=a.Util.Methods.intersection(this.isOff,d3.set(this.scale().domain()))),null!=this._hoverCallback&&(this.datumCurrentlyFocusedOn=this.scale().domain().indexOf(this.datumCurrentlyFocusedOn)>=0?this.datumCurrentlyFocusedOn:void 0),this._invalidateLayout()},c.prototype._computeLayout=function(a,c,d,e){b.prototype._computeLayout.call(this,a,c,d,e);var f=this.measureTextHeight(),g=this.colorScale.domain().length;return this.nRowsDrawn=Math.min(g,Math.floor(this.availableHeight/f)),this},c.prototype._requestedSpace=function(b,d){var e=this.measureTextHeight(),f=this.colorScale.domain().length,g=Math.min(f,Math.floor(d/e)),h=this.content.append("g").classed(c.SUBELEMENT_CLASS,!0),i=h.append("text"),j=d3.max(this.colorScale.domain(),function(b){return a.Util.Text.getTextWidth(i,b)});h.remove(),j=void 0===j?0:j;var k=j+e+2*c.MARGIN;return{width:Math.min(k,b),height:g*e,wantsWidth:k>b,wantsHeight:f>g}},c.prototype.measureTextHeight=function(){var b=this.content.append("g").classed(c.SUBELEMENT_CLASS,!0),d=a.Util.Text.getTextHeight(b.append("text"));return 0===d&&(d=1),b.remove(),d},c.prototype._doRender=function(){b.prototype._doRender.call(this);var d=this.colorScale.domain().slice(0,this.nRowsDrawn),e=this.measureTextHeight(),f=this.availableWidth-e-c.MARGIN,g=e/2-c.MARGIN,h=this.content.selectAll("."+c.SUBELEMENT_CLASS).data(d,function(a){return a}),i=h.enter().append("g").classed(c.SUBELEMENT_CLASS,!0);return i.append("circle").attr("cx",c.MARGIN+g).attr("cy",c.MARGIN+g).attr("r",g),i.append("text").attr("x",e).attr("y",c.MARGIN+e/2),h.exit().remove(),h.attr("transform",function(a){return"translate(0,"+d.indexOf(a)*e+")"}),h.selectAll("circle").attr("fill",this.colorScale._d3Scale),h.selectAll("text").text(function(b){var c=a.Util.Text.getTextMeasure(d3.select(this));return a.Util.Text.getTruncatedText(b,f,c)}),this.updateClasses(),this.updateListeners(),this},c.prototype.updateListeners=function(){var a=this;if(this._isSetup){var b=this.content.selectAll("."+c.SUBELEMENT_CLASS);if(null!=this._hoverCallback){var d=function(b){return function(c){a.datumCurrentlyFocusedOn=b?c:void 0,a._hoverCallback(a.datumCurrentlyFocusedOn),a.updateClasses()}};b.on("mouseover",d(!0)),b.on("mouseout",d(!1))}else b.on("mouseover",null),b.on("mouseout",null);null!=this._toggleCallback?b.on("click",function(b){var c=a.isOff.has(b);c?a.isOff.remove(b):a.isOff.add(b),a._toggleCallback(b,c),a.updateClasses()}):b.on("click",null)}},c.prototype.updateClasses=function(){var a=this;if(this._isSetup){var b=this.content.selectAll("."+c.SUBELEMENT_CLASS);null!=this._hoverCallback?(b.classed("focus",function(b){return a.datumCurrentlyFocusedOn===b}),b.classed("hover",void 0!==this.datumCurrentlyFocusedOn)):(b.classed("hover",!1),b.classed("focus",!1)),null!=this._toggleCallback?(b.classed("toggled-on",function(b){return!a.isOff.has(b)}),b.classed("toggled-off",function(b){return a.isOff.has(b)})):(b.classed("toggled-on",!1),b.classed("toggled-off",!1))}},c.SUBELEMENT_CLASS="legend-row",c.MARGIN=5,c}(a.Abstract.Component);b.Legend=c}(a.Component||(a.Component={}));a.Component}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b,c){var d=this;if(a.call(this),null==b&&null==c)throw new Error("Gridlines must have at least one scale");this.classed("gridlines",!0),this.xScale=b,this.yScale=c,null!=this.xScale&&this.xScale.broadcaster.registerListener(this,function(){return d._render()}),null!=this.yScale&&this.yScale.broadcaster.registerListener(this,function(){return d._render()})}return __extends(b,a),b.prototype.remove=function(){return a.prototype.remove.call(this),null!=this.xScale&&this.xScale.broadcaster.deregisterListener(this),null!=this.yScale&&this.yScale.broadcaster.deregisterListener(this),this},b.prototype._setup=function(){return a.prototype._setup.call(this),this.xLinesContainer=this.content.append("g").classed("x-gridlines",!0),this.yLinesContainer=this.content.append("g").classed("y-gridlines",!0),this},b.prototype._doRender=function(){return a.prototype._doRender.call(this),this.redrawXLines(),this.redrawYLines(),this},b.prototype.redrawXLines=function(){var a=this;if(null!=this.xScale){var b=this.xScale.ticks(),c=function(b){return a.xScale.scale(b)},d=this.xLinesContainer.selectAll("line").data(b);d.enter().append("line"),d.attr("x1",c).attr("y1",0).attr("x2",c).attr("y2",this.availableHeight),d.exit().remove()}},b.prototype.redrawYLines=function(){var a=this;if(null!=this.yScale){var b=this.yScale.ticks(),c=function(b){return a.yScale.scale(b)},d=this.yLinesContainer.selectAll("line").data(b);d.enter().append("line"),d.attr("x1",0).attr("y1",c).attr("x2",this.availableWidth).attr("y2",c),d.exit().remove()}},b}(a.Abstract.Component);b.Gridlines=c}(a.Component||(a.Component={}));a.Component}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){!function(a){function b(b,c,d){"undefined"==typeof c&&(c=a.ONE_DAY),"undefined"==typeof d&&(d="");var e=function(a){var e=Math.round((a.valueOf()-b)/c);return e.toString()+d};return e}a.ONE_DAY=864e5,a.generateRelativeDateFormatter=b}(a.Axis||(a.Axis={}));a.Axis}(a.Util||(a.Util={}));a.Util}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(a,c,d){if(b.call(this,a),null==c||null==d)throw new Error("XYPlots require an xScale and yScale");this.classed("xy-renderer",!0),this.project("x","x",c),this.project("y","y",d)}return __extends(c,b),c.prototype.project=function(a,c,d){return"x"===a&&null!=d&&(this.xScale=d,this._updateXDomainer()),"y"===a&&null!=d&&(this.yScale=d,this._updateYDomainer()),b.prototype.project.call(this,a,c,d),this},c.prototype._computeLayout=function(a,c,d,e){return b.prototype._computeLayout.call(this,a,c,d,e),this.xScale.range([0,this.availableWidth]),this.yScale.range([this.availableHeight,0]),this},c.prototype._updateXDomainer=function(){if(this.xScale instanceof a.Abstract.QuantitativeScale){var b=this.xScale;b._userSetDomainer||b.domainer().pad().nice()}return this},c.prototype._updateYDomainer=function(){if(this.yScale instanceof a.Abstract.QuantitativeScale){var b=this.yScale;b._userSetDomainer||b.domainer().pad().nice()}return this},c}(a.Abstract.Plot);b.XYPlot=c}(a.Abstract||(a.Abstract={}));a.Abstract}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(c,d,e){b.call(this,c,d,e),this._animators={"circles-reset":new a.Animator.Null,circles:(new a.Animator.IterativeDelay).duration(250).delay(5)},this.classed("circle-renderer",!0),this.project("r",3),this.project("fill",function(){return"steelblue"})}return __extends(c,b),c.prototype.project=function(a,c,d){return a="cx"===a?"x":a,a="cy"===a?"y":a,b.prototype.project.call(this,a,c,d),this},c.prototype._paint=function(){b.prototype._paint.call(this);var a=this._generateAttrToProjector();a.cx=a.x,a.cy=a.y,delete a.x,delete a.y;var c=this.renderArea.selectAll("circle").data(this._dataSource.data());if(c.enter().append("circle"),this._dataChanged){var d=a.r;a.r=function(){return 0},this._applyAnimatedAttributes(c,"circles-reset",a),a.r=d}this._applyAnimatedAttributes(c,"circles",a),c.exit().remove()},c}(a.Abstract.XYPlot);b.Scatter=c}(a.Plot||(a.Plot={}));a.Plot}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(c,d,e,f){b.call(this,c,d,e),this._animators={cells:new a.Animator.Null},this.classed("grid-renderer",!0),this.xScale.rangeType("bands",0,0),this.yScale.rangeType("bands",0,0),this.colorScale=f,this.project("fill","value",f)}return __extends(c,b),c.prototype.project=function(a,c,d){return b.prototype.project.call(this,a,c,d),"fill"===a&&(this.colorScale=this._projectors.fill.scale),this},c.prototype._paint=function(){b.prototype._paint.call(this);var a=this.renderArea.selectAll("rect").data(this._dataSource.data());a.enter().append("rect");var c=this.xScale.rangeBand(),d=this.yScale.rangeBand(),e=this._generateAttrToProjector();e.width=function(){return c},e.height=function(){return d},this._applyAnimatedAttributes(a,"cells",e),a.exit().remove()},c}(a.Abstract.XYPlot);b.Grid=c}(a.Plot||(a.Plot={}));a.Plot}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(c,d,e){b.call(this,c,d,e),this._baselineValue=0,this._barAlignmentFactor=0,this._animators={"bars-reset":new a.Animator.Null,bars:new a.Animator.IterativeDelay,baseline:new a.Animator.Null},this.classed("bar-renderer",!0),this.project("fill",function(){return"steelblue"}),this.baseline(this._baselineValue)}return __extends(c,b),c.prototype._setup=function(){return b.prototype._setup.call(this),this._baseline=this.renderArea.append("line").classed("baseline",!0),this._bars=this.renderArea.selectAll("rect").data([]),this},c.prototype._paint=function(){b.prototype._paint.call(this),this._bars=this.renderArea.selectAll("rect").data(this._dataSource.data()),this._bars.enter().append("rect");var a=this._isVertical?this.yScale:this.xScale,c=a.scale(this._baselineValue),d=this._isVertical?"y":"x",e=this._isVertical?"height":"width";if(this._dataChanged&&this._animate){var f=this._generateAttrToProjector();f[d]=function(){return c},f[e]=function(){return 0},this._applyAnimatedAttributes(this._bars,"bars-reset",f)}var g=this._generateAttrToProjector();null!=g.fill&&this._bars.attr("fill",g.fill),this._applyAnimatedAttributes(this._bars,"bars",g),this._bars.exit().remove();var h={x1:this._isVertical?0:c,y1:this._isVertical?c:0,x2:this._isVertical?this.availableWidth:c,y2:this._isVertical?c:this.availableHeight};this._applyAnimatedAttributes(this._baseline,"baseline",h)},c.prototype.baseline=function(a){return this._baselineValue=a,this._updateXDomainer(),this._updateYDomainer(),this._render(),this},c.prototype.barAlignment=function(a){var b=a.toLowerCase(),c=this.constructor._BarAlignmentToFactor;if(void 0===c[b])throw new Error("unsupported bar alignment");return this._barAlignmentFactor=c[b],this._render(),this},c.prototype.parseExtent=function(a){if("number"==typeof a)return{min:a,max:a};if(a instanceof Object&&"min"in a&&"max"in a)return a;throw new Error("input '"+a+"' can't be parsed as an IExtent")},c.prototype.selectBar=function(a,b,c){if("undefined"==typeof c&&(c=!0),!this._isSetup)return null;var d=[],e=this.parseExtent(a),f=this.parseExtent(b),g=.5;if(this._bars.each(function(){var a=this.getBBox();a.x+a.width>=e.min-g&&a.x<=e.max+g&&a.y+a.height>=f.min-g&&a.y<=f.max+g&&d.push(this)}),d.length>0){var h=d3.selectAll(d);return h.classed("selected",c),h}return null},c.prototype.deselectAll=function(){return this._isSetup&&this._bars.classed("selected",!1),this},c.prototype._updateDomainer=function(b){if(b instanceof a.Abstract.QuantitativeScale){var c=b;c._userSetDomainer||(null!=this._baselineValue?c.domainer().addPaddingException(this._baselineValue,"BAR_PLOT+"+this._plottableID).addIncludedValue(this._baselineValue,"BAR_PLOT+"+this._plottableID):c.domainer().removePaddingException("BAR_PLOT+"+this._plottableID).removeIncludedValue("BAR_PLOT+"+this._plottableID)),c._autoDomainIfAutomaticMode()}return this},c.prototype._generateAttrToProjector=function(){var d=this,e=b.prototype._generateAttrToProjector.call(this),f=this._isVertical?this.yScale:this.xScale,g=this._isVertical?this.xScale:this.yScale,h=this._isVertical?"y":"x",i=this._isVertical?"x":"y",j=g instanceof a.Scale.Ordinal&&"bands"===g.rangeType(),k=f.scale(this._baselineValue);if(null==e.width){var l=j?g.rangeBand():c.DEFAULT_WIDTH;e.width=function(){return l}}var m=e[i],n=e.width;if(j){var o=g.rangeBand();e[i]=function(a,b){return m(a,b)-n(a,b)/2+o/2}}else e[i]=function(a,b){return m(a,b)-n(a,b)*d._barAlignmentFactor};var p=e[h];return e[h]=function(a,b){var c=p(a,b);return c>k?k:c},e.height=function(a,b){return Math.abs(k-p(a,b))},e},c.DEFAULT_WIDTH=10,c._BarAlignmentToFactor={},c}(a.Abstract.XYPlot);b.BarPlot=c}(a.Abstract||(a.Abstract={}));a.Abstract}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b,c,d){a.call(this,b,c,d),this._isVertical=!0}return __extends(b,a),b.prototype._updateYDomainer=function(){return this._updateDomainer(this.yScale),this},b._BarAlignmentToFactor={left:0,center:.5,right:1},b}(a.Abstract.BarPlot);b.VerticalBar=c}(a.Plot||(a.Plot={}));a.Plot}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b,c,d){a.call(this,b,c,d),this.isVertical=!1}return __extends(b,a),b.prototype._updateXDomainer=function(){return this._updateDomainer(this.xScale),this},b.prototype._generateAttrToProjector=function(){var b=a.prototype._generateAttrToProjector.call(this),c=b.width;return b.width=b.height,b.height=c,b},b._BarAlignmentToFactor={top:0,center:.5,bottom:1},b}(a.Abstract.BarPlot);b.HorizontalBar=c}(a.Plot||(a.Plot={}));a.Plot}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(c,d,e){b.call(this,c,d,e),this._animators={"line-reset":new a.Animator.Null,line:(new a.Animator.Default).duration(600).easing("exp-in-out")},this.classed("line-renderer",!0),this.project("stroke",function(){return"steelblue"}),this.project("stroke-width",function(){return"2px"})}return __extends(c,b),c.prototype._setup=function(){return b.prototype._setup.call(this),this.linePath=this.renderArea.append("path").classed("line",!0),this},c.prototype._getResetYFunction=function(){var a=this.yScale.domain(),b=Math.max(a[0],a[1]),c=Math.min(a[0],a[1]),d=0; -0>b?d=b:c>0&&(d=c);var e=this.yScale.scale(d);return function(){return e}},c.prototype._paint=function(){b.prototype._paint.call(this);var a=this._generateAttrToProjector(),c=a.x,d=a.y;delete a.x,delete a.y,this.linePath.datum(this._dataSource.data()),this._dataChanged&&(a.d=d3.svg.line().x(c).y(this._getResetYFunction()),this._applyAnimatedAttributes(this.linePath,"line-reset",a)),a.d=d3.svg.line().x(c).y(d),this._applyAnimatedAttributes(this.linePath,"line",a)},c}(a.Abstract.XYPlot);b.Line=c}(a.Plot||(a.Plot={}));a.Plot}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(c,d,e){b.call(this,c,d,e),this.classed("area-renderer",!0),this.project("y0",0,e),this.project("fill",function(){return"steelblue"}),this.project("fill-opacity",function(){return.5}),this.project("stroke",function(){return"none"}),this._animators["area-reset"]=new a.Animator.Null,this._animators.area=(new a.Animator.Default).duration(600).easing("exp-in-out")}return __extends(c,b),c.prototype._setup=function(){return b.prototype._setup.call(this),this.areaPath=this.renderArea.append("path").classed("area",!0),this},c.prototype._onDataSourceUpdate=function(){b.prototype._onDataSourceUpdate.call(this),null!=this.yScale&&this._updateYDomainer()},c.prototype._updateYDomainer=function(){b.prototype._updateYDomainer.call(this);var a=this.yScale,c=this._projectors.y0,d=null!=c?c.accessor:null,e=null!=d?this.dataSource()._getExtent(d):[],f=2===e.length&&e[0]===e[1]?e[0]:null;return a._userSetDomainer||(null!=f?a.domainer().addPaddingException(f,"AREA_PLOT+"+this._plottableID):a.domainer().removePaddingException("AREA_PLOT+"+this._plottableID),a._autoDomainIfAutomaticMode()),this},c.prototype.project=function(a,c,d){return b.prototype.project.call(this,a,c,d),"y0"===a&&this._updateYDomainer(),this},c.prototype._getResetYFunction=function(){return this._generateAttrToProjector().y0},c.prototype._paint=function(){b.prototype._paint.call(this);var a=this._generateAttrToProjector(),c=a.x,d=a.y0,e=a.y;delete a.x,delete a.y0,delete a.y,this.areaPath.datum(this._dataSource.data()),this._dataChanged&&(a.d=d3.svg.area().x(c).y0(d).y1(this._getResetYFunction()),this._applyAnimatedAttributes(this.areaPath,"area-reset",a)),a.d=d3.svg.area().x(c).y0(d).y1(e),this._applyAnimatedAttributes(this.areaPath,"area",a)},c}(a.Plot.Line);b.Area=c}(a.Plot||(a.Plot={}));a.Plot}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){var b=function(){function a(){}return a.prototype.animate=function(a,b){return a.attr(b)},a}();a.Null=b}(a.Animator||(a.Animator={}));a.Animator}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){var b=function(){function a(){this._durationMsec=300,this._delayMsec=0,this._easing="exp-out"}return a.prototype.animate=function(a,b){return a.transition().ease(this._easing).duration(this._durationMsec).delay(this._delayMsec).attr(b)},a.prototype.duration=function(a){return void 0===a?this._durationMsec:(this._durationMsec=a,this)},a.prototype.delay=function(a){return void 0===a?this._delayMsec:(this._delayMsec=a,this)},a.prototype.easing=function(a){return void 0===a?this._easing:(this._easing=a,this)},a}();a.Default=b}(a.Animator||(a.Animator={}));a.Animator}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(){a.apply(this,arguments),this._delayMsec=15}return __extends(b,a),b.prototype.animate=function(a,b){var c=this;return a.transition().ease(this._easing).duration(this._durationMsec).delay(function(a,b){return b*c._delayMsec}).attr(b)},b}(a.Animator.Default);b.IterativeDelay=c}(a.Animator||(a.Animator={}));a.Animator}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){!function(a){function b(){e||(d3.select(document).on("keydown",d),e=!0)}function c(a,c){e||b(),null==f[a]&&(f[a]=[]),f[a].push(c)}function d(){null!=f[d3.event.keyCode]&&f[d3.event.keyCode].forEach(function(a){a(d3.event)})}var e=!1,f=[];a.initialize=b,a.addCallback=c}(a.KeyEventListener||(a.KeyEventListener={}));a.KeyEventListener}(a.Core||(a.Core={}));a.Core}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){var b=function(){function a(a){if(null==a)throw new Error("Interactions require a component to listen to");this.componentToListenTo=a}return a.prototype._anchor=function(a){this.hitBox=a},a.prototype.registerWithComponent=function(){return this.componentToListenTo.registerInteraction(this),this},a}();a.Interaction=b}(a.Abstract||(a.Abstract={}));a.Abstract}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b){a.call(this,b)}return __extends(b,a),b.prototype._anchor=function(b){var c=this;a.prototype._anchor.call(this,b),b.on(this._listenTo(),function(){var a=d3.mouse(b.node()),d=a[0],e=a[1];c._callback(d,e)})},b.prototype._listenTo=function(){return"click"},b.prototype.callback=function(a){return this._callback=a,this},b}(a.Abstract.Interaction);b.Click=c;var d=function(a){function b(b){a.call(this,b)}return __extends(b,a),b.prototype._listenTo=function(){return"dblclick"},b}(c);b.DoubleClick=d}(a.Interaction||(a.Interaction={}));a.Interaction}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b){a.call(this,b)}return __extends(b,a),b.prototype._anchor=function(b){var c=this;a.prototype._anchor.call(this,b),b.on("mousemove",function(){var a=d3.mouse(b.node()),d=a[0],e=a[1];c.mousemove(d,e)})},b.prototype.mousemove=function(){},b}(a.Abstract.Interaction);b.Mousemove=c}(a.Interaction||(a.Interaction={}));a.Interaction}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(a,c){b.call(this,a),this.activated=!1,this.keyCode=c}return __extends(c,b),c.prototype._anchor=function(c){var d=this;b.prototype._anchor.call(this,c),c.on("mouseover",function(){d.activated=!0}),c.on("mouseout",function(){d.activated=!1}),a.Core.KeyEventListener.addCallback(this.keyCode,function(){d.activated&&null!=d._callback&&d._callback()})},c.prototype.callback=function(a){return this._callback=a,this},c}(a.Abstract.Interaction);b.Key=c}(a.Interaction||(a.Interaction={}));a.Interaction}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b,c,d){var e=this;if(a.call(this,b),null==c||null==d)throw new Error("panZoomInteractions require an xScale and yScale");this.xScale=c,this.yScale=d,this.zoom=d3.behavior.zoom(),this.zoom.x(this.xScale._d3Scale),this.zoom.y(this.yScale._d3Scale),this.zoom.on("zoom",function(){return e.rerenderZoomed()})}return __extends(b,a),b.prototype.resetZoom=function(){var a=this;this.zoom=d3.behavior.zoom(),this.zoom.x(this.xScale._d3Scale),this.zoom.y(this.yScale._d3Scale),this.zoom.on("zoom",function(){return a.rerenderZoomed()}),this.zoom(this.hitBox)},b.prototype._anchor=function(b){a.prototype._anchor.call(this,b),this.zoom(b)},b.prototype.rerenderZoomed=function(){var a=this.xScale._d3Scale.domain(),b=this.yScale._d3Scale.domain();this.xScale.domain(a),this.yScale.domain(b)},b}(a.Abstract.Interaction);b.PanZoom=c}(a.Interaction||(a.Interaction={}));a.Interaction}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b){var c=this;a.call(this,b),this.dragInitialized=!1,this.origin=[0,0],this.location=[0,0],this.dragBehavior=d3.behavior.drag(),this.dragBehavior.on("dragstart",function(){return c._dragstart()}),this.dragBehavior.on("drag",function(){return c._drag()}),this.dragBehavior.on("dragend",function(){return c._dragend()})}return __extends(b,a),b.prototype.callback=function(a){return this.callbackToCall=a,this},b.prototype._dragstart=function(){var a=this.componentToListenTo.availableWidth,b=this.componentToListenTo.availableHeight,c=function(a,b){return function(c){return Math.min(Math.max(c,a),b)}};this.constrainX=c(0,a),this.constrainY=c(0,b)},b.prototype._drag=function(){this.dragInitialized||(this.origin=[d3.event.x,d3.event.y],this.dragInitialized=!0),this.location=[this.constrainX(d3.event.x),this.constrainY(d3.event.y)]},b.prototype._dragend=function(){this.dragInitialized&&(this.dragInitialized=!1,this._doDragend())},b.prototype._doDragend=function(){null!=this.callbackToCall&&this.callbackToCall([this.origin,this.location])},b.prototype._anchor=function(b){return a.prototype._anchor.call(this,b),b.call(this.dragBehavior),this},b.prototype.setupZoomCallback=function(a,b){function c(c){return null==c?(f&&(null!=a&&a.domain(d),null!=b&&b.domain(e)),void(f=!f)):(f=!1,null!=a&&a.domain([a.invert(c.xMin),a.invert(c.xMax)]),null!=b&&b.domain([b.invert(c.yMax),b.invert(c.yMin)]),void this.clearBox())}var d=null!=a?a.domain():null,e=null!=b?b.domain():null,f=!1;return this.callback(c),this},b}(a.Abstract.Interaction);b.Drag=c}(a.Interaction||(a.Interaction={}));a.Interaction}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(){a.apply(this,arguments),this.boxIsDrawn=!1}return __extends(b,a),b.prototype._dragstart=function(){a.prototype._dragstart.call(this),null!=this.callbackToCall&&this.callbackToCall(null),this.clearBox()},b.prototype.clearBox=function(){return null!=this.dragBox?(this.dragBox.attr("height",0).attr("width",0),this.boxIsDrawn=!1,this):void 0},b.prototype.setBox=function(a,b,c,d){if(null!=this.dragBox){var e=Math.abs(a-b),f=Math.abs(c-d),g=Math.min(a,b),h=Math.min(c,d);return this.dragBox.attr({x:g,y:h,width:e,height:f}),this.boxIsDrawn=e>0&&f>0,this}},b.prototype._anchor=function(c){a.prototype._anchor.call(this,c);var d=b.CLASS_DRAG_BOX,e=this.componentToListenTo.foregroundContainer;return this.dragBox=e.append("rect").classed(d,!0).attr("x",0).attr("y",0),this},b.CLASS_DRAG_BOX="drag-box",b}(a.Interaction.Drag);b.DragBox=c}(a.Interaction||(a.Interaction={}));a.Interaction}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(){a.apply(this,arguments)}return __extends(b,a),b.prototype._drag=function(){a.prototype._drag.call(this),this.setBox(this.origin[0],this.location[0])},b.prototype._doDragend=function(){if(null!=this.callbackToCall){var a=Math.min(this.origin[0],this.location[0]),b=Math.max(this.origin[0],this.location[0]),c={xMin:a,xMax:b};this.callbackToCall(c)}},b.prototype.setBox=function(b,c){return a.prototype.setBox.call(this,b,c,0,this.componentToListenTo.availableHeight),this},b}(a.Interaction.DragBox);b.XDragBox=c}(a.Interaction||(a.Interaction={}));a.Interaction}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(){a.apply(this,arguments)}return __extends(b,a),b.prototype._drag=function(){a.prototype._drag.call(this),this.setBox(this.origin[0],this.location[0],this.origin[1],this.location[1])},b.prototype._doDragend=function(){if(null!=this.callbackToCall){var a=Math.min(this.origin[0],this.location[0]),b=Math.max(this.origin[0],this.location[0]),c=Math.min(this.origin[1],this.location[1]),d=Math.max(this.origin[1],this.location[1]),e={xMin:a,xMax:b,yMin:c,yMax:d};this.callbackToCall(e)}},b}(a.Interaction.DragBox);b.XYDragBox=c}(a.Interaction||(a.Interaction={}));a.Interaction}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(){a.apply(this,arguments)}return __extends(b,a),b.prototype._drag=function(){a.prototype._drag.call(this),this.setBox(this.origin[1],this.location[1])},b.prototype._doDragend=function(){if(null!=this.callbackToCall){var a=Math.min(this.origin[1],this.location[1]),b=Math.max(this.origin[1],this.location[1]),c={yMin:a,yMax:b};this.callbackToCall(c)}},b.prototype.setBox=function(b,c){return a.prototype.setBox.call(this,0,this.componentToListenTo.availableWidth,b,c),this},b}(a.Interaction.DragBox);b.YDragBox=c}(a.Interaction||(a.Interaction={}));a.Interaction}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(){b.call(this),this.xTable=new a.Component.Table,this.yTable=new a.Component.Table,this.centerComponent=new a.Component.Group,this.xyTable=(new a.Component.Table).addComponent(0,0,this.yTable).addComponent(1,1,this.xTable).addComponent(0,1,this.centerComponent),this.addComponent(1,0,this.xyTable)}return __extends(c,b),c.prototype.yAxis=function(a){if(null!=a){if(null!=this._yAxis)throw new Error("yAxis already assigned!");return this._yAxis=a,this.yTable.addComponent(0,1,this._yAxis),this}return this._yAxis},c.prototype.xAxis=function(a){if(null!=a){if(null!=this._xAxis)throw new Error("xAxis already assigned!");return this._xAxis=a,this.xTable.addComponent(0,0,this._xAxis),this}return this._xAxis},c.prototype.yLabel=function(b){if(null!=b){if(null!=this._yLabel){if("string"==typeof b)return this._yLabel.text(b),this;throw new Error("yLabel already assigned!")}return"string"==typeof b&&(b=new a.Component.AxisLabel(b,"vertical-left")),this._yLabel=b,this.yTable.addComponent(0,0,this._yLabel),this}return this._yLabel},c.prototype.xLabel=function(b){if(null!=b){if(null!=this._xLabel){if("string"==typeof b)return this._xLabel.text(b),this;throw new Error("xLabel already assigned!")}return"string"==typeof b&&(b=new a.Component.AxisLabel(b,"horizontal")),this._xLabel=b,this.xTable.addComponent(1,0,this._xLabel),this}return this._xLabel},c.prototype.titleLabel=function(b){if(null!=b){if(null!=this._titleLabel){if("string"==typeof b)return this._titleLabel.text(b),this;throw new Error("titleLabel already assigned!")}return"string"==typeof b&&(b=new a.Component.TitleLabel(b,"horizontal")),this._titleLabel=b,this.addComponent(0,0,this._titleLabel),this}return this._titleLabel},c.prototype.center=function(a){return this.centerComponent.merge(a),this},c}(a.Component.Table);b.StandardChart=c}(a.Template||(a.Template={}));a.Template}(Plottable||(Plottable={})); \ No newline at end of file +var Plottable;!function(a){!function(a){!function(a){function b(a,b,c){return Math.min(b,c)<=a&&a<=Math.max(b,c)}function c(a){null!=window.console&&(null!=window.console.warn?console.warn(a):null!=window.console.log&&console.log(a))}function d(a,b){if(a.length!==b.length)throw new Error("attempted to add arrays of unequal length");return a.map(function(c,d){return a[d]+b[d]})}function e(a,b){var c=d3.set();return a.forEach(function(a){b.has(a)&&c.add(a)}),c}function f(a){return"function"==typeof a?a:"string"==typeof a&&"#"!==a[0]?function(b){return b[a]}:function(){return a}}function g(a,b){var c=d3.set();return a.forEach(function(a){return c.add(a)}),b.forEach(function(a){return c.add(a)}),c}function h(a,b){var c=f(a);return function(a,d){return c(a,d,b.dataSource().metadata())}}function i(a){var b={};return a.forEach(function(a){return b[a]=!0}),d3.keys(b)}function j(a){var b=d3.set(),c=[];return a.forEach(function(a){b.has(a)||(b.add(a),c.push(a))}),c}function k(a,b){for(var c=[],d=0;b>d;d++)c[d]="function"==typeof a?a(d):a;return c}function l(a){return Array.prototype.concat.apply([],a)}function m(a,b){if(null==a||null==b)return a===b;if(a.length!==b.length)return!1;for(var c=0;cd;){var f=d+e>>>1,g=null==c?b[f]:c(b[f]);a>g?d=f+1:e=f}return d}a.sortedIndex=b}(a.OpenSource||(a.OpenSource={}));a.OpenSource}(a.Util||(a.Util={}));a.Util}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){var b=function(){function a(){this.counter={}}return a.prototype.setDefault=function(a){null==this.counter[a]&&(this.counter[a]=0)},a.prototype.increment=function(a){return this.setDefault(a),++this.counter[a]},a.prototype.decrement=function(a){return this.setDefault(a),--this.counter[a]},a.prototype.get=function(a){return this.setDefault(a),this.counter[a]},a}();a.IDCounter=b}(a.Util||(a.Util={}));a.Util}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){var b=function(){function a(){this.keyValuePairs=[]}return a.prototype.set=function(a,b){if(a!==a)throw new Error("NaN may not be used as a key to the StrictEqualityAssociativeArray");for(var c=0;cb){var h=e("."),i=Math.floor(b/h);return"...".substr(0,i)}for(;f+g>b;)d=d.substr(0,d.length-1).trim(),f=e(d);if(e(d+"...")>b)throw new Error("_addEllipsesToLine failed :(");return d+"..."}function k(b,c,d,e,f,g){"undefined"==typeof f&&(f="left"),"undefined"==typeof g&&(g="top");var h={left:0,center:.5,right:1},i={top:0,center:.5,bottom:1};if(void 0===h[f]||void 0===i[g])throw new Error("unrecognized alignment x:"+f+", y:"+g);var j=c.append("g"),k=j.append("text");k.text(b);var l=a.DOM.getBBox(k),m=l.height,n=l.width;if(n>d||m>e)return a.Methods.warn("Insufficient space to fit text: "+b),k.text(""),{width:0,height:0};var o={left:"start",center:"middle",right:"end"},p=o[f],q=d*h[f],r=e*i[g],s=.85-i[g];return k.attr("text-anchor",p).attr("y",s+"em"),a.DOM.translate(j,q,r),{width:n,height:m}}function l(a,b,c,d,e,f,g){if("undefined"==typeof e&&(e="left"),"undefined"==typeof f&&(f="top"),"undefined"==typeof g&&(g="right"),"right"!==g&&"left"!==g)throw new Error("unrecognized rotation: "+g);var h="right"===g,i={left:"bottom",right:"top",center:"center",top:"left",bottom:"right"},j={left:"top",right:"bottom",center:"center",top:"right",bottom:"left"},l=h?i:j,m=b.append("g"),n=k(a,m,d,c,l[f],l[e]),o=d3.transform("");return o.rotate="right"===g?90:-90,o.translate=[h?c:0,h?0:d],m.attr("transform",o.toString()),n}function m(b,c,d,e,f,g){"undefined"==typeof f&&(f="left"),"undefined"==typeof g&&(g="top");var i=h(c),j=0,l=c.append("g");b.forEach(function(b,c){var e=l.append("g");a.DOM.translate(e,0,c*i);var h=k(b,e,d,i,f,g);h.width>j&&(j=h.width)});var m=i*b.length,n=e-m,o={center:.5,top:0,bottom:1};return a.DOM.translate(l,0,n*o[g]),{width:j,height:m}}function n(b,c,d,e,f,g,i){"undefined"==typeof f&&(f="left"),"undefined"==typeof g&&(g="top"),"undefined"==typeof i&&(i="left");var j=h(c),k=0,m=c.append("g");b.forEach(function(b,c){var d=m.append("g");a.DOM.translate(d,c*j,0);var h=l(b,d,j,e,f,g,i);h.height>k&&(k=h.height)});var n=j*b.length,o=d-n,p={center:.5,left:0,right:1};return a.DOM.translate(m,o*p[f],0),{width:n,height:k}}function o(b,c,d,e,f,g){var h=null!=f?f:1.1*c>d,i=h?c:d,j=h?d:c,k=a.WordWrap.breakTextToFitRect(b,i,j,e);if(0===k.lines.length)return{textFits:k.textFits,usedWidth:0,usedHeight:0};var l,o;if(null==g){var p=h?d3.max:d3.sum,q=h?d3.sum:d3.max;l=p(k.lines,function(a){return e(a).width}),o=q(k.lines,function(a){return e(a).height})}else{var r=g.g.append("g").classed("writeText-inner-g",!0),s=h?m:n,t=s(k.lines,r,c,d,g.xAlign,g.yAlign);l=t.width,o=t.height}return{textFits:k.textFits,usedWidth:l,usedHeight:o}}b.getTextMeasure=c;var p="a",q=function(){function b(b){var g=this;this.cache=new a.Cache(c(b),p,a.Methods.objEq),this.measure=d(e(f(function(a){return g.cache.get(a)})))}return b.prototype.clear=function(){return this.cache.clear(),this},b}();b.CachingCharacterMeasurer=q,b.getTruncatedText=g,b.getTextHeight=h,b.getTextWidth=i,b._addEllipsesToLine=j,b.writeLineHorizontally=k,b.writeLineVertically=l,b.writeTextHorizontally=m,b.writeTextVertically=n,b.writeText=o}(a.Text||(a.Text={}));a.Text}(a.Util||(a.Util={}));a.Util}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){!function(b){function c(b,c,e,f){var g=function(a){return f(a).width},h=d(b,c,g),i=f("hello world").height,j=Math.floor(e/i),k=j>=h.length;return k||(h=h.splice(0,j),j>0&&(h[j-1]=a.Text._addEllipsesToLine(h[j-1],c,f))),{originalText:b,lines:h,textFits:k}}function d(a,b,c){for(var d=[],e=a.split("\n"),g=0,h=e.length;h>g;g++){var i=e[g];null!==i?d=d.concat(f(i,b,c)):d.push("")}return d}function e(a,b,c){var d=h(a),e=d.map(c),f=d3.max(e);return b>=f}function f(a,b,c){for(var d,e=[],f=h(a),i="",j=0;d||je;e++){var g=a[e];""===c||j(c[0],g,d)?c+=g:(b.push(c),c=g),d=g}return c&&b.push(c),b}function i(a){return null==a?!0:""===a.trim()}function j(a,b,c){return m.test(a)&&m.test(b)?!0:m.test(a)||m.test(b)?!1:l.test(c)||k.test(b)?!1:!0}var k=/[{\[]/,l=/[!"%),-.:;?\]}]/,m=/^\s+$/;b.breakTextToFitRect=c,b.canWrapWithoutBreakingWords=e}(a.WordWrap||(a.WordWrap={}));a.WordWrap}(a.Util||(a.Util={}));a.Util}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){!function(a){function b(a){return a.node().getBBox()}function c(b){null!=window.requestAnimationFrame?window.requestAnimationFrame(b):setTimeout(b,a.POLYFILL_TIMEOUT_MSEC)}function d(a,b){var c=a.getPropertyValue(b),d=parseFloat(c);return d!==d?0:d}function e(a){for(var b=a.node();null!==b&&"svg"!==b.nodeName;)b=b.parentNode;return null==b}function f(a){var b=window.getComputedStyle(a);return d(b,"width")+d(b,"padding-left")+d(b,"padding-right")+d(b,"border-left-width")+d(b,"border-right-width")}function g(a){var b=window.getComputedStyle(a);return d(b,"height")+d(b,"padding-top")+d(b,"padding-bottom")+d(b,"border-top-width")+d(b,"border-bottom-width")}function h(a){var b=a.node().clientWidth;if(0===b){var c=a.attr("width");if(-1!==c.indexOf("%")){for(var d=a.node().parentNode;null!=d&&0===d.clientWidth;)d=d.parentNode;if(null==d)throw new Error("Could not compute width of element");b=d.clientWidth*parseFloat(c)/100}else b=parseFloat(c)}return b}function i(a,b,c){var d=d3.transform(a.attr("transform"));return null==b?d.translate:(c=null==c?0:c,d.translate[0]=b,d.translate[1]=c,a.attr("transform",d.toString()),a)}function j(a,b){return a.rightb.right?!1:a.bottomb.bottom?!1:!0}a.getBBox=b,a.POLYFILL_TIMEOUT_MSEC=1e3/60,a.requestAnimationFramePolyfill=c,a.isSelectionRemovedFromSVG=e,a.getElementWidth=f,a.getElementHeight=g,a.getSVGPixelWidth=h,a.translate=i,a.boxesOverlap=j}(a.DOM||(a.DOM={}));a.DOM}(a.Util||(a.Util={}));a.Util}(Plottable||(Plottable={}));var Plottable;!function(a){a.MILLISECONDS_IN_ONE_DAY=864e5;var b=function(){function b(){}return b.currency=function(a,c,d,e){"undefined"==typeof a&&(a=2),"undefined"==typeof c&&(c="$"),"undefined"==typeof d&&(d=!0),"undefined"==typeof e&&(e=!0);var f=b.fixed(a);return function(a){var g=f(Math.abs(a));return e&&b._valueChanged(Math.abs(a),g)?"":(""!==g&&(d?g=c+g:g+=c,0>a&&(g="-"+g)),g)}},b.fixed=function(a,c){return"undefined"==typeof a&&(a=3),"undefined"==typeof c&&(c=!0),b.verifyPrecision(a),function(d){var e=d.toFixed(a);return c&&b._valueChanged(d,e)?"":e}},b.general=function(a,c){return"undefined"==typeof a&&(a=3),"undefined"==typeof c&&(c=!0),b.verifyPrecision(a),function(d){if("number"==typeof d){var e=Math.pow(10,a),f=String(Math.round(d*e)/e);return c&&b._valueChanged(d,f)?"":f}return String(d)}},b.identity=function(){return function(a){return String(a)}},b.percentage=function(a,c){"undefined"==typeof a&&(a=0),"undefined"==typeof c&&(c=!0);var d=b.fixed(a);return function(a){var e=d(100*a);return c&&b._valueChanged(100*a,e)?"":(""!==e&&(e+="%"),e)}},b.siSuffix=function(a){return"undefined"==typeof a&&(a=3),b.verifyPrecision(a),function(b){return d3.format("."+a+"s")(b)}},b.time=function(){var a=8,b={};return b[0]={format:".%L",filter:function(a){return 0!==a.getMilliseconds()}},b[1]={format:":%S",filter:function(a){return 0!==a.getSeconds()}},b[2]={format:"%I:%M",filter:function(a){return 0!==a.getMinutes()}},b[3]={format:"%I %p",filter:function(a){return 0!==a.getHours()}},b[4]={format:"%a %d",filter:function(a){return 0!==a.getDay()&&1!==a.getDate()}},b[5]={format:"%b %d",filter:function(a){return 1!==a.getDate()}},b[6]={format:"%b",filter:function(a){return 0!==a.getMonth()}},b[7]={format:"%Y",filter:function(){return!0}},function(c){for(var d=0;a>d;d++)if(b[d].filter(c))return d3.time.format(b[d].format)(c)}},b.relativeDate=function(b,c,d){return"undefined"==typeof b&&(b=0),"undefined"==typeof c&&(c=a.MILLISECONDS_IN_ONE_DAY),"undefined"==typeof d&&(d=""),function(a){var e=Math.round((a.valueOf()-b)/c);return e.toString()+d}},b.verifyPrecision=function(a){if(0>a||a>20)throw new RangeError("Formatter precision must be between 0 and 20")},b._valueChanged=function(a,b){return a!==parseFloat(b)},b}();a.Formatters=b}(Plottable||(Plottable={}));var Plottable;!function(a){a.version="0.24.0"}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){var b=function(){function a(){}return a.CORAL_RED="#fd373e",a.INDIGO="#5177c4",a.ROBINS_EGG_BLUE="#06bdbd",a.FERN="#62bb60",a.BURNING_ORANGE="#ff7939",a.ROYAL_HEATH="#962565",a.CONIFER="#99ce50",a.CERISE_RED="#db2e65",a.BRIGHT_SUN="#ffe43d",a.JACARTA="#2c2b6f",a.PLOTTABLE_COLORS=[a.CORAL_RED,a.INDIGO,a.ROBINS_EGG_BLUE,a.FERN,a.BURNING_ORANGE,a.ROYAL_HEATH,a.CONIFER,a.CERISE_RED,a.BRIGHT_SUN,a.JACARTA],a}();a.Colors=b}(a.Core||(a.Core={}));a.Core}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){var b=function(){function a(){this._plottableID=a.nextID++}return a.nextID=0,a}();a.PlottableObject=b}(a.Abstract||(a.Abstract={}));a.Abstract}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(c){b.call(this),this.key2callback=new a.Util.StrictEqualityAssociativeArray,this.listenable=c}return __extends(c,b),c.prototype.registerListener=function(a,b){return this.key2callback.set(a,b),this},c.prototype.broadcast=function(){for(var a=this,b=[],c=0;c=0&&(this._components.splice(b,1),this._invalidateLayout())},b.prototype._addComponent=function(a,b){return"undefined"==typeof b&&(b=!1),null==a||this._components.indexOf(a)>=0?!1:(b?this._components.unshift(a):this._components.push(a),a._parent=this,this._isAnchored&&a._anchor(this.content),this._invalidateLayout(),!0)},b.prototype.components=function(){return this._components.slice()},b.prototype.empty=function(){return 0===this._components.length},b.prototype.detachAll=function(){return this._components.slice().forEach(function(a){return a.detach()}),this},b.prototype.remove=function(){a.prototype.remove.call(this),this._components.slice().forEach(function(a){return a.remove()})},b}(a.Component);a.ComponentContainer=b}(a.Abstract||(a.Abstract={}));a.Abstract}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b){"undefined"==typeof b&&(b=[]);var c=this;a.call(this),this.classed("component-group",!0),b.forEach(function(a){return c._addComponent(a)})}return __extends(b,a),b.prototype._requestedSpace=function(a,b){var c=this._components.map(function(c){return c._requestedSpace(a,b)}),d=this.empty();return{width:d?0:d3.max(c,function(a){return a.width}),height:d?0:d3.max(c,function(a){return a.height}),wantsWidth:d?!1:c.map(function(a){return a.wantsWidth}).some(function(a){return a}),wantsHeight:d?!1:c.map(function(a){return a.wantsHeight}).some(function(a){return a})}},b.prototype.merge=function(a){return this._addComponent(a),this},b.prototype._computeLayout=function(b,c,d,e){var f=this;return a.prototype._computeLayout.call(this,b,c,d,e),this._components.forEach(function(a){a._computeLayout(0,0,f.availableWidth,f.availableHeight)}),this},b.prototype._isFixedWidth=function(){return this._components.every(function(a){return a._isFixedWidth()})},b.prototype._isFixedHeight=function(){return this._components.every(function(a){return a._isFixedHeight()})},b}(a.Abstract.ComponentContainer);b.Group=c}(a.Component||(a.Component={}));a.Component}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(a){"undefined"==typeof a&&(a=[]);var c=this;b.call(this),this.rowPadding=0,this.colPadding=0,this.rows=[],this.rowWeights=[],this.colWeights=[],this.nRows=0,this.nCols=0,this.classed("table",!0),a.forEach(function(a,b){a.forEach(function(a,d){c.addComponent(b,d,a)})})}return __extends(c,b),c.prototype.addComponent=function(a,b,c){if(this._addComponent(c)){this.nRows=Math.max(a+1,this.nRows),this.nCols=Math.max(b+1,this.nCols),this.padTableToSize(this.nRows,this.nCols);var d=this.rows[a][b];if(null!=d)throw new Error("Table.addComponent cannot be called on a cell where a component already exists (for the moment)");this.rows[a][b]=c}return this},c.prototype._removeComponent=function(a){b.prototype._removeComponent.call(this,a);var c,d;a:for(var e=0;e0&&v&&e!==x,C=f>0&&w&&f!==y;if(!B&&!C)break;if(r>5)break}return e=h-d3.sum(u.guaranteedWidths),f=i-d3.sum(u.guaranteedHeights),n=c.calcProportionalSpace(k,e),o=c.calcProportionalSpace(j,f),{colProportionalSpace:n,rowProportionalSpace:o,guaranteedWidths:u.guaranteedWidths,guaranteedHeights:u.guaranteedHeights,wantsWidth:v,wantsHeight:w}},c.prototype.determineGuarantees=function(b,c){var d=a.Util.Methods.createFilledArray(0,this.nCols),e=a.Util.Methods.createFilledArray(0,this.nRows),f=a.Util.Methods.createFilledArray(!1,this.nCols),g=a.Util.Methods.createFilledArray(!1,this.nRows);return this.rows.forEach(function(a,h){a.forEach(function(a,i){var j;j=null!=a?a._requestedSpace(b[i],c[h]):{width:0,height:0,wantsWidth:!1,wantsHeight:!1};var k=Math.min(j.width,b[i]),l=Math.min(j.height,c[h]);d[i]=Math.max(d[i],k),e[h]=Math.max(e[h],l),f[i]=f[i]||j.wantsWidth,g[h]=g[h]||j.wantsHeight})}),{guaranteedWidths:d,guaranteedHeights:e,wantsWidthArr:f,wantsHeightArr:g}},c.prototype._requestedSpace=function(a,b){var c=this.iterateLayout(a,b);return{width:d3.sum(c.guaranteedWidths),height:d3.sum(c.guaranteedHeights),wantsWidth:c.wantsWidth,wantsHeight:c.wantsHeight}},c.prototype._computeLayout=function(c,d,e,f){var g=this;b.prototype._computeLayout.call(this,c,d,e,f);var h=this.iterateLayout(this.availableWidth,this.availableHeight),i=a.Util.Methods.addArrays(h.rowProportionalSpace,h.guaranteedHeights),j=a.Util.Methods.addArrays(h.colProportionalSpace,h.guaranteedWidths),k=0;this.rows.forEach(function(a,b){var c=0;a.forEach(function(a,d){null!=a&&a._computeLayout(c,k,j[d],i[b]),c+=j[d]+g.colPadding}),k+=i[b]+g.rowPadding})},c.prototype.padding=function(a,b){return this.rowPadding=a,this.colPadding=b,this._invalidateLayout(),this},c.prototype.rowWeight=function(a,b){return this.rowWeights[a]=b,this._invalidateLayout(),this},c.prototype.colWeight=function(a,b){return this.colWeights[a]=b,this._invalidateLayout(),this},c.prototype._isFixedWidth=function(){var a=d3.transpose(this.rows);return c.fixedSpace(a,function(a){return null==a||a._isFixedWidth()})},c.prototype._isFixedHeight=function(){return c.fixedSpace(this.rows,function(a){return null==a||a._isFixedHeight()})},c.prototype.padTableToSize=function(a,b){for(var c=0;a>c;c++){void 0===this.rows[c]&&(this.rows[c]=[],this.rowWeights[c]=null);for(var d=0;b>d;d++)void 0===this.rows[c][d]&&(this.rows[c][d]=null)}for(d=0;b>d;d++)void 0===this.colWeights[d]&&(this.colWeights[d]=null)},c.calcComponentWeights=function(a,b,c){return a.map(function(a,d){if(null!=a)return a;var e=b[d].map(c),f=e.reduce(function(a,b){return a&&b},!0);return f?0:1})},c.calcProportionalSpace=function(b,c){var d=d3.sum(b);return 0===d?a.Util.Methods.createFilledArray(0,b.length):b.map(function(a){return c*a/d})},c.fixedSpace=function(a,b){var c=function(a){return a.reduce(function(a,b){return a&&b},!0)},d=function(a){return c(a.map(b))};return c(a.map(d))},c}(a.Abstract.ComponentContainer);b.Table=c}(a.Component||(a.Component={}));a.Component}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(c){b.call(this),this.autoDomainAutomatically=!0,this.broadcaster=new a.Core.Broadcaster(this),this._rendererAttrID2Extent={},this._d3Scale=c}return __extends(c,b),c.prototype._getAllExtents=function(){return d3.values(this._rendererAttrID2Extent)},c.prototype._getExtent=function(){return[]},c.prototype.autoDomain=function(){return this.autoDomainAutomatically=!0,this._setDomain(this._getExtent()),this},c.prototype._autoDomainIfAutomaticMode=function(){this.autoDomainAutomatically&&this.autoDomain() +},c.prototype.scale=function(a){return this._d3Scale(a)},c.prototype.domain=function(a){return null==a?this._getDomain():(this.autoDomainAutomatically=!1,this._setDomain(a),this)},c.prototype._getDomain=function(){return this._d3Scale.domain()},c.prototype._setDomain=function(a){this._d3Scale.domain(a),this.broadcaster.broadcast()},c.prototype.range=function(a){return null==a?this._d3Scale.range():(this._d3Scale.range(a),this)},c.prototype.copy=function(){return new c(this._d3Scale.copy())},c.prototype.updateExtent=function(a,b,c){return this._rendererAttrID2Extent[a+b]=c,this._autoDomainIfAutomaticMode(),this},c.prototype.removeExtent=function(a,b){return delete this._rendererAttrID2Extent[a+b],this._autoDomainIfAutomaticMode(),this},c}(b.PlottableObject);b.Scale=c}(a.Abstract||(a.Abstract={}));a.Abstract}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(c){b.call(this),this._dataChanged=!1,this._animate=!1,this._animators={},this._ANIMATION_DURATION=250,this._projectors={},this.animateOnNextRender=!0,this.clipPathEnabled=!0,this.classed("plot",!0);var d;d=null!=c?"function"==typeof c.data?c:d=new a.DataSource(c):new a.DataSource,this.dataSource(d)}return __extends(c,b),c.prototype._anchor=function(a){b.prototype._anchor.call(this,a),this.animateOnNextRender=!0,this._dataChanged=!0,this.updateAllProjectors()},c.prototype.remove=function(){var a=this;b.prototype.remove.call(this),this._dataSource.broadcaster.deregisterListener(this);var c=Object.keys(this._projectors);c.forEach(function(b){var c=a._projectors[b];null!=c.scale&&c.scale.broadcaster.deregisterListener(a)})},c.prototype.dataSource=function(a){var b=this;if(null==a)return this._dataSource;var c=this._dataSource;return null!=c&&this._dataSource.broadcaster.deregisterListener(this),this._dataSource=a,this._dataSource.broadcaster.registerListener(this,function(){return b._onDataSourceUpdate()}),this._onDataSourceUpdate(),this},c.prototype._onDataSourceUpdate=function(){this.updateAllProjectors(),this.animateOnNextRender=!0,this._dataChanged=!0,this._render()},c.prototype.project=function(b,c,d){var e=this;b=b.toLowerCase();var f=this._projectors[b],g=null!=f?f.scale:null;null!=g&&(g.removeExtent(this._plottableID,b),g.broadcaster.deregisterListener(this)),null!=d&&d.broadcaster.registerListener(this,function(){return e._render()});var h=a.Util.Methods._applyAccessor(c,this);return this._projectors[b]={accessor:h,scale:d},this.updateProjector(b),this._render(),this},c.prototype._generateAttrToProjector=function(){var a=this,b={};return d3.keys(this._projectors).forEach(function(c){var d=a._projectors[c],e=d.accessor,f=d.scale,g=null==f?e:function(a,b){return f.scale(e(a,b))};b[c]=g}),b},c.prototype._doRender=function(){this._isAnchored&&(this._paint(),this._dataChanged=!1,this.animateOnNextRender=!1)},c.prototype._paint=function(){},c.prototype._setup=function(){b.prototype._setup.call(this),this.renderArea=this.content.append("g").classed("render-area",!0)},c.prototype.animate=function(a){return this._animate=a,this},c.prototype.detach=function(){return b.prototype.detach.call(this),this.updateAllProjectors(),this},c.prototype.updateAllProjectors=function(){var a=this;return d3.keys(this._projectors).forEach(function(b){return a.updateProjector(b)}),this},c.prototype.updateProjector=function(a){var b=this._projectors[a];if(null!=b.scale){var c=this.dataSource()._getExtent(b.accessor);0!==c.length&&this._isAnchored?b.scale.updateExtent(this._plottableID,a,c):b.scale.removeExtent(this._plottableID,a)}return this},c.prototype._applyAnimatedAttributes=function(a,b,c){return this._animate&&this.animateOnNextRender&&null!=this._animators[b]?this._animators[b].animate(a,c,this):a.attr(c)},c.prototype.animator=function(a,b){return void 0===b?this._animators[a]:(this._animators[a]=b,this)},c}(b.Component);b.Plot=c}(a.Abstract||(a.Abstract={}));a.Abstract}(Plottable||(Plottable={}));var Plottable;!function(a){!function(b){!function(b){!function(c){var d=function(){function a(){}return a.prototype.render=function(){b.flush()},a}();c.Immediate=d;var e=function(){function c(){}return c.prototype.render=function(){a.Util.DOM.requestAnimationFramePolyfill(b.flush)},c}();c.AnimationFrame=e;var f=function(){function c(){this._timeoutMsec=a.Util.DOM.POLYFILL_TIMEOUT_MSEC}return c.prototype.render=function(){setTimeout(b.flush,this._timeoutMsec)},c}();c.Timeout=f}(b.RenderPolicy||(b.RenderPolicy={}));b.RenderPolicy}(b.RenderController||(b.RenderController={}));b.RenderController}(a.Core||(a.Core={}));a.Core}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){!function(b){function c(a){b._renderPolicy=a}function d(a){h[a._plottableID]=a,f()}function e(a){i[a._plottableID]=a,h[a._plottableID]=a,f()}function f(){j||(j=!0,b._renderPolicy.render())}function g(){if(j){var b=d3.values(i);b.forEach(function(a){return a._computeLayout()});var c=d3.values(h);c.forEach(function(a){return a._render()});var d={};Object.keys(h).forEach(function(a){try{h[a]._doRender()}catch(b){setTimeout(function(){throw b},0),d[a]=h[a]}}),i={},h=d,j=!1}a.ResizeBroadcaster.clearResizing()}var h={},i={},j=!1;b._renderPolicy=new b.RenderPolicy.AnimationFrame,b.setRenderPolicy=c,b.registerToRender=d,b.registerToComputeLayout=e,b.flush=g}(a.RenderController||(a.RenderController={}));a.RenderController}(a.Core||(a.Core={}));a.Core}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){!function(b){function c(){void 0===i&&(i=new a.Broadcaster(b),window.addEventListener("resize",d))}function d(){j=!0,i.broadcast()}function e(){return j}function f(){j=!1}function g(a){c(),i.registerListener(a._plottableID,function(){return a._invalidateLayout()})}function h(a){i&&i.deregisterListener(a._plottableID)}var i,j=!1;b.resizing=e,b.clearResizing=f,b.register=g,b.deregister=h}(a.ResizeBroadcaster||(a.ResizeBroadcaster={}));a.ResizeBroadcaster}(a.Core||(a.Core={}));a.Core}(Plottable||(Plottable={}));var Plottable;!function(){}(Plottable||(Plottable={}));var Plottable;!function(a){var b=function(){function a(a){this.doNice=!1,this.padProportion=0,this.paddingExceptions=d3.map(),this.unregisteredPaddingExceptions=d3.set(),this.includedValues=d3.map(),this.unregisteredIncludedValues=d3.map(),this.combineExtents=a}return a.prototype.computeDomain=function(a,b){var c;return c=null!=this.combineExtents?this.combineExtents(a):0===a.length?b._defaultExtent():[d3.min(a,function(a){return a[0]}),d3.max(a,function(a){return a[1]})],c=this.includeDomain(c),c=this.padDomain(b,c),c=this.niceDomain(b,c)},a.prototype.pad=function(a){return"undefined"==typeof a&&(a=.05),this.padProportion=a,this},a.prototype.addPaddingException=function(a,b){return null!=b?this.paddingExceptions.set(b,a):this.unregisteredPaddingExceptions.add(a),this},a.prototype.removePaddingException=function(a){return"string"==typeof a?this.paddingExceptions.remove(a):this.unregisteredPaddingExceptions.remove(a),this},a.prototype.addIncludedValue=function(a,b){return null!=b?this.includedValues.set(b,a):this.unregisteredIncludedValues.set(a,a),this},a.prototype.removeIncludedValue=function(a){return"string"==typeof a?this.includedValues.remove(a):this.unregisteredIncludedValues.remove(a),this},a.prototype.nice=function(a){return this.doNice=!0,this.niceCount=a,this},a.defaultCombineExtents=function(a){return 0===a.length?[0,1]:[d3.min(a,function(a){return a[0]}),d3.max(a,function(a){return a[1]})]},a.prototype.padDomain=function(b,c){var d=c[0],e=c[1];if(d===e&&this.padProportion>0){var f=d.valueOf();return d instanceof Date?[f-a.ONE_DAY,f+a.ONE_DAY]:[f-a.PADDING_FOR_IDENTICAL_DOMAIN,f+a.PADDING_FOR_IDENTICAL_DOMAIN]}if(b.domain()[0]===b.domain()[1])return c;var g=this.padProportion/2,h=b.invert(b.scale(d)-(b.scale(e)-b.scale(d))*g),i=b.invert(b.scale(e)+(b.scale(e)-b.scale(d))*g),j=this.paddingExceptions.values().concat(this.unregisteredPaddingExceptions.values()),k=d3.set(j);return k.has(d)&&(h=d),k.has(e)&&(i=e),[h,i]},a.prototype.niceDomain=function(a,b){return this.doNice?a._niceDomain(b,this.niceCount):b},a.prototype.includeDomain=function(a){var b=this.includedValues.values().concat(this.unregisteredIncludedValues.values());return b.reduce(function(a,b){return[Math.min(a[0],b),Math.max(a[1],b)]},a)},a.PADDING_FOR_IDENTICAL_DOMAIN=1,a.ONE_DAY=864e5,a}();a.Domainer=b}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(c){b.call(this,c),this._lastRequestedTickCount=10,this._PADDING_FOR_IDENTICAL_DOMAIN=1,this._userSetDomainer=!1,this._domainer=new a.Domainer}return __extends(c,b),c.prototype._getExtent=function(){return this._domainer.computeDomain(this._getAllExtents(),this)},c.prototype.invert=function(a){return this._d3Scale.invert(a)},c.prototype.copy=function(){return new c(this._d3Scale.copy())},c.prototype.domain=function(a){return b.prototype.domain.call(this,a)},c.prototype._setDomain=function(c){var d=function(a){return a!==a||1/0===a||a===-1/0};return d(c[0])||d(c[1])?void a.Util.Methods.warn("Warning: QuantitativeScales cannot take NaN or Infinity as a domain value. Ignoring."):void b.prototype._setDomain.call(this,c)},c.prototype.interpolate=function(a){return null==a?this._d3Scale.interpolate():(this._d3Scale.interpolate(a),this)},c.prototype.rangeRound=function(a){return this._d3Scale.rangeRound(a),this},c.prototype.clamp=function(a){return null==a?this._d3Scale.clamp():(this._d3Scale.clamp(a),this)},c.prototype.ticks=function(a){return null!=a&&(this._lastRequestedTickCount=a),this._d3Scale.ticks(this._lastRequestedTickCount)},c.prototype.tickFormat=function(a,b){return this._d3Scale.tickFormat(a,b)},c.prototype._niceDomain=function(a,b){return this._d3Scale.copy().domain(a).nice(b).domain()},c.prototype.domainer=function(a){return null==a?this._domainer:(this._domainer=a,this._userSetDomainer=!0,this._autoDomainIfAutomaticMode(),this)},c.prototype._defaultExtent=function(){return[0,1]},c}(b.Scale);b.QuantitativeScale=c}(a.Abstract||(a.Abstract={}));a.Abstract}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b){a.call(this,null==b?d3.scale.linear():b)}return __extends(b,a),b.prototype.copy=function(){return new b(this._d3Scale.copy())},b}(a.Abstract.QuantitativeScale);b.Linear=c}(a.Scale||(a.Scale={}));a.Scale}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(d){b.call(this,null==d?d3.scale.log():d),c.warned||(c.warned=!0,a.Util.Methods.warn("Plottable.Scale.Log is deprecated. If possible, use Plottable.Scale.ModifiedLog instead."))}return __extends(c,b),c.prototype.copy=function(){return new c(this._d3Scale.copy())},c.prototype._defaultExtent=function(){return[1,10]},c.warned=!1,c}(a.Abstract.QuantitativeScale);b.Log=c}(a.Scale||(a.Scale={}));a.Scale}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(a){if("undefined"==typeof a&&(a=10),b.call(this,d3.scale.linear()),this._showIntermediateTicks=!1,this.base=a,this.pivot=this.base,this.untransformedDomain=this._defaultExtent(),this._lastRequestedTickCount=10,1>=a)throw new Error("ModifiedLogScale: The base must be > 1")}return __extends(c,b),c.prototype.adjustedLog=function(a){var b=0>a?-1:1;return a*=b,aa?-1:1;return a*=b,a=Math.pow(this.base,a),a=d&&e>=a}),m=j.concat(l).concat(k);return m.length<=1&&(m=d3.scale.linear().domain([d,e]).ticks(this._lastRequestedTickCount)),m},c.prototype.logTicks=function(b,c){var d=this,e=this.howManyTicks(b,c);if(0===e)return[];var f=Math.floor(Math.log(b)/Math.log(this.base)),g=Math.ceil(Math.log(c)/Math.log(this.base)),h=d3.range(g,f,-Math.ceil((g-f)/e)),i=this._showIntermediateTicks?Math.floor(e/h.length):1,j=d3.range(this.base,1,-(this.base-1)/i).map(Math.floor),k=a.Util.Methods.uniqNumbers(j),l=h.map(function(a){return k.map(function(b){return Math.pow(d.base,a-1)*b})}),m=a.Util.Methods.flatten(l),n=m.filter(function(a){return a>=b&&c>=a}),o=n.sort(function(a,b){return a-b});return o},c.prototype.howManyTicks=function(a,b){var c=this.adjustedLog(d3.min(this.untransformedDomain)),d=this.adjustedLog(d3.max(this.untransformedDomain)),e=this.adjustedLog(a),f=this.adjustedLog(b),g=(f-e)/(d-c),h=Math.ceil(g*this._lastRequestedTickCount);return h},c.prototype.copy=function(){return new c(this.base)},c.prototype._niceDomain=function(a){return a},c.prototype.showIntermediateTicks=function(a){return null==a?this._showIntermediateTicks:void(this._showIntermediateTicks=a)},c}(a.Abstract.QuantitativeScale);b.ModifiedLog=c}(a.Scale||(a.Scale={}));a.Scale}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(a){if(b.call(this,null==a?d3.scale.ordinal():a),this._range=[0,1],this._rangeType="bands",this._innerPadding=.3,this._outerPadding=.5,this._innerPadding>this._outerPadding)throw new Error("outerPadding must be >= innerPadding so cat axis bands work out reasonably")}return __extends(c,b),c.prototype._getExtent=function(){var b=this._getAllExtents();return a.Util.Methods.uniq(a.Util.Methods.flatten(b))},c.prototype.domain=function(a){return b.prototype.domain.call(this,a)},c.prototype._setDomain=function(a){b.prototype._setDomain.call(this,a),this.range(this.range())},c.prototype.range=function(a){return null==a?this._range:(this._range=a,"points"===this._rangeType?this._d3Scale.rangePoints(a,2*this._outerPadding):"bands"===this._rangeType&&this._d3Scale.rangeBands(a,this._innerPadding,this._outerPadding),this)},c.prototype.rangeBand=function(){return this._d3Scale.rangeBand()},c.prototype.innerPadding=function(){var a=this.domain();if(a.length<2)return 0;var b=Math.abs(this.scale(a[1])-this.scale(a[0]));return b-this.rangeBand()},c.prototype.fullBandStartAndWidth=function(a){var b=this.scale(a)-this.innerPadding()/2,c=this.rangeBand()+this.innerPadding();return[b,c]},c.prototype.rangeType=function(a,b,c){if(null==a)return this._rangeType;if("points"!==a&&"bands"!==a)throw new Error("Unsupported range type: "+a);return this._rangeType=a,null!=b&&(this._outerPadding=b),null!=c&&(this._innerPadding=c),this.broadcaster.broadcast(),this},c.prototype.copy=function(){return new c(this._d3Scale.copy())},c}(a.Abstract.Scale);b.Ordinal=c}(a.Scale||(a.Scale={}));a.Scale}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(c){var d;switch(c){case null:case void 0:d=d3.scale.ordinal().range(a.Core.Colors.PLOTTABLE_COLORS);break;case"Category10":case"category10":case"10":d=d3.scale.category10();break;case"Category20":case"category20":case"20":d=d3.scale.category20();break;case"Category20b":case"category20b":case"20b":d=d3.scale.category20b();break;case"Category20c":case"category20c":case"20c":d=d3.scale.category20c();break;default:throw new Error("Unsupported ColorScale type")}b.call(this,d)}return __extends(c,b),c.prototype._getExtent=function(){var b=this._getAllExtents(),c=[];return b.forEach(function(a){c=c.concat(a)}),a.Util.Methods.uniq(c)},c}(a.Abstract.Scale);b.Color=c}(a.Scale||(a.Scale={}));a.Scale}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b){a.call(this,null==b?d3.time.scale():b),this._PADDING_FOR_IDENTICAL_DOMAIN=864e5}return __extends(b,a),b.prototype.tickInterval=function(a,b){var c=d3.time.scale();return c.domain(this.domain()),c.range(this.range()),c.ticks(a.range,b)},b.prototype.domain=function(b){return null==b?a.prototype.domain.call(this):("string"==typeof b[0]&&(b=b.map(function(a){return new Date(a)})),a.prototype.domain.call(this,b))},b.prototype.copy=function(){return new b(this._d3Scale.copy())},b}(a.Abstract.QuantitativeScale);b.Time=c}(a.Scale||(a.Scale={}));a.Scale}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(c,d){"undefined"==typeof c&&(c="reds"),"undefined"==typeof d&&(d="linear"),this._colorRange=this._resolveColorValues(c),this._scaleType=d,a.call(this,b.getD3InterpolatedScale(this._colorRange,this._scaleType))}return __extends(b,a),b.getD3InterpolatedScale=function(a,c){var d;switch(c){case"linear":d=d3.scale.linear();break;case"log":d=d3.scale.log();break;case"sqrt":d=d3.scale.sqrt();break;case"pow":d=d3.scale.pow()}if(null==d)throw new Error("unknown Quantitative scale type "+c);return d.range([0,1]).interpolate(b.interpolateColors(a))},b.interpolateColors=function(a){if(a.length<2)throw new Error("Color scale arrays must have at least two elements.");return function(){return function(b){b=Math.max(0,Math.min(1,b));var c=b*(a.length-1),d=Math.floor(c),e=Math.ceil(c),f=c-d;return d3.interpolateLab(a[d],a[e])(f)}}},b.prototype.colorRange=function(a){return null==a?this._colorRange:(this._colorRange=this._resolveColorValues(a),this._resetScale(),this)},b.prototype.scaleType=function(a){return null==a?this._scaleType:(this._scaleType=a,this._resetScale(),this)},b.prototype._resetScale=function(){this._d3Scale=b.getD3InterpolatedScale(this._colorRange,this._scaleType),this._autoDomainIfAutomaticMode(),this.broadcaster.broadcast()},b.prototype._resolveColorValues=function(a){return a instanceof Array?a:null!=b.COLOR_SCALES[a]?b.COLOR_SCALES[a]:b.COLOR_SCALES.reds},b.prototype.autoDomain=function(){var a=this._getAllExtents();return a.length>0&&this._setDomain([d3.min(a,function(a){return a[0]}),d3.max(a,function(a){return a[1]})]),this},b.COLOR_SCALES={reds:["#FFFFFF","#FFF6E1","#FEF4C0","#FED976","#FEB24C","#FD8D3C","#FC4E2A","#E31A1C","#B10026"],blues:["#FFFFFF","#CCFFFF","#A5FFFD","#85F7FB","#6ED3EF","#55A7E0","#417FD0","#2545D3","#0B02E1"],posneg:["#0B02E1","#2545D3","#417FD0","#55A7E0","#6ED3EF","#85F7FB","#A5FFFD","#CCFFFF","#FFFFFF","#FFF6E1","#FEF4C0","#FED976","#FEB24C","#FD8D3C","#FC4E2A","#E31A1C","#B10026"]},b}(a.Abstract.QuantitativeScale);b.InterpolatedColor=c}(a.Scale||(a.Scale={}));a.Scale}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){var b=function(){function a(a){var b=this;if(this.rescaleInProgress=!1,null==a)throw new Error("ScaleDomainCoordinator requires scales to coordinate");this.scales=a,this.scales.forEach(function(a){return a.broadcaster.registerListener(b,function(a){return b.rescale(a)})})}return a.prototype.rescale=function(a){if(!this.rescaleInProgress){this.rescaleInProgress=!0;var b=a.domain();this.scales.forEach(function(a){return a.domain(b)}),this.rescaleInProgress=!1}},a}();a.ScaleDomainCoordinator=b}(a.Util||(a.Util={}));a.Util}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(c){function d(b,d,e){"undefined"==typeof e&&(e=a.Formatters.identity());var f=this;if(c.call(this),this._width="auto",this._height="auto",this._endTickLength=5,this._tickLength=5,this._tickLabelPadding=10,this._gutter=15,this._showEndTickLabels=!1,null==b||null==d)throw new Error("Axis requires a scale and orientation");this._scale=b,this.orient(d),this.classed("axis",!0),this._isHorizontal()?this.classed("x-axis",!0):this.classed("y-axis",!0),this.formatter(e),this._scale.broadcaster.registerListener(this,function(){return f.rescale()})}return __extends(d,c),d.prototype.remove=function(){c.prototype.remove.call(this),this._scale.broadcaster.deregisterListener(this)},d.prototype._isHorizontal=function(){return"top"===this._orientation||"bottom"===this._orientation},d.prototype._computeWidth=function(){return this._computedWidth=this._maxLabelTickLength(),this._computedWidth},d.prototype._computeHeight=function(){return this._computedHeight=this._maxLabelTickLength(),this._computedHeight},d.prototype._requestedSpace=function(a,b){var c=this._width,d=this._height;return this._isHorizontal()?("auto"===this._height&&(null==this._computedHeight&&this._computeHeight(),d=this._computedHeight+this._gutter),c=0):("auto"===this._width&&(null==this._computedWidth&&this._computeWidth(),c=this._computedWidth+this._gutter),d=0),{width:c,height:d,wantsWidth:!this._isHorizontal()&&c>a,wantsHeight:this._isHorizontal()&&d>b}},d.prototype._isFixedHeight=function(){return this._isHorizontal()},d.prototype._isFixedWidth=function(){return!this._isHorizontal()},d.prototype._computeLayout=function(a,b,d,e){c.prototype._computeLayout.call(this,a,b,d,e),this._scale.range(this._isHorizontal()?[0,this.availableWidth]:[this.availableHeight,0])},d.prototype._setup=function(){c.prototype._setup.call(this),this._tickMarkContainer=this.content.append("g").classed(d.TICK_MARK_CLASS+"-container",!0),this._tickLabelContainer=this.content.append("g").classed(d.TICK_LABEL_CLASS+"-container",!0),this._baseline=this.content.append("line").classed("baseline",!0)},d.prototype._getTickValues=function(){return[]},d.prototype._doRender=function(){var a=this._getTickValues(),b=this._tickMarkContainer.selectAll("."+d.TICK_MARK_CLASS).data(a);b.enter().append("line").classed(d.TICK_MARK_CLASS,!0),b.attr(this._generateTickMarkAttrHash()),d3.select(b[0][0]).classed(d.END_TICK_MARK_CLASS,!0).attr(this._generateTickMarkAttrHash(!0)),d3.select(b[0][a.length-1]).classed(d.END_TICK_MARK_CLASS,!0).attr(this._generateTickMarkAttrHash(!0)),b.exit().remove(),this._baseline.attr(this._generateBaselineAttrHash())},d.prototype._generateBaselineAttrHash=function(){var a={x1:0,y1:0,x2:0,y2:0};switch(this._orientation){case"bottom":a.x2=this.availableWidth;break;case"top":a.x2=this.availableWidth,a.y1=this.availableHeight,a.y2=this.availableHeight;break;case"left":a.x1=this.availableWidth,a.x2=this.availableWidth,a.y2=this.availableHeight;break;case"right":a.y2=this.availableHeight}return a},d.prototype._generateTickMarkAttrHash=function(a){var b=this;"undefined"==typeof a&&(a=!1);var c={x1:0,y1:0,x2:0,y2:0},d=function(a){return b._scale.scale(a)};this._isHorizontal()?(c.x1=d,c.x2=d):(c.y1=d,c.y2=d);var e=a?this._endTickLength:this._tickLength;switch(this._orientation){case"bottom":c.y2=e;break;case"top":c.y1=this.availableHeight,c.y2=this.availableHeight-e;break;case"left":c.x1=this.availableWidth,c.x2=this.availableWidth-e;break;case"right":c.x2=e}return c},d.prototype.rescale=function(){return null!=this.element?this._render():null},d.prototype._invalidateLayout=function(){this._computedWidth=null,this._computedHeight=null,c.prototype._invalidateLayout.call(this)},d.prototype.width=function(a){if(null==a)return this.availableWidth;if(this._isHorizontal())throw new Error("width cannot be set on a horizontal Axis");if("auto"!==a&&0>a)throw new Error("invalid value for width");return this._width=a,this._invalidateLayout(),this},d.prototype.height=function(a){if(null==a)return this.availableHeight;if(!this._isHorizontal())throw new Error("height cannot be set on a vertical Axis");if("auto"!==a&&0>a)throw new Error("invalid value for height");return this._height=a,this._invalidateLayout(),this},d.prototype.formatter=function(a){return void 0===a?this._formatter:(this._formatter=a,this._invalidateLayout(),this)},d.prototype.tickLength=function(a){if(null==a)return this._tickLength;if(0>a)throw new Error("tick length must be positive");return this._tickLength=a,this._invalidateLayout(),this},d.prototype.endTickLength=function(a){if(null==a)return this._endTickLength;if(0>a)throw new Error("end tick length must be positive");return this._endTickLength=a,this._invalidateLayout(),this},d.prototype._maxLabelTickLength=function(){return this.showEndTickLabels()?Math.max(this.tickLength(),this.endTickLength()):this.tickLength()},d.prototype.tickLabelPadding=function(a){if(null==a)return this._tickLabelPadding;if(0>a)throw new Error("tick label padding must be positive");return this._tickLabelPadding=a,this._invalidateLayout(),this},d.prototype.gutter=function(a){if(null==a)return this._gutter;if(0>a)throw new Error("gutter size must be positive");return this._gutter=a,this._invalidateLayout(),this},d.prototype.orient=function(a){if(null==a)return this._orientation;var b=a.toLowerCase();if("top"!==b&&"bottom"!==b&&"left"!==b&&"right"!==b)throw new Error("unsupported orientation");return this._orientation=b,this._invalidateLayout(),this},d.prototype.showEndTickLabels=function(a){return null==a?this._showEndTickLabels:(this._showEndTickLabels=a,this._render(),this)},d.prototype._hideEndTickLabels=function(){var a=this,c=this.element.select(".bounding-box")[0][0].getBoundingClientRect(),d=function(b){return Math.floor(c.left)<=Math.ceil(b.left)&&Math.floor(c.top)<=Math.ceil(b.top)&&Math.floor(b.right)<=Math.ceil(c.left+a.availableWidth)&&Math.floor(b.bottom)<=Math.ceil(c.top+a.availableHeight)},e=this._tickLabelContainer.selectAll("."+b.Axis.TICK_LABEL_CLASS);if(0!==e[0].length){var f=e[0][0];d(f.getBoundingClientRect())||d3.select(f).style("visibility","hidden");var g=e[0][e[0].length-1];d(g.getBoundingClientRect())||d3.select(g).style("visibility","hidden")}},d.prototype._hideOverlappingTickLabels=function(){var c,d=this._tickLabelContainer.selectAll("."+b.Axis.TICK_LABEL_CLASS).filter(function(){return"visible"===d3.select(this).style("visibility")});d.each(function(){var b=this.getBoundingClientRect(),d=d3.select(this);null!=c&&a.Util.DOM.boxesOverlap(b,c)?d.style("visibility","hidden"):(c=b,d.style("visibility","visible"))})},d.END_TICK_MARK_CLASS="end-tick-mark",d.TICK_MARK_CLASS="tick-mark",d.TICK_LABEL_CLASS="tick-label",d}(b.Component);b.Axis=c}(a.Abstract||(a.Abstract={}));a.Abstract}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(a,d){if(d=d.toLowerCase(),"top"!==d&&"bottom"!==d)throw new Error("unsupported orientation: "+d);b.call(this,a,d),this.classed("time-axis",!0),this.previousSpan=0,this.previousIndex=c.minorIntervals.length-1,this.tickLabelPadding(5)}return __extends(c,b),c.prototype._computeHeight=function(){if(null!==this._computedHeight)return this._computedHeight;var a=this._measureTextHeight(this._majorTickLabels)+this._measureTextHeight(this._minorTickLabels);return this.tickLength(a),this.endTickLength(a),this._computedHeight=this._maxLabelTickLength()+2*this.tickLabelPadding(),this._computedHeight},c.prototype.calculateWorstWidth=function(b,c){var d=new Date(9999,8,29,12,59,9999);return a.Util.Text.getTextWidth(b,d3.time.format(c)(d))},c.prototype.getIntervalLength=function(a){var b=this._scale.domain()[0],c=Math.abs(this._scale.scale(a.timeUnit.offset(b,a.step))-this._scale.scale(b));return c},c.prototype.isEnoughSpace=function(a,b){var c=this.calculateWorstWidth(a,b.formatString)+2*this.tickLabelPadding(),d=Math.min(this.getIntervalLength(b),this.availableWidth);return d>c},c.prototype._setup=function(){b.prototype._setup.call(this),this._majorTickLabels=this.content.append("g").classed(a.Abstract.Axis.TICK_LABEL_CLASS,!0),this._minorTickLabels=this.content.append("g").classed(a.Abstract.Axis.TICK_LABEL_CLASS,!0)},c.prototype.getTickLevel=function(){var b=c.minorIntervals.length-1,d=Math.abs(this._scale.domain()[1]-this._scale.domain()[0]);d<=this.previousSpan+1&&(b=this.previousIndex);for(var e=b;e>=0;){if(!this.isEnoughSpace(this._minorTickLabels,c.minorIntervals[e])||!this.isEnoughSpace(this._majorTickLabels,c.majorIntervals[e])){e++;break}e--}return e=Math.min(e,c.minorIntervals.length-1),0>e&&(e=0,a.Util.Methods.warn("could not find suitable interval to display labels")),this.previousIndex=Math.max(0,e-1),this.previousSpan=d,e},c.prototype._getTickIntervalValues=function(a){return this._scale.tickInterval(a.timeUnit,a.step)},c.prototype._getTickValues=function(){var a=this.getTickLevel(),b=this._getTickIntervalValues(c.minorIntervals[a]),d=this._getTickIntervalValues(c.majorIntervals[a]);return b.concat(d)},c.prototype._measureTextHeight=function(b){var c=b.append("g").classed(a.Abstract.Axis.TICK_LABEL_CLASS,!0),d=a.Util.Text.getTextHeight(c.append("text"));return c.remove(),d},c.prototype.renderTickLabels=function(b,c,d){var e=this;b.selectAll("."+a.Abstract.Axis.TICK_LABEL_CLASS).remove();var f=this._scale.tickInterval(c.timeUnit,c.step);f.splice(0,0,this._scale.domain()[0]),f.push(this._scale.domain()[1]);var g=1===c.step,h=[];g?f.map(function(a,b){b+1>=f.length||h.push(new Date((f[b+1].valueOf()-f[b].valueOf())/2+f[b].valueOf()))}):h=f,h=h.filter(function(a){return e.canFitLabelFilter(b,a,d3.time.format(c.formatString)(a),g)});var i=b.selectAll("."+a.Abstract.Axis.TICK_LABEL_CLASS).data(h,function(a){return a.valueOf()}),j=i.enter().append("g").classed(a.Abstract.Axis.TICK_LABEL_CLASS,!0);j.append("text");var k=g?0:this.tickLabelPadding(),l="bottom"===this._orientation?this._maxLabelTickLength()/2*d:this.availableHeight-this._maxLabelTickLength()/2*d+2*this.tickLabelPadding(),m=i.selectAll("text");m.size()>0&&a.Util.DOM.translate(m,k,l),i.exit().remove(),i.attr("transform",function(a){return"translate("+e._scale.scale(a)+",0)"});var n=g?"middle":"start";i.selectAll("text").text(function(a){return d3.time.format(c.formatString)(a)}).style("text-anchor",n)},c.prototype.canFitLabelFilter=function(b,c,d,e){var f,g,h=a.Util.Text.getTextWidth(b,d)+this.tickLabelPadding();return e?(f=this._scale.scale(c)+h/2,g=this._scale.scale(c)-h/2):(f=this._scale.scale(c)+h,g=this._scale.scale(c)),f0},c.prototype.adjustTickLength=function(b,c){var d=this._getTickIntervalValues(c),e=this._tickMarkContainer.selectAll("."+a.Abstract.Axis.TICK_MARK_CLASS).filter(function(a){return d.map(function(a){return a.valueOf() +}).indexOf(a.valueOf())>=0});"top"===this._orientation&&(b=this.availableHeight-b),e.attr("y2",b)},c.prototype.generateLabellessTicks=function(b){if(!(0>b)){var d=this._getTickIntervalValues(c.minorIntervals[b]),e=this._getTickValues().concat(d),f=this._tickMarkContainer.selectAll("."+a.Abstract.Axis.TICK_MARK_CLASS).data(e);f.enter().append("line").classed(a.Abstract.Axis.TICK_MARK_CLASS,!0),f.attr(this._generateTickMarkAttrHash()),f.exit().remove(),this.adjustTickLength(this.tickLabelPadding(),c.minorIntervals[b])}},c.prototype._doRender=function(){b.prototype._doRender.call(this);var a=this.getTickLevel();this.renderTickLabels(this._minorTickLabels,c.minorIntervals[a],1),this.renderTickLabels(this._majorTickLabels,c.majorIntervals[a],2);var d=this._scale.domain(),e=this._scale.scale(d[1])-this._scale.scale(d[0]);1.5*this.getIntervalLength(c.minorIntervals[a])>=e&&this.generateLabellessTicks(a-1),this.adjustTickLength(this._maxLabelTickLength()/2,c.minorIntervals[a]),this.adjustTickLength(this._maxLabelTickLength(),c.majorIntervals[a])},c.minorIntervals=[{timeUnit:d3.time.second,step:1,formatString:"%I:%M:%S %p"},{timeUnit:d3.time.second,step:5,formatString:"%I:%M:%S %p"},{timeUnit:d3.time.second,step:10,formatString:"%I:%M:%S %p"},{timeUnit:d3.time.second,step:15,formatString:"%I:%M:%S %p"},{timeUnit:d3.time.second,step:30,formatString:"%I:%M:%S %p"},{timeUnit:d3.time.minute,step:1,formatString:"%I:%M %p"},{timeUnit:d3.time.minute,step:5,formatString:"%I:%M %p"},{timeUnit:d3.time.minute,step:10,formatString:"%I:%M %p"},{timeUnit:d3.time.minute,step:15,formatString:"%I:%M %p"},{timeUnit:d3.time.minute,step:30,formatString:"%I:%M %p"},{timeUnit:d3.time.hour,step:1,formatString:"%I %p"},{timeUnit:d3.time.hour,step:3,formatString:"%I %p"},{timeUnit:d3.time.hour,step:6,formatString:"%I %p"},{timeUnit:d3.time.hour,step:12,formatString:"%I %p"},{timeUnit:d3.time.day,step:1,formatString:"%a %e"},{timeUnit:d3.time.day,step:1,formatString:"%e"},{timeUnit:d3.time.month,step:1,formatString:"%B"},{timeUnit:d3.time.month,step:1,formatString:"%b"},{timeUnit:d3.time.month,step:3,formatString:"%B"},{timeUnit:d3.time.month,step:6,formatString:"%B"},{timeUnit:d3.time.year,step:1,formatString:"%Y"},{timeUnit:d3.time.year,step:1,formatString:"%y"},{timeUnit:d3.time.year,step:5,formatString:"%Y"},{timeUnit:d3.time.year,step:25,formatString:"%Y"},{timeUnit:d3.time.year,step:50,formatString:"%Y"},{timeUnit:d3.time.year,step:100,formatString:"%Y"},{timeUnit:d3.time.year,step:200,formatString:"%Y"},{timeUnit:d3.time.year,step:500,formatString:"%Y"},{timeUnit:d3.time.year,step:1e3,formatString:"%Y"}],c.majorIntervals=[{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.day,step:1,formatString:"%B %e, %Y"},{timeUnit:d3.time.month,step:1,formatString:"%B %Y"},{timeUnit:d3.time.month,step:1,formatString:"%B %Y"},{timeUnit:d3.time.year,step:1,formatString:"%Y"},{timeUnit:d3.time.year,step:1,formatString:"%Y"},{timeUnit:d3.time.year,step:1,formatString:"%Y"},{timeUnit:d3.time.year,step:1,formatString:"%Y"},{timeUnit:d3.time.year,step:1e5,formatString:""},{timeUnit:d3.time.year,step:1e5,formatString:""},{timeUnit:d3.time.year,step:1e5,formatString:""},{timeUnit:d3.time.year,step:1e5,formatString:""},{timeUnit:d3.time.year,step:1e5,formatString:""},{timeUnit:d3.time.year,step:1e5,formatString:""},{timeUnit:d3.time.year,step:1e5,formatString:""},{timeUnit:d3.time.year,step:1e5,formatString:""},{timeUnit:d3.time.year,step:1e5,formatString:""}],c}(a.Abstract.Axis);b.Time=c}(a.Axis||(a.Axis={}));a.Axis}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(c,d,e){"undefined"==typeof e&&(e=a.Formatters.general(3,!1)),b.call(this,c,d,e),this.tickLabelPositioning="center",this.showFirstTickLabel=!1,this.showLastTickLabel=!1}return __extends(c,b),c.prototype._computeWidth=function(){var b=this,c=this._getTickValues(),d=this._tickLabelContainer.append("text").classed(a.Abstract.Axis.TICK_LABEL_CLASS,!0),e=a.Util.Text.getTextMeasure(d),f=c.map(function(a){var c=b._formatter(a);return e(c).width});d.remove();var g=d3.max(f);return this._computedWidth="center"===this.tickLabelPositioning?this._maxLabelTickLength()+this.tickLabelPadding()+g:Math.max(this._maxLabelTickLength(),this.tickLabelPadding()+g),this._computedWidth},c.prototype._computeHeight=function(){var b=this._tickLabelContainer.append("text").classed(a.Abstract.Axis.TICK_LABEL_CLASS,!0),c=a.Util.Text.getTextMeasure(b),d=c("test").height;return b.remove(),this._computedHeight="center"===this.tickLabelPositioning?this._maxLabelTickLength()+this.tickLabelPadding()+d:Math.max(this._maxLabelTickLength(),this.tickLabelPadding()+d),this._computedHeight},c.prototype._getTickValues=function(){return this._scale.ticks()},c.prototype._doRender=function(){b.prototype._doRender.call(this);var c={x:0,y:0,dx:"0em",dy:"0.3em"},d=this._maxLabelTickLength(),e=this.tickLabelPadding(),f="middle",g=0,h=0,i=0,j=0;if(this._isHorizontal())switch(this.tickLabelPositioning){case"left":f="end",g=-e,j=e;break;case"center":j=d+e;break;case"right":f="start",g=e,j=e}else switch(this.tickLabelPositioning){case"top":c.dy="-0.3em",i=e,h=-e;break;case"center":i=d+e;break;case"bottom":c.dy="1em",i=e,h=e}var k=this._generateTickMarkAttrHash();switch(this._orientation){case"bottom":c.x=k.x1,c.dy="0.95em",h=k.y1+j;break;case"top":c.x=k.x1,c.dy="-.25em",h=k.y1-j;break;case"left":f="end",g=k.x1-i,c.y=k.y1;break;case"right":f="start",g=k.x1+i,c.y=k.y1}var l=this._getTickValues(),m=this._tickLabelContainer.selectAll("."+a.Abstract.Axis.TICK_LABEL_CLASS).data(l);m.enter().append("text").classed(a.Abstract.Axis.TICK_LABEL_CLASS,!0),m.exit().remove(),m.style("text-anchor",f).style("visibility","visible").attr(c).text(this._formatter);var n="translate("+g+", "+h+")";this._tickLabelContainer.attr("transform",n),this.showEndTickLabels()||this._hideEndTickLabels(),this._hideOverlappingTickLabels()},c.prototype.tickLabelPosition=function(a){if(null==a)return this.tickLabelPositioning;var b=a.toLowerCase();if(this._isHorizontal()){if("left"!==b&&"center"!==b&&"right"!==b)throw new Error(b+" is not a valid tick label position for a horizontal NumericAxis")}else if("top"!==b&&"center"!==b&&"bottom"!==b)throw new Error(b+" is not a valid tick label position for a vertical NumericAxis");return this.tickLabelPositioning=b,this._invalidateLayout(),this},c.prototype.showEndTickLabel=function(a,b){if(this._isHorizontal()&&"left"===a||!this._isHorizontal()&&"bottom"===a)return void 0===b?this.showFirstTickLabel:(this.showFirstTickLabel=b,this._render(),this);if(this._isHorizontal()&&"right"===a||!this._isHorizontal()&&"top"===a)return void 0===b?this.showLastTickLabel:(this.showLastTickLabel=b,this._render(),this);throw new Error("Attempt to show "+a+" tick label on a "+(this._isHorizontal()?"horizontal":"vertical")+" axis")},c}(a.Abstract.Axis);b.Numeric=c}(a.Axis||(a.Axis={}));a.Axis}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(c,d,e){"undefined"==typeof d&&(d="bottom"),"undefined"==typeof e&&(e=a.Formatters.identity());var f=this;if(b.call(this,c,d,e),this.classed("category-axis",!0),"bands"!==c.rangeType())throw new Error("Only rangeBands category axes are implemented");this._scale.broadcaster.registerListener(this,function(){return f._invalidateLayout()})}return __extends(c,b),c.prototype._setup=function(){b.prototype._setup.call(this),this.measurer=new a.Util.Text.CachingCharacterMeasurer(this._tickLabelContainer)},c.prototype._requestedSpace=function(a,b){var c=this._isHorizontal()?0:this._maxLabelTickLength()+this.tickLabelPadding(),d=this._isHorizontal()?this._maxLabelTickLength()+this.tickLabelPadding():0;if(0===this._scale.domain().length)return{width:0,height:0,wantsWidth:!1,wantsHeight:!1};var e=this._scale.copy();e.range(this._isHorizontal()?[0,a]:[b,0]);var f=this.measureTicks(a,b,e,this._scale.domain());return{width:f.usedWidth+c,height:f.usedHeight+d,wantsWidth:!f.textFits,wantsHeight:!f.textFits}},c.prototype._getTickValues=function(){return this._scale.domain()},c.prototype.measureTicks=function(b,c,d,e){var f="string"!=typeof e[0],g=this,h=[],i=function(a){return g.measurer.measure(a)},j=f?function(a){return e.each(a)}:function(a){return e.forEach(a)};j(function(e){var j,k=d.fullBandStartAndWidth(e)[1],l=g._isHorizontal()?k:b-g._maxLabelTickLength()-g.tickLabelPadding(),m=g._isHorizontal()?c-g._maxLabelTickLength()-g.tickLabelPadding():k,n=g._formatter;if(f){var o=d3.select(this),p={left:"right",right:"left",top:"center",bottom:"center"},q={left:"center",right:"center",top:"bottom",bottom:"top"};j=a.Util.Text.writeText(n(e),l,m,i,!0,{g:o,xAlign:p[g._orientation],yAlign:q[g._orientation]})}else j=a.Util.Text.writeText(n(e),l,m,i,!0);h.push(j)});var k=this._isHorizontal()?d3.sum:d3.max,l=this._isHorizontal()?d3.max:d3.sum;return{textFits:h.every(function(a){return a.textFits}),usedWidth:k(h,function(a){return a.usedWidth}),usedHeight:l(h,function(a){return a.usedHeight})}},c.prototype._doRender=function(){var c=this;b.prototype._doRender.call(this);var d=this._tickLabelContainer.selectAll("."+a.Abstract.Axis.TICK_LABEL_CLASS).data(this._scale.domain(),function(a){return a}),e=function(a){var b=c._scale.fullBandStartAndWidth(a),d=b[0],e=c._isHorizontal()?d:0,f=c._isHorizontal()?0:d;return"translate("+e+","+f+")"};d.enter().append("g").classed(a.Abstract.Axis.TICK_LABEL_CLASS,!0),d.exit().remove(),d.attr("transform",e),d.text(""),this.measureTicks(this.availableWidth,this.availableHeight,this._scale,d);var f=this._isHorizontal()?[this._scale.rangeBand()/2,0]:[0,this._scale.rangeBand()/2],g="right"===this._orientation?this._maxLabelTickLength()+this.tickLabelPadding():0,h="bottom"===this._orientation?this._maxLabelTickLength()+this.tickLabelPadding():0;a.Util.DOM.translate(this._tickLabelContainer,g,h),a.Util.DOM.translate(this._tickMarkContainer,f[0],f[1])},c.prototype._computeLayout=function(a,c,d,e){return this.measurer.clear(),b.prototype._computeLayout.call(this,a,c,d,e)},c}(a.Abstract.Axis);b.Category=c}(a.Axis||(a.Axis={}));a.Axis}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(a,c){if("undefined"==typeof a&&(a=""),"undefined"==typeof c&&(c="horizontal"),b.call(this),this.classed("label",!0),this.text(a),c=c.toLowerCase(),"vertical-left"===c&&(c="left"),"vertical-right"===c&&(c="right"),"horizontal"!==c&&"left"!==c&&"right"!==c)throw new Error(c+" is not a valid orientation for LabelComponent");this.orientation=c,this.xAlign("center").yAlign("center"),this._fixedHeightFlag=!0,this._fixedWidthFlag=!0}return __extends(c,b),c.prototype.xAlign=function(a){var c=a.toLowerCase();return b.prototype.xAlign.call(this,c),this.xAlignment=c,this},c.prototype.yAlign=function(a){var c=a.toLowerCase();return b.prototype.yAlign.call(this,c),this.yAlignment=c,this},c.prototype._requestedSpace=function(a,b){var c=this.measurer(this._text),d="horizontal"===this.orientation?c.width:c.height,e="horizontal"===this.orientation?c.height:c.width;return{width:d,height:e,wantsWidth:d>a,wantsHeight:e>b}},c.prototype._setup=function(){b.prototype._setup.call(this),this.textContainer=this.content.append("g"),this.measurer=a.Util.Text.getTextMeasure(this.textContainer),this.text(this._text)},c.prototype.text=function(a){return void 0===a?this._text:(this._text=a,this._invalidateLayout(),this)},c.prototype._doRender=function(){b.prototype._doRender.call(this),this.textContainer.text("");var c="horizontal"===this.orientation?this.availableWidth:this.availableHeight,d=a.Util.Text.getTruncatedText(this._text,c,this.measurer);"horizontal"===this.orientation?a.Util.Text.writeLineHorizontally(d,this.textContainer,this.availableWidth,this.availableHeight,this.xAlignment,this.yAlignment):a.Util.Text.writeLineVertically(d,this.textContainer,this.availableWidth,this.availableHeight,this.xAlignment,this.yAlignment,this.orientation)},c.prototype._computeLayout=function(c,d,e,f){return b.prototype._computeLayout.call(this,c,d,e,f),this.measurer=a.Util.Text.getTextMeasure(this.textContainer),this},c}(a.Abstract.Component);b.Label=c;var d=function(a){function b(b,c){a.call(this,b,c),this.classed("title-label",!0)}return __extends(b,a),b}(c);b.TitleLabel=d;var e=function(a){function b(b,c){a.call(this,b,c),this.classed("axis-label",!0)}return __extends(b,a),b}(c);b.AxisLabel=e}(a.Component||(a.Component={}));a.Component}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(a){b.call(this),this.classed("legend",!0),this.scale(a),this.xAlign("RIGHT").yAlign("TOP"),this.xOffset(5).yOffset(5),this._fixedWidthFlag=!0,this._fixedHeightFlag=!0}return __extends(c,b),c.prototype.remove=function(){b.prototype.remove.call(this),null!=this.colorScale&&this.colorScale.broadcaster.deregisterListener(this)},c.prototype.toggleCallback=function(a){return void 0!==a?(this._toggleCallback=a,this.isOff=d3.set(),this.updateListeners(),this.updateClasses(),this):this._toggleCallback},c.prototype.hoverCallback=function(a){return void 0!==a?(this._hoverCallback=a,this.datumCurrentlyFocusedOn=void 0,this.updateListeners(),this.updateClasses(),this):this._hoverCallback},c.prototype.scale=function(a){var b=this;return null!=a?(null!=this.colorScale&&this.colorScale.broadcaster.deregisterListener(this),this.colorScale=a,this.colorScale.broadcaster.registerListener(this,function(){return b.updateDomain()}),this.updateDomain(),this):this.colorScale},c.prototype.updateDomain=function(){null!=this._toggleCallback&&(this.isOff=a.Util.Methods.intersection(this.isOff,d3.set(this.scale().domain()))),null!=this._hoverCallback&&(this.datumCurrentlyFocusedOn=this.scale().domain().indexOf(this.datumCurrentlyFocusedOn)>=0?this.datumCurrentlyFocusedOn:void 0),this._invalidateLayout()},c.prototype._computeLayout=function(a,c,d,e){b.prototype._computeLayout.call(this,a,c,d,e);var f=this.measureTextHeight(),g=this.colorScale.domain().length;this.nRowsDrawn=Math.min(g,Math.floor(this.availableHeight/f))},c.prototype._requestedSpace=function(b,d){var e=this.measureTextHeight(),f=this.colorScale.domain().length,g=Math.min(f,Math.floor((d-2*c.MARGIN)/e)),h=this.content.append("g").classed(c.SUBELEMENT_CLASS,!0),i=h.append("text"),j=d3.max(this.colorScale.domain(),function(b){return a.Util.Text.getTextWidth(i,b)});h.remove(),j=void 0===j?0:j;var k=0===g?0:j+e+2*c.MARGIN,l=0===g?0:f*e+2*c.MARGIN;return{width:k,height:l,wantsWidth:k>b,wantsHeight:l>d}},c.prototype.measureTextHeight=function(){var b=this.content.append("g").classed(c.SUBELEMENT_CLASS,!0),d=a.Util.Text.getTextHeight(b.append("text"));return 0===d&&(d=1),b.remove(),d},c.prototype._doRender=function(){b.prototype._doRender.call(this);var d=this.colorScale.domain().slice(0,this.nRowsDrawn),e=this.measureTextHeight(),f=this.availableWidth-e-c.MARGIN,g=.3*e,h=this.content.selectAll("."+c.SUBELEMENT_CLASS).data(d,function(a){return a}),i=h.enter().append("g").classed(c.SUBELEMENT_CLASS,!0);i.append("circle"),i.append("g").classed("text-container",!0),h.exit().remove(),h.selectAll("circle").attr("cx",e/2).attr("cy",e/2).attr("r",g).attr("fill",this.colorScale._d3Scale),h.selectAll("g.text-container").text("").attr("transform","translate("+e+", 0)").each(function(b){var c=d3.select(this),d=a.Util.Text.getTextMeasure(c),e=a.Util.Text.getTruncatedText(b,f,d),g=d(e);a.Util.Text.writeLineHorizontally(e,c,g.width,g.height)}),h.attr("transform",function(a){return"translate("+c.MARGIN+","+(d.indexOf(a)*e+c.MARGIN)+")"}),this.updateClasses(),this.updateListeners()},c.prototype.updateListeners=function(){var a=this;if(this._isSetup){var b=this.content.selectAll("."+c.SUBELEMENT_CLASS);if(null!=this._hoverCallback){var d=function(b){return function(c){a.datumCurrentlyFocusedOn=b?c:void 0,a._hoverCallback(a.datumCurrentlyFocusedOn),a.updateClasses()}};b.on("mouseover",d(!0)),b.on("mouseout",d(!1))}else b.on("mouseover",null),b.on("mouseout",null);null!=this._toggleCallback?b.on("click",function(b){var c=a.isOff.has(b);c?a.isOff.remove(b):a.isOff.add(b),a._toggleCallback(b,c),a.updateClasses()}):b.on("click",null)}},c.prototype.updateClasses=function(){var a=this;if(this._isSetup){var b=this.content.selectAll("."+c.SUBELEMENT_CLASS);null!=this._hoverCallback?(b.classed("focus",function(b){return a.datumCurrentlyFocusedOn===b}),b.classed("hover",void 0!==this.datumCurrentlyFocusedOn)):(b.classed("hover",!1),b.classed("focus",!1)),null!=this._toggleCallback?(b.classed("toggled-on",function(b){return!a.isOff.has(b)}),b.classed("toggled-off",function(b){return a.isOff.has(b)})):(b.classed("toggled-on",!1),b.classed("toggled-off",!1))}},c.SUBELEMENT_CLASS="legend-row",c.MARGIN=5,c}(a.Abstract.Component);b.Legend=c}(a.Component||(a.Component={}));a.Component}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b,c){var d=this;if(a.call(this),null==b&&null==c)throw new Error("Gridlines must have at least one scale");this.classed("gridlines",!0),this.xScale=b,this.yScale=c,null!=this.xScale&&this.xScale.broadcaster.registerListener(this,function(){return d._render()}),null!=this.yScale&&this.yScale.broadcaster.registerListener(this,function(){return d._render()})}return __extends(b,a),b.prototype.remove=function(){return a.prototype.remove.call(this),null!=this.xScale&&this.xScale.broadcaster.deregisterListener(this),null!=this.yScale&&this.yScale.broadcaster.deregisterListener(this),this},b.prototype._setup=function(){a.prototype._setup.call(this),this.xLinesContainer=this.content.append("g").classed("x-gridlines",!0),this.yLinesContainer=this.content.append("g").classed("y-gridlines",!0)},b.prototype._doRender=function(){a.prototype._doRender.call(this),this.redrawXLines(),this.redrawYLines()},b.prototype.redrawXLines=function(){var a=this;if(null!=this.xScale){var b=this.xScale.ticks(),c=function(b){return a.xScale.scale(b)},d=this.xLinesContainer.selectAll("line").data(b);d.enter().append("line"),d.attr("x1",c).attr("y1",0).attr("x2",c).attr("y2",this.availableHeight).classed("zeroline",function(a){return 0===a}),d.exit().remove()}},b.prototype.redrawYLines=function(){var a=this;if(null!=this.yScale){var b=this.yScale.ticks(),c=function(b){return a.yScale.scale(b)},d=this.yLinesContainer.selectAll("line").data(b);d.enter().append("line"),d.attr("x1",0).attr("y1",c).attr("x2",this.availableWidth).attr("y2",c).classed("zeroline",function(a){return 0===a}),d.exit().remove()}},b}(a.Abstract.Component);b.Gridlines=c}(a.Component||(a.Component={}));a.Component}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(a){var b=function(b){function c(a,c,d){if(b.call(this,a),null==c||null==d)throw new Error("XYPlots require an xScale and yScale");this.classed("xy-plot",!0),this.project("x","x",c),this.project("y","y",d)}return __extends(c,b),c.prototype.project=function(a,c,d){return"x"===a&&null!=d&&(this.xScale=d,this._updateXDomainer()),"y"===a&&null!=d&&(this.yScale=d,this._updateYDomainer()),b.prototype.project.call(this,a,c,d),this},c.prototype._computeLayout=function(a,c,d,e){b.prototype._computeLayout.call(this,a,c,d,e),this.xScale.range([0,this.availableWidth]),this.yScale.range([this.availableHeight,0])},c.prototype._updateXDomainer=function(){if(this.xScale instanceof a.QuantitativeScale){var b=this.xScale;b._userSetDomainer||b.domainer().pad().nice()}},c.prototype._updateYDomainer=function(){if(this.yScale instanceof a.QuantitativeScale){var b=this.yScale;b._userSetDomainer||b.domainer().pad().nice()}},c}(a.Plot);a.XYPlot=b}(a.Abstract||(a.Abstract={}));a.Abstract}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(c,d,e){b.call(this,c,d,e),this._animators={"circles-reset":new a.Animator.Null,circles:(new a.Animator.IterativeDelay).duration(250).delay(5)},this.classed("scatter-plot",!0),this.project("r",3),this.project("opacity",.6),this.project("fill",function(){return a.Core.Colors.INDIGO})}return __extends(c,b),c.prototype.project=function(a,c,d){return a="cx"===a?"x":a,a="cy"===a?"y":a,b.prototype.project.call(this,a,c,d),this},c.prototype._paint=function(){b.prototype._paint.call(this);var a=this._generateAttrToProjector();a.cx=a.x,a.cy=a.y,delete a.x,delete a.y;var c=this.renderArea.selectAll("circle").data(this._dataSource.data());if(c.enter().append("circle"),this._dataChanged){var d=a.r;a.r=function(){return 0},this._applyAnimatedAttributes(c,"circles-reset",a),a.r=d}this._applyAnimatedAttributes(c,"circles",a),c.exit().remove()},c}(a.Abstract.XYPlot);b.Scatter=c}(a.Plot||(a.Plot={}));a.Plot}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(c,d,e,f){b.call(this,c,d,e),this._animators={cells:new a.Animator.Null},this.classed("grid-plot",!0),this.xScale.rangeType("bands",0,0),this.yScale.rangeType("bands",0,0),this.colorScale=f,this.project("fill","value",f)}return __extends(c,b),c.prototype.project=function(a,c,d){return b.prototype.project.call(this,a,c,d),"fill"===a&&(this.colorScale=this._projectors.fill.scale),this},c.prototype._paint=function(){b.prototype._paint.call(this);var a=this.renderArea.selectAll("rect").data(this._dataSource.data());a.enter().append("rect");var c=this.xScale.rangeBand(),d=this.yScale.rangeBand(),e=this._generateAttrToProjector();e.width=function(){return c},e.height=function(){return d},this._applyAnimatedAttributes(a,"cells",e),a.exit().remove()},c}(a.Abstract.XYPlot);b.Grid=c}(a.Plot||(a.Plot={}));a.Plot}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(c){function d(b,d,e){c.call(this,b,d,e),this._baselineValue=0,this._barAlignmentFactor=0,this._animators={"bars-reset":new a.Animator.Null,bars:new a.Animator.IterativeDelay,baseline:new a.Animator.Null},this.classed("bar-plot",!0),this.project("fill",function(){return a.Core.Colors.INDIGO}),this.baseline(this._baselineValue)}return __extends(d,c),d.prototype._setup=function(){c.prototype._setup.call(this),this._baseline=this.renderArea.append("line").classed("baseline",!0),this._bars=this.renderArea.selectAll("rect").data([])},d.prototype._paint=function(){c.prototype._paint.call(this),this._bars=this.renderArea.selectAll("rect").data(this._dataSource.data()),this._bars.enter().append("rect");var a=this._isVertical?this.yScale:this.xScale,b=a.scale(this._baselineValue),d=this._isVertical?"y":"x",e=this._isVertical?"height":"width";if(this._dataChanged&&this._animate){var f=this._generateAttrToProjector();f[d]=function(){return b},f[e]=function(){return 0},this._applyAnimatedAttributes(this._bars,"bars-reset",f)}var g=this._generateAttrToProjector();null!=g.fill&&this._bars.attr("fill",g.fill),this._applyAnimatedAttributes(this._bars,"bars",g),this._bars.exit().remove();var h={x1:this._isVertical?0:b,y1:this._isVertical?b:0,x2:this._isVertical?this.availableWidth:b,y2:this._isVertical?b:this.availableHeight};this._applyAnimatedAttributes(this._baseline,"baseline",h)},d.prototype.baseline=function(a){return this._baselineValue=a,this._updateXDomainer(),this._updateYDomainer(),this._render(),this},d.prototype.barAlignment=function(a){var b=a.toLowerCase(),c=this.constructor._BarAlignmentToFactor;if(void 0===c[b])throw new Error("unsupported bar alignment");return this._barAlignmentFactor=c[b],this._render(),this},d.prototype.parseExtent=function(a){if("number"==typeof a)return{min:a,max:a};if(a instanceof Object&&"min"in a&&"max"in a)return a;throw new Error("input '"+a+"' can't be parsed as an IExtent")},d.prototype.selectBar=function(a,b,c){if("undefined"==typeof c&&(c=!0),!this._isSetup)return null;var d=[],e=this.parseExtent(a),f=this.parseExtent(b),g=.5;if(this._bars.each(function(){var a=this.getBBox();a.x+a.width>=e.min-g&&a.x<=e.max+g&&a.y+a.height>=f.min-g&&a.y<=f.max+g&&d.push(this)}),d.length>0){var h=d3.selectAll(d);return h.classed("selected",c),h}return null},d.prototype.deselectAll=function(){return this._isSetup&&this._bars.classed("selected",!1),this},d.prototype._updateDomainer=function(a){if(a instanceof b.QuantitativeScale){var c=a;c._userSetDomainer||(null!=this._baselineValue?c.domainer().addPaddingException(this._baselineValue,"BAR_PLOT+"+this._plottableID).addIncludedValue(this._baselineValue,"BAR_PLOT+"+this._plottableID):c.domainer().removePaddingException("BAR_PLOT+"+this._plottableID).removeIncludedValue("BAR_PLOT+"+this._plottableID),c.domainer().pad()),c._autoDomainIfAutomaticMode()}},d.prototype._generateAttrToProjector=function(){var b=this,e=c.prototype._generateAttrToProjector.call(this),f=this._isVertical?this.yScale:this.xScale,g=this._isVertical?this.xScale:this.yScale,h=this._isVertical?"y":"x",i=this._isVertical?"x":"y",j=g instanceof a.Scale.Ordinal&&"bands"===g.rangeType(),k=f.scale(this._baselineValue);if(null==e.width){var l=j?g.rangeBand():d.DEFAULT_WIDTH;e.width=function(){return l}}var m=e[i],n=e.width;if(j){var o=g.rangeBand();e[i]=function(a,b){return m(a,b)-n(a,b)/2+o/2}}else e[i]=function(a,c){return m(a,c)-n(a,c)*b._barAlignmentFactor};var p=e[h];return e[h]=function(a,b){var c=p(a,b);return c>k?k:c},e.height=function(a,b){return Math.abs(k-p(a,b))},e},d.DEFAULT_WIDTH=10,d._BarAlignmentToFactor={},d}(b.XYPlot);b.BarPlot=c}(a.Abstract||(a.Abstract={}));a.Abstract}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b,c,d){a.call(this,b,c,d),this._isVertical=!0}return __extends(b,a),b.prototype._updateYDomainer=function(){this._updateDomainer(this.yScale)},b._BarAlignmentToFactor={left:0,center:.5,right:1},b}(a.Abstract.BarPlot);b.VerticalBar=c}(a.Plot||(a.Plot={}));a.Plot}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b,c,d){a.call(this,b,c,d),this.isVertical=!1}return __extends(b,a),b.prototype._updateXDomainer=function(){this._updateDomainer(this.xScale)},b.prototype._generateAttrToProjector=function(){var b=a.prototype._generateAttrToProjector.call(this),c=b.width;return b.width=b.height,b.height=c,b},b._BarAlignmentToFactor={top:0,center:.5,bottom:1},b}(a.Abstract.BarPlot);b.HorizontalBar=c}(a.Plot||(a.Plot={}));a.Plot}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(c,d,e){b.call(this,c,d,e),this._animators={"line-reset":new a.Animator.Null,line:(new a.Animator.Default).duration(600).easing("exp-in-out")},this.classed("line-plot",!0),this.project("stroke",function(){return a.Core.Colors.INDIGO}),this.project("stroke-width",function(){return"2px"})}return __extends(c,b),c.prototype._setup=function(){b.prototype._setup.call(this),this.linePath=this.renderArea.append("path").classed("line",!0)},c.prototype._getResetYFunction=function(){var a=this.yScale.domain(),b=Math.max(a[0],a[1]),c=Math.min(a[0],a[1]),d=0;0>b?d=b:c>0&&(d=c);var e=this.yScale.scale(d);return function(){return e}},c.prototype._generateAttrToProjector=function(){function a(a){return-1===d.indexOf(a)}var c=b.prototype._generateAttrToProjector.call(this),d=this._wholeDatumAttributes(),e=d3.keys(c).filter(a);return e.forEach(function(a){var b=c[a];c[a]=function(a,c){return a.length>0?b(a[0],c):null}}),c},c.prototype._paint=function(){b.prototype._paint.call(this);var a=this._generateAttrToProjector(),c=a.x,d=a.y;delete a.x,delete a.y,this.linePath.datum(this._dataSource.data()),this._dataChanged&&(a.d=d3.svg.line().x(c).y(this._getResetYFunction()),this._applyAnimatedAttributes(this.linePath,"line-reset",a)),a.d=d3.svg.line().x(c).y(d),this._applyAnimatedAttributes(this.linePath,"line",a)},c.prototype._wholeDatumAttributes=function(){return["x","y"]},c}(a.Abstract.XYPlot);b.Line=c}(a.Plot||(a.Plot={}));a.Plot}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(c,d,e){b.call(this,c,d,e),this.classed("area-plot",!0),this.project("y0",0,e),this.project("fill",function(){return a.Core.Colors.INDIGO}),this.project("fill-opacity",function(){return.25}),this.project("stroke",function(){return a.Core.Colors.INDIGO}),this._animators["area-reset"]=new a.Animator.Null,this._animators.area=(new a.Animator.Default).duration(600).easing("exp-in-out")}return __extends(c,b),c.prototype._setup=function(){b.prototype._setup.call(this),this.areaPath=this.renderArea.append("path").classed("area",!0)},c.prototype._onDataSourceUpdate=function(){b.prototype._onDataSourceUpdate.call(this),null!=this.yScale&&this._updateYDomainer()},c.prototype._updateYDomainer=function(){b.prototype._updateYDomainer.call(this);var a=this.yScale,c=this._projectors.y0,d=null!=c?c.accessor:null,e=null!=d?this.dataSource()._getExtent(d):[],f=2===e.length&&e[0]===e[1]?e[0]:null;a._userSetDomainer||(null!=f?a.domainer().addPaddingException(f,"AREA_PLOT+"+this._plottableID):a.domainer().removePaddingException("AREA_PLOT+"+this._plottableID),a._autoDomainIfAutomaticMode())},c.prototype.project=function(a,c,d){return b.prototype.project.call(this,a,c,d),"y0"===a&&this._updateYDomainer(),this},c.prototype._getResetYFunction=function(){return this._generateAttrToProjector().y0},c.prototype._paint=function(){b.prototype._paint.call(this);var a=this._generateAttrToProjector(),c=a.x,d=a.y0,e=a.y;delete a.x,delete a.y0,delete a.y,this.areaPath.datum(this._dataSource.data()),this._dataChanged&&(a.d=d3.svg.area().x(c).y0(d).y1(this._getResetYFunction()),this._applyAnimatedAttributes(this.areaPath,"area-reset",a)),a.d=d3.svg.area().x(c).y0(d).y1(e),this._applyAnimatedAttributes(this.areaPath,"area",a) +},c.prototype._wholeDatumAttributes=function(){var a=b.prototype._wholeDatumAttributes.call(this);return a.push("y0"),a},c}(b.Line);b.Area=c}(a.Plot||(a.Plot={}));a.Plot}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){var b=function(){function a(){}return a.prototype.animate=function(a,b){return a.attr(b)},a}();a.Null=b}(a.Animator||(a.Animator={}));a.Animator}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){var b=function(){function a(){this._durationMsec=300,this._delayMsec=0,this._easing="exp-out"}return a.prototype.animate=function(a,b){return a.transition().ease(this._easing).duration(this._durationMsec).delay(this._delayMsec).attr(b)},a.prototype.duration=function(a){return void 0===a?this._durationMsec:(this._durationMsec=a,this)},a.prototype.delay=function(a){return void 0===a?this._delayMsec:(this._delayMsec=a,this)},a.prototype.easing=function(a){return void 0===a?this._easing:(this._easing=a,this)},a}();a.Default=b}(a.Animator||(a.Animator={}));a.Animator}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(a){var b=function(a){function b(){a.apply(this,arguments),this._delayMsec=15}return __extends(b,a),b.prototype.animate=function(a,b){var c=this;return a.transition().ease(this._easing).duration(this._durationMsec).delay(function(a,b){return b*c._delayMsec}).attr(b)},b}(a.Default);a.IterativeDelay=b}(a.Animator||(a.Animator={}));a.Animator}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){!function(a){function b(){e||(d3.select(document).on("keydown",d),e=!0)}function c(a,c){e||b(),null==f[a]&&(f[a]=[]),f[a].push(c)}function d(){null!=f[d3.event.keyCode]&&f[d3.event.keyCode].forEach(function(a){a(d3.event)})}var e=!1,f=[];a.initialize=b,a.addCallback=c}(a.KeyEventListener||(a.KeyEventListener={}));a.KeyEventListener}(a.Core||(a.Core={}));a.Core}(Plottable||(Plottable={}));var Plottable;!function(a){!function(a){var b=function(){function a(a){if(null==a)throw new Error("Interactions require a component to listen to");this.componentToListenTo=a}return a.prototype._anchor=function(a){this.hitBox=a},a.prototype.registerWithComponent=function(){return this.componentToListenTo.registerInteraction(this),this},a}();a.Interaction=b}(a.Abstract||(a.Abstract={}));a.Abstract}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b){a.call(this,b)}return __extends(b,a),b.prototype._anchor=function(b){var c=this;a.prototype._anchor.call(this,b),b.on(this._listenTo(),function(){var a=d3.mouse(b.node()),d=a[0],e=a[1];c._callback(d,e)})},b.prototype._listenTo=function(){return"click"},b.prototype.callback=function(a){return this._callback=a,this},b}(a.Abstract.Interaction);b.Click=c;var d=function(a){function b(b){a.call(this,b)}return __extends(b,a),b.prototype._listenTo=function(){return"dblclick"},b}(c);b.DoubleClick=d}(a.Interaction||(a.Interaction={}));a.Interaction}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b){a.call(this,b)}return __extends(b,a),b.prototype._anchor=function(b){var c=this;a.prototype._anchor.call(this,b),b.on("mousemove",function(){var a=d3.mouse(b.node()),d=a[0],e=a[1];c.mousemove(d,e)})},b.prototype.mousemove=function(){},b}(a.Abstract.Interaction);b.Mousemove=c}(a.Interaction||(a.Interaction={}));a.Interaction}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(a,c){b.call(this,a),this.activated=!1,this.keyCode=c}return __extends(c,b),c.prototype._anchor=function(c){var d=this;b.prototype._anchor.call(this,c),c.on("mouseover",function(){d.activated=!0}),c.on("mouseout",function(){d.activated=!1}),a.Core.KeyEventListener.addCallback(this.keyCode,function(){d.activated&&null!=d._callback&&d._callback()})},c.prototype.callback=function(a){return this._callback=a,this},c}(a.Abstract.Interaction);b.Key=c}(a.Interaction||(a.Interaction={}));a.Interaction}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(c,d,e){var f=this;b.call(this,c),null==d&&(d=new a.Scale.Linear),null==e&&(e=new a.Scale.Linear),this.xScale=d,this.yScale=e,this.zoom=d3.behavior.zoom(),this.zoom.x(this.xScale._d3Scale),this.zoom.y(this.yScale._d3Scale),this.zoom.on("zoom",function(){return f.rerenderZoomed()})}return __extends(c,b),c.prototype.resetZoom=function(){var a=this;this.zoom=d3.behavior.zoom(),this.zoom.x(this.xScale._d3Scale),this.zoom.y(this.yScale._d3Scale),this.zoom.on("zoom",function(){return a.rerenderZoomed()}),this.zoom(this.hitBox)},c.prototype._anchor=function(a){b.prototype._anchor.call(this,a),this.zoom(a)},c.prototype.rerenderZoomed=function(){var a=this.xScale._d3Scale.domain(),b=this.yScale._d3Scale.domain();this.xScale.domain(a),this.yScale.domain(b)},c}(a.Abstract.Interaction);b.PanZoom=c}(a.Interaction||(a.Interaction={}));a.Interaction}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b){var c=this;a.call(this,b),this.dragInitialized=!1,this.origin=[0,0],this.location=[0,0],this.dragBehavior=d3.behavior.drag(),this.dragBehavior.on("dragstart",function(){return c._dragstart()}),this.dragBehavior.on("drag",function(){return c._drag()}),this.dragBehavior.on("dragend",function(){return c._dragend()})}return __extends(b,a),b.prototype.callback=function(a){return this.callbackToCall=a,this},b.prototype._dragstart=function(){var a=this.componentToListenTo.availableWidth,b=this.componentToListenTo.availableHeight,c=function(a,b){return function(c){return Math.min(Math.max(c,a),b)}};this.constrainX=c(0,a),this.constrainY=c(0,b)},b.prototype._drag=function(){this.dragInitialized||(this.origin=[d3.event.x,d3.event.y],this.dragInitialized=!0),this.location=[this.constrainX(d3.event.x),this.constrainY(d3.event.y)]},b.prototype._dragend=function(){this.dragInitialized&&(this.dragInitialized=!1,this._doDragend())},b.prototype._doDragend=function(){null!=this.callbackToCall&&this.callbackToCall([this.origin,this.location])},b.prototype._anchor=function(b){return a.prototype._anchor.call(this,b),b.call(this.dragBehavior),this},b.prototype.setupZoomCallback=function(a,b){function c(c){return null==c?(f&&(null!=a&&a.domain(d),null!=b&&b.domain(e)),void(f=!f)):(f=!1,null!=a&&a.domain([a.invert(c.xMin),a.invert(c.xMax)]),null!=b&&b.domain([b.invert(c.yMax),b.invert(c.yMin)]),void this.clearBox())}var d=null!=a?a.domain():null,e=null!=b?b.domain():null,f=!1;return this.callback(c),this},b}(a.Abstract.Interaction);b.Drag=c}(a.Interaction||(a.Interaction={}));a.Interaction}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(a){var b=function(a){function b(){a.apply(this,arguments),this.boxIsDrawn=!1}return __extends(b,a),b.prototype._dragstart=function(){a.prototype._dragstart.call(this),null!=this.callbackToCall&&this.callbackToCall(null),this.clearBox()},b.prototype.clearBox=function(){return null!=this.dragBox?(this.dragBox.attr("height",0).attr("width",0),this.boxIsDrawn=!1,this):void 0},b.prototype.setBox=function(a,b,c,d){if(null!=this.dragBox){var e=Math.abs(a-b),f=Math.abs(c-d),g=Math.min(a,b),h=Math.min(c,d);return this.dragBox.attr({x:g,y:h,width:e,height:f}),this.boxIsDrawn=e>0&&f>0,this}},b.prototype._anchor=function(c){a.prototype._anchor.call(this,c);var d=b.CLASS_DRAG_BOX,e=this.componentToListenTo.backgroundContainer;return this.dragBox=e.append("rect").classed(d,!0).attr("x",0).attr("y",0),this},b.CLASS_DRAG_BOX="drag-box",b}(a.Drag);a.DragBox=b}(a.Interaction||(a.Interaction={}));a.Interaction}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(a){var b=function(a){function b(){a.apply(this,arguments)}return __extends(b,a),b.prototype._drag=function(){a.prototype._drag.call(this),this.setBox(this.origin[0],this.location[0])},b.prototype._doDragend=function(){if(null!=this.callbackToCall){var a=Math.min(this.origin[0],this.location[0]),b=Math.max(this.origin[0],this.location[0]),c={xMin:a,xMax:b};this.callbackToCall(c)}},b.prototype.setBox=function(b,c){return a.prototype.setBox.call(this,b,c,0,this.componentToListenTo.availableHeight),this},b}(a.DragBox);a.XDragBox=b}(a.Interaction||(a.Interaction={}));a.Interaction}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(a){var b=function(a){function b(){a.apply(this,arguments)}return __extends(b,a),b.prototype._drag=function(){a.prototype._drag.call(this),this.setBox(this.origin[0],this.location[0],this.origin[1],this.location[1])},b.prototype._doDragend=function(){if(null!=this.callbackToCall){var a=Math.min(this.origin[0],this.location[0]),b=Math.max(this.origin[0],this.location[0]),c=Math.min(this.origin[1],this.location[1]),d=Math.max(this.origin[1],this.location[1]),e={xMin:a,xMax:b,yMin:c,yMax:d};this.callbackToCall(e)}},b}(a.DragBox);a.XYDragBox=b}(a.Interaction||(a.Interaction={}));a.Interaction}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(a){var b=function(a){function b(){a.apply(this,arguments)}return __extends(b,a),b.prototype._drag=function(){a.prototype._drag.call(this),this.setBox(this.origin[1],this.location[1])},b.prototype._doDragend=function(){if(null!=this.callbackToCall){var a=Math.min(this.origin[1],this.location[1]),b=Math.max(this.origin[1],this.location[1]),c={yMin:a,yMax:b};this.callbackToCall(c)}},b.prototype.setBox=function(b,c){return a.prototype.setBox.call(this,0,this.componentToListenTo.availableWidth,b,c),this},b}(a.DragBox);a.YDragBox=b}(a.Interaction||(a.Interaction={}));a.Interaction}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(a){var b=function(a){function b(b){a.call(this),this._event2Callback={},this.connected=!1,this._target=b}return __extends(b,a),b.prototype.target=function(a){if(null==a)return this._target;var b=this.connected;return this.disconnect(),this._target=a,b&&this.connect(),this},b.prototype.getEventString=function(a){return a+".dispatcher"+this._plottableID},b.prototype.connect=function(){var a=this;if(this.connected)throw new Error("Can't connect dispatcher twice!");return this.connected=!0,Object.keys(this._event2Callback).forEach(function(b){var c=a._event2Callback[b];a._target.on(a.getEventString(b),c)}),this},b.prototype.disconnect=function(){var a=this;return this.connected=!1,Object.keys(this._event2Callback).forEach(function(b){a._target.on(a.getEventString(b),null)}),this},b}(a.PlottableObject);a.Dispatcher=b}(a.Abstract||(a.Abstract={}));a.Abstract}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(a){function b(b){var c=this;a.call(this,b),this._event2Callback.mouseover=function(){null!=c._mouseover&&c._mouseover(c.getMousePosition())},this._event2Callback.mousemove=function(){null!=c._mousemove&&c._mousemove(c.getMousePosition())},this._event2Callback.mouseout=function(){null!=c._mouseout&&c._mouseout(c.getMousePosition())}}return __extends(b,a),b.prototype.getMousePosition=function(){var a=d3.mouse(this._target.node());return{x:a[0],y:a[1]}},b.prototype.mouseover=function(a){return void 0===a?this._mouseover:(this._mouseover=a,this)},b.prototype.mousemove=function(a){return void 0===a?this._mousemove:(this._mousemove=a,this)},b.prototype.mouseout=function(a){return void 0===a?this._mouseout:(this._mouseout=a,this)},b}(a.Abstract.Dispatcher);b.Mouse=c}(a.Dispatcher||(a.Dispatcher={}));a.Dispatcher}(Plottable||(Plottable={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},Plottable;!function(a){!function(b){var c=function(b){function c(){b.call(this),this.xTable=new a.Component.Table,this.yTable=new a.Component.Table,this.centerComponent=new a.Component.Group,this.xyTable=(new a.Component.Table).addComponent(0,0,this.yTable).addComponent(1,1,this.xTable).addComponent(0,1,this.centerComponent),this.addComponent(1,0,this.xyTable)}return __extends(c,b),c.prototype.yAxis=function(a){if(null!=a){if(null!=this._yAxis)throw new Error("yAxis already assigned!");return this._yAxis=a,this.yTable.addComponent(0,1,this._yAxis),this}return this._yAxis},c.prototype.xAxis=function(a){if(null!=a){if(null!=this._xAxis)throw new Error("xAxis already assigned!");return this._xAxis=a,this.xTable.addComponent(0,0,this._xAxis),this}return this._xAxis},c.prototype.yLabel=function(b){if(null!=b){if(null!=this._yLabel){if("string"==typeof b)return this._yLabel.text(b),this;throw new Error("yLabel already assigned!")}return"string"==typeof b&&(b=new a.Component.AxisLabel(b,"vertical-left")),this._yLabel=b,this.yTable.addComponent(0,0,this._yLabel),this}return this._yLabel},c.prototype.xLabel=function(b){if(null!=b){if(null!=this._xLabel){if("string"==typeof b)return this._xLabel.text(b),this;throw new Error("xLabel already assigned!")}return"string"==typeof b&&(b=new a.Component.AxisLabel(b,"horizontal")),this._xLabel=b,this.xTable.addComponent(1,0,this._xLabel),this}return this._xLabel},c.prototype.titleLabel=function(b){if(null!=b){if(null!=this._titleLabel){if("string"==typeof b)return this._titleLabel.text(b),this;throw new Error("titleLabel already assigned!")}return"string"==typeof b&&(b=new a.Component.TitleLabel(b,"horizontal")),this._titleLabel=b,this.addComponent(0,0,this._titleLabel),this}return this._titleLabel},c.prototype.center=function(a){return this.centerComponent.merge(a),this},c}(a.Component.Table);b.StandardChart=c}(a.Template||(a.Template={}));a.Template}(Plottable||(Plottable={})); \ No newline at end of file diff --git a/plottable.zip b/plottable.zip index f4098b5b42..f64ce99418 100644 Binary files a/plottable.zip and b/plottable.zip differ