webglimpse
Version:
Webglimpse is a data visualization library for the web.
1 lines • 1.3 MB
Source Map (JSON)
{"version":3,"file":"webglimpse.mjs","sources":["../../src/webglimpse/util/util.ts","../../src/webglimpse/util/cache.ts","../../src/webglimpse/util/multikey_cache.ts","../../src/webglimpse/bounds.ts","../../src/webglimpse/color.ts","../../src/webglimpse/matrix.ts","../../src/webglimpse/util/notification.ts","../../src/webglimpse/util/ordered_set.ts","../../src/webglimpse/util/sorted_arrays.ts","../../src/webglimpse/util/binary_tree.ts","../../src/webglimpse/util/sorted_multimap.ts","../../src/webglimpse/util/split.ts","../../src/webglimpse/buffer.ts","../../src/webglimpse/shader.ts","../../src/webglimpse/core.ts","../../src/webglimpse/misc.ts","../../src/webglimpse/texture.ts","../../src/webglimpse/text.ts","../../src/webglimpse/label.ts","../../src/webglimpse/scroll.ts","../../src/webglimpse/layout/inset_layout.ts","../../src/webglimpse/layout/corner_layout.ts","../../src/webglimpse/layout/row_layout.ts","../../src/webglimpse/layout/column_layout.ts","../../src/webglimpse/layout/overlay_layout.ts","../../src/webglimpse/layout/card_layout.ts","../../src/webglimpse/painter/border_painter.ts","../../src/webglimpse/plot/axis.ts","../../src/webglimpse/plot/plot_layout.ts","../../src/webglimpse/gradient.ts","../../src/webglimpse/plot/heatmap_painter.ts","../../src/webglimpse/plot/edge_axis_painter.ts","../../src/webglimpse/plot/line_painter.ts","../../src/webglimpse/time.ts","../../src/webglimpse/timeline/time_axis.ts","../../src/webglimpse/timeline/time_axis_painter.ts","../../src/webglimpse/timeline/time_grid_painter.ts","../../src/webglimpse/timeline/timeline_lanes.ts","../../src/webglimpse/timeline/timeline_events_row.ts","../../src/webglimpse/timeline/timeline_model.ts","../../src/webglimpse/timeline/timeline_layout.ts","../../src/webglimpse/timeline/timeline_cursor_painter.ts","../../src/webglimpse/timeline/timeline_annotation_painter.ts","../../src/webglimpse/timeline/timeline_annotation_style.ts","../../src/webglimpse/timeline/timeline_event_style.ts","../../src/webglimpse/timeline/timeline_ui.ts","../../src/webglimpse/timeline/timeline_timeseries_row.ts","../../src/webglimpse/timeline/timeline_styles.ts","../../src/webglimpse/timeline/timeline_pane.ts","../../src/public_api.ts","../../src/webglimpse.ts"],"sourcesContent":["/*\r\n * Copyright (c) 2014, Metron, Inc.\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without modification,\r\n * are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice, this\r\n * list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * 3. Neither the name of the copyright holder nor the names of its contributors\r\n * may be used to endorse or promote products derived from this software without\r\n * specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR\r\n * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\r\n * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\n\r\n// Alias for more readable access to static constants\r\nexport let GL = WebGLRenderingContext;\r\n\r\n\r\nexport function hasval(value: any): boolean {\r\n // Double-equals is weird: ( undefined == null ) is true\r\n return (value != null);\r\n}\r\n\r\n\r\nexport function isNumber(value: any): boolean {\r\n return typeof (value) === 'number';\r\n}\r\n\r\n\r\nexport function isString(value: any): boolean {\r\n return typeof (value) === 'string';\r\n}\r\n\r\n\r\nexport function isEmpty(array: any[]): boolean {\r\n return (array.length === 0);\r\n}\r\n\r\n\r\nexport function notEmpty(array: any[]): boolean {\r\n return (array.length > 0);\r\n}\r\n\r\n\r\nexport function alwaysTrue(): boolean {\r\n return true;\r\n}\r\n\r\n\r\nexport function alwaysFalse(): boolean {\r\n return false;\r\n}\r\n\r\n\r\nexport function constantFn<V>(value: V): () => V {\r\n return function (): V {\r\n return value;\r\n };\r\n}\r\n\r\n\r\nexport function log10(x: number): number {\r\n return Math.log(x) * (1.0 / Math.LN10);\r\n}\r\n\r\n\r\nexport function order(x: number): number {\r\n return Math.floor(log10(x) + 1e-12);\r\n}\r\n\r\n\r\nexport function clamp(xMin: number, xMax: number, x: number): number {\r\n return Math.max(xMin, Math.min(xMax, x));\r\n}\r\n\r\n\r\nexport function copyArray<T>(values: T[]): T[] {\r\n return values.slice(0);\r\n}\r\n\r\n\r\nexport function ensureCapacityFloat32(buffer: Float32Array, minNewCapacity: number): Float32Array {\r\n // if minNewCapacity is NaN, null, or undefined, don't try to resize the buffer\r\n if (!minNewCapacity || buffer.length >= minNewCapacity) {\r\n return buffer;\r\n }\r\n else {\r\n const newCapacity = Math.max(minNewCapacity, 2 * buffer.length);\r\n return new Float32Array(newCapacity);\r\n }\r\n}\r\n\r\n\r\nexport function ensureCapacityUint32(buffer: Uint32Array, minNewCapacity: number): Uint32Array {\r\n // if minNewCapacity is NaN, null, or undefined, don't try to resize the buffer\r\n if (!minNewCapacity || buffer.length >= minNewCapacity) {\r\n return buffer;\r\n }\r\n else {\r\n const newCapacity = Math.max(minNewCapacity, 2 * buffer.length);\r\n return new Uint32Array(newCapacity);\r\n }\r\n}\r\n\r\n\r\nexport function ensureCapacityUint16(buffer: Uint16Array, minNewCapacity: number): Uint16Array {\r\n // if minNewCapacity is NaN, null, or undefined, don't try to resize the buffer\r\n if (!minNewCapacity || buffer.length >= minNewCapacity) {\r\n return buffer;\r\n }\r\n else {\r\n const newCapacity = Math.max(minNewCapacity, 2 * buffer.length);\r\n return new Uint16Array(newCapacity);\r\n }\r\n}\r\n\r\n\r\nexport interface StringMap<V> {\r\n [key: string]: V;\r\n}\r\n\r\nexport type IdFunction<V> = (value: V) => string;\r\n\r\n\r\nexport let getObjectId = (function () {\r\n const keyName = 'webglimpse_ObjectId';\r\n let nextValue = 0;\r\n return function (obj: any): string {\r\n let value = obj[keyName];\r\n if (!hasval(value)) {\r\n value = (nextValue++).toString();\r\n obj[keyName] = value;\r\n }\r\n return value;\r\n };\r\n})();\r\n\r\n\r\nexport function concatLines(...lines: string[]) {\r\n return lines.join('\\n');\r\n}\r\n\r\n\r\n/**\r\n * Parses a timestamp from the format 'YYYY-MM-DDTHH:mm:ss[.SSS]ZZ' into posix-milliseconds.\r\n *\r\n * Format examples:\r\n * - '2014-01-01T00:00:00Z'\r\n * - '2014-01-01T00:00:00.000+00:00'\r\n *\r\n * Use of a colon in numeric timezones is optional. However, it is strongly encouraged, for\r\n * compatibility with Date in major browsers.\r\n *\r\n * Parsing is strict, and will throw an error if the input string does not match the expected\r\n * format. A notable example is that the seconds field must not have more than three decimal\r\n * places.\r\n *\r\n */\r\nimport moment from 'moment';\r\n\r\nexport function parseTime_PMILLIS(time_ISO8601: string): number {\r\n\r\n // Moment's lenient parsing is way too lenient -- but its strict parsing is a little too\r\n // strict, so we have to try several possible formats.\r\n //\r\n // We could pass in multiple formats to try all at once, but Moment's docs warn that that\r\n // can be slow. Plus, we expect some formats to be more common than others, so we can make\r\n // the common formats fast at the expense of the less common ones.\r\n //\r\n\r\n let m = moment(time_ISO8601, 'YYYY-MM-DDTHH:mm:ssZZ', true);\r\n if (m.isValid()) {\r\n return m.valueOf();\r\n }\r\n\r\n m = moment(time_ISO8601, 'YYYY-MM-DDTHH:mm:ss.SSSZZ', true);\r\n if (m.isValid()) {\r\n return m.valueOf();\r\n }\r\n\r\n m = moment(time_ISO8601, 'YYYY-MM-DDTHH:mm:ss.SSZZ', true);\r\n if (m.isValid()) {\r\n return m.valueOf();\r\n }\r\n\r\n m = moment(time_ISO8601, 'YYYY-MM-DDTHH:mm:ss.SZZ', true);\r\n if (m.isValid()) {\r\n return m.valueOf();\r\n }\r\n\r\n throw new Error('Failed to parse time-string: \\'' + time_ISO8601 + '\\'');\r\n}\r\n\r\n\r\n/**\r\n * Formats a timestamp from posix-millis into the format 'YYYY-MM-DDThh:mm:ss.SSSZZ' (for\r\n * example '2014-01-01T00:00:00.000Z').\r\n *\r\n * The input value is effectively truncated (not rounded!) to milliseconds. So for example,\r\n * formatTime_ISO8601(12345.999) will return '1970-01-01T00:00:12.345Z' -- exactly the same\r\n * as for an input of 12345.\r\n *\r\n */\r\nexport function formatTime_ISO8601(time_PMILLIS: number): string {\r\n return moment(time_PMILLIS).toISOString();\r\n}\r\n\r\n\r\n\r\n","/*\r\n * Copyright (c) 2014, Metron, Inc.\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without modification,\r\n * are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice, this\r\n * list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * 3. Neither the name of the copyright holder nor the names of its contributors\r\n * may be used to endorse or promote products derived from this software without\r\n * specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR\r\n * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\r\n * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\n\r\n\r\nexport interface CacheHelper<V> {\r\n create(key: string): V;\r\n dispose(value: V, key: string): void;\r\n}\r\n\r\n\r\nclass CacheEntry<V> {\r\n value: V;\r\n touched = false;\r\n\r\n constructor(value: V) {\r\n this.value = value;\r\n }\r\n}\r\n\r\n\r\nexport class Cache<V> {\r\n private helper: CacheHelper<V>;\r\n private map: { [k: string]: CacheEntry<V>; };\r\n\r\n constructor(helper: CacheHelper<V>) {\r\n this.helper = helper;\r\n this.map = {};\r\n }\r\n\r\n value(key: string): V {\r\n if (!this.map.hasOwnProperty(key)) {\r\n this.map[key] = new CacheEntry<V>(this.helper.create(key));\r\n }\r\n const en = this.map[key];\r\n\r\n en.touched = true;\r\n return en.value;\r\n }\r\n\r\n clear() {\r\n for (const k in this.map) {\r\n if (this.map.hasOwnProperty(k)) {\r\n this.helper.dispose(this.map[k].value, k);\r\n }\r\n }\r\n this.map = {};\r\n }\r\n\r\n remove(key: string) {\r\n if (this.map.hasOwnProperty(key)) {\r\n this.helper.dispose(this.map[key].value, key);\r\n delete this.map[key];\r\n }\r\n }\r\n\r\n removeAll(keys: string[]) {\r\n for (let i = 0; i < keys.length; i++) {\r\n this.remove(keys[i]);\r\n }\r\n }\r\n\r\n retain(key: string) {\r\n const newMap: { [k: string]: CacheEntry<V>; } = {};\r\n if (this.map.hasOwnProperty(key)) {\r\n newMap[key] = this.map[key];\r\n delete this.map[key];\r\n }\r\n for (const k in this.map) {\r\n if (this.map.hasOwnProperty(k)) {\r\n this.helper.dispose(this.map[k].value, k);\r\n }\r\n }\r\n this.map = newMap;\r\n }\r\n\r\n retainAll(keys: string[]) {\r\n const newMap: { [key: string]: CacheEntry<V>; } = {};\r\n for (let i = 0; i < keys.length; i++) {\r\n const k = keys[i];\r\n if (this.map.hasOwnProperty(k)) {\r\n newMap[k] = this.map[k];\r\n delete this.map[k];\r\n }\r\n }\r\n for (const k2 in this.map) {\r\n if (this.map.hasOwnProperty(k2)) {\r\n this.helper.dispose(this.map[k2].value, k2);\r\n }\r\n }\r\n this.map = newMap;\r\n }\r\n\r\n resetTouches() {\r\n for (const k in this.map) {\r\n if (this.map.hasOwnProperty(k)) {\r\n this.map[k].touched = false;\r\n }\r\n }\r\n }\r\n\r\n retainTouched() {\r\n const newMap: { [k: string]: CacheEntry<V>; } = {};\r\n for (const k in this.map) {\r\n if (this.map.hasOwnProperty(k)) {\r\n const en = this.map[k];\r\n if (en.touched) {\r\n newMap[k] = this.map[k];\r\n }\r\n else {\r\n this.helper.dispose(en.value, k);\r\n }\r\n }\r\n }\r\n this.map = newMap;\r\n }\r\n}\r\n\r\n\r\n","/*\r\n * Copyright (c) 2014, Metron, Inc.\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without modification,\r\n * are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice, this\r\n * list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * 3. Neither the name of the copyright holder nor the names of its contributors\r\n * may be used to endorse or promote products derived from this software without\r\n * specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR\r\n * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\r\n * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n */\r\n\r\n\r\n\r\nexport interface MultiKeyCacheHelper<V> {\r\n create(keyParts: string[]): V;\r\n dispose(value: V, keyParts: string[]): void;\r\n}\r\n\r\n\r\nclass MultiKeyCacheEntry<V> {\r\n keyParts: string[];\r\n value: V;\r\n touched = false;\r\n\r\n constructor(keyParts: string[], value: V) {\r\n this.keyParts = keyParts;\r\n this.value = value;\r\n }\r\n}\r\n\r\n\r\nexport class MultiKeyCache<V> {\r\n private helper: MultiKeyCacheHelper<V>;\r\n private map: { [key: string]: MultiKeyCacheEntry<V>; };\r\n\r\n constructor(helper: MultiKeyCacheHelper<V>) {\r\n this.helper = helper;\r\n this.map = {};\r\n }\r\n\r\n private combineKeyParts(keyParts: string[]): string {\r\n const esc = '\\\\';\r\n const sep = ';';\r\n const escapedEsc = esc + esc;\r\n const escapedSep = esc + sep;\r\n\r\n const escapedParts = <string[]>[];\r\n for (let n = 0; n < keyParts.length; n++) {\r\n escapedParts[n] = keyParts[n].replace(esc, escapedEsc).replace(sep, escapedSep);\r\n }\r\n return escapedParts.join(sep);\r\n }\r\n\r\n value(...keyParts: string[]): V {\r\n const key = this.combineKeyParts(keyParts);\r\n if (!this.map.hasOwnProperty(key)) {\r\n this.map[key] = new MultiKeyCacheEntry<V>(keyParts, this.helper.create(keyParts));\r\n }\r\n const en = this.map[key];\r\n\r\n en.touched = true;\r\n return en.value;\r\n }\r\n\r\n remove(...keyParts: string[]) {\r\n const key = this.combineKeyParts(keyParts);\r\n if (this.map.hasOwnProperty(key)) {\r\n const en = this.map[key];\r\n this.helper.dispose(en.value, en.keyParts);\r\n delete this.map[key];\r\n }\r\n }\r\n\r\n retain(...keyParts: string[]) {\r\n const newMap: { [k: string]: MultiKeyCacheEntry<V>; } = {};\r\n const retainKey = this.combineKeyParts(keyParts);\r\n if (this.map.hasOwnProperty(retainKey)) {\r\n newMap[retainKey] = this.map[retainKey];\r\n delete this.map[retainKey];\r\n }\r\n for (const key in this.map) {\r\n if (this.map.hasOwnProperty(key)) {\r\n const en = this.map[key];\r\n this.helper.dispose(en.value, en.keyParts);\r\n }\r\n }\r\n this.map = newMap;\r\n }\r\n\r\n resetTouches() {\r\n for (const key in this.map) {\r\n if (this.map.hasOwnProperty(key)) {\r\n this.map[key].touched = false;\r\n }\r\n }\r\n }\r\n\r\n retainTouched() {\r\n const newMap: { [key: string]: MultiKeyCacheEntry<V>; } = {};\r\n for (const key in this.map) {\r\n if (this.map.hasOwnProperty(key)) {\r\n const en = this.map[key];\r\n if (en.touched) {\r\n newMap[key] = this.map[key];\r\n }\r\n else {\r\n this.helper.dispose(en.value, en.keyParts);\r\n }\r\n }\r\n }\r\n this.map = newMap;\r\n }\r\n\r\n clear() {\r\n for (const key in this.map) {\r\n if (this.map.hasOwnProperty(key)) {\r\n const en = this.map[key];\r\n this.helper.dispose(en.value, en.keyParts);\r\n }\r\n }\r\n this.map = {};\r\n }\r\n}\r\n\r\n\r\nexport interface TwoKeyCacheHelper<V> {\r\n create(keyPart1: string, keyPart2: string): V;\r\n dispose(value: V, keyPart1: string, keyPart2: string): void;\r\n}\r\n\r\n\r\nexport class TwoKeyCache<V> {\r\n private cache: MultiKeyCache<V>;\r\n\r\n constructor(helper: TwoKeyCacheHelper<V>) {\r\n this.cache = new MultiKeyCache<V>({\r\n create: function (keyParts: string[]): V {\r\n return helper.create(keyParts[0], keyParts[1]);\r\n },\r\n dispose: function (value: V, keyParts: string[]) {\r\n helper.dispose(value, keyParts[0], keyParts[1]);\r\n }\r\n });\r\n }\r\n\r\n value(keyPart1: string, keyPart2: string): V { return this.cache.value(keyPart1, keyPart2); }\r\n remove(keyPart1: string, keyPart2: string) { this.cache.remove(keyPart1, keyPart2); }\r\n retain(keyPart1: string, keyPart2: string) { this.cache.retain(keyPart1, keyPart2); }\r\n resetTouches() { this.cache.resetTouches(); }\r\n retainTouched() { this.cache.retainTouched(); }\r\n clear() { this.cache.clear(); }\r\n}\r\n\r\n\r\nexport interface ThreeKeyCacheHelper<V> {\r\n create(keyPart1: string, keyPart2: string, keyPart3: string): V;\r\n dispose(value: V, keyPart1: string, keyPart2: string, keyPart3: string): void;\r\n}\r\n\r\n\r\nexport class ThreeKeyCache<V> {\r\n private cache: MultiKeyCache<V>;\r\n\r\n constructor(helper: ThreeKeyCacheHelper<V>) {\r\n this.cache = new MultiKeyCache<V>({\r\n create: function (keyParts: string[]): V {\r\n return helper.create(keyParts[0], keyParts[1], keyParts[2]);\r\n },\r\n dispose: function (value: V, keyParts: string[]) {\r\n helper.dispose(value, keyParts[0], keyParts[1], keyParts[2]);\r\n }\r\n });\r\n }\r\n\r\n value(keyPart1: string, keyPart2: string, keyPart3: string): V { return this.cache.value(keyPart1, keyPart2, keyPart3); }\r\n remove(keyPart1: string, keyPart2: string, keyPart3: string) { this.cache.remove(keyPart1, keyPart2, keyPart3); }\r\n retain(keyPart1: string, keyPart2: string, keyPart3: string) { this.cache.retain(keyPart1, keyPart2, keyPart3); }\r\n resetTouches() { this.cache.resetTouches(); }\r\n retainTouched() { this.cache.retainTouched(); }\r\n clear() { this.cache.clear(); }\r\n}\r\n\r\nexport interface SixKeyCacheHelper<V> {\r\n create(keyPart1: string, keyPart2: string, keyPart3: string, keyPart4: string, keyPart5: string, keyPart6: string): V;\r\n dispose(value: V, keyPart1: string, keyPart2: string, keyPart3: string, keyPart4: string, keyPart5: string, keyPart6: string): void;\r\n}\r\nexport class SixKeyCache<V> {\r\n private cache: MultiKeyCache<V>;\r\n\r\n constructor(helper: SixKeyCacheHelper<V>) {\r\n this.cache = new MultiKeyCache<V>({\r\n create: function (keyParts: string[]): V {\r\n return helper.create(keyParts[0], keyParts[1], keyParts[2], keyParts[3], keyParts[4], keyParts[5]);\r\n },\r\n dispose: function (value: V, keyParts: string[]) {\r\n helper.dispose(value, keyParts[0], keyParts[1], keyParts[2], keyParts[3], keyParts[4], keyParts[5]);\r\n }\r\n });\r\n }\r\n\r\n value(keyPart1: string, keyPart2: string, keyPart3: string, keyPart4: string, keyPart5: string, keyPart6: string): V { return this.cache.value(keyPart1, keyPart2, keyPart3, keyPart4, keyPart5, keyPart6); }\r\n remove(keyPart1: string, keyPart2: string, keyPart3: string, keyPart4: string, keyPart5: string, keyPart6: string) { this.cache.remove(keyPart1, keyPart2, keyPart3, keyPart4, keyPart5, keyPart6); }\r\n retain(keyPart1: string, keyPart2: string, keyPart3: string, keyPart4: string, keyPart5: string, keyPart6: string) { this.cache.retain(keyPart1, keyPart2, keyPart3, keyPart4, keyPart5, keyPart6); }\r\n resetTouches() { this.cache.resetTouches(); }\r\n retainTouched() { this.cache.retainTouched(); }\r\n clear() { this.cache.clear(); }\r\n}\r\n\r\n\r\n","/*\r\n * Copyright (c) 2014, Metron, Inc.\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without modification,\r\n * are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice, this\r\n * list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * 3. Neither the name of the copyright holder nor the names of its contributors\r\n * may be used to endorse or promote products derived from this software without\r\n * specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR\r\n * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\r\n * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n */\r\nimport { xFrac, yFrac } from './core';\r\nimport { clamp } from './util/util';\r\n\r\nexport class BoundsUnmodifiable {\r\n private bounds: Bounds;\r\n\r\n constructor(bounds: Bounds) { this.bounds = bounds; }\r\n\r\n get iStart(): number { return this.bounds.iStart; }\r\n get jStart(): number { return this.bounds.jStart; }\r\n get iEnd(): number { return this.bounds.iEnd; }\r\n get jEnd(): number { return this.bounds.jEnd; }\r\n\r\n get i(): number { return this.bounds.i; }\r\n get j(): number { return this.bounds.j; }\r\n get w(): number { return this.bounds.w; }\r\n get h(): number { return this.bounds.h; }\r\n\r\n xFrac(i: number): number { return this.bounds.xFrac(i); }\r\n yFrac(j: number): number { return this.bounds.yFrac(j); }\r\n contains(i: number, j: number): boolean { return this.bounds.contains(i, j); }\r\n}\r\n\r\n\r\nexport class Bounds {\r\n private _iStart: number;\r\n private _jStart: number;\r\n private _iEnd: number;\r\n private _jEnd: number;\r\n private _unmod: BoundsUnmodifiable;\r\n\r\n constructor() {\r\n this._iStart = 0;\r\n this._jStart = 0;\r\n this._iEnd = 0;\r\n this._jEnd = 0;\r\n this._unmod = new BoundsUnmodifiable(this);\r\n }\r\n\r\n get iStart(): number { return this._iStart; }\r\n get jStart(): number { return this._jStart; }\r\n get iEnd(): number { return this._iEnd; }\r\n get jEnd(): number { return this._jEnd; }\r\n\r\n get i(): number { return this._iStart; }\r\n get j(): number { return this._jStart; }\r\n get w(): number { return this._iEnd - this._iStart; }\r\n get h(): number { return this._jEnd - this._jStart; }\r\n\r\n get unmod(): BoundsUnmodifiable { return this._unmod; }\r\n\r\n xFrac(i: number): number {\r\n return (i - this._iStart) / (this._iEnd - this._iStart);\r\n }\r\n\r\n yFrac(j: number): number {\r\n return (j - this._jStart) / (this._jEnd - this._jStart);\r\n }\r\n\r\n contains(i: number, j: number): boolean {\r\n return (this._iStart <= i && i < this._iEnd && this._jStart <= j && j < this._jEnd);\r\n }\r\n\r\n setEdges(iStart: number, iEnd: number, jStart: number, jEnd: number) {\r\n this._iStart = iStart;\r\n this._jStart = jStart;\r\n this._iEnd = iEnd;\r\n this._jEnd = jEnd;\r\n }\r\n\r\n setRect(i: number, j: number, w: number, h: number) {\r\n this.setEdges(i, i + w, j, j + h);\r\n }\r\n\r\n setBounds(bounds: BoundsUnmodifiable) {\r\n this.setEdges(bounds.iStart, bounds.iEnd, bounds.jStart, bounds.jEnd);\r\n }\r\n\r\n cropToEdges(iCropStart: number, iCropEnd: number, jCropStart: number, jCropEnd: number) {\r\n this._iStart = clamp(iCropStart, iCropEnd, this._iStart);\r\n this._jStart = clamp(jCropStart, jCropEnd, this._jStart);\r\n this._iEnd = clamp(iCropStart, iCropEnd, this._iEnd);\r\n this._jEnd = clamp(jCropStart, jCropEnd, this._jEnd);\r\n }\r\n\r\n cropToRect(iCrop: number, jCrop: number, wCrop: number, hCrop: number) {\r\n this.cropToEdges(iCrop, iCrop + wCrop, jCrop, jCrop + hCrop);\r\n }\r\n\r\n cropToBounds(cropBounds: BoundsUnmodifiable) {\r\n this.cropToEdges(cropBounds.iStart, cropBounds.iEnd, cropBounds.jStart, cropBounds.jEnd);\r\n }\r\n}\r\n\r\n\r\nexport function newBoundsFromRect(i: number, j: number, w: number, h: number): Bounds {\r\n const b = new Bounds();\r\n b.setRect(i, j, w, h);\r\n return b;\r\n}\r\n\r\n\r\nexport function newBoundsFromEdges(iStart: number, iEnd: number, jStart: number, jEnd: number): Bounds {\r\n const b = new Bounds();\r\n b.setEdges(iStart, iEnd, jStart, jEnd);\r\n return b;\r\n}\r\n\r\n\r\nexport interface Size {\r\n w: number;\r\n h: number;\r\n}\r\n\r\n\r\n","/*\r\n * Copyright (c) 2014, Metron, Inc.\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without modification,\r\n * are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice, this\r\n * list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * 3. Neither the name of the copyright holder nor the names of its contributors\r\n * may be used to endorse or promote products derived from this software without\r\n * specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR\r\n * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\r\n * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n */\r\nimport { hasval } from './util/util';\r\n\r\nexport class Color {\r\n private _r: number;\r\n private _g: number;\r\n private _b: number;\r\n private _a: number;\r\n\r\n get r(): number { return this._r; }\r\n get g(): number { return this._g; }\r\n get b(): number { return this._b; }\r\n get a(): number { return this._a; }\r\n\r\n get cssString(): string {\r\n return 'rgba(' + Math.round(255 * this._r) + ',' + Math.round(255 * this._g) + ',' + Math.round(255 * this._b) + ',' + this._a + ')';\r\n }\r\n\r\n get rgbaString(): string {\r\n return '' + Math.round(255 * this._r) + ',' + Math.round(255 * this._g) + ',' + Math.round(255 * this._b) + ',' + Math.round(255 * this._a);\r\n }\r\n\r\n constructor(r: number, g: number, b: number, a: number = 1) {\r\n this._r = r;\r\n this._g = g;\r\n this._b = b;\r\n this._a = a;\r\n }\r\n\r\n withAlphaTimes(aFactor: number): Color {\r\n return new Color(this._r, this._g, this._b, aFactor * this._a);\r\n }\r\n}\r\n\r\n\r\nexport function darker(color: Color, factor: number): Color {\r\n return new Color(color.r * factor, color.g * factor, color.b * factor, color.a);\r\n}\r\n\r\n\r\nexport function rgba(r: number, g: number, b: number, a: number): Color {\r\n return new Color(r, g, b, a);\r\n}\r\n\r\n\r\nexport function rgb(r: number, g: number, b: number): Color {\r\n return new Color(r, g, b, 1);\r\n}\r\n\r\n\r\nexport function sameColor(c1: Color, c2: Color): boolean {\r\n if (c1 === c2) {\r\n return true;\r\n }\r\n if (!hasval(c1) || !hasval(c2)) {\r\n return false;\r\n }\r\n return (c1.r === c2.r && c1.g === c2.g && c1.b === c2.b && c1.a === c2.a);\r\n}\r\n\r\n\r\nexport function parseRgba(rgbaString: string): Color {\r\n const tokens = rgbaString.split(',', 4);\r\n return new Color(parseInt(tokens[0], 10) / 255, parseInt(tokens[1], 10) / 255, parseInt(tokens[2], 10) / 255, parseInt(tokens[3], 10) / 255);\r\n}\r\n\r\n\r\n/**\r\n * Creates a Color object based on a CSS color string. Supports the following notations:\r\n * - hex\r\n * - rgb/rgba\r\n * - hsl/hsla\r\n * - named colors\r\n * Behavior is undefined for strings that are not in one of the listed notations.\r\n *\r\n * Optional alphaOverride provided for forcing value of rbga alpha.\r\n *\r\n * Note that different browsers may use different color values for the named colors.\r\n *\r\n */\r\nexport let parseCssColor = (function () {\r\n const canvas = document.createElement('canvas');\r\n canvas.width = 1;\r\n canvas.height = 1;\r\n const g = canvas.getContext('2d', { willReadFrequently: true});\r\n return function (cssColorString: string, alphaOverride?: number): Color {\r\n g.clearRect(0, 0, 1, 1);\r\n g.fillStyle = cssColorString;\r\n g.fillRect(0, 0, 1, 1);\r\n\r\n const rgbaData = g.getImageData(0, 0, 1, 1).data;\r\n const R = rgbaData[0] / 255;\r\n const G = rgbaData[1] / 255;\r\n const B = rgbaData[2] / 255;\r\n const A = hasval(alphaOverride) ? alphaOverride : rgbaData[3] / 255;\r\n return rgba(R, G, B, A);\r\n };\r\n})();\r\n\r\n\r\nexport function gray(brightness: number): Color {\r\n return new Color(brightness, brightness, brightness, 1);\r\n}\r\n\r\n\r\n// XXX: Make final\r\n\r\nexport let black = rgb(0, 0, 0);\r\nexport let white = rgb(1, 1, 1);\r\n\r\nexport let red = rgb(1, 0, 0);\r\nexport let green = rgb(0, 1, 0);\r\nexport let blue = rgb(0, 0, 1);\r\n\r\nexport let cyan = rgb(0, 1, 1);\r\nexport let magenta = rgb(1, 0, 1);\r\nexport let yellow = rgb(1, 1, 0);\r\n\r\nexport let periwinkle = rgb(0.561, 0.561, 0.961);\r\n\r\n\r\n","/*\r\n * Copyright (c) 2014, Metron, Inc.\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without modification,\r\n * are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice, this\r\n * list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * 3. Neither the name of the copyright holder nor the names of its contributors\r\n * may be used to endorse or promote products derived from this software without\r\n * specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR\r\n * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\r\n * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n */\r\nimport { BoundsUnmodifiable } from './bounds';\r\nimport { Axis2D } from './plot/axis';\r\n\r\n// see: http://www.cs.rit.edu/usr/local/pub/wrc/graphics/doc/opengl/books/blue/glOrtho.html\r\n// see: http://www.songho.ca/opengl/gl_projectionmatrix.html#ortho\r\nexport function glOrtho(left: number, right: number, bottom: number, top: number, near: number, far: number): Float32Array {\r\n\r\n const tx = (right + left) / (right - left);\r\n const ty = (top + bottom) / (top - bottom);\r\n const tz = (far + near) / (far - near);\r\n\r\n // GL ES (and therefore WebGL) requires matrices to be column-major\r\n return new Float32Array([\r\n 2 / (right - left), 0, 0, 0,\r\n 0, 2 / (top - bottom), 0, 0,\r\n 0, 0, -2 / (far - near), 0,\r\n -tx, -ty, -tz, 1\r\n ]);\r\n}\r\n\r\nexport function glOrthoViewport(viewport: BoundsUnmodifiable): Float32Array {\r\n return glOrtho(-0.5, viewport.w - 0.5, -0.5, viewport.h - 0.5, -1, 1);\r\n}\r\n\r\nexport function glOrthoAxis(axis: Axis2D): Float32Array {\r\n return glOrtho(axis.xAxis.vMin, axis.xAxis.vMax, axis.yAxis.vMin, axis.yAxis.vMax, -1, 1);\r\n}\r\n","/*\r\n * Copyright (c) 2014, Metron, Inc.\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without modification,\r\n * are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice, this\r\n * list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * 3. Neither the name of the copyright holder nor the names of its contributors\r\n * may be used to endorse or promote products derived from this software without\r\n * specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR\r\n * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\r\n * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n */\r\nimport { OrderedSet } from './ordered_set';\r\nimport { getObjectId } from './util';\r\n\r\nexport type Listener = () => any;\r\n\r\n\r\nexport type Listener1<A> = (a: A) => any;\r\n\r\n\r\nexport type Listener2<A, B> = (a: A, b: B) => any;\r\n\r\n\r\nexport type Listener3<A, B, C> = (a: A, b: B, c: C) => any;\r\n\r\n\r\ntype Action = () => void;\r\n\r\n\r\nexport class Notification {\r\n private _listeners: OrderedSet<Listener> = new OrderedSet<Listener>([], getObjectId, false);\r\n private _deferring = false;\r\n private _deferred: Action[] = [];\r\n\r\n on(listener: Listener) {\r\n if (this._deferring) {\r\n const self = this;\r\n this._deferred.push(function () { self._listeners.add(listener); });\r\n }\r\n else {\r\n this._listeners.add(listener);\r\n }\r\n }\r\n\r\n off(listener: Listener) {\r\n if (this._deferring) {\r\n const self = this;\r\n this._deferred.push(function () { self._listeners.removeValue(listener); });\r\n }\r\n else {\r\n this._listeners.removeValue(listener);\r\n }\r\n }\r\n\r\n dispose() {\r\n this._listeners.removeAll();\r\n }\r\n\r\n fire(): any {\r\n this._deferring = true;\r\n try {\r\n for (let n = 0; n < this._listeners.length; n++) {\r\n const consumed = this._listeners.valueAt(n)();\r\n if (consumed) {\r\n return consumed;\r\n }\r\n }\r\n return false;\r\n }\r\n finally {\r\n if (this._deferred.length > 0) {\r\n for (let n = 0; n < this._deferred.length; n++) {\r\n this._deferred[n]();\r\n }\r\n this._deferred = [];\r\n }\r\n this._deferring = false;\r\n }\r\n }\r\n}\r\n\r\n\r\nexport class Notification1<A> {\r\n private _listeners: OrderedSet<Listener1<A>> = new OrderedSet<Listener1<A>>([], getObjectId, false);\r\n private _deferring = false;\r\n private _deferred: Action[] = [];\r\n\r\n on(listener: Listener1<A>) {\r\n if (this._deferring) {\r\n const self = this;\r\n this._deferred.push(function () { self._listeners.add(listener); });\r\n }\r\n else {\r\n this._listeners.add(listener);\r\n }\r\n }\r\n\r\n off(listener: Listener1<A>) {\r\n if (this._deferring) {\r\n const self = this;\r\n this._deferred.push(function () { self._listeners.removeValue(listener); });\r\n }\r\n else {\r\n this._listeners.removeValue(listener);\r\n }\r\n }\r\n\r\n dispose() {\r\n this._listeners.removeAll();\r\n }\r\n\r\n fire(a: A): any {\r\n this._deferring = true;\r\n try {\r\n for (let n = 0; n < this._listeners.length; n++) {\r\n const consumed = this._listeners.valueAt(n)(a);\r\n if (consumed) {\r\n return consumed;\r\n }\r\n }\r\n return false;\r\n }\r\n finally {\r\n if (this._deferred.length > 0) {\r\n for (let n = 0; n < this._deferred.length; n++) {\r\n this._deferred[n]();\r\n }\r\n this._deferred = [];\r\n }\r\n this._deferring = false;\r\n }\r\n }\r\n}\r\n\r\n\r\nexport class Notification2<A, B> {\r\n private _listeners: OrderedSet<Listener2<A, B>> = new OrderedSet<Listener2<A, B>>([], getObjectId, false);\r\n private _deferring = false;\r\n private _deferred: Action[] = [];\r\n\r\n on(listener: Listener2<A, B>) {\r\n if (this._deferring) {\r\n const self = this;\r\n this._deferred.push(function () { self._listeners.add(listener); });\r\n }\r\n else {\r\n this._listeners.add(listener);\r\n }\r\n }\r\n\r\n off(listener: Listener2<A, B>) {\r\n if (this._deferring) {\r\n const self = this;\r\n this._deferred.push(function () { self._listeners.removeValue(listener); });\r\n }\r\n else {\r\n this._listeners.removeValue(listener);\r\n }\r\n }\r\n\r\n dispose() {\r\n this._listeners.removeAll();\r\n }\r\n\r\n fire(a: A, b: B): any {\r\n this._deferring = true;\r\n try {\r\n for (let n = 0; n < this._listeners.length; n++) {\r\n const consumed = this._listeners.valueAt(n)(a, b);\r\n if (consumed) {\r\n return consumed;\r\n }\r\n }\r\n return false;\r\n }\r\n finally {\r\n if (this._deferred.length > 0) {\r\n for (let n = 0; n < this._deferred.length; n++) {\r\n this._deferred[n]();\r\n }\r\n this._deferred = [];\r\n }\r\n this._deferring = false;\r\n }\r\n }\r\n}\r\n\r\n\r\nexport class Notification3<A, B, C> {\r\n private _listeners: OrderedSet<Listener3<A, B, C>> = new OrderedSet<Listener3<A, B, C>>([], getObjectId, false);\r\n private _deferring = false;\r\n private _deferred: Action[] = [];\r\n\r\n on(listener: Listener3<A, B, C>) {\r\n if (this._deferring) {\r\n const self = this;\r\n this._deferred.push(function () { self._listeners.add(listener); });\r\n }\r\n else {\r\n this._listeners.add(listener);\r\n }\r\n }\r\n\r\n off(listener: Listener3<A, B, C>) {\r\n if (this._deferring) {\r\n const self = this;\r\n this._deferred.push(function () { self._listeners.removeValue(listener); });\r\n }\r\n else {\r\n this._listeners.removeValue(listener);\r\n }\r\n }\r\n\r\n dispose() {\r\n this._listeners.removeAll();\r\n }\r\n\r\n fire(a: A, b: B, c: C): any {\r\n this._deferring = true;\r\n try {\r\n for (let n = 0; n < this._listeners.length; n++) {\r\n const consumed = this._listeners.valueAt(n)(a, b, c);\r\n if (consumed) {\r\n return consumed;\r\n }\r\n }\r\n return false;\r\n }\r\n finally {\r\n if (this._deferred.length > 0) {\r\n for (let n = 0; n < this._deferred.length; n++) {\r\n this._deferred[n]();\r\n }\r\n this._deferred = [];\r\n }\r\n this._deferring = false;\r\n }\r\n }\r\n}\r\n\r\n\r\n","/*\r\n * Copyright (c) 2014, Metron, Inc.\r\n * All rights reserved.\r\n *\r\n * Redistribution and use in source and binary forms, with or without modification,\r\n * are permitted provided that the following conditions are met:\r\n *\r\n * 1. Redistributions of source code must retain the above copyright notice, this\r\n * list of conditions and the following disclaimer.\r\n *\r\n * 2. Redistributions in binary form must reproduce the above copyright notice,\r\n * this list of conditions and the following disclaimer in the documentation\r\n * and/or other materials provided with the distribution.\r\n *\r\n * 3. Neither the name of the copyright holder nor the names of its contributors\r\n * may be used to endorse or promote products derived from this software without\r\n * specific prior written permission.\r\n *\r\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\r\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r\n * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR\r\n * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\r\n * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n */\r\nimport { IdFunction, StringMap, isString, getObjectId, copyArray, hasval } from './util';\r\nimport { Notification2, Notification3 } from './notification';\r\nimport { indexOf } from './sorted_arrays';\r\n\r\nfunction requireString(s: string): string {\r\n if (isString(s)) {\r\n return s;\r\n }\r\n else {\r\n throw new Error('Expected a string, but value is ' + s);\r\n }\r\n}\r\n\r\n\r\nexport class OrderedSet<V> {\r\n private _idOf: IdFunction<V>;\r\n private _ids: string[];\r\n private _indexes: StringMap<number>;\r\n private _valuesArray: V[];\r\n private _valuesMap: StringMap<V>;\r\n private _valueAdded: Notification2<V, number>;\r\n private _valueMoved: Notification3<V, number, number>;\r\n private _valueRemoved: Notification2<V, number>;\r\n\r\n constructor(values: V[] = [], idFn: IdFunction<V> = getObjectId, useNotifications: boolean = true) {\r\n this._idOf = idFn;\r\n this._valuesArray = copyArray(values);\r\n this._ids = [];\r\n this._indexes = {};\r\n this._valuesMap = {};\r\n for (let n = 0; n < this._valuesArray.length; n++) {\r\n const value = this._valuesArray[n];\r\n const id = requireString(this._idOf(value));\r\n this._ids[n] = id;\r\n this._indexes[id] = n;\r\n this._valuesMap[id] = value;\r\n }\r\n if (useNotifications) {\r\n this._valueAdded = new Notification2<V, number>();\r\n this._valueMoved = new Notification3<V, number, number>();\r\n this._valueRemoved = new Notification2<V, number>();\r\n }\r\n }\r\n\r\n get valueAdded(): Notification2<V, number> {\r\n return this._valueAdded;\r\n }\r\n\r\n get valueMoved(): Notification3<V, number, number> {\r\n return this._valueMoved;\r\n }\r\n\r\n get valueRemoved(): Notification2<V, number> {\r\n return this._valueRemoved;\r\n }\r\n\r\n get length(): number {\r\n return this._valuesArray.length;\r\n }\r\n\r\n get isEmpty(): boolean {\r\n return (this._valuesArray.length === 0);\r\n }\r\n\r\n toArray(): V[] {\r\n return copyArray(this._valuesArray);\r\n }\r\n\r\n /**\r\n * The callback should not modify its array arg; if it does, the subsequent behavior\r\n * of this OrderedSet is undefined.\r\n */\r\n every(callbackFn: (value: V, index: number, array: V[])