From cdb533fa84de9dce9deba4a6d4b0df23a735c84d Mon Sep 17 00:00:00 2001 From: Tom MacWright Date: Fri, 12 Aug 2016 10:29:00 -0400 Subject: [PATCH] Begin d3 v4 update --- ARCHITECTURE.md | 2 +- index.html | 34 +- js/lib/d3-compat.js | 48 - js/lib/d3.combobox.js | 11 +- js/lib/d3.dimensions.js | 23 - js/lib/d3.geo.tile.js | 6 +- js/lib/d3.keybinding.js | 233 +- js/lib/d3.v3.js | 6040 ----------------- js/lib/index.js | 9 - modules/actions/circularize.js | 9 +- modules/behavior/add_way.js | 4 +- modules/behavior/breathe.js | 1 + modules/behavior/copy.js | 4 +- modules/behavior/drag.js | 13 +- modules/behavior/draw.js | 26 +- modules/behavior/draw_way.js | 8 +- modules/behavior/hash.js | 1 + modules/behavior/hover.js | 17 +- modules/behavior/lasso.js | 1 + modules/behavior/paste.js | 4 +- modules/behavior/select.js | 1 + modules/behavior/tail.js | 10 +- modules/core/connection.js | 24 +- modules/core/context.js | 10 +- modules/core/difference.js | 1 + modules/core/entity.js | 1 + modules/core/history.js | 18 +- modules/core/relation.js | 7 +- modules/core/way.js | 5 +- modules/geo/raw_mercator.js | 6 +- modules/id.js | 1 - modules/modes/drag_node.js | 4 +- modules/modes/move.js | 7 +- modules/modes/rotate_way.js | 6 +- modules/modes/save.js | 1 + modules/modes/select.js | 4 +- modules/renderer/background.js | 15 +- modules/renderer/background_source.js | 5 +- modules/renderer/features.js | 12 +- modules/renderer/map.js | 100 +- modules/renderer/tile_layer.js | 8 +- modules/services/mapillary.js | 11 +- modules/services/nominatim.js | 1 + modules/services/taginfo.js | 1 + modules/svg/areas.js | 1 + modules/svg/debug.js | 3 +- modules/svg/defs.js | 71 +- modules/svg/gpx.js | 9 +- modules/svg/labels.js | 11 +- modules/svg/layers.js | 13 +- modules/svg/lines.js | 1 + modules/svg/mapillary_images.js | 14 +- modules/svg/mapillary_signs.js | 14 +- modules/svg/one_way_segments.js | 5 +- modules/svg/path.js | 5 +- modules/svg/tag_classes.js | 1 + modules/svg/vertices.js | 1 + modules/ui/account.js | 1 + modules/ui/attribution.js | 1 + modules/ui/background.js | 4 +- modules/ui/commit.js | 14 +- modules/ui/conflicts.js | 12 +- modules/ui/contributors.js | 1 + modules/ui/disclosure.js | 6 +- modules/ui/entity_editor.js | 6 +- modules/ui/feature_info.js | 1 + modules/ui/feature_list.js | 1 + modules/ui/fields/access.js | 16 +- modules/ui/fields/address.js | 25 +- modules/ui/fields/check.js | 6 +- modules/ui/fields/combo.js | 18 +- modules/ui/fields/cycleway.js | 17 +- modules/ui/fields/input.js | 11 +- modules/ui/fields/lanes.js | 6 +- modules/ui/fields/localized.js | 38 +- modules/ui/fields/maxspeed.js | 22 +- modules/ui/fields/radio.js | 6 +- modules/ui/fields/restrictions.js | 17 +- modules/ui/fields/textarea.js | 10 +- modules/ui/fields/wikipedia.js | 37 +- modules/ui/full_screen.js | 4 +- modules/ui/help.js | 4 +- modules/ui/info.js | 8 +- modules/ui/init.js | 10 +- modules/ui/inspector.js | 1 + modules/ui/intro/area.js | 4 +- modules/ui/intro/intro.js | 4 +- modules/ui/intro/line.js | 17 +- modules/ui/intro/navigation.js | 4 +- modules/ui/intro/point.js | 6 +- modules/ui/intro/start_editing.js | 6 +- modules/ui/lasso.js | 1 + modules/ui/map_data.js | 4 +- modules/ui/map_in_map.js | 15 +- modules/ui/modal.js | 4 +- modules/ui/modes.js | 4 +- modules/ui/preset.js | 14 +- modules/ui/preset_icon.js | 6 +- modules/ui/preset_list.js | 15 +- modules/ui/radial_menu.js | 1 + modules/ui/raw_member_editor.js | 6 +- modules/ui/raw_membership_editor.js | 8 +- modules/ui/raw_tag_editor.js | 34 +- modules/ui/save.js | 4 +- modules/ui/scale.js | 1 + modules/ui/selection_list.js | 1 + modules/ui/source_switch.js | 1 + modules/ui/splash.js | 1 + modules/ui/success.js | 6 +- modules/ui/tag_reference.js | 1 + modules/ui/toggle.js | 1 + modules/ui/undo_redo.js | 4 +- modules/ui/zoom.js | 4 +- js/lib/d3.one.js => modules/util/bind_once.js | 4 +- .../d3.curtain.js => modules/util/curtain.js | 28 +- modules/util/dimensions.js | 24 + .../util/get_set_value.js | 18 +- modules/util/index.js | 1 + modules/util/jsonp_request.js | 1 + modules/util/rebind.js | 16 + modules/util/tooltip.js | 14 +- .../util/trigger_event.js | 4 +- modules/util/util.js | 15 + package.json | 4 +- rollup.config.js | 2 +- test/bench/event-binding-cost.html | 1 - test/bench/removing.html | 1 - test/index.html | 1 - test/rendering.html | 1 - test/spec/actions/circularize.js | 2 +- test/spec/actions/move.js | 2 +- test/spec/actions/orthogonalize.js | 2 +- test/spec/actions/restrict_turn.js | 2 +- test/spec/actions/straighten.js | 2 +- test/spec/renderer/tile_layer.js | 2 +- test/spec/svg/areas.js | 2 +- test/spec/svg/lines.js | 2 +- 137 files changed, 842 insertions(+), 6691 deletions(-) delete mode 100644 js/lib/d3-compat.js delete mode 100644 js/lib/d3.dimensions.js delete mode 100644 js/lib/d3.v3.js delete mode 100644 js/lib/index.js rename js/lib/d3.one.js => modules/util/bind_once.js (58%) rename js/lib/d3.curtain.js => modules/util/curtain.js (87%) create mode 100644 modules/util/dimensions.js rename js/lib/d3.value.js => modules/util/get_set_value.js (52%) create mode 100644 modules/util/rebind.js rename js/lib/d3.trigger.js => modules/util/trigger_event.js (64%) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 51c8e1802..56279ae3f 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -12,7 +12,7 @@ changes; which provides a callback-based [Observer pattern](http://en.wikipedia.org/wiki/Observer_pattern) between different parts of iD; -[d3.geo.path](https://github.com/mbostock/d3/wiki/Geo-Paths#wiki-path), which +[d3.geoPath](https://github.com/mbostock/d3/wiki/Geo-Paths#wiki-path), which generates SVG paths for lines and areas; and [d3.behavior.zoom](https://github.com/mbostock/d3/wiki/Zoom-Behavior#wiki-zoom), which implements map panning and zooming. diff --git a/index.html b/index.html index 24a3f8daa..de3dba5a1 100644 --- a/index.html +++ b/index.html @@ -12,7 +12,6 @@ - @@ -24,24 +23,23 @@ .taginfo(iD.services.taginfo.init()) .assetPath('dist/'); - d3.select('#id-container') - .call(id.ui()); + id.ui()(document.getElementById('id-container')); - d3.select('#about-list').insert('li', '.user-list') - .attr('class', 'source-switch') - .call(iD.ui.SourceSwitch(id) - .keys([ - { - 'url': 'http://www.openstreetmap.org', - 'oauth_consumer_key': '5A043yRSEugj4DJ5TljuapfnrflWDte8jTOcWLlT', - 'oauth_secret': 'aB3jKq1TRsCOUrfOIZ6oQMEDmv2ptV76PA54NGLL' - }, - { - 'url': 'http://api06.dev.openstreetmap.org', - 'oauth_consumer_key': 'zwQZFivccHkLs3a8Rq5CoS412fE5aPCXDw9DZj7R', - 'oauth_secret': 'aMnOOCwExO2XYtRVWJ1bI9QOdqh1cay2UgpbhA6p' - } - ])); + // d3.select('#about-list').insert('li', '.user-list') + // .attr('class', 'source-switch') + // .call(iD.ui.SourceSwitch(id) + // .keys([ + // { + // 'url': 'http://www.openstreetmap.org', + // 'oauth_consumer_key': '5A043yRSEugj4DJ5TljuapfnrflWDte8jTOcWLlT', + // 'oauth_secret': 'aB3jKq1TRsCOUrfOIZ6oQMEDmv2ptV76PA54NGLL' + // }, + // { + // 'url': 'http://api06.dev.openstreetmap.org', + // 'oauth_consumer_key': 'zwQZFivccHkLs3a8Rq5CoS412fE5aPCXDw9DZj7R', + // 'oauth_secret': 'aMnOOCwExO2XYtRVWJ1bI9QOdqh1cay2UgpbhA6p' + // } + // ])); diff --git a/js/lib/d3-compat.js b/js/lib/d3-compat.js deleted file mode 100644 index 88a8fafe7..000000000 --- a/js/lib/d3-compat.js +++ /dev/null @@ -1,48 +0,0 @@ -(function() { - - // get a reference to the d3.selection prototype, - // and keep a reference to the old d3.selection.on - var d3_selectionPrototype = d3.selection.prototype, - d3_on = d3_selectionPrototype.on; - - // our shims are organized by event: - // "desired-event": ["shimmed-event", wrapperFunction] - var shims = { - "mouseenter": ["mouseover", relatedTarget], - "mouseleave": ["mouseout", relatedTarget] - }; - - // rewrite the d3.selection.on function to shim the events with wrapped - // callbacks - d3_selectionPrototype.on = function(evt, callback, useCapture) { - var bits = evt.split("."), - type = bits.shift(), - shim = shims[type]; - if (shim) { - evt = bits.length ? [shim[0], bits].join(".") : shim[0]; - if (typeof callback === "function") { - callback = shim[1](callback); - } - return d3_on.call(this, evt, callback, useCapture); - } else { - return d3_on.apply(this, arguments); - } - }; - - function relatedTarget(callback) { - return function() { - var related = d3.event.relatedTarget; - if (this === related || childOf(this, related)) { - return undefined; - } - return callback.apply(this, arguments); - }; - } - - function childOf(p, c) { - if (p === c) return false; - while (c && c !== p) c = c.parentNode; - return c === p; - } - -})(); diff --git a/js/lib/d3.combobox.js b/js/lib/d3.combobox.js index ee190c708..b34495e17 100644 --- a/js/lib/d3.combobox.js +++ b/js/lib/d3.combobox.js @@ -1,4 +1,7 @@ -d3.combobox = function() { +import { rebind } from '../../modules/util/rebind'; +import * as d3 from 'd3'; + +export function d3combobox() { var event = d3.dispatch('accept'), data = [], suggestions = [], @@ -280,10 +283,10 @@ d3.combobox = function() { return combobox; }; - return d3.rebind(combobox, event, 'on'); + return rebind(combobox, event, 'on'); }; -d3.combobox.off = function(input) { +d3combobox.off = function(input) { input .on('focus.typeahead', null) .on('blur.typeahead', null) @@ -298,4 +301,4 @@ d3.combobox.off = function(input) { d3.select(document.body) .on('scroll.combobox', null); -}; +} diff --git a/js/lib/d3.dimensions.js b/js/lib/d3.dimensions.js deleted file mode 100644 index dac05c9b6..000000000 --- a/js/lib/d3.dimensions.js +++ /dev/null @@ -1,23 +0,0 @@ -d3.selection.prototype.dimensions = function (dimensions) { - var refresh = (function(node) { - var cr = node.getBoundingClientRect(); - var prop = [cr.width, cr.height]; - this.property('__dimensions__', prop); - return prop; - }).bind(this); - - var node = this.node(); - - if (!arguments.length) { - if (!node) return [0,0]; - return this.property('__dimensions__') || refresh(node); - } - if (dimensions === null) { - if (!node) return [0,0]; - return refresh(node); - } - - return this - .property('__dimensions__', [dimensions[0], dimensions[1]]) - .attr({width: dimensions[0], height: dimensions[1]}); -}; diff --git a/js/lib/d3.geo.tile.js b/js/lib/d3.geo.tile.js index 2761deb61..2187e52e1 100644 --- a/js/lib/d3.geo.tile.js +++ b/js/lib/d3.geo.tile.js @@ -1,4 +1,6 @@ -d3.geo.tile = function() { +import * as d3 from 'd3'; + +export function d3geoTile() { var size = [960, 500], scale = 256, scaleExtent = [0, 20], @@ -61,4 +63,4 @@ d3.geo.tile = function() { }; return tile; -}; +} diff --git a/js/lib/d3.keybinding.js b/js/lib/d3.keybinding.js index b940c3fc6..36d168f0d 100644 --- a/js/lib/d3.keybinding.js +++ b/js/lib/d3.keybinding.js @@ -1,3 +1,6 @@ +import * as d3 from 'd3'; + + /* * This code is licensed under the MIT license. * @@ -7,7 +10,7 @@ * See https://github.com/keithamus/jwerty * */ -d3.keybinding = function(namespace) { +export function d3keybinding(namespace) { var bindings = []; function matches(binding, event) { @@ -74,10 +77,10 @@ d3.keybinding = function(namespace) { // Normalise matching errors if (code[i] === '++') code[i] = '+'; - if (code[i] in d3.keybinding.modifierCodes) { - binding.event[d3.keybinding.modifierProperties[d3.keybinding.modifierCodes[code[i]]]] = true; - } else if (code[i] in d3.keybinding.keyCodes) { - binding.event.keyCode = d3.keybinding.keyCodes[code[i]]; + if (code[i] in d3keybinding.modifierCodes) { + binding.event[d3keybinding.modifierProperties[d3keybinding.modifierCodes[code[i]]]] = true; + } else if (code[i] in d3keybinding.keyCodes) { + binding.event.keyCode = d3keybinding.keyCodes[code[i]]; } } @@ -89,120 +92,118 @@ d3.keybinding = function(namespace) { return keybinding; }; -(function () { - d3.keybinding.modifierCodes = { - // Shift key, ⇧ - '⇧': 16, shift: 16, - // CTRL key, on Mac: ⌃ - '⌃': 17, ctrl: 17, - // ALT key, on Mac: ⌥ (Alt) - '⌥': 18, alt: 18, option: 18, - // META, on Mac: ⌘ (CMD), on Windows (Win), on Linux (Super) - '⌘': 91, meta: 91, cmd: 91, 'super': 91, win: 91 - }; +d3keybinding.modifierCodes = { + // Shift key, ⇧ + '⇧': 16, shift: 16, + // CTRL key, on Mac: ⌃ + '⌃': 17, ctrl: 17, + // ALT key, on Mac: ⌥ (Alt) + '⌥': 18, alt: 18, option: 18, + // META, on Mac: ⌘ (CMD), on Windows (Win), on Linux (Super) + '⌘': 91, meta: 91, cmd: 91, 'super': 91, win: 91 +}; - d3.keybinding.modifierProperties = { - 16: 'shiftKey', - 17: 'ctrlKey', - 18: 'altKey', - 91: 'metaKey' - }; +d3keybinding.modifierProperties = { + 16: 'shiftKey', + 17: 'ctrlKey', + 18: 'altKey', + 91: 'metaKey' +}; - d3.keybinding.keyCodes = { - // Backspace key, on Mac: ⌫ (Backspace) - '⌫': 8, backspace: 8, - // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥ - '⇥': 9, '⇆': 9, tab: 9, - // Return key, ↩ - '↩': 13, 'return': 13, enter: 13, '⌅': 13, - // Pause/Break key - 'pause': 19, 'pause-break': 19, - // Caps Lock key, ⇪ - '⇪': 20, caps: 20, 'caps-lock': 20, - // Escape key, on Mac: ⎋, on Windows: Esc - '⎋': 27, escape: 27, esc: 27, - // Space key - space: 32, - // Page-Up key, or pgup, on Mac: ↖ - '↖': 33, pgup: 33, 'page-up': 33, - // Page-Down key, or pgdown, on Mac: ↘ - '↘': 34, pgdown: 34, 'page-down': 34, - // END key, on Mac: ⇟ - '⇟': 35, end: 35, - // HOME key, on Mac: ⇞ - '⇞': 36, home: 36, - // Insert key, or ins - ins: 45, insert: 45, - // Delete key, on Mac: ⌦ (Delete) - '⌦': 46, del: 46, 'delete': 46, - // Left Arrow Key, or ← - '←': 37, left: 37, 'arrow-left': 37, - // Up Arrow Key, or ↑ - '↑': 38, up: 38, 'arrow-up': 38, - // Right Arrow Key, or → - '→': 39, right: 39, 'arrow-right': 39, - // Up Arrow Key, or ↓ - '↓': 40, down: 40, 'arrow-down': 40, - // odities, printing characters that come out wrong: - // Firefox Equals - 'ffequals': 61, - // Num-Multiply, or * - '*': 106, star: 106, asterisk: 106, multiply: 106, - // Num-Plus or + - '+': 107, 'plus': 107, - // Num-Subtract, or - - '-': 109, subtract: 109, - // Firefox Plus - 'ffplus': 171, - // Firefox Minus - 'ffminus': 173, - // Semicolon - ';': 186, semicolon: 186, - // = or equals - '=': 187, 'equals': 187, - // Comma, or , - ',': 188, comma: 188, - 'dash': 189, //??? - // Period, or ., or full-stop - '.': 190, period: 190, 'full-stop': 190, - // Slash, or /, or forward-slash - '/': 191, slash: 191, 'forward-slash': 191, - // Tick, or `, or back-quote - '`': 192, tick: 192, 'back-quote': 192, - // Open bracket, or [ - '[': 219, 'open-bracket': 219, - // Back slash, or \ - '\\': 220, 'back-slash': 220, - // Close backet, or ] - ']': 221, 'close-bracket': 221, - // Apostrophe, or Quote, or ' - '\'': 222, quote: 222, apostrophe: 222 - }; +d3keybinding.keyCodes = { + // Backspace key, on Mac: ⌫ (Backspace) + '⌫': 8, backspace: 8, + // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥ + '⇥': 9, '⇆': 9, tab: 9, + // Return key, ↩ + '↩': 13, 'return': 13, enter: 13, '⌅': 13, + // Pause/Break key + 'pause': 19, 'pause-break': 19, + // Caps Lock key, ⇪ + '⇪': 20, caps: 20, 'caps-lock': 20, + // Escape key, on Mac: ⎋, on Windows: Esc + '⎋': 27, escape: 27, esc: 27, + // Space key + space: 32, + // Page-Up key, or pgup, on Mac: ↖ + '↖': 33, pgup: 33, 'page-up': 33, + // Page-Down key, or pgdown, on Mac: ↘ + '↘': 34, pgdown: 34, 'page-down': 34, + // END key, on Mac: ⇟ + '⇟': 35, end: 35, + // HOME key, on Mac: ⇞ + '⇞': 36, home: 36, + // Insert key, or ins + ins: 45, insert: 45, + // Delete key, on Mac: ⌦ (Delete) + '⌦': 46, del: 46, 'delete': 46, + // Left Arrow Key, or ← + '←': 37, left: 37, 'arrow-left': 37, + // Up Arrow Key, or ↑ + '↑': 38, up: 38, 'arrow-up': 38, + // Right Arrow Key, or → + '→': 39, right: 39, 'arrow-right': 39, + // Up Arrow Key, or ↓ + '↓': 40, down: 40, 'arrow-down': 40, + // odities, printing characters that come out wrong: + // Firefox Equals + 'ffequals': 61, + // Num-Multiply, or * + '*': 106, star: 106, asterisk: 106, multiply: 106, + // Num-Plus or + + '+': 107, 'plus': 107, + // Num-Subtract, or - + '-': 109, subtract: 109, + // Firefox Plus + 'ffplus': 171, + // Firefox Minus + 'ffminus': 173, + // Semicolon + ';': 186, semicolon: 186, + // = or equals + '=': 187, 'equals': 187, + // Comma, or , + ',': 188, comma: 188, + 'dash': 189, //??? + // Period, or ., or full-stop + '.': 190, period: 190, 'full-stop': 190, + // Slash, or /, or forward-slash + '/': 191, slash: 191, 'forward-slash': 191, + // Tick, or `, or back-quote + '`': 192, tick: 192, 'back-quote': 192, + // Open bracket, or [ + '[': 219, 'open-bracket': 219, + // Back slash, or \ + '\\': 220, 'back-slash': 220, + // Close backet, or ] + ']': 221, 'close-bracket': 221, + // Apostrophe, or Quote, or ' + '\'': 222, quote: 222, apostrophe: 222 +}; - // NUMPAD 0-9 - var i = 95, n = 0; - while (++i < 106) { - d3.keybinding.keyCodes['num-' + n] = i; - ++n; - } +// NUMPAD 0-9 +var i = 95, n = 0; +while (++i < 106) { + d3keybinding.keyCodes['num-' + n] = i; + ++n; +} - // 0-9 - i = 47; n = 0; - while (++i < 58) { - d3.keybinding.keyCodes[n] = i; - ++n; - } +// 0-9 +i = 47; n = 0; +while (++i < 58) { + d3keybinding.keyCodes[n] = i; + ++n; +} - // F1-F25 - i = 111; n = 1; - while (++i < 136) { - d3.keybinding.keyCodes['f' + n] = i; - ++n; - } +// F1-F25 +i = 111; n = 1; +while (++i < 136) { + d3keybinding.keyCodes['f' + n] = i; + ++n; +} - // a-z - i = 64; - while (++i < 91) { - d3.keybinding.keyCodes[String.fromCharCode(i).toLowerCase()] = i; - } -})(); +// a-z +i = 64; +while (++i < 91) { + d3keybinding.keyCodes[String.fromCharCode(i).toLowerCase()] = i; +} diff --git a/js/lib/d3.v3.js b/js/lib/d3.v3.js deleted file mode 100644 index 2e6e1fedb..000000000 --- a/js/lib/d3.v3.js +++ /dev/null @@ -1,6040 +0,0 @@ -var d3 = {version: "3.5.5"}; // semver -d3.ascending = d3_ascending; - -function d3_ascending(a, b) { - return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; -} -d3.descending = function(a, b) { - return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN; -}; -d3.min = function(array, f) { - var i = -1, - n = array.length, - a, - b; - if (arguments.length === 1) { - while (++i < n) if ((b = array[i]) != null && b >= b) { a = b; break; } - while (++i < n) if ((b = array[i]) != null && a > b) a = b; - } else { - while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) { a = b; break; } - while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b; - } - return a; -}; -d3.max = function(array, f) { - var i = -1, - n = array.length, - a, - b; - if (arguments.length === 1) { - while (++i < n) if ((b = array[i]) != null && b >= b) { a = b; break; } - while (++i < n) if ((b = array[i]) != null && b > a) a = b; - } else { - while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) { a = b; break; } - while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b; - } - return a; -}; -d3.extent = function(array, f) { - var i = -1, - n = array.length, - a, - b, - c; - if (arguments.length === 1) { - while (++i < n) if ((b = array[i]) != null && b >= b) { a = c = b; break; } - while (++i < n) if ((b = array[i]) != null) { - if (a > b) a = b; - if (c < b) c = b; - } - } else { - while (++i < n) if ((b = f.call(array, array[i], i)) != null && b >= b) { a = c = b; break; } - while (++i < n) if ((b = f.call(array, array[i], i)) != null) { - if (a > b) a = b; - if (c < b) c = b; - } - } - return [a, c]; -}; -function d3_number(x) { - return x === null ? NaN : +x; -} - -function d3_numeric(x) { - return !isNaN(x); -} - -d3.sum = function(array, f) { - var s = 0, - n = array.length, - a, - i = -1; - if (arguments.length === 1) { - while (++i < n) if (d3_numeric(a = +array[i])) s += a; // zero and null are equivalent - } else { - while (++i < n) if (d3_numeric(a = +f.call(array, array[i], i))) s += a; - } - return s; -}; - -d3.mean = function(array, f) { - var s = 0, - n = array.length, - a, - i = -1, - j = n; - if (arguments.length === 1) { - while (++i < n) if (d3_numeric(a = d3_number(array[i]))) s += a; else --j; - } else { - while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) s += a; else --j; - } - if (j) return s / j; -}; -// R-7 per -d3.quantile = function(values, p) { - var H = (values.length - 1) * p + 1, - h = Math.floor(H), - v = +values[h - 1], - e = H - h; - return e ? v + e * (values[h] - v) : v; -}; - -d3.median = function(array, f) { - var numbers = [], - n = array.length, - a, - i = -1; - if (arguments.length === 1) { - while (++i < n) if (d3_numeric(a = d3_number(array[i]))) numbers.push(a); - } else { - while (++i < n) if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) numbers.push(a); - } - if (numbers.length) return d3.quantile(numbers.sort(d3_ascending), .5); -}; - -d3.variance = function(array, f) { - var n = array.length, - m = 0, - a, - d, - s = 0, - i = -1, - j = 0; - if (arguments.length === 1) { - while (++i < n) { - if (d3_numeric(a = d3_number(array[i]))) { - d = a - m; - m += d / ++j; - s += d * (a - m); - } - } - } else { - while (++i < n) { - if (d3_numeric(a = d3_number(f.call(array, array[i], i)))) { - d = a - m; - m += d / ++j; - s += d * (a - m); - } - } - } - if (j > 1) return s / (j - 1); -}; - -d3.deviation = function() { - var v = d3.variance.apply(this, arguments); - return v ? Math.sqrt(v) : v; -}; - -function d3_bisector(compare) { - return { - left: function(a, x, lo, hi) { - if (arguments.length < 3) lo = 0; - if (arguments.length < 4) hi = a.length; - while (lo < hi) { - var mid = lo + hi >>> 1; - if (compare(a[mid], x) < 0) lo = mid + 1; - else hi = mid; - } - return lo; - }, - right: function(a, x, lo, hi) { - if (arguments.length < 3) lo = 0; - if (arguments.length < 4) hi = a.length; - while (lo < hi) { - var mid = lo + hi >>> 1; - if (compare(a[mid], x) > 0) hi = mid; - else lo = mid + 1; - } - return lo; - } - }; -} - -var d3_bisect = d3_bisector(d3_ascending); -d3.bisectLeft = d3_bisect.left; -d3.bisect = d3.bisectRight = d3_bisect.right; - -d3.bisector = function(f) { - return d3_bisector(f.length === 1 - ? function(d, x) { return d3_ascending(f(d), x); } - : f); -}; -d3.shuffle = function(array, i0, i1) { - if ((m = arguments.length) < 3) { i1 = array.length; if (m < 2) i0 = 0; } - var m = i1 - i0, t, i; - while (m) { - i = Math.random() * m-- | 0; - t = array[m + i0], array[m + i0] = array[i + i0], array[i + i0] = t; - } - return array; -}; -d3.permute = function(array, indexes) { - var i = indexes.length, permutes = new Array(i); - while (i--) permutes[i] = array[indexes[i]]; - return permutes; -}; -d3.pairs = function(array) { - var i = 0, n = array.length - 1, p0, p1 = array[0], pairs = new Array(n < 0 ? 0 : n); - while (i < n) pairs[i] = [p0 = p1, p1 = array[++i]]; - return pairs; -}; - -d3.zip = function() { - if (!(n = arguments.length)) return []; - for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m;) { - for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n;) { - zip[j] = arguments[j][i]; - } - } - return zips; -}; - -function d3_zipLength(d) { - return d.length; -} - -d3.transpose = function(matrix) { - return d3.zip.apply(d3, matrix); -}; -d3.keys = function(map) { - var keys = []; - for (var key in map) keys.push(key); - return keys; -}; -d3.values = function(map) { - var values = []; - for (var key in map) values.push(map[key]); - return values; -}; -d3.entries = function(map) { - var entries = []; - for (var key in map) entries.push({key: key, value: map[key]}); - return entries; -}; -d3.merge = function(arrays) { - var n = arrays.length, - m, - i = -1, - j = 0, - merged, - array; - - while (++i < n) j += arrays[i].length; - merged = new Array(j); - - while (--n >= 0) { - array = arrays[n]; - m = array.length; - while (--m >= 0) { - merged[--j] = array[m]; - } - } - - return merged; -}; -var abs = Math.abs; - -d3.range = function(start, stop, step) { - if (arguments.length < 3) { - step = 1; - if (arguments.length < 2) { - stop = start; - start = 0; - } - } - if ((stop - start) / step === Infinity) throw new Error("infinite range"); - var range = [], - k = d3_range_integerScale(abs(step)), - i = -1, - j; - start *= k, stop *= k, step *= k; - if (step < 0) while ((j = start + step * ++i) > stop) range.push(j / k); - else while ((j = start + step * ++i) < stop) range.push(j / k); - return range; -}; - -function d3_range_integerScale(x) { - var k = 1; - while (x * k % 1) k *= 10; - return k; -} -function d3_class(ctor, properties) { - for (var key in properties) { - Object.defineProperty(ctor.prototype, key, { - value: properties[key], - enumerable: false - }); - } -} - -d3.map = function(object, f) { - var map = new d3_Map; - if (object instanceof d3_Map) { - object.forEach(function(key, value) { map.set(key, value); }); - } else if (Array.isArray(object)) { - var i = -1, - n = object.length, - o; - if (arguments.length === 1) while (++i < n) map.set(i, object[i]); - else while (++i < n) map.set(f.call(object, o = object[i], i), o); - } else { - for (var key in object) map.set(key, object[key]); - } - return map; -}; - -function d3_Map() { - this._ = Object.create(null); -} - -var d3_map_proto = "__proto__", - d3_map_zero = "\0"; - -d3_class(d3_Map, { - has: d3_map_has, - get: function(key) { - return this._[d3_map_escape(key)]; - }, - set: function(key, value) { - return this._[d3_map_escape(key)] = value; - }, - remove: d3_map_remove, - keys: d3_map_keys, - values: function() { - var values = []; - for (var key in this._) values.push(this._[key]); - return values; - }, - entries: function() { - var entries = []; - for (var key in this._) entries.push({key: d3_map_unescape(key), value: this._[key]}); - return entries; - }, - size: d3_map_size, - empty: d3_map_empty, - forEach: function(f) { - for (var key in this._) f.call(this, d3_map_unescape(key), this._[key]); - } -}); - -function d3_map_escape(key) { - return (key += "") === d3_map_proto || key[0] === d3_map_zero ? d3_map_zero + key : key; -} - -function d3_map_unescape(key) { - return (key += "")[0] === d3_map_zero ? key.slice(1) : key; -} - -function d3_map_has(key) { - return d3_map_escape(key) in this._; -} - -function d3_map_remove(key) { - return (key = d3_map_escape(key)) in this._ && delete this._[key]; -} - -function d3_map_keys() { - var keys = []; - for (var key in this._) keys.push(d3_map_unescape(key)); - return keys; -} - -function d3_map_size() { - var size = 0; - for (var key in this._) ++size; - return size; -} - -function d3_map_empty() { - for (var key in this._) return false; - return true; -} - -d3.nest = function() { - var nest = {}, - keys = [], - sortKeys = [], - sortValues, - rollup; - - function map(mapType, array, depth) { - if (depth >= keys.length) return rollup - ? rollup.call(nest, array) : (sortValues - ? array.sort(sortValues) - : array); - - var i = -1, - n = array.length, - key = keys[depth++], - keyValue, - object, - setter, - valuesByKey = new d3_Map, - values; - - while (++i < n) { - if (values = valuesByKey.get(keyValue = key(object = array[i]))) { - values.push(object); - } else { - valuesByKey.set(keyValue, [object]); - } - } - - if (mapType) { - object = mapType(); - setter = function(keyValue, values) { - object.set(keyValue, map(mapType, values, depth)); - }; - } else { - object = {}; - setter = function(keyValue, values) { - object[keyValue] = map(mapType, values, depth); - }; - } - - valuesByKey.forEach(setter); - return object; - } - - function entries(map, depth) { - if (depth >= keys.length) return map; - - var array = [], - sortKey = sortKeys[depth++]; - - map.forEach(function(key, keyMap) { - array.push({key: key, values: entries(keyMap, depth)}); - }); - - return sortKey - ? array.sort(function(a, b) { return sortKey(a.key, b.key); }) - : array; - } - - nest.map = function(array, mapType) { - return map(mapType, array, 0); - }; - - nest.entries = function(array) { - return entries(map(d3.map, array, 0), 0); - }; - - nest.key = function(d) { - keys.push(d); - return nest; - }; - - // Specifies the order for the most-recently specified key. - // Note: only applies to entries. Map keys are unordered! - nest.sortKeys = function(order) { - sortKeys[keys.length - 1] = order; - return nest; - }; - - // Specifies the order for leaf values. - // Applies to both maps and entries array. - nest.sortValues = function(order) { - sortValues = order; - return nest; - }; - - nest.rollup = function(f) { - rollup = f; - return nest; - }; - - return nest; -}; - -d3.set = function(array) { - var set = new d3_Set; - if (array) for (var i = 0, n = array.length; i < n; ++i) set.add(array[i]); - return set; -}; - -function d3_Set() { - this._ = Object.create(null); -} - -d3_class(d3_Set, { - has: d3_map_has, - add: function(key) { - this._[d3_map_escape(key += "")] = true; - return key; - }, - remove: d3_map_remove, - values: d3_map_keys, - size: d3_map_size, - empty: d3_map_empty, - forEach: function(f) { - for (var key in this._) f.call(this, d3_map_unescape(key)); - } -}); -d3.behavior = {}; -var d3_document = this.document; - -function d3_documentElement(node) { - return node - && (node.ownerDocument // node is a Node - || node.document // node is a Window - || node).documentElement; // node is a Document -} - -function d3_window(node) { - return node - && ((node.ownerDocument && node.ownerDocument.defaultView) // node is a Node - || (node.document && node) // node is a Window - || node.defaultView); // node is a Document -} -// Copies a variable number of methods from source to target. -d3.rebind = function(target, source) { - var i = 1, n = arguments.length, method; - while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]); - return target; -}; - -// Method is assumed to be a standard D3 getter-setter: -// If passed with no arguments, gets the value. -// If passed with arguments, sets the value and returns the target. -function d3_rebind(target, source, method) { - return function() { - var value = method.apply(source, arguments); - return value === source ? target : value; - }; -} -function d3_vendorSymbol(object, name) { - if (name in object) return name; - name = name.charAt(0).toUpperCase() + name.slice(1); - for (var i = 0, n = d3_vendorPrefixes.length; i < n; ++i) { - var prefixName = d3_vendorPrefixes[i] + name; - if (prefixName in object) return prefixName; - } -} - -var d3_vendorPrefixes = ["webkit", "ms", "moz", "Moz", "o", "O"]; -var d3_arraySlice = [].slice, - d3_array = function(list) { return d3_arraySlice.call(list); }; // conversion for NodeLists -function d3_noop() {} - -d3.dispatch = function() { - var dispatch = new d3_dispatch, - i = -1, - n = arguments.length; - while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); - return dispatch; -}; - -function d3_dispatch() {} - -d3_dispatch.prototype.on = function(type, listener) { - var i = type.indexOf("."), - name = ""; - - // Extract optional namespace, e.g., "click.foo" - if (i >= 0) { - name = type.slice(i + 1); - type = type.slice(0, i); - } - - if (type) return arguments.length < 2 - ? this[type].on(name) - : this[type].on(name, listener); - - if (arguments.length === 2) { - if (listener == null) for (type in this) { - if (this.hasOwnProperty(type)) this[type].on(name, null); - } - return this; - } -}; - -function d3_dispatch_event(dispatch) { - var listeners = [], - listenerByName = new d3_Map; - - function event() { - var z = listeners, // defensive reference - i = -1, - n = z.length, - l; - while (++i < n) if (l = z[i].on) l.apply(this, arguments); - return dispatch; - } - - event.on = function(name, listener) { - var l = listenerByName.get(name), - i; - - // return the current listener, if any - if (arguments.length < 2) return l && l.on; - - // remove the old listener, if any (with copy-on-write) - if (l) { - l.on = null; - listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1)); - listenerByName.remove(name); - } - - // add the new listener, if any - if (listener) listeners.push(listenerByName.set(name, {on: listener})); - - return dispatch; - }; - - return event; -} - -d3.event = null; - -function d3_eventPreventDefault() { - d3.event.preventDefault(); -} - -function d3_eventCancel() { - d3.event.preventDefault(); - d3.event.stopPropagation(); -} - -function d3_eventSource() { - var e = d3.event, s; - while (s = e.sourceEvent) e = s; - return e; -} - -// Like d3.dispatch, but for custom events abstracting native UI events. These -// events have a target component (such as a brush), a target element (such as -// the svg:g element containing the brush) and the standard arguments `d` (the -// target element's data) and `i` (the selection index of the target element). -function d3_eventDispatch(target) { - var dispatch = new d3_dispatch, - i = 0, - n = arguments.length; - - while (++i < n) dispatch[arguments[i]] = d3_dispatch_event(dispatch); - - // Creates a dispatch context for the specified `thiz` (typically, the target - // DOM element that received the source event) and `argumentz` (typically, the - // data `d` and index `i` of the target element). The returned function can be - // used to dispatch an event to any registered listeners; the function takes a - // single argument as input, being the event to dispatch. The event must have - // a "type" attribute which corresponds to a type registered in the - // constructor. This context will automatically populate the "sourceEvent" and - // "target" attributes of the event, as well as setting the `d3.event` global - // for the duration of the notification. - dispatch.of = function(thiz, argumentz) { - return function(e1) { - try { - var e0 = - e1.sourceEvent = d3.event; - e1.target = target; - d3.event = e1; - dispatch[e1.type].apply(thiz, argumentz); - } finally { - d3.event = e0; - } - }; - }; - - return dispatch; -} -d3.requote = function(s) { - return s.replace(d3_requote_re, "\\$&"); -}; - -var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g; -var d3_subclass = {}.__proto__? - -// Until ECMAScript supports array subclassing, prototype injection works well. -function(object, prototype) { - object.__proto__ = prototype; -}: - -// And if your browser doesn't support __proto__, we'll use direct extension. -function(object, prototype) { - for (var property in prototype) object[property] = prototype[property]; -}; - -function d3_selection(groups) { - d3_subclass(groups, d3_selectionPrototype); - return groups; -} - -var d3_select = function(s, n) { return n.querySelector(s); }, - d3_selectAll = function(s, n) { return n.querySelectorAll(s); }, - d3_selectMatches = function(n, s) { - var d3_selectMatcher = n.matches || n[d3_vendorSymbol(n, "matchesSelector")]; - d3_selectMatches = function(n, s) { - return d3_selectMatcher.call(n, s); - }; - return d3_selectMatches(n, s); - }; - -// Prefer Sizzle, if available. -if (typeof Sizzle === "function") { - d3_select = function(s, n) { return Sizzle(s, n)[0] || null; }; - d3_selectAll = Sizzle; - d3_selectMatches = Sizzle.matchesSelector; -} - -d3.selection = function() { - return d3.select(d3_document.documentElement); -}; - -var d3_selectionPrototype = d3.selection.prototype = []; - - -d3_selectionPrototype.select = function(selector) { - var subgroups = [], - subgroup, - subnode, - group, - node; - - selector = d3_selection_selector(selector); - - for (var j = -1, m = this.length; ++j < m;) { - subgroups.push(subgroup = []); - subgroup.parentNode = (group = this[j]).parentNode; - for (var i = -1, n = group.length; ++i < n;) { - if (node = group[i]) { - subgroup.push(subnode = selector.call(node, node.__data__, i, j)); - if (subnode && "__data__" in node) subnode.__data__ = node.__data__; - } else { - subgroup.push(null); - } - } - } - - return d3_selection(subgroups); -}; - -function d3_selection_selector(selector) { - return typeof selector === "function" ? selector : function() { - return d3_select(selector, this); - }; -} - -d3_selectionPrototype.selectAll = function(selector) { - var subgroups = [], - subgroup, - node; - - selector = d3_selection_selectorAll(selector); - - for (var j = -1, m = this.length; ++j < m;) { - for (var group = this[j], i = -1, n = group.length; ++i < n;) { - if (node = group[i]) { - subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i, j))); - subgroup.parentNode = node; - } - } - } - - return d3_selection(subgroups); -}; - -function d3_selection_selectorAll(selector) { - return typeof selector === "function" ? selector : function() { - return d3_selectAll(selector, this); - }; -} -var d3_nsPrefix = { - svg: "http://www.w3.org/2000/svg", - xhtml: "http://www.w3.org/1999/xhtml", - xlink: "http://www.w3.org/1999/xlink", - xml: "http://www.w3.org/XML/1998/namespace", - xmlns: "http://www.w3.org/2000/xmlns/" -}; - -d3.ns = { - prefix: d3_nsPrefix, - qualify: function(name) { - var i = name.indexOf(":"), - prefix = name; - if (i >= 0) { - prefix = name.slice(0, i); - name = name.slice(i + 1); - } - return d3_nsPrefix.hasOwnProperty(prefix) - ? {space: d3_nsPrefix[prefix], local: name} - : name; - } -}; - -d3_selectionPrototype.attr = function(name, value) { - if (arguments.length < 2) { - - // For attr(string), return the attribute value for the first node. - if (typeof name === "string") { - var node = this.node(); - name = d3.ns.qualify(name); - return name.local - ? node.getAttributeNS(name.space, name.local) - : node.getAttribute(name); - } - - // For attr(object), the object specifies the names and values of the - // attributes to set or remove. The values may be functions that are - // evaluated for each element. - for (value in name) this.each(d3_selection_attr(value, name[value])); - return this; - } - - return this.each(d3_selection_attr(name, value)); -}; - -function d3_selection_attr(name, value) { - name = d3.ns.qualify(name); - - // For attr(string, null), remove the attribute with the specified name. - function attrNull() { - this.removeAttribute(name); - } - function attrNullNS() { - this.removeAttributeNS(name.space, name.local); - } - - // For attr(string, string), set the attribute with the specified name. - function attrConstant() { - this.setAttribute(name, value); - } - function attrConstantNS() { - this.setAttributeNS(name.space, name.local, value); - } - - // For attr(string, function), evaluate the function for each element, and set - // or remove the attribute as appropriate. - function attrFunction() { - var x = value.apply(this, arguments); - if (x == null) this.removeAttribute(name); - else this.setAttribute(name, x); - } - function attrFunctionNS() { - var x = value.apply(this, arguments); - if (x == null) this.removeAttributeNS(name.space, name.local); - else this.setAttributeNS(name.space, name.local, x); - } - - return value == null - ? (name.local ? attrNullNS : attrNull) : (typeof value === "function" - ? (name.local ? attrFunctionNS : attrFunction) - : (name.local ? attrConstantNS : attrConstant)); -} -function d3_collapse(s) { - return s.trim().replace(/\s+/g, " "); -} - -d3_selectionPrototype.classed = function(name, value) { - if (arguments.length < 2) { - - // For classed(string), return true only if the first node has the specified - // class or classes. Note that even if the browser supports DOMTokenList, it - // probably doesn't support it on SVG elements (which can be animated). - if (typeof name === "string") { - var node = this.node(), - n = (name = d3_selection_classes(name)).length, - i = -1; - if (value = node.classList) { - while (++i < n) if (!value.contains(name[i])) return false; - } else { - value = node.getAttribute("class"); - while (++i < n) if (!d3_selection_classedRe(name[i]).test(value)) return false; - } - return true; - } - - // For classed(object), the object specifies the names of classes to add or - // remove. The values may be functions that are evaluated for each element. - for (value in name) this.each(d3_selection_classed(value, name[value])); - return this; - } - - // Otherwise, both a name and a value are specified, and are handled as below. - return this.each(d3_selection_classed(name, value)); -}; - -function d3_selection_classedRe(name) { - return new RegExp("(?:^|\\s+)" + d3.requote(name) + "(?:\\s+|$)", "g"); -} - -function d3_selection_classes(name) { - return (name + "").trim().split(/^|\s+/); -} - -// Multiple class names are allowed (e.g., "foo bar"). -function d3_selection_classed(name, value) { - name = d3_selection_classes(name).map(d3_selection_classedName); - var n = name.length; - - function classedConstant() { - var i = -1; - while (++i < n) name[i](this, value); - } - - // When the value is a function, the function is still evaluated only once per - // element even if there are multiple class names. - function classedFunction() { - var i = -1, x = value.apply(this, arguments); - while (++i < n) name[i](this, x); - } - - return typeof value === "function" - ? classedFunction - : classedConstant; -} - -function d3_selection_classedName(name) { - var re = d3_selection_classedRe(name); - return function(node, value) { - if (c = node.classList) return value ? c.add(name) : c.remove(name); - var c = node.getAttribute("class") || ""; - if (value) { - re.lastIndex = 0; - if (!re.test(c)) node.setAttribute("class", d3_collapse(c + " " + name)); - } else { - node.setAttribute("class", d3_collapse(c.replace(re, " "))); - } - }; -} - -d3_selectionPrototype.style = function(name, value, priority) { - var n = arguments.length; - if (n < 3) { - - // For style(object) or style(object, string), the object specifies the - // names and values of the attributes to set or remove. The values may be - // functions that are evaluated for each element. The optional string - // specifies the priority. - if (typeof name !== "string") { - if (n < 2) value = ""; - for (priority in name) this.each(d3_selection_style(priority, name[priority], value)); - return this; - } - - // For style(string), return the computed style value for the first node. - if (n < 2) { - var node = this.node(); - return d3_window(node).getComputedStyle(node, null).getPropertyValue(name); - } - - // For style(string, string) or style(string, function), use the default - // priority. The priority is ignored for style(string, null). - priority = ""; - } - - // Otherwise, a name, value and priority are specified, and handled as below. - return this.each(d3_selection_style(name, value, priority)); -}; - -function d3_selection_style(name, value, priority) { - - // For style(name, null) or style(name, null, priority), remove the style - // property with the specified name. The priority is ignored. - function styleNull() { - this.style.removeProperty(name); - } - - // For style(name, string) or style(name, string, priority), set the style - // property with the specified name, using the specified priority. - function styleConstant() { - this.style.setProperty(name, value, priority); - } - - // For style(name, function) or style(name, function, priority), evaluate the - // function for each element, and set or remove the style property as - // appropriate. When setting, use the specified priority. - function styleFunction() { - var x = value.apply(this, arguments); - if (x == null) this.style.removeProperty(name); - else this.style.setProperty(name, x, priority); - } - - return value == null - ? styleNull : (typeof value === "function" - ? styleFunction : styleConstant); -} - -d3_selectionPrototype.property = function(name, value) { - if (arguments.length < 2) { - - // For property(string), return the property value for the first node. - if (typeof name === "string") return this.node()[name]; - - // For property(object), the object specifies the names and values of the - // properties to set or remove. The values may be functions that are - // evaluated for each element. - for (value in name) this.each(d3_selection_property(value, name[value])); - return this; - } - - // Otherwise, both a name and a value are specified, and are handled as below. - return this.each(d3_selection_property(name, value)); -}; - -function d3_selection_property(name, value) { - - // For property(name, null), remove the property with the specified name. - function propertyNull() { - delete this[name]; - } - - // For property(name, string), set the property with the specified name. - function propertyConstant() { - this[name] = value; - } - - // For property(name, function), evaluate the function for each element, and - // set or remove the property as appropriate. - function propertyFunction() { - var x = value.apply(this, arguments); - if (x == null) delete this[name]; - else this[name] = x; - } - - return value == null - ? propertyNull : (typeof value === "function" - ? propertyFunction : propertyConstant); -} - -d3_selectionPrototype.text = function(value) { - return arguments.length - ? this.each(typeof value === "function" - ? function() { var v = value.apply(this, arguments); this.textContent = v == null ? "" : v; } : value == null - ? function() { if (this.textContent !== "") this.textContent = ""; } - : function() { if (this.textContent !== value) this.textContent = value; }) - : this.node().textContent; -}; - -d3_selectionPrototype.html = function(value) { - return arguments.length - ? this.each(typeof value === "function" - ? function() { var v = value.apply(this, arguments); this.innerHTML = v == null ? "" : v; } : value == null - ? function() { this.innerHTML = ""; } - : function() { this.innerHTML = value; }) - : this.node().innerHTML; -}; - -d3_selectionPrototype.append = function(name) { - name = d3_selection_creator(name); - return this.select(function() { - return this.appendChild(name.apply(this, arguments)); - }); -}; - -function d3_selection_creator(name) { - - function create() { - var document = this.ownerDocument, - namespace = this.namespaceURI; - return namespace - ? document.createElementNS(namespace, name) - : document.createElement(name); - } - - function createNS() { - return this.ownerDocument.createElementNS(name.space, name.local); - } - - return typeof name === "function" ? name - : (name = d3.ns.qualify(name)).local ? createNS - : create; -} - -d3_selectionPrototype.insert = function(name, before) { - name = d3_selection_creator(name); - before = d3_selection_selector(before); - return this.select(function() { - return this.insertBefore(name.apply(this, arguments), before.apply(this, arguments) || null); - }); -}; - -// TODO remove(selector)? -// TODO remove(node)? -// TODO remove(function)? -d3_selectionPrototype.remove = function() { - return this.each(d3_selectionRemove); -}; - -function d3_selectionRemove() { - var parent = this.parentNode; - if (parent) parent.removeChild(this); -} - -d3_selectionPrototype.data = function(value, key) { - var i = -1, - n = this.length, - group, - node; - - // If no value is specified, return the first value. - if (!arguments.length) { - value = new Array(n = (group = this[0]).length); - while (++i < n) { - if (node = group[i]) { - value[i] = node.__data__; - } - } - return value; - } - - function bind(group, groupData) { - var i, - n = group.length, - m = groupData.length, - n0 = Math.min(n, m), - updateNodes = new Array(m), - enterNodes = new Array(m), - exitNodes = new Array(n), - node, - nodeData; - - if (key) { - var nodeByKeyValue = new d3_Map, - keyValues = new Array(n), - keyValue; - - for (i = -1; ++i < n;) { - if (nodeByKeyValue.has(keyValue = key.call(node = group[i], node.__data__, i))) { - exitNodes[i] = node; // duplicate selection key - } else { - nodeByKeyValue.set(keyValue, node); - } - keyValues[i] = keyValue; - } - - for (i = -1; ++i < m;) { - if (!(node = nodeByKeyValue.get(keyValue = key.call(groupData, nodeData = groupData[i], i)))) { - enterNodes[i] = d3_selection_dataNode(nodeData); - } else if (node !== true) { // no duplicate data key - updateNodes[i] = node; - node.__data__ = nodeData; - } - nodeByKeyValue.set(keyValue, true); - } - - for (i = -1; ++i < n;) { - if (nodeByKeyValue.get(keyValues[i]) !== true) { - exitNodes[i] = group[i]; - } - } - } else { - for (i = -1; ++i < n0;) { - node = group[i]; - nodeData = groupData[i]; - if (node) { - node.__data__ = nodeData; - updateNodes[i] = node; - } else { - enterNodes[i] = d3_selection_dataNode(nodeData); - } - } - for (; i < m; ++i) { - enterNodes[i] = d3_selection_dataNode(groupData[i]); - } - for (; i < n; ++i) { - exitNodes[i] = group[i]; - } - } - - enterNodes.update - = updateNodes; - - enterNodes.parentNode - = updateNodes.parentNode - = exitNodes.parentNode - = group.parentNode; - - enter.push(enterNodes); - update.push(updateNodes); - exit.push(exitNodes); - } - - var enter = d3_selection_enter([]), - update = d3_selection([]), - exit = d3_selection([]); - - if (typeof value === "function") { - while (++i < n) { - bind(group = this[i], value.call(group, group.parentNode.__data__, i)); - } - } else { - while (++i < n) { - bind(group = this[i], value); - } - } - - update.enter = function() { return enter; }; - update.exit = function() { return exit; }; - return update; -}; - -function d3_selection_dataNode(data) { - return {__data__: data}; -} - -d3_selectionPrototype.datum = function(value) { - return arguments.length - ? this.property("__data__", value) - : this.property("__data__"); -}; - -d3_selectionPrototype.filter = function(filter) { - var subgroups = [], - subgroup, - group, - node; - - if (typeof filter !== "function") filter = d3_selection_filter(filter); - - for (var j = 0, m = this.length; j < m; j++) { - subgroups.push(subgroup = []); - subgroup.parentNode = (group = this[j]).parentNode; - for (var i = 0, n = group.length; i < n; i++) { - if ((node = group[i]) && filter.call(node, node.__data__, i, j)) { - subgroup.push(node); - } - } - } - - return d3_selection(subgroups); -}; - -function d3_selection_filter(selector) { - return function() { - return d3_selectMatches(this, selector); - }; -} - -d3_selectionPrototype.order = function() { - for (var j = -1, m = this.length; ++j < m;) { - for (var group = this[j], i = group.length - 1, next = group[i], node; --i >= 0;) { - if (node = group[i]) { - if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next); - next = node; - } - } - } - return this; -}; - -d3_selectionPrototype.sort = function(comparator) { - comparator = d3_selection_sortComparator.apply(this, arguments); - for (var j = -1, m = this.length; ++j < m;) this[j].sort(comparator); - return this.order(); -}; - -function d3_selection_sortComparator(comparator) { - if (!arguments.length) comparator = d3_ascending; - return function(a, b) { - return a && b ? comparator(a.__data__, b.__data__) : !a - !b; - }; -} - -d3_selectionPrototype.each = function(callback) { - return d3_selection_each(this, function(node, i, j) { - callback.call(node, node.__data__, i, j); - }); -}; - -function d3_selection_each(groups, callback) { - for (var j = 0, m = groups.length; j < m; j++) { - for (var group = groups[j], i = 0, n = group.length, node; i < n; i++) { - if (node = group[i]) callback(node, i, j); - } - } - return groups; -} - -d3_selectionPrototype.call = function(callback) { - var args = d3_array(arguments); - callback.apply(args[0] = this, args); - return this; -}; - -d3_selectionPrototype.empty = function() { - return !this.node(); -}; - -d3_selectionPrototype.node = function() { - for (var j = 0, m = this.length; j < m; j++) { - for (var group = this[j], i = 0, n = group.length; i < n; i++) { - var node = group[i]; - if (node) return node; - } - } - return null; -}; - -d3_selectionPrototype.size = function() { - var n = 0; - d3_selection_each(this, function() { ++n; }); - return n; -}; - -function d3_selection_enter(selection) { - d3_subclass(selection, d3_selection_enterPrototype); - return selection; -} - -var d3_selection_enterPrototype = []; - -d3.selection.enter = d3_selection_enter; -d3.selection.enter.prototype = d3_selection_enterPrototype; - -d3_selection_enterPrototype.append = d3_selectionPrototype.append; -d3_selection_enterPrototype.empty = d3_selectionPrototype.empty; -d3_selection_enterPrototype.node = d3_selectionPrototype.node; -d3_selection_enterPrototype.call = d3_selectionPrototype.call; -d3_selection_enterPrototype.size = d3_selectionPrototype.size; - - -d3_selection_enterPrototype.select = function(selector) { - var subgroups = [], - subgroup, - subnode, - upgroup, - group, - node; - - for (var j = -1, m = this.length; ++j < m;) { - upgroup = (group = this[j]).update; - subgroups.push(subgroup = []); - subgroup.parentNode = group.parentNode; - for (var i = -1, n = group.length; ++i < n;) { - if (node = group[i]) { - subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i, j)); - subnode.__data__ = node.__data__; - } else { - subgroup.push(null); - } - } - } - - return d3_selection(subgroups); -}; - -d3_selection_enterPrototype.insert = function(name, before) { - if (arguments.length < 2) before = d3_selection_enterInsertBefore(this); - return d3_selectionPrototype.insert.call(this, name, before); -}; - -function d3_selection_enterInsertBefore(enter) { - var i0, j0; - return function(d, i, j) { - var group = enter[j].update, - n = group.length, - node; - if (j != j0) j0 = j, i0 = 0; - if (i >= i0) i0 = i + 1; - while (!(node = group[i0]) && ++i0 < n); - return node; - }; -} - -// TODO fast singleton implementation? -d3.select = function(node) { - var group; - if (typeof node === "string") { - group = [d3_select(node, d3_document)]; - group.parentNode = d3_document.documentElement; - } else { - group = [node]; - group.parentNode = d3_documentElement(node); - } - return d3_selection([group]); -}; - -d3.selectAll = function(nodes) { - var group; - if (typeof nodes === "string") { - group = d3_array(d3_selectAll(nodes, d3_document)); - group.parentNode = d3_document.documentElement; - } else { - group = nodes; - group.parentNode = null; - } - return d3_selection([group]); -}; - -d3_selectionPrototype.on = function(type, listener, capture) { - var n = arguments.length; - if (n < 3) { - - // For on(object) or on(object, boolean), the object specifies the event - // types and listeners to add or remove. The optional boolean specifies - // whether the listener captures events. - if (typeof type !== "string") { - if (n < 2) listener = false; - for (capture in type) this.each(d3_selection_on(capture, type[capture], listener)); - return this; - } - - // For on(string), return the listener for the first node. - if (n < 2) return (n = this.node()["__on" + type]) && n._; - - // For on(string, function), use the default capture. - capture = false; - } - - // Otherwise, a type, listener and capture are specified, and handled as below. - return this.each(d3_selection_on(type, listener, capture)); -}; - -function d3_selection_on(type, listener, capture) { - var name = "__on" + type, - i = type.indexOf("."), - wrap = d3_selection_onListener; - - if (i > 0) type = type.slice(0, i); - var filter = d3_selection_onFilters.get(type); - if (filter) type = filter, wrap = d3_selection_onFilter; - - function onRemove() { - var l = this[name]; - if (l) { - this.removeEventListener(type, l, l.$); - delete this[name]; - } - } - - function onAdd() { - var l = wrap(listener, d3_array(arguments)); - if (typeof Raven !== 'undefined') l = Raven.wrap(l); - onRemove.call(this); - this.addEventListener(type, this[name] = l, l.$ = capture); - l._ = listener; - } - - function removeAll() { - var re = new RegExp("^__on([^.]+)" + d3.requote(type) + "$"), - match; - for (var name in this) { - if (match = name.match(re)) { - var l = this[name]; - this.removeEventListener(match[1], l, l.$); - delete this[name]; - } - } - } - - return i - ? listener ? onAdd : onRemove - : listener ? d3_noop : removeAll; -} - -var d3_selection_onFilters = d3.map({ - mouseenter: "mouseover", - mouseleave: "mouseout" -}); - -if (d3_document) { - d3_selection_onFilters.forEach(function(k) { - if ("on" + k in d3_document) d3_selection_onFilters.remove(k); - }); -} - -function d3_selection_onListener(listener, argumentz) { - return function(e) { - var o = d3.event; // Events can be reentrant (e.g., focus). - d3.event = e; - argumentz[0] = this.__data__; - try { - listener.apply(this, argumentz); - } finally { - d3.event = o; - } - }; -} - -function d3_selection_onFilter(listener, argumentz) { - var l = d3_selection_onListener(listener, argumentz); - return function(e) { - var target = this, related = e.relatedTarget; - if (!related || (related !== target && !(related.compareDocumentPosition(target) & 8))) { - l.call(target, e); - } - }; -} - -var d3_event_dragSelect, - d3_event_dragId = 0; - -function d3_event_dragSuppress(node) { - var name = ".dragsuppress-" + ++d3_event_dragId, - click = "click" + name, - w = d3.select(d3_window(node)) - .on("touchmove" + name, d3_eventPreventDefault) - .on("dragstart" + name, d3_eventPreventDefault) - .on("selectstart" + name, d3_eventPreventDefault); - - if (d3_event_dragSelect == null) { - d3_event_dragSelect = "onselectstart" in node ? false - : d3_vendorSymbol(node.style, "userSelect"); - } - - if (d3_event_dragSelect) { - var style = d3_documentElement(node).style, - select = style[d3_event_dragSelect]; - style[d3_event_dragSelect] = "none"; - } - - return function(suppressClick) { - w.on(name, null); - if (d3_event_dragSelect) style[d3_event_dragSelect] = select; - if (suppressClick) { // suppress the next click, but only if it’s immediate - var off = function() { w.on(click, null); }; - w.on(click, function() { d3_eventCancel(); off(); }, true); - setTimeout(off, 0); - } - }; -} - -d3.mouse = function(container) { - return d3_mousePoint(container, d3_eventSource()); -}; - -// https://bugs.webkit.org/show_bug.cgi?id=44083 -var d3_mouse_bug44083 = this.navigator && /WebKit/.test(this.navigator.userAgent) ? -1 : 0; - -function d3_mousePoint(container, e) { - if (e.changedTouches) e = e.changedTouches[0]; - var svg = container.ownerSVGElement || container; - if (svg.createSVGPoint) { - var point = svg.createSVGPoint(); - if (d3_mouse_bug44083 < 0) { - var window = d3_window(container); - if (window.scrollX || window.scrollY) { - svg = d3.select("body").append("svg").style({ - position: "absolute", - top: 0, - left: 0, - margin: 0, - padding: 0, - border: "none" - }, "important"); - var ctm = svg[0][0].getScreenCTM(); - d3_mouse_bug44083 = !(ctm.f || ctm.e); - svg.remove(); - } - } - if (d3_mouse_bug44083) point.x = e.pageX, point.y = e.pageY; - else point.x = e.clientX, point.y = e.clientY; - point = point.matrixTransform(container.getScreenCTM().inverse()); - return [point.x, point.y]; - } - var rect = container.getBoundingClientRect(); - return [e.clientX - rect.left - container.clientLeft, e.clientY - rect.top - container.clientTop]; -}; - -d3.touches = function(container, touches) { - if (arguments.length < 2) touches = d3_eventSource().touches; - return touches ? d3_array(touches).map(function(touch) { - var point = d3_mousePoint(container, touch); - point.identifier = touch.identifier; - return point; - }) : []; -}; -var ε = 1e-6, - ε2 = ε * ε, - π = Math.PI, - τ = 2 * π, - τε = τ - ε, - halfπ = π / 2, - d3_radians = π / 180, - d3_degrees = 180 / π; - -function d3_sgn(x) { - return x > 0 ? 1 : x < 0 ? -1 : 0; -} - -// Returns the 2D cross product of AB and AC vectors, i.e., the z-component of -// the 3D cross product in a quadrant I Cartesian coordinate system (+x is -// right, +y is up). Returns a positive value if ABC is counter-clockwise, -// negative if clockwise, and zero if the points are collinear. -function d3_cross2d(a, b, c) { - return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]); -} - -function d3_acos(x) { - return x > 1 ? 0 : x < -1 ? π : Math.acos(x); -} - -function d3_asin(x) { - return x > 1 ? halfπ : x < -1 ? -halfπ : Math.asin(x); -} - -function d3_sinh(x) { - return ((x = Math.exp(x)) - 1 / x) / 2; -} - -function d3_cosh(x) { - return ((x = Math.exp(x)) + 1 / x) / 2; -} - -function d3_tanh(x) { - return ((x = Math.exp(2 * x)) - 1) / (x + 1); -} - -function d3_haversin(x) { - return (x = Math.sin(x / 2)) * x; -} - -var ρ = Math.SQRT2, - ρ2 = 2, - ρ4 = 4; - -// p0 = [ux0, uy0, w0] -// p1 = [ux1, uy1, w1] -d3.interpolateZoom = function(p0, p1) { - var ux0 = p0[0], uy0 = p0[1], w0 = p0[2], - ux1 = p1[0], uy1 = p1[1], w1 = p1[2]; - - var dx = ux1 - ux0, - dy = uy1 - uy0, - d2 = dx * dx + dy * dy, - d1 = Math.sqrt(d2), - b0 = (w1 * w1 - w0 * w0 + ρ4 * d2) / (2 * w0 * ρ2 * d1), - b1 = (w1 * w1 - w0 * w0 - ρ4 * d2) / (2 * w1 * ρ2 * d1), - r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0), - r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1), - dr = r1 - r0, - S = (dr || Math.log(w1 / w0)) / ρ; - - function interpolate(t) { - var s = t * S; - if (dr) { - // General case. - var coshr0 = d3_cosh(r0), - u = w0 / (ρ2 * d1) * (coshr0 * d3_tanh(ρ * s + r0) - d3_sinh(r0)); - return [ - ux0 + u * dx, - uy0 + u * dy, - w0 * coshr0 / d3_cosh(ρ * s + r0) - ]; - } - // Special case for u0 ~= u1. - return [ - ux0 + t * dx, - uy0 + t * dy, - w0 * Math.exp(ρ * s) - ]; - } - - interpolate.duration = S * 1000; - - return interpolate; -}; - -d3.behavior.zoom = function() { - var view = {x: 0, y: 0, k: 1}, - translate0, // translate when we started zooming (to avoid drift) - center0, // implicit desired position of translate0 after zooming - center, // explicit desired position of translate0 after zooming - size = [960, 500], // viewport size; required for zoom interpolation - scaleExtent = d3_behavior_zoomInfinity, - duration = 250, - zooming = 0, - mousedown = "mousedown.zoom", - mousemove = "mousemove.zoom", - mouseup = "mouseup.zoom", - mousewheelTimer, - touchstart = "touchstart.zoom", - touchtime, // time of last touchstart (to detect double-tap) - event = d3_eventDispatch(zoom, "zoomstart", "zoom", "zoomend"), - x0, - x1, - y0, - y1; - - // Lazily determine the DOM’s support for Wheel events. - // https://developer.mozilla.org/en-US/docs/Mozilla_event_reference/wheel - if (!d3_behavior_zoomWheel) { - d3_behavior_zoomWheel = "onwheel" in d3_document ? (d3_behavior_zoomDelta = function() { return -d3.event.deltaY * (d3.event.deltaMode ? 120 : 1); }, "wheel") - : "onmousewheel" in d3_document ? (d3_behavior_zoomDelta = function() { return d3.event.wheelDelta; }, "mousewheel") - : (d3_behavior_zoomDelta = function() { return -d3.event.detail; }, "MozMousePixelScroll"); - } - - function zoom(g) { - g .on(mousedown, mousedowned) - .on(d3_behavior_zoomWheel + ".zoom", mousewheeled) - .on("dblclick.zoom", dblclicked) - .on(touchstart, touchstarted); - } - - zoom.event = function(g) { - g.each(function() { - var dispatch = event.of(this, arguments), - view1 = view; - if (d3_transitionInheritId) { - d3.select(this).transition() - .each("start.zoom", function() { - view = this.__chart__ || {x: 0, y: 0, k: 1}; // pre-transition state - zoomstarted(dispatch); - }) - .tween("zoom:zoom", function() { - var dx = size[0], - dy = size[1], - cx = center0 ? center0[0] : dx / 2, - cy = center0 ? center0[1] : dy / 2, - i = d3.interpolateZoom( - [(cx - view.x) / view.k, (cy - view.y) / view.k, dx / view.k], - [(cx - view1.x) / view1.k, (cy - view1.y) / view1.k, dx / view1.k] - ); - return function(t) { - var l = i(t), k = dx / l[2]; - this.__chart__ = view = {x: cx - l[0] * k, y: cy - l[1] * k, k: k}; - zoomed(dispatch); - }; - }) - .each("interrupt.zoom", function() { - zoomended(dispatch); - }) - .each("end.zoom", function() { - zoomended(dispatch); - }); - } else { - this.__chart__ = view; - zoomstarted(dispatch); - zoomed(dispatch); - zoomended(dispatch); - } - }); - } - - zoom.translate = function(_) { - if (!arguments.length) return [view.x, view.y]; - view = {x: +_[0], y: +_[1], k: view.k}; // copy-on-write - rescale(); - return zoom; - }; - - zoom.scale = function(_) { - if (!arguments.length) return view.k; - view = {x: view.x, y: view.y, k: +_}; // copy-on-write - rescale(); - return zoom; - }; - - zoom.scaleExtent = function(_) { - if (!arguments.length) return scaleExtent; - scaleExtent = _ == null ? d3_behavior_zoomInfinity : [+_[0], +_[1]]; - return zoom; - }; - - zoom.center = function(_) { - if (!arguments.length) return center; - center = _ && [+_[0], +_[1]]; - return zoom; - }; - - zoom.size = function(_) { - if (!arguments.length) return size; - size = _ && [+_[0], +_[1]]; - return zoom; - }; - - zoom.duration = function(_) { - if (!arguments.length) return duration; - duration = +_; // TODO function based on interpolateZoom distance? - return zoom; - }; - - zoom.x = function(z) { - if (!arguments.length) return x1; - x1 = z; - x0 = z.copy(); - view = {x: 0, y: 0, k: 1}; // copy-on-write - return zoom; - }; - - zoom.y = function(z) { - if (!arguments.length) return y1; - y1 = z; - y0 = z.copy(); - view = {x: 0, y: 0, k: 1}; // copy-on-write - return zoom; - }; - - function location(p) { - return [(p[0] - view.x) / view.k, (p[1] - view.y) / view.k]; - } - - function point(l) { - return [l[0] * view.k + view.x, l[1] * view.k + view.y]; - } - - function scaleTo(s) { - view.k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], s)); - } - - function translateTo(p, l) { - l = point(l); - view.x += p[0] - l[0]; - view.y += p[1] - l[1]; - } - - function zoomTo(that, p, l, k) { - that.__chart__ = {x: view.x, y: view.y, k: view.k}; - - scaleTo(Math.pow(2, k)); - translateTo(center0 = p, l); - - that = d3.select(that); - if (duration > 0) that = that.transition().duration(duration); - that.call(zoom.event); - } - - function rescale() { - if (x1) x1.domain(x0.range().map(function(x) { return (x - view.x) / view.k; }).map(x0.invert)); - if (y1) y1.domain(y0.range().map(function(y) { return (y - view.y) / view.k; }).map(y0.invert)); - } - - function zoomstarted(dispatch) { - if (!zooming++) dispatch({type: "zoomstart"}); - } - - function zoomed(dispatch) { - rescale(); - dispatch({type: "zoom", scale: view.k, translate: [view.x, view.y]}); - } - - function zoomended(dispatch) { - if (!--zooming) dispatch({type: "zoomend"}), center0 = null; - } - - function mousedowned() { - var that = this, - target = d3.event.target, - dispatch = event.of(that, arguments), - dragged = 0, - subject = d3.select(d3_window(that)).on(mousemove, moved).on(mouseup, ended), - location0 = location(d3.mouse(that)), - dragRestore = d3_event_dragSuppress(that); - - d3_selection_interrupt.call(that); - zoomstarted(dispatch); - - function moved() { - dragged = 1; - translateTo(d3.mouse(that), location0); - zoomed(dispatch); - } - - function ended() { - subject.on(mousemove, null).on(mouseup, null); - dragRestore(dragged && d3.event.target === target); - zoomended(dispatch); - } - } - - // These closures persist for as long as at least one touch is active. - function touchstarted() { - var that = this, - dispatch = event.of(that, arguments), - locations0 = {}, // touchstart locations - distance0 = 0, // distance² between initial touches - scale0, // scale when we started touching - zoomName = ".zoom-" + d3.event.changedTouches[0].identifier, - touchmove = "touchmove" + zoomName, - touchend = "touchend" + zoomName, - targets = [], - subject = d3.select(that), - dragRestore = d3_event_dragSuppress(that); - - started(); - zoomstarted(dispatch); - - // Workaround for Chrome issue 412723: the touchstart listener must be set - // after the touchmove listener. - subject.on(mousedown, null).on(touchstart, started); // prevent duplicate events - - // Updates locations of any touches in locations0. - function relocate() { - var touches = d3.touches(that); - scale0 = view.k; - touches.forEach(function(t) { - if (t.identifier in locations0) locations0[t.identifier] = location(t); - }); - return touches; - } - - // Temporarily override touchstart while gesture is active. - function started() { - - // Listen for touchmove and touchend on the target of touchstart. - var target = d3.event.target; - d3.select(target).on(touchmove, moved).on(touchend, ended); - targets.push(target); - - // Only track touches started on the same subject element. - var changed = d3.event.changedTouches; - for (var i = 0, n = changed.length; i < n; ++i) { - locations0[changed[i].identifier] = null; - } - - var touches = relocate(), - now = Date.now(); - - if (touches.length === 1) { - if (now - touchtime < 500) { // dbltap - var p = touches[0]; - zoomTo(that, p, locations0[p.identifier], Math.floor(Math.log(view.k) / Math.LN2) + 1); - d3_eventPreventDefault(); - } - touchtime = now; - } else if (touches.length > 1) { - var p = touches[0], q = touches[1], - dx = p[0] - q[0], dy = p[1] - q[1]; - distance0 = dx * dx + dy * dy; - } - } - - function moved() { - var touches = d3.touches(that), - p0, l0, - p1, l1; - - d3_selection_interrupt.call(that); - - for (var i = 0, n = touches.length; i < n; ++i, l1 = null) { - p1 = touches[i]; - if (l1 = locations0[p1.identifier]) { - if (l0) break; - p0 = p1, l0 = l1; - } - } - - if (l1) { - var distance1 = (distance1 = p1[0] - p0[0]) * distance1 + (distance1 = p1[1] - p0[1]) * distance1, - scale1 = distance0 && Math.sqrt(distance1 / distance0); - p0 = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2]; - l0 = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2]; - scaleTo(scale1 * scale0); - } - - touchtime = null; - translateTo(p0, l0); - zoomed(dispatch); - } - - function ended() { - // If there are any globally-active touches remaining, remove the ended - // touches from locations0. - if (d3.event.touches.length) { - var changed = d3.event.changedTouches; - for (var i = 0, n = changed.length; i < n; ++i) { - delete locations0[changed[i].identifier]; - } - // If locations0 is not empty, then relocate and continue listening for - // touchmove and touchend. - for (var identifier in locations0) { - return void relocate(); // locations may have detached due to rotation - } - } - // Otherwise, remove touchmove and touchend listeners. - d3.selectAll(targets).on(zoomName, null); - subject.on(mousedown, mousedowned).on(touchstart, touchstarted); - dragRestore(); - zoomended(dispatch); - } - } - - function mousewheeled() { - var dispatch = event.of(this, arguments); - if (mousewheelTimer) clearTimeout(mousewheelTimer); - else d3_selection_interrupt.call(this), translate0 = location(center0 = center || d3.mouse(this)), zoomstarted(dispatch); - mousewheelTimer = setTimeout(function() { mousewheelTimer = null; zoomended(dispatch); }, 50); - d3_eventPreventDefault(); - scaleTo(Math.pow(2, d3_behavior_zoomDelta() * .002) * view.k); - translateTo(center0, translate0); - zoomed(dispatch); - } - - function dblclicked() { - var p = d3.mouse(this), - k = Math.log(view.k) / Math.LN2; - - zoomTo(this, p, location(p), d3.event.shiftKey ? Math.ceil(k) - 1 : Math.floor(k) + 1); - } - - return d3.rebind(zoom, event, "on"); -}; - -var d3_behavior_zoomInfinity = [0, Infinity], // default scale extent - d3_behavior_zoomDelta, // initialized lazily - d3_behavior_zoomWheel; -function d3_functor(v) { - return typeof v === "function" ? v : function() { return v; }; -} - -d3.functor = d3_functor; - -d3.touch = function(container, touches, identifier) { - if (arguments.length < 3) identifier = touches, touches = d3_eventSource().changedTouches; - if (touches) for (var i = 0, n = touches.length, touch; i < n; ++i) { - if ((touch = touches[i]).identifier === identifier) { - return d3_mousePoint(container, touch); - } - } -}; - -var d3_timer_queueHead, - d3_timer_queueTail, - d3_timer_interval, // is an interval (or frame) active? - d3_timer_timeout, // is a timeout active? - d3_timer_active, // active timer object - d3_timer_frame = this[d3_vendorSymbol(this, "requestAnimationFrame")] || function(callback) { setTimeout(callback, 17); }; - -// The timer will continue to fire until callback returns true. -d3.timer = function(callback, delay, then) { - var n = arguments.length; - if (n < 2) delay = 0; - if (n < 3) then = Date.now(); - - // Add the callback to the tail of the queue. - var time = then + delay, timer = {c: callback, t: time, f: false, n: null}; - if (d3_timer_queueTail) d3_timer_queueTail.n = timer; - else d3_timer_queueHead = timer; - d3_timer_queueTail = timer; - - // Start animatin'! - if (!d3_timer_interval) { - d3_timer_timeout = clearTimeout(d3_timer_timeout); - d3_timer_interval = 1; - d3_timer_frame(d3_timer_step); - } -}; - -function d3_timer_step() { - var now = d3_timer_mark(), - delay = d3_timer_sweep() - now; - if (delay > 24) { - if (isFinite(delay)) { - clearTimeout(d3_timer_timeout); - d3_timer_timeout = setTimeout(d3_timer_step, delay); - } - d3_timer_interval = 0; - } else { - d3_timer_interval = 1; - d3_timer_frame(d3_timer_step); - } -} - -d3.timer.flush = function() { - d3_timer_mark(); - d3_timer_sweep(); -}; - -function d3_timer_mark() { - var now = Date.now(); - d3_timer_active = d3_timer_queueHead; - while (d3_timer_active) { - if (now >= d3_timer_active.t) d3_timer_active.f = d3_timer_active.c(now - d3_timer_active.t); - d3_timer_active = d3_timer_active.n; - } - return now; -} - -// Flush after callbacks to avoid concurrent queue modification. -// Returns the time of the earliest active timer, post-sweep. -function d3_timer_sweep() { - var t0, - t1 = d3_timer_queueHead, - time = Infinity; - while (t1) { - if (t1.f) { - t1 = t0 ? t0.n = t1.n : d3_timer_queueHead = t1.n; - } else { - if (t1.t < time) time = t1.t; - t1 = (t0 = t1).n; - } - } - d3_timer_queueTail = t0; - return time; -} -d3.geo = {}; - -d3.geo.stream = function(object, listener) { - if (object && d3_geo_streamObjectType.hasOwnProperty(object.type)) { - d3_geo_streamObjectType[object.type](object, listener); - } else { - d3_geo_streamGeometry(object, listener); - } -}; - -function d3_geo_streamGeometry(geometry, listener) { - if (geometry && d3_geo_streamGeometryType.hasOwnProperty(geometry.type)) { - d3_geo_streamGeometryType[geometry.type](geometry, listener); - } -} - -var d3_geo_streamObjectType = { - Feature: function(feature, listener) { - d3_geo_streamGeometry(feature.geometry, listener); - }, - FeatureCollection: function(object, listener) { - var features = object.features, i = -1, n = features.length; - while (++i < n) d3_geo_streamGeometry(features[i].geometry, listener); - } -}; - -var d3_geo_streamGeometryType = { - Sphere: function(object, listener) { - listener.sphere(); - }, - Point: function(object, listener) { - object = object.coordinates; - listener.point(object[0], object[1], object[2]); - }, - MultiPoint: function(object, listener) { - var coordinates = object.coordinates, i = -1, n = coordinates.length; - while (++i < n) object = coordinates[i], listener.point(object[0], object[1], object[2]); - }, - LineString: function(object, listener) { - d3_geo_streamLine(object.coordinates, listener, 0); - }, - MultiLineString: function(object, listener) { - var coordinates = object.coordinates, i = -1, n = coordinates.length; - while (++i < n) d3_geo_streamLine(coordinates[i], listener, 0); - }, - Polygon: function(object, listener) { - d3_geo_streamPolygon(object.coordinates, listener); - }, - MultiPolygon: function(object, listener) { - var coordinates = object.coordinates, i = -1, n = coordinates.length; - while (++i < n) d3_geo_streamPolygon(coordinates[i], listener); - }, - GeometryCollection: function(object, listener) { - var geometries = object.geometries, i = -1, n = geometries.length; - while (++i < n) d3_geo_streamGeometry(geometries[i], listener); - } -}; - -function d3_geo_streamLine(coordinates, listener, closed) { - var i = -1, n = coordinates.length - closed, coordinate; - listener.lineStart(); - while (++i < n) coordinate = coordinates[i], listener.point(coordinate[0], coordinate[1], coordinate[2]); - listener.lineEnd(); -} - -function d3_geo_streamPolygon(coordinates, listener) { - var i = -1, n = coordinates.length; - listener.polygonStart(); - while (++i < n) d3_geo_streamLine(coordinates[i], listener, 1); - listener.polygonEnd(); -} - -d3.geo.length = function(object) { - d3_geo_lengthSum = 0; - d3.geo.stream(object, d3_geo_length); - return d3_geo_lengthSum; -}; - -var d3_geo_lengthSum; - -var d3_geo_length = { - sphere: d3_noop, - point: d3_noop, - lineStart: d3_geo_lengthLineStart, - lineEnd: d3_noop, - polygonStart: d3_noop, - polygonEnd: d3_noop -}; - -function d3_geo_lengthLineStart() { - var λ0, sinφ0, cosφ0; - - d3_geo_length.point = function(λ, φ) { - λ0 = λ * d3_radians, sinφ0 = Math.sin(φ *= d3_radians), cosφ0 = Math.cos(φ); - d3_geo_length.point = nextPoint; - }; - - d3_geo_length.lineEnd = function() { - d3_geo_length.point = d3_geo_length.lineEnd = d3_noop; - }; - - function nextPoint(λ, φ) { - var sinφ = Math.sin(φ *= d3_radians), - cosφ = Math.cos(φ), - t = abs((λ *= d3_radians) - λ0), - cosΔλ = Math.cos(t); - d3_geo_lengthSum += Math.atan2(Math.sqrt((t = cosφ * Math.sin(t)) * t + (t = cosφ0 * sinφ - sinφ0 * cosφ * cosΔλ) * t), sinφ0 * sinφ + cosφ0 * cosφ * cosΔλ); - λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ; - } -} -function d3_identity(d) { - return d; -} -function d3_true() { - return true; -} - -function d3_geo_spherical(cartesian) { - return [ - Math.atan2(cartesian[1], cartesian[0]), - d3_asin(cartesian[2]) - ]; -} - -function d3_geo_sphericalEqual(a, b) { - return abs(a[0] - b[0]) < ε && abs(a[1] - b[1]) < ε; -} - -// General spherical polygon clipping algorithm: takes a polygon, cuts it into -// visible line segments and rejoins the segments by interpolating along the -// clip edge. -function d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener) { - var subject = [], - clip = []; - - segments.forEach(function(segment) { - if ((n = segment.length - 1) <= 0) return; - var n, p0 = segment[0], p1 = segment[n]; - - // If the first and last points of a segment are coincident, then treat as - // a closed ring. - // TODO if all rings are closed, then the winding order of the exterior - // ring should be checked. - if (d3_geo_sphericalEqual(p0, p1)) { - listener.lineStart(); - for (var i = 0; i < n; ++i) listener.point((p0 = segment[i])[0], p0[1]); - listener.lineEnd(); - return; - } - - var a = new d3_geo_clipPolygonIntersection(p0, segment, null, true), - b = new d3_geo_clipPolygonIntersection(p0, null, a, false); - a.o = b; - subject.push(a); - clip.push(b); - a = new d3_geo_clipPolygonIntersection(p1, segment, null, false); - b = new d3_geo_clipPolygonIntersection(p1, null, a, true); - a.o = b; - subject.push(a); - clip.push(b); - }); - clip.sort(compare); - d3_geo_clipPolygonLinkCircular(subject); - d3_geo_clipPolygonLinkCircular(clip); - if (!subject.length) return; - - for (var i = 0, entry = clipStartInside, n = clip.length; i < n; ++i) { - clip[i].e = entry = !entry; - } - - var start = subject[0], - points, - point; - while (1) { - // Find first unvisited intersection. - var current = start, - isSubject = true; - while (current.v) if ((current = current.n) === start) return; - points = current.z; - listener.lineStart(); - do { - current.v = current.o.v = true; - if (current.e) { - if (isSubject) { - for (var i = 0, n = points.length; i < n; ++i) listener.point((point = points[i])[0], point[1]); - } else { - interpolate(current.x, current.n.x, 1, listener); - } - current = current.n; - } else { - if (isSubject) { - points = current.p.z; - for (var i = points.length - 1; i >= 0; --i) listener.point((point = points[i])[0], point[1]); - } else { - interpolate(current.x, current.p.x, -1, listener); - } - current = current.p; - } - current = current.o; - points = current.z; - isSubject = !isSubject; - } while (!current.v); - listener.lineEnd(); - } -} - -function d3_geo_clipPolygonLinkCircular(array) { - if (!(n = array.length)) return; - var n, - i = 0, - a = array[0], - b; - while (++i < n) { - a.n = b = array[i]; - b.p = a; - a = b; - } - a.n = b = array[0]; - b.p = a; -} - -function d3_geo_clipPolygonIntersection(point, points, other, entry) { - this.x = point; - this.z = points; - this.o = other; // another intersection - this.e = entry; // is an entry? - this.v = false; // visited - this.n = this.p = null; // next & previous -} - -function d3_geo_clip(pointVisible, clipLine, interpolate, clipStart) { - return function(rotate, listener) { - var line = clipLine(listener), - rotatedClipStart = rotate.invert(clipStart[0], clipStart[1]); - - var clip = { - point: point, - lineStart: lineStart, - lineEnd: lineEnd, - polygonStart: function() { - clip.point = pointRing; - clip.lineStart = ringStart; - clip.lineEnd = ringEnd; - segments = []; - polygon = []; - }, - polygonEnd: function() { - clip.point = point; - clip.lineStart = lineStart; - clip.lineEnd = lineEnd; - - segments = d3.merge(segments); - var clipStartInside = d3_geo_pointInPolygon(rotatedClipStart, polygon); - if (segments.length) { - if (!polygonStarted) listener.polygonStart(), polygonStarted = true; - d3_geo_clipPolygon(segments, d3_geo_clipSort, clipStartInside, interpolate, listener); - } else if (clipStartInside) { - if (!polygonStarted) listener.polygonStart(), polygonStarted = true; - listener.lineStart(); - interpolate(null, null, 1, listener); - listener.lineEnd(); - } - if (polygonStarted) listener.polygonEnd(), polygonStarted = false; - segments = polygon = null; - }, - sphere: function() { - listener.polygonStart(); - listener.lineStart(); - interpolate(null, null, 1, listener); - listener.lineEnd(); - listener.polygonEnd(); - } - }; - - function point(λ, φ) { - var point = rotate(λ, φ); - if (pointVisible(λ = point[0], φ = point[1])) listener.point(λ, φ); - } - function pointLine(λ, φ) { - var point = rotate(λ, φ); - line.point(point[0], point[1]); - } - function lineStart() { clip.point = pointLine; line.lineStart(); } - function lineEnd() { clip.point = point; line.lineEnd(); } - - var segments; - - var buffer = d3_geo_clipBufferListener(), - ringListener = clipLine(buffer), - polygonStarted = false, - polygon, - ring; - - function pointRing(λ, φ) { - ring.push([λ, φ]); - var point = rotate(λ, φ); - ringListener.point(point[0], point[1]); - } - - function ringStart() { - ringListener.lineStart(); - ring = []; - } - - function ringEnd() { - pointRing(ring[0][0], ring[0][1]); - ringListener.lineEnd(); - - var clean = ringListener.clean(), - ringSegments = buffer.buffer(), - segment, - n = ringSegments.length; - - ring.pop(); - polygon.push(ring); - ring = null; - - if (!n) return; - - // No intersections. - if (clean & 1) { - segment = ringSegments[0]; - var n = segment.length - 1, - i = -1, - point; - if (n > 0) { - if (!polygonStarted) listener.polygonStart(), polygonStarted = true; - listener.lineStart(); - while (++i < n) listener.point((point = segment[i])[0], point[1]); - listener.lineEnd(); - } - return; - } - - // Rejoin connected segments. - // TODO reuse bufferListener.rejoin()? - if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift())); - - segments.push(ringSegments.filter(d3_geo_clipSegmentLength1)); - } - - return clip; - }; -} - -function d3_geo_clipSegmentLength1(segment) { - return segment.length > 1; -} - -function d3_geo_clipBufferListener() { - var lines = [], - line; - return { - lineStart: function() { lines.push(line = []); }, - point: function(λ, φ) { line.push([λ, φ]); }, - lineEnd: d3_noop, - buffer: function() { - var buffer = lines; - lines = []; - line = null; - return buffer; - }, - rejoin: function() { - if (lines.length > 1) lines.push(lines.pop().concat(lines.shift())); - } - }; -} - -// Intersection points are sorted along the clip edge. For both antimeridian -// cutting and circle clipping, the same comparison is used. -function d3_geo_clipSort(a, b) { - return ((a = a.x)[0] < 0 ? a[1] - halfπ - ε : halfπ - a[1]) - - ((b = b.x)[0] < 0 ? b[1] - halfπ - ε : halfπ - b[1]); -} - -var d3_geo_clipAntimeridian = d3_geo_clip( - d3_true, - d3_geo_clipAntimeridianLine, - d3_geo_clipAntimeridianInterpolate, - [-π, -π / 2]); - -// Takes a line and cuts into visible segments. Return values: -// 0: there were intersections or the line was empty. -// 1: no intersections. -// 2: there were intersections, and the first and last segments should be -// rejoined. -function d3_geo_clipAntimeridianLine(listener) { - var λ0 = NaN, - φ0 = NaN, - sλ0 = NaN, - clean; // no intersections - - return { - lineStart: function() { - listener.lineStart(); - clean = 1; - }, - point: function(λ1, φ1) { - var sλ1 = λ1 > 0 ? π : -π, - dλ = abs(λ1 - λ0); - if (abs(dλ - π) < ε) { // line crosses a pole - listener.point(λ0, φ0 = (φ0 + φ1) / 2 > 0 ? halfπ : -halfπ); - listener.point(sλ0, φ0); - listener.lineEnd(); - listener.lineStart(); - listener.point(sλ1, φ0); - listener.point(λ1, φ0); - clean = 0; - } else if (sλ0 !== sλ1 && dλ >= π) { // line crosses antimeridian - // handle degeneracies - if (abs(λ0 - sλ0) < ε) λ0 -= sλ0 * ε; - if (abs(λ1 - sλ1) < ε) λ1 -= sλ1 * ε; - φ0 = d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1); - listener.point(sλ0, φ0); - listener.lineEnd(); - listener.lineStart(); - listener.point(sλ1, φ0); - clean = 0; - } - listener.point(λ0 = λ1, φ0 = φ1); - sλ0 = sλ1; - }, - lineEnd: function() { - listener.lineEnd(); - λ0 = φ0 = NaN; - }, - // if there are intersections, we always rejoin the first and last segments. - clean: function() { return 2 - clean; } - }; -} - -function d3_geo_clipAntimeridianIntersect(λ0, φ0, λ1, φ1) { - var cosφ0, - cosφ1, - sinλ0_λ1 = Math.sin(λ0 - λ1); - return abs(sinλ0_λ1) > ε - ? Math.atan((Math.sin(φ0) * (cosφ1 = Math.cos(φ1)) * Math.sin(λ1) - - Math.sin(φ1) * (cosφ0 = Math.cos(φ0)) * Math.sin(λ0)) - / (cosφ0 * cosφ1 * sinλ0_λ1)) - : (φ0 + φ1) / 2; -} - -function d3_geo_clipAntimeridianInterpolate(from, to, direction, listener) { - var φ; - if (from == null) { - φ = direction * halfπ; - listener.point(-π, φ); - listener.point( 0, φ); - listener.point( π, φ); - listener.point( π, 0); - listener.point( π, -φ); - listener.point( 0, -φ); - listener.point(-π, -φ); - listener.point(-π, 0); - listener.point(-π, φ); - } else if (abs(from[0] - to[0]) > ε) { - var s = from[0] < to[0] ? π : -π; - φ = direction * s / 2; - listener.point(-s, φ); - listener.point( 0, φ); - listener.point( s, φ); - } else { - listener.point(to[0], to[1]); - } -} -// TODO -// cross and scale return new vectors, -// whereas add and normalize operate in-place - -function d3_geo_cartesian(spherical) { - var λ = spherical[0], - φ = spherical[1], - cosφ = Math.cos(φ); - return [ - cosφ * Math.cos(λ), - cosφ * Math.sin(λ), - Math.sin(φ) - ]; -} - -function d3_geo_cartesianDot(a, b) { - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; -} - -function d3_geo_cartesianCross(a, b) { - return [ - a[1] * b[2] - a[2] * b[1], - a[2] * b[0] - a[0] * b[2], - a[0] * b[1] - a[1] * b[0] - ]; -} - -function d3_geo_cartesianAdd(a, b) { - a[0] += b[0]; - a[1] += b[1]; - a[2] += b[2]; -} - -function d3_geo_cartesianScale(vector, k) { - return [ - vector[0] * k, - vector[1] * k, - vector[2] * k - ]; -} - -function d3_geo_cartesianNormalize(d) { - var l = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]); - d[0] /= l; - d[1] /= l; - d[2] /= l; -} -function d3_geo_compose(a, b) { - - function compose(x, y) { - return x = a(x, y), b(x[0], x[1]); - } - - if (a.invert && b.invert) compose.invert = function(x, y) { - return x = b.invert(x, y), x && a.invert(x[0], x[1]); - }; - - return compose; -} - -function d3_geo_equirectangular(λ, φ) { - return [λ, φ]; -} - -(d3.geo.equirectangular = function() { - return d3_geo_projection(d3_geo_equirectangular); -}).raw = d3_geo_equirectangular.invert = d3_geo_equirectangular; - -d3.geo.rotation = function(rotate) { - rotate = d3_geo_rotation(rotate[0] % 360 * d3_radians, rotate[1] * d3_radians, rotate.length > 2 ? rotate[2] * d3_radians : 0); - - function forward(coordinates) { - coordinates = rotate(coordinates[0] * d3_radians, coordinates[1] * d3_radians); - return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; - } - - forward.invert = function(coordinates) { - coordinates = rotate.invert(coordinates[0] * d3_radians, coordinates[1] * d3_radians); - return coordinates[0] *= d3_degrees, coordinates[1] *= d3_degrees, coordinates; - }; - - return forward; -}; - -function d3_geo_identityRotation(λ, φ) { - return [λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ]; -} - -d3_geo_identityRotation.invert = d3_geo_equirectangular; - -// Note: |δλ| must be < 2π -function d3_geo_rotation(δλ, δφ, δγ) { - return δλ ? (δφ || δγ ? d3_geo_compose(d3_geo_rotationλ(δλ), d3_geo_rotationφγ(δφ, δγ)) - : d3_geo_rotationλ(δλ)) - : (δφ || δγ ? d3_geo_rotationφγ(δφ, δγ) - : d3_geo_identityRotation); -} - -function d3_geo_forwardRotationλ(δλ) { - return function(λ, φ) { - return λ += δλ, [λ > π ? λ - τ : λ < -π ? λ + τ : λ, φ]; - }; -} - -function d3_geo_rotationλ(δλ) { - var rotation = d3_geo_forwardRotationλ(δλ); - rotation.invert = d3_geo_forwardRotationλ(-δλ); - return rotation; -} - -function d3_geo_rotationφγ(δφ, δγ) { - var cosδφ = Math.cos(δφ), - sinδφ = Math.sin(δφ), - cosδγ = Math.cos(δγ), - sinδγ = Math.sin(δγ); - - function rotation(λ, φ) { - var cosφ = Math.cos(φ), - x = Math.cos(λ) * cosφ, - y = Math.sin(λ) * cosφ, - z = Math.sin(φ), - k = z * cosδφ + x * sinδφ; - return [ - Math.atan2(y * cosδγ - k * sinδγ, x * cosδφ - z * sinδφ), - d3_asin(k * cosδγ + y * sinδγ) - ]; - } - - rotation.invert = function(λ, φ) { - var cosφ = Math.cos(φ), - x = Math.cos(λ) * cosφ, - y = Math.sin(λ) * cosφ, - z = Math.sin(φ), - k = z * cosδγ - y * sinδγ; - return [ - Math.atan2(y * cosδγ + z * sinδγ, x * cosδφ + k * sinδφ), - d3_asin(k * cosδφ - x * sinδφ) - ]; - }; - - return rotation; -} - -d3.geo.circle = function() { - var origin = [0, 0], - angle, - precision = 6, - interpolate; - - function circle() { - var center = typeof origin === "function" ? origin.apply(this, arguments) : origin, - rotate = d3_geo_rotation(-center[0] * d3_radians, -center[1] * d3_radians, 0).invert, - ring = []; - - interpolate(null, null, 1, { - point: function(x, y) { - ring.push(x = rotate(x, y)); - x[0] *= d3_degrees, x[1] *= d3_degrees; - } - }); - - return {type: "Polygon", coordinates: [ring]}; - } - - circle.origin = function(x) { - if (!arguments.length) return origin; - origin = x; - return circle; - }; - - circle.angle = function(x) { - if (!arguments.length) return angle; - interpolate = d3_geo_circleInterpolate((angle = +x) * d3_radians, precision * d3_radians); - return circle; - }; - - circle.precision = function(_) { - if (!arguments.length) return precision; - interpolate = d3_geo_circleInterpolate(angle * d3_radians, (precision = +_) * d3_radians); - return circle; - }; - - return circle.angle(90); -}; - -// Interpolates along a circle centered at [0°, 0°], with a given radius and -// precision. -function d3_geo_circleInterpolate(radius, precision) { - var cr = Math.cos(radius), - sr = Math.sin(radius); - return function(from, to, direction, listener) { - var step = direction * precision; - if (from != null) { - from = d3_geo_circleAngle(cr, from); - to = d3_geo_circleAngle(cr, to); - if (direction > 0 ? from < to: from > to) from += direction * τ; - } else { - from = radius + direction * τ; - to = radius - .5 * step; - } - for (var point, t = from; direction > 0 ? t > to : t < to; t -= step) { - listener.point((point = d3_geo_spherical([ - cr, - -sr * Math.cos(t), - -sr * Math.sin(t) - ]))[0], point[1]); - } - }; -} - -// Signed angle of a cartesian point relative to [cr, 0, 0]. -function d3_geo_circleAngle(cr, point) { - var a = d3_geo_cartesian(point); - a[0] -= cr; - d3_geo_cartesianNormalize(a); - var angle = d3_acos(-a[1]); - return ((-a[2] < 0 ? -angle : angle) + 2 * Math.PI - ε) % (2 * Math.PI); -} -// Adds floating point numbers with twice the normal precision. -// Reference: J. R. Shewchuk, Adaptive Precision Floating-Point Arithmetic and -// Fast Robust Geometric Predicates, Discrete & Computational Geometry 18(3) -// 305–363 (1997). -// Code adapted from GeographicLib by Charles F. F. Karney, -// http://geographiclib.sourceforge.net/ -// See lib/geographiclib/LICENSE for details. - -function d3_adder() {} - -d3_adder.prototype = { - s: 0, // rounded value - t: 0, // exact error - add: function(y) { - d3_adderSum(y, this.t, d3_adderTemp); - d3_adderSum(d3_adderTemp.s, this.s, this); - if (this.s) this.t += d3_adderTemp.t; - else this.s = d3_adderTemp.t; - }, - reset: function() { - this.s = this.t = 0; - }, - valueOf: function() { - return this.s; - } -}; - -var d3_adderTemp = new d3_adder; - -function d3_adderSum(a, b, o) { - var x = o.s = a + b, // a + b - bv = x - a, av = x - bv; // b_virtual & a_virtual - o.t = (a - av) + (b - bv); // a_roundoff + b_roundoff -} - -d3.geo.area = function(object) { - d3_geo_areaSum = 0; - d3.geo.stream(object, d3_geo_area); - return d3_geo_areaSum; -}; - -var d3_geo_areaSum, - d3_geo_areaRingSum = new d3_adder; - -var d3_geo_area = { - sphere: function() { d3_geo_areaSum += 4 * π; }, - point: d3_noop, - lineStart: d3_noop, - lineEnd: d3_noop, - - // Only count area for polygon rings. - polygonStart: function() { - d3_geo_areaRingSum.reset(); - d3_geo_area.lineStart = d3_geo_areaRingStart; - }, - polygonEnd: function() { - var area = 2 * d3_geo_areaRingSum; - d3_geo_areaSum += area < 0 ? 4 * π + area : area; - d3_geo_area.lineStart = d3_geo_area.lineEnd = d3_geo_area.point = d3_noop; - } -}; - -function d3_geo_areaRingStart() { - var λ00, φ00, λ0, cosφ0, sinφ0; // start point and previous point - - // For the first point, … - d3_geo_area.point = function(λ, φ) { - d3_geo_area.point = nextPoint; - λ0 = (λ00 = λ) * d3_radians, cosφ0 = Math.cos(φ = (φ00 = φ) * d3_radians / 2 + π / 4), sinφ0 = Math.sin(φ); - }; - - // For subsequent points, … - function nextPoint(λ, φ) { - λ *= d3_radians; - φ = φ * d3_radians / 2 + π / 4; // half the angular distance from south pole - - // Spherical excess E for a spherical triangle with vertices: south pole, - // previous point, current point. Uses a formula derived from Cagnoli’s - // theorem. See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2). - var dλ = λ - λ0, - sdλ = dλ >= 0 ? 1 : -1, - adλ = sdλ * dλ, - cosφ = Math.cos(φ), - sinφ = Math.sin(φ), - k = sinφ0 * sinφ, - u = cosφ0 * cosφ + k * Math.cos(adλ), - v = k * sdλ * Math.sin(adλ); - d3_geo_areaRingSum.add(Math.atan2(v, u)); - - // Advance the previous points. - λ0 = λ, cosφ0 = cosφ, sinφ0 = sinφ; - } - - // For the last point, return to the start. - d3_geo_area.lineEnd = function() { - nextPoint(λ00, φ00); - }; -} - -function d3_geo_pointInPolygon(point, polygon) { - var meridian = point[0], - parallel = point[1], - meridianNormal = [Math.sin(meridian), -Math.cos(meridian), 0], - polarAngle = 0, - winding = 0; - d3_geo_areaRingSum.reset(); - - for (var i = 0, n = polygon.length; i < n; ++i) { - var ring = polygon[i], - m = ring.length; - if (!m) continue; - var point0 = ring[0], - λ0 = point0[0], - φ0 = point0[1] / 2 + π / 4, - sinφ0 = Math.sin(φ0), - cosφ0 = Math.cos(φ0), - j = 1; - - while (true) { - if (j === m) j = 0; - point = ring[j]; - var λ = point[0], - φ = point[1] / 2 + π / 4, - sinφ = Math.sin(φ), - cosφ = Math.cos(φ), - dλ = λ - λ0, - sdλ = dλ >= 0 ? 1 : -1, - adλ = sdλ * dλ, - antimeridian = adλ > π, - k = sinφ0 * sinφ; - d3_geo_areaRingSum.add(Math.atan2(k * sdλ * Math.sin(adλ), cosφ0 * cosφ + k * Math.cos(adλ))); - - polarAngle += antimeridian ? dλ + sdλ * τ : dλ; - - // Are the longitudes either side of the point's meridian, and are the - // latitudes smaller than the parallel? - if (antimeridian ^ λ0 >= meridian ^ λ >= meridian) { - var arc = d3_geo_cartesianCross(d3_geo_cartesian(point0), d3_geo_cartesian(point)); - d3_geo_cartesianNormalize(arc); - var intersection = d3_geo_cartesianCross(meridianNormal, arc); - d3_geo_cartesianNormalize(intersection); - var φarc = (antimeridian ^ dλ >= 0 ? -1 : 1) * d3_asin(intersection[2]); - if (parallel > φarc || parallel === φarc && (arc[0] || arc[1])) { - winding += antimeridian ^ dλ >= 0 ? 1 : -1; - } - } - if (!j++) break; - λ0 = λ, sinφ0 = sinφ, cosφ0 = cosφ, point0 = point; - } - } - - // First, determine whether the South pole is inside or outside: - // - // It is inside if: - // * the polygon winds around it in a clockwise direction. - // * the polygon does not (cumulatively) wind around it, but has a negative - // (counter-clockwise) area. - // - // Second, count the (signed) number of times a segment crosses a meridian - // from the point to the South pole. If it is zero, then the point is the - // same side as the South pole. - - return (polarAngle < -ε || polarAngle < ε && d3_geo_areaRingSum < 0) ^ (winding & 1); -} - -// Clip features against a small circle centered at [0°, 0°]. -function d3_geo_clipCircle(radius) { - var cr = Math.cos(radius), - smallRadius = cr > 0, - notHemisphere = abs(cr) > ε, // TODO optimise for this common case - interpolate = d3_geo_circleInterpolate(radius, 6 * d3_radians); - - return d3_geo_clip(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-π, radius - π]); - - function visible(λ, φ) { - return Math.cos(λ) * Math.cos(φ) > cr; - } - - // Takes a line and cuts into visible segments. Return values used for - // polygon clipping: - // 0: there were intersections or the line was empty. - // 1: no intersections. - // 2: there were intersections, and the first and last segments should be - // rejoined. - function clipLine(listener) { - var point0, // previous point - c0, // code for previous point - v0, // visibility of previous point - v00, // visibility of first point - clean; // no intersections - return { - lineStart: function() { - v00 = v0 = false; - clean = 1; - }, - point: function(λ, φ) { - var point1 = [λ, φ], - point2, - v = visible(λ, φ), - c = smallRadius - ? v ? 0 : code(λ, φ) - : v ? code(λ + (λ < 0 ? π : -π), φ) : 0; - if (!point0 && (v00 = v0 = v)) listener.lineStart(); - // Handle degeneracies. - // TODO ignore if not clipping polygons. - if (v !== v0) { - point2 = intersect(point0, point1); - if (d3_geo_sphericalEqual(point0, point2) || d3_geo_sphericalEqual(point1, point2)) { - point1[0] += ε; - point1[1] += ε; - v = visible(point1[0], point1[1]); - } - } - if (v !== v0) { - clean = 0; - if (v) { - // outside going in - listener.lineStart(); - point2 = intersect(point1, point0); - listener.point(point2[0], point2[1]); - } else { - // inside going out - point2 = intersect(point0, point1); - listener.point(point2[0], point2[1]); - listener.lineEnd(); - } - point0 = point2; - } else if (notHemisphere && point0 && smallRadius ^ v) { - var t; - // If the codes for two points are different, or are both zero, - // and there this segment intersects with the small circle. - if (!(c & c0) && (t = intersect(point1, point0, true))) { - clean = 0; - if (smallRadius) { - listener.lineStart(); - listener.point(t[0][0], t[0][1]); - listener.point(t[1][0], t[1][1]); - listener.lineEnd(); - } else { - listener.point(t[1][0], t[1][1]); - listener.lineEnd(); - listener.lineStart(); - listener.point(t[0][0], t[0][1]); - } - } - } - if (v && (!point0 || !d3_geo_sphericalEqual(point0, point1))) { - listener.point(point1[0], point1[1]); - } - point0 = point1, v0 = v, c0 = c; - }, - lineEnd: function() { - if (v0) listener.lineEnd(); - point0 = null; - }, - // Rejoin first and last segments if there were intersections and the first - // and last points were visible. - clean: function() { return clean | ((v00 && v0) << 1); } - }; - } - - // Intersects the great circle between a and b with the clip circle. - function intersect(a, b, two) { - var pa = d3_geo_cartesian(a), - pb = d3_geo_cartesian(b); - - // We have two planes, n1.p = d1 and n2.p = d2. - // Find intersection line p(t) = c1 n1 + c2 n2 + t (n1 ⨯ n2). - var n1 = [1, 0, 0], // normal - n2 = d3_geo_cartesianCross(pa, pb), - n2n2 = d3_geo_cartesianDot(n2, n2), - n1n2 = n2[0], // d3_geo_cartesianDot(n1, n2), - determinant = n2n2 - n1n2 * n1n2; - - // Two polar points. - if (!determinant) return !two && a; - - var c1 = cr * n2n2 / determinant, - c2 = -cr * n1n2 / determinant, - n1xn2 = d3_geo_cartesianCross(n1, n2), - A = d3_geo_cartesianScale(n1, c1), - B = d3_geo_cartesianScale(n2, c2); - d3_geo_cartesianAdd(A, B); - - // Solve |p(t)|^2 = 1. - var u = n1xn2, - w = d3_geo_cartesianDot(A, u), - uu = d3_geo_cartesianDot(u, u), - t2 = w * w - uu * (d3_geo_cartesianDot(A, A) - 1); - - if (t2 < 0) return; - - var t = Math.sqrt(t2), - q = d3_geo_cartesianScale(u, (-w - t) / uu); - d3_geo_cartesianAdd(q, A); - q = d3_geo_spherical(q); - if (!two) return q; - - // Two intersection points. - var λ0 = a[0], - λ1 = b[0], - φ0 = a[1], - φ1 = b[1], - z; - if (λ1 < λ0) z = λ0, λ0 = λ1, λ1 = z; - var δλ = λ1 - λ0, - polar = abs(δλ - π) < ε, - meridian = polar || δλ < ε; - - if (!polar && φ1 < φ0) z = φ0, φ0 = φ1, φ1 = z; - - // Check that the first point is between a and b. - if (meridian - ? polar - ? φ0 + φ1 > 0 ^ q[1] < (abs(q[0] - λ0) < ε ? φ0 : φ1) - : φ0 <= q[1] && q[1] <= φ1 - : δλ > π ^ (λ0 <= q[0] && q[0] <= λ1)) { - var q1 = d3_geo_cartesianScale(u, (-w + t) / uu); - d3_geo_cartesianAdd(q1, A); - return [q, d3_geo_spherical(q1)]; - } - } - - // Generates a 4-bit vector representing the location of a point relative to - // the small circle's bounding box. - function code(λ, φ) { - var r = smallRadius ? radius : π - radius, - code = 0; - if (λ < -r) code |= 1; // left - else if (λ > r) code |= 2; // right - if (φ < -r) code |= 4; // below - else if (φ > r) code |= 8; // above - return code; - } -} - -// Liang–Barsky line clipping. -function d3_geom_clipLine(x0, y0, x1, y1) { - return function(line) { - var a = line.a, - b = line.b, - ax = a.x, - ay = a.y, - bx = b.x, - by = b.y, - t0 = 0, - t1 = 1, - dx = bx - ax, - dy = by - ay, - r; - - r = x0 - ax; - if (!dx && r > 0) return; - r /= dx; - if (dx < 0) { - if (r < t0) return; - if (r < t1) t1 = r; - } else if (dx > 0) { - if (r > t1) return; - if (r > t0) t0 = r; - } - - r = x1 - ax; - if (!dx && r < 0) return; - r /= dx; - if (dx < 0) { - if (r > t1) return; - if (r > t0) t0 = r; - } else if (dx > 0) { - if (r < t0) return; - if (r < t1) t1 = r; - } - - r = y0 - ay; - if (!dy && r > 0) return; - r /= dy; - if (dy < 0) { - if (r < t0) return; - if (r < t1) t1 = r; - } else if (dy > 0) { - if (r > t1) return; - if (r > t0) t0 = r; - } - - r = y1 - ay; - if (!dy && r < 0) return; - r /= dy; - if (dy < 0) { - if (r > t1) return; - if (r > t0) t0 = r; - } else if (dy > 0) { - if (r < t0) return; - if (r < t1) t1 = r; - } - - if (t0 > 0) line.a = {x: ax + t0 * dx, y: ay + t0 * dy}; - if (t1 < 1) line.b = {x: ax + t1 * dx, y: ay + t1 * dy}; - return line; - }; -} - -var d3_geo_clipExtentMAX = 1e9; - -d3.geo.clipExtent = function() { - var x0, y0, x1, y1, - stream, - clip, - clipExtent = { - stream: function(output) { - if (stream) stream.valid = false; - stream = clip(output); - stream.valid = true; // allow caching by d3.geo.path - return stream; - }, - extent: function(_) { - if (!arguments.length) return [[x0, y0], [x1, y1]]; - clip = d3_geo_clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]); - if (stream) stream.valid = false, stream = null; - return clipExtent; - } - }; - return clipExtent.extent([[0, 0], [960, 500]]); -}; - -function d3_geo_clipExtent(x0, y0, x1, y1) { - return function(listener) { - var listener_ = listener, - bufferListener = d3_geo_clipBufferListener(), - clipLine = d3_geom_clipLine(x0, y0, x1, y1), - segments, - polygon, - ring; - - var clip = { - point: point, - lineStart: lineStart, - lineEnd: lineEnd, - polygonStart: function() { - listener = bufferListener; - segments = []; - polygon = []; - clean = true; - }, - polygonEnd: function() { - listener = listener_; - segments = d3.merge(segments); - var clipStartInside = insidePolygon([x0, y1]), - inside = clean && clipStartInside, - visible = segments.length; - if (inside || visible) { - listener.polygonStart(); - if (inside) { - listener.lineStart(); - interpolate(null, null, 1, listener); - listener.lineEnd(); - } - if (visible) { - d3_geo_clipPolygon(segments, compare, clipStartInside, interpolate, listener); - } - listener.polygonEnd(); - } - segments = polygon = ring = null; - } - }; - - function insidePolygon(p) { - var wn = 0, // the winding number counter - n = polygon.length, - y = p[1]; - - for (var i = 0; i < n; ++i) { - for (var j = 1, v = polygon[i], m = v.length, a = v[0], b; j < m; ++j) { - b = v[j]; - if (a[1] <= y) { - if (b[1] > y && d3_cross2d(a, b, p) > 0) ++wn; - } else { - if (b[1] <= y && d3_cross2d(a, b, p) < 0) --wn; - } - a = b; - } - } - return wn !== 0; - } - - function interpolate(from, to, direction, listener) { - var a = 0, a1 = 0; - if (from == null || - (a = corner(from, direction)) !== (a1 = corner(to, direction)) || - comparePoints(from, to) < 0 ^ direction > 0) { - do { - listener.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0); - } while ((a = (a + direction + 4) % 4) !== a1); - } else { - listener.point(to[0], to[1]); - } - } - - function pointVisible(x, y) { - return x0 <= x && x <= x1 && y0 <= y && y <= y1; - } - - function point(x, y) { - if (pointVisible(x, y)) listener.point(x, y); - } - - var x__, y__, v__, // first point - x_, y_, v_, // previous point - first, - clean; - - function lineStart() { - clip.point = linePoint; - if (polygon) polygon.push(ring = []); - first = true; - v_ = false; - x_ = y_ = NaN; - } - - function lineEnd() { - // TODO rather than special-case polygons, simply handle them separately. - // Ideally, coincident intersection points should be jittered to avoid - // clipping issues. - if (segments) { - linePoint(x__, y__); - if (v__ && v_) bufferListener.rejoin(); - segments.push(bufferListener.buffer()); - } - clip.point = point; - if (v_) listener.lineEnd(); - } - - function linePoint(x, y) { - x = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, x)); - y = Math.max(-d3_geo_clipExtentMAX, Math.min(d3_geo_clipExtentMAX, y)); - var v = pointVisible(x, y); - if (polygon) ring.push([x, y]); - if (first) { - x__ = x, y__ = y, v__ = v; - first = false; - if (v) { - listener.lineStart(); - listener.point(x, y); - } - } else { - if (v && v_) listener.point(x, y); - else { - var l = {a: {x: x_, y: y_}, b: {x: x, y: y}}; - if (clipLine(l)) { - if (!v_) { - listener.lineStart(); - listener.point(l.a.x, l.a.y); - } - listener.point(l.b.x, l.b.y); - if (!v) listener.lineEnd(); - clean = false; - } else if (v) { - listener.lineStart(); - listener.point(x, y); - clean = false; - } - } - } - x_ = x, y_ = y, v_ = v; - } - - return clip; - }; - - function corner(p, direction) { - return abs(p[0] - x0) < ε ? direction > 0 ? 0 : 3 - : abs(p[0] - x1) < ε ? direction > 0 ? 2 : 1 - : abs(p[1] - y0) < ε ? direction > 0 ? 1 : 0 - : direction > 0 ? 3 : 2; // abs(p[1] - y1) < ε - } - - function compare(a, b) { - return comparePoints(a.x, b.x); - } - - function comparePoints(a, b) { - var ca = corner(a, 1), - cb = corner(b, 1); - return ca !== cb ? ca - cb - : ca === 0 ? b[1] - a[1] - : ca === 1 ? a[0] - b[0] - : ca === 2 ? a[1] - b[1] - : b[0] - a[0]; - } -} - -function d3_geo_conic(projectAt) { - var φ0 = 0, - φ1 = π / 3, - m = d3_geo_projectionMutator(projectAt), - p = m(φ0, φ1); - - p.parallels = function(_) { - if (!arguments.length) return [φ0 / π * 180, φ1 / π * 180]; - return m(φ0 = _[0] * π / 180, φ1 = _[1] * π / 180); - }; - - return p; -} - -function d3_geo_conicEqualArea(φ0, φ1) { - var sinφ0 = Math.sin(φ0), - n = (sinφ0 + Math.sin(φ1)) / 2, - C = 1 + sinφ0 * (2 * n - sinφ0), - ρ0 = Math.sqrt(C) / n; - - function forward(λ, φ) { - var ρ = Math.sqrt(C - 2 * n * Math.sin(φ)) / n; - return [ - ρ * Math.sin(λ *= n), - ρ0 - ρ * Math.cos(λ) - ]; - } - - forward.invert = function(x, y) { - var ρ0_y = ρ0 - y; - return [ - Math.atan2(x, ρ0_y) / n, - d3_asin((C - (x * x + ρ0_y * ρ0_y) * n * n) / (2 * n)) - ]; - }; - - return forward; -} - -(d3.geo.conicEqualArea = function() { - return d3_geo_conic(d3_geo_conicEqualArea); -}).raw = d3_geo_conicEqualArea; - -// ESRI:102003 -d3.geo.albers = function() { - return d3.geo.conicEqualArea() - .rotate([96, 0]) - .center([-.6, 38.7]) - .parallels([29.5, 45.5]) - .scale(1070); -}; - -// A composite projection for the United States, configured by default for -// 960×500. Also works quite well at 960×600 with scale 1285. The set of -// standard parallels for each region comes from USGS, which is published here: -// http://egsc.usgs.gov/isb/pubs/MapProjections/projections.html#albers -d3.geo.albersUsa = function() { - var lower48 = d3.geo.albers(); - - // EPSG:3338 - var alaska = d3.geo.conicEqualArea() - .rotate([154, 0]) - .center([-2, 58.5]) - .parallels([55, 65]); - - // ESRI:102007 - var hawaii = d3.geo.conicEqualArea() - .rotate([157, 0]) - .center([-3, 19.9]) - .parallels([8, 18]); - - var point, - pointStream = {point: function(x, y) { point = [x, y]; }}, - lower48Point, - alaskaPoint, - hawaiiPoint; - - function albersUsa(coordinates) { - var x = coordinates[0], y = coordinates[1]; - point = null; - (lower48Point(x, y), point) - || (alaskaPoint(x, y), point) - || hawaiiPoint(x, y); - return point; - } - - albersUsa.invert = function(coordinates) { - var k = lower48.scale(), - t = lower48.translate(), - x = (coordinates[0] - t[0]) / k, - y = (coordinates[1] - t[1]) / k; - return (y >= .120 && y < .234 && x >= -.425 && x < -.214 ? alaska - : y >= .166 && y < .234 && x >= -.214 && x < -.115 ? hawaii - : lower48).invert(coordinates); - }; - - // A naïve multi-projection stream. - // The projections must have mutually exclusive clip regions on the sphere, - // as this will avoid emitting interleaving lines and polygons. - albersUsa.stream = function(stream) { - var lower48Stream = lower48.stream(stream), - alaskaStream = alaska.stream(stream), - hawaiiStream = hawaii.stream(stream); - return { - point: function(x, y) { - lower48Stream.point(x, y); - alaskaStream.point(x, y); - hawaiiStream.point(x, y); - }, - sphere: function() { - lower48Stream.sphere(); - alaskaStream.sphere(); - hawaiiStream.sphere(); - }, - lineStart: function() { - lower48Stream.lineStart(); - alaskaStream.lineStart(); - hawaiiStream.lineStart(); - }, - lineEnd: function() { - lower48Stream.lineEnd(); - alaskaStream.lineEnd(); - hawaiiStream.lineEnd(); - }, - polygonStart: function() { - lower48Stream.polygonStart(); - alaskaStream.polygonStart(); - hawaiiStream.polygonStart(); - }, - polygonEnd: function() { - lower48Stream.polygonEnd(); - alaskaStream.polygonEnd(); - hawaiiStream.polygonEnd(); - } - }; - }; - - albersUsa.precision = function(_) { - if (!arguments.length) return lower48.precision(); - lower48.precision(_); - alaska.precision(_); - hawaii.precision(_); - return albersUsa; - }; - - albersUsa.scale = function(_) { - if (!arguments.length) return lower48.scale(); - lower48.scale(_); - alaska.scale(_ * .35); - hawaii.scale(_); - return albersUsa.translate(lower48.translate()); - }; - - albersUsa.translate = function(_) { - if (!arguments.length) return lower48.translate(); - var k = lower48.scale(), x = +_[0], y = +_[1]; - - lower48Point = lower48 - .translate(_) - .clipExtent([[x - .455 * k, y - .238 * k], [x + .455 * k, y + .238 * k]]) - .stream(pointStream).point; - - alaskaPoint = alaska - .translate([x - .307 * k, y + .201 * k]) - .clipExtent([[x - .425 * k + ε, y + .120 * k + ε], [x - .214 * k - ε, y + .234 * k - ε]]) - .stream(pointStream).point; - - hawaiiPoint = hawaii - .translate([x - .205 * k, y + .212 * k]) - .clipExtent([[x - .214 * k + ε, y + .166 * k + ε], [x - .115 * k - ε, y + .234 * k - ε]]) - .stream(pointStream).point; - - return albersUsa; - }; - - return albersUsa.scale(1070); -}; - -d3.geo.bounds = (function() { - var λ0, φ0, λ1, φ1, // bounds - λ_, // previous λ-coordinate - λ__, φ__, // first point - p0, // previous 3D point - dλSum, - ranges, - range; - - var bound = { - point: point, - lineStart: lineStart, - lineEnd: lineEnd, - - polygonStart: function() { - bound.point = ringPoint; - bound.lineStart = ringStart; - bound.lineEnd = ringEnd; - dλSum = 0; - d3_geo_area.polygonStart(); - }, - polygonEnd: function() { - d3_geo_area.polygonEnd(); - bound.point = point; - bound.lineStart = lineStart; - bound.lineEnd = lineEnd; - if (d3_geo_areaRingSum < 0) λ0 = -(λ1 = 180), φ0 = -(φ1 = 90); - else if (dλSum > ε) φ1 = 90; - else if (dλSum < -ε) φ0 = -90; - range[0] = λ0, range[1] = λ1; - } - }; - - function point(λ, φ) { - ranges.push(range = [λ0 = λ, λ1 = λ]); - if (φ < φ0) φ0 = φ; - if (φ > φ1) φ1 = φ; - } - - function linePoint(λ, φ) { - var p = d3_geo_cartesian([λ * d3_radians, φ * d3_radians]); - if (p0) { - var normal = d3_geo_cartesianCross(p0, p), - equatorial = [normal[1], -normal[0], 0], - inflection = d3_geo_cartesianCross(equatorial, normal); - d3_geo_cartesianNormalize(inflection); - inflection = d3_geo_spherical(inflection); - var dλ = λ - λ_, - s = dλ > 0 ? 1 : -1, - λi = inflection[0] * d3_degrees * s, - antimeridian = abs(dλ) > 180; - if (antimeridian ^ (s * λ_ < λi && λi < s * λ)) { - var φi = inflection[1] * d3_degrees; - if (φi > φ1) φ1 = φi; - } else if (λi = (λi + 360) % 360 - 180, antimeridian ^ (s * λ_ < λi && λi < s * λ)) { - var φi = -inflection[1] * d3_degrees; - if (φi < φ0) φ0 = φi; - } else { - if (φ < φ0) φ0 = φ; - if (φ > φ1) φ1 = φ; - } - if (antimeridian) { - if (λ < λ_) { - if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ; - } else { - if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ; - } - } else { - if (λ1 >= λ0) { - if (λ < λ0) λ0 = λ; - if (λ > λ1) λ1 = λ; - } else { - if (λ > λ_) { - if (angle(λ0, λ) > angle(λ0, λ1)) λ1 = λ; - } else { - if (angle(λ, λ1) > angle(λ0, λ1)) λ0 = λ; - } - } - } - } else { - point(λ, φ); - } - p0 = p, λ_ = λ; - } - - function lineStart() { bound.point = linePoint; } - function lineEnd() { - range[0] = λ0, range[1] = λ1; - bound.point = point; - p0 = null; - } - - function ringPoint(λ, φ) { - if (p0) { - var dλ = λ - λ_; - dλSum += abs(dλ) > 180 ? dλ + (dλ > 0 ? 360 : -360) : dλ; - } else λ__ = λ, φ__ = φ; - d3_geo_area.point(λ, φ); - linePoint(λ, φ); - } - - function ringStart() { - d3_geo_area.lineStart(); - } - - function ringEnd() { - ringPoint(λ__, φ__); - d3_geo_area.lineEnd(); - if (abs(dλSum) > ε) λ0 = -(λ1 = 180); - range[0] = λ0, range[1] = λ1; - p0 = null; - } - - // Finds the left-right distance between two longitudes. - // This is almost the same as (λ1 - λ0 + 360°) % 360°, except that we want - // the distance between ±180° to be 360°. - function angle(λ0, λ1) { return (λ1 -= λ0) < 0 ? λ1 + 360 : λ1; } - - function compareRanges(a, b) { return a[0] - b[0]; } - - function withinRange(x, range) { - return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x; - } - - return function(feature) { - φ1 = λ1 = -(λ0 = φ0 = Infinity); - ranges = []; - - d3.geo.stream(feature, bound); - - var n = ranges.length; - if (n) { - // First, sort ranges by their minimum longitudes. - ranges.sort(compareRanges); - - // Then, merge any ranges that overlap. - for (var i = 1, a = ranges[0], b, merged = [a]; i < n; ++i) { - b = ranges[i]; - if (withinRange(b[0], a) || withinRange(b[1], a)) { - if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1]; - if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0]; - } else { - merged.push(a = b); - } - } - - // Finally, find the largest gap between the merged ranges. - // The final bounding box will be the inverse of this gap. - var best = -Infinity, dλ; - for (var n = merged.length - 1, i = 0, a = merged[n], b; i <= n; a = b, ++i) { - b = merged[i]; - if ((dλ = angle(a[1], b[0])) > best) best = dλ, λ0 = b[0], λ1 = a[1]; - } - } - ranges = range = null; - - return λ0 === Infinity || φ0 === Infinity - ? [[NaN, NaN], [NaN, NaN]] - : [[λ0, φ0], [λ1, φ1]]; - }; -})(); - -d3.geo.centroid = function(object) { - d3_geo_centroidW0 = d3_geo_centroidW1 = - d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = - d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = - d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0; - d3.geo.stream(object, d3_geo_centroid); - - var x = d3_geo_centroidX2, - y = d3_geo_centroidY2, - z = d3_geo_centroidZ2, - m = x * x + y * y + z * z; - - // If the area-weighted centroid is undefined, fall back to length-weighted centroid. - if (m < ε2) { - x = d3_geo_centroidX1, y = d3_geo_centroidY1, z = d3_geo_centroidZ1; - // If the feature has zero length, fall back to arithmetic mean of point vectors. - if (d3_geo_centroidW1 < ε) x = d3_geo_centroidX0, y = d3_geo_centroidY0, z = d3_geo_centroidZ0; - m = x * x + y * y + z * z; - // If the feature still has an undefined centroid, then return. - if (m < ε2) return [NaN, NaN]; - } - - return [Math.atan2(y, x) * d3_degrees, d3_asin(z / Math.sqrt(m)) * d3_degrees]; -}; - -var d3_geo_centroidW0, - d3_geo_centroidW1, - d3_geo_centroidX0, - d3_geo_centroidY0, - d3_geo_centroidZ0, - d3_geo_centroidX1, - d3_geo_centroidY1, - d3_geo_centroidZ1, - d3_geo_centroidX2, - d3_geo_centroidY2, - d3_geo_centroidZ2; - -var d3_geo_centroid = { - sphere: d3_noop, - point: d3_geo_centroidPoint, - lineStart: d3_geo_centroidLineStart, - lineEnd: d3_geo_centroidLineEnd, - polygonStart: function() { - d3_geo_centroid.lineStart = d3_geo_centroidRingStart; - }, - polygonEnd: function() { - d3_geo_centroid.lineStart = d3_geo_centroidLineStart; - } -}; - -// Arithmetic mean of Cartesian vectors. -function d3_geo_centroidPoint(λ, φ) { - λ *= d3_radians; - var cosφ = Math.cos(φ *= d3_radians); - d3_geo_centroidPointXYZ(cosφ * Math.cos(λ), cosφ * Math.sin(λ), Math.sin(φ)); -} - -function d3_geo_centroidPointXYZ(x, y, z) { - ++d3_geo_centroidW0; - d3_geo_centroidX0 += (x - d3_geo_centroidX0) / d3_geo_centroidW0; - d3_geo_centroidY0 += (y - d3_geo_centroidY0) / d3_geo_centroidW0; - d3_geo_centroidZ0 += (z - d3_geo_centroidZ0) / d3_geo_centroidW0; -} - -function d3_geo_centroidLineStart() { - var x0, y0, z0; // previous point - - d3_geo_centroid.point = function(λ, φ) { - λ *= d3_radians; - var cosφ = Math.cos(φ *= d3_radians); - x0 = cosφ * Math.cos(λ); - y0 = cosφ * Math.sin(λ); - z0 = Math.sin(φ); - d3_geo_centroid.point = nextPoint; - d3_geo_centroidPointXYZ(x0, y0, z0); - }; - - function nextPoint(λ, φ) { - λ *= d3_radians; - var cosφ = Math.cos(φ *= d3_radians), - x = cosφ * Math.cos(λ), - y = cosφ * Math.sin(λ), - z = Math.sin(φ), - w = Math.atan2( - Math.sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), - x0 * x + y0 * y + z0 * z); - d3_geo_centroidW1 += w; - d3_geo_centroidX1 += w * (x0 + (x0 = x)); - d3_geo_centroidY1 += w * (y0 + (y0 = y)); - d3_geo_centroidZ1 += w * (z0 + (z0 = z)); - d3_geo_centroidPointXYZ(x0, y0, z0); - } -} - -function d3_geo_centroidLineEnd() { - d3_geo_centroid.point = d3_geo_centroidPoint; -} - -// See J. E. Brock, The Inertia Tensor for a Spherical Triangle, -// J. Applied Mechanics 42, 239 (1975). -function d3_geo_centroidRingStart() { - var λ00, φ00, // first point - x0, y0, z0; // previous point - - d3_geo_centroid.point = function(λ, φ) { - λ00 = λ, φ00 = φ; - d3_geo_centroid.point = nextPoint; - λ *= d3_radians; - var cosφ = Math.cos(φ *= d3_radians); - x0 = cosφ * Math.cos(λ); - y0 = cosφ * Math.sin(λ); - z0 = Math.sin(φ); - d3_geo_centroidPointXYZ(x0, y0, z0); - }; - - d3_geo_centroid.lineEnd = function() { - nextPoint(λ00, φ00); - d3_geo_centroid.lineEnd = d3_geo_centroidLineEnd; - d3_geo_centroid.point = d3_geo_centroidPoint; - }; - - function nextPoint(λ, φ) { - λ *= d3_radians; - var cosφ = Math.cos(φ *= d3_radians), - x = cosφ * Math.cos(λ), - y = cosφ * Math.sin(λ), - z = Math.sin(φ), - cx = y0 * z - z0 * y, - cy = z0 * x - x0 * z, - cz = x0 * y - y0 * x, - m = Math.sqrt(cx * cx + cy * cy + cz * cz), - u = x0 * x + y0 * y + z0 * z, - v = m && -d3_acos(u) / m, // area weight - w = Math.atan2(m, u); // line weight - d3_geo_centroidX2 += v * cx; - d3_geo_centroidY2 += v * cy; - d3_geo_centroidZ2 += v * cz; - d3_geo_centroidW1 += w; - d3_geo_centroidX1 += w * (x0 + (x0 = x)); - d3_geo_centroidY1 += w * (y0 + (y0 = y)); - d3_geo_centroidZ1 += w * (z0 + (z0 = z)); - d3_geo_centroidPointXYZ(x0, y0, z0); - } -} - -// TODO Unify this code with d3.geom.polygon area? - -var d3_geo_pathAreaSum, d3_geo_pathAreaPolygon, d3_geo_pathArea = { - point: d3_noop, - lineStart: d3_noop, - lineEnd: d3_noop, - - // Only count area for polygon rings. - polygonStart: function() { - d3_geo_pathAreaPolygon = 0; - d3_geo_pathArea.lineStart = d3_geo_pathAreaRingStart; - }, - polygonEnd: function() { - d3_geo_pathArea.lineStart = d3_geo_pathArea.lineEnd = d3_geo_pathArea.point = d3_noop; - d3_geo_pathAreaSum += abs(d3_geo_pathAreaPolygon / 2); - } -}; - -function d3_geo_pathAreaRingStart() { - var x00, y00, x0, y0; - - // For the first point, … - d3_geo_pathArea.point = function(x, y) { - d3_geo_pathArea.point = nextPoint; - x00 = x0 = x, y00 = y0 = y; - }; - - // For subsequent points, … - function nextPoint(x, y) { - d3_geo_pathAreaPolygon += y0 * x - x0 * y; - x0 = x, y0 = y; - } - - // For the last point, return to the start. - d3_geo_pathArea.lineEnd = function() { - nextPoint(x00, y00); - }; -} - -var d3_geo_pathBoundsX0, - d3_geo_pathBoundsY0, - d3_geo_pathBoundsX1, - d3_geo_pathBoundsY1; - -var d3_geo_pathBounds = { - point: d3_geo_pathBoundsPoint, - lineStart: d3_noop, - lineEnd: d3_noop, - polygonStart: d3_noop, - polygonEnd: d3_noop -}; - -function d3_geo_pathBoundsPoint(x, y) { - if (x < d3_geo_pathBoundsX0) d3_geo_pathBoundsX0 = x; - if (x > d3_geo_pathBoundsX1) d3_geo_pathBoundsX1 = x; - if (y < d3_geo_pathBoundsY0) d3_geo_pathBoundsY0 = y; - if (y > d3_geo_pathBoundsY1) d3_geo_pathBoundsY1 = y; -} -function d3_geo_pathBuffer() { - var pointCircle = d3_geo_pathBufferCircle(4.5), - buffer = []; - - var stream = { - point: point, - - // While inside a line, override point to moveTo then lineTo. - lineStart: function() { stream.point = pointLineStart; }, - lineEnd: lineEnd, - - // While inside a polygon, override lineEnd to closePath. - polygonStart: function() { stream.lineEnd = lineEndPolygon; }, - polygonEnd: function() { stream.lineEnd = lineEnd; stream.point = point; }, - - pointRadius: function(_) { - pointCircle = d3_geo_pathBufferCircle(_); - return stream; - }, - - result: function() { - if (buffer.length) { - var result = buffer.join(""); - buffer = []; - return result; - } - } - }; - - function point(x, y) { - buffer.push("M", x, ",", y, pointCircle); - } - - function pointLineStart(x, y) { - buffer.push("M", x, ",", y); - stream.point = pointLine; - } - - function pointLine(x, y) { - buffer.push("L", x, ",", y); - } - - function lineEnd() { - stream.point = point; - } - - function lineEndPolygon() { - buffer.push("Z"); - } - - return stream; -} - -function d3_geo_pathBufferCircle(radius) { - return "m0," + radius - + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius - + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius - + "z"; -} - -// TODO Unify this code with d3.geom.polygon centroid? -// TODO Enforce positive area for exterior, negative area for interior? - -var d3_geo_pathCentroid = { - point: d3_geo_pathCentroidPoint, - - // For lines, weight by length. - lineStart: d3_geo_pathCentroidLineStart, - lineEnd: d3_geo_pathCentroidLineEnd, - - // For polygons, weight by area. - polygonStart: function() { - d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidRingStart; - }, - polygonEnd: function() { - d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; - d3_geo_pathCentroid.lineStart = d3_geo_pathCentroidLineStart; - d3_geo_pathCentroid.lineEnd = d3_geo_pathCentroidLineEnd; - } -}; - -function d3_geo_pathCentroidPoint(x, y) { - d3_geo_centroidX0 += x; - d3_geo_centroidY0 += y; - ++d3_geo_centroidZ0; -} - -function d3_geo_pathCentroidLineStart() { - var x0, y0; - - d3_geo_pathCentroid.point = function(x, y) { - d3_geo_pathCentroid.point = nextPoint; - d3_geo_pathCentroidPoint(x0 = x, y0 = y); - }; - - function nextPoint(x, y) { - var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); - d3_geo_centroidX1 += z * (x0 + x) / 2; - d3_geo_centroidY1 += z * (y0 + y) / 2; - d3_geo_centroidZ1 += z; - d3_geo_pathCentroidPoint(x0 = x, y0 = y); - } -} - -function d3_geo_pathCentroidLineEnd() { - d3_geo_pathCentroid.point = d3_geo_pathCentroidPoint; -} - -function d3_geo_pathCentroidRingStart() { - var x00, y00, x0, y0; - - // For the first point, … - d3_geo_pathCentroid.point = function(x, y) { - d3_geo_pathCentroid.point = nextPoint; - d3_geo_pathCentroidPoint(x00 = x0 = x, y00 = y0 = y); - }; - - // For subsequent points, … - function nextPoint(x, y) { - var dx = x - x0, dy = y - y0, z = Math.sqrt(dx * dx + dy * dy); - d3_geo_centroidX1 += z * (x0 + x) / 2; - d3_geo_centroidY1 += z * (y0 + y) / 2; - d3_geo_centroidZ1 += z; - - z = y0 * x - x0 * y; - d3_geo_centroidX2 += z * (x0 + x); - d3_geo_centroidY2 += z * (y0 + y); - d3_geo_centroidZ2 += z * 3; - d3_geo_pathCentroidPoint(x0 = x, y0 = y); - } - - // For the last point, return to the start. - d3_geo_pathCentroid.lineEnd = function() { - nextPoint(x00, y00); - }; -} - -function d3_geo_pathContext(context) { - var pointRadius = 4.5; - - var stream = { - point: point, - - // While inside a line, override point to moveTo then lineTo. - lineStart: function() { stream.point = pointLineStart; }, - lineEnd: lineEnd, - - // While inside a polygon, override lineEnd to closePath. - polygonStart: function() { stream.lineEnd = lineEndPolygon; }, - polygonEnd: function() { stream.lineEnd = lineEnd; stream.point = point; }, - - pointRadius: function(_) { - pointRadius = _; - return stream; - }, - - result: d3_noop - }; - - function point(x, y) { - context.moveTo(x + pointRadius, y); - context.arc(x, y, pointRadius, 0, τ); - } - - function pointLineStart(x, y) { - context.moveTo(x, y); - stream.point = pointLine; - } - - function pointLine(x, y) { - context.lineTo(x, y); - } - - function lineEnd() { - stream.point = point; - } - - function lineEndPolygon() { - context.closePath(); - } - - return stream; -} - -function d3_geo_resample(project) { - var δ2 = .5, // precision, px² - cosMinDistance = Math.cos(30 * d3_radians), // cos(minimum angular distance) - maxDepth = 16; - - function resample(stream) { - return (maxDepth ? resampleRecursive : resampleNone)(stream); - } - - function resampleNone(stream) { - return d3_geo_transformPoint(stream, function(x, y) { - x = project(x, y); - stream.point(x[0], x[1]); - }); - } - - function resampleRecursive(stream) { - var λ00, φ00, x00, y00, a00, b00, c00, // first point - λ0, x0, y0, a0, b0, c0; // previous point - - var resample = { - point: point, - lineStart: lineStart, - lineEnd: lineEnd, - polygonStart: function() { stream.polygonStart(); resample.lineStart = ringStart; }, - polygonEnd: function() { stream.polygonEnd(); resample.lineStart = lineStart; } - }; - - function point(x, y) { - x = project(x, y); - stream.point(x[0], x[1]); - } - - function lineStart() { - x0 = NaN; - resample.point = linePoint; - stream.lineStart(); - } - - function linePoint(λ, φ) { - var c = d3_geo_cartesian([λ, φ]), p = project(λ, φ); - resampleLineTo(x0, y0, λ0, a0, b0, c0, x0 = p[0], y0 = p[1], λ0 = λ, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream); - stream.point(x0, y0); - } - - function lineEnd() { - resample.point = point; - stream.lineEnd(); - } - - function ringStart() { - lineStart(); - resample.point = ringPoint; - resample.lineEnd = ringEnd; - } - - function ringPoint(λ, φ) { - linePoint(λ00 = λ, φ00 = φ), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0; - resample.point = linePoint; - } - - function ringEnd() { - resampleLineTo(x0, y0, λ0, a0, b0, c0, x00, y00, λ00, a00, b00, c00, maxDepth, stream); - resample.lineEnd = lineEnd; - lineEnd(); - } - - return resample; - } - - function resampleLineTo(x0, y0, λ0, a0, b0, c0, x1, y1, λ1, a1, b1, c1, depth, stream) { - var dx = x1 - x0, - dy = y1 - y0, - d2 = dx * dx + dy * dy; - if (d2 > 4 * δ2 && depth--) { - var a = a0 + a1, - b = b0 + b1, - c = c0 + c1, - m = Math.sqrt(a * a + b * b + c * c), - φ2 = Math.asin(c /= m), - λ2 = abs(abs(c) - 1) < ε || abs(λ0 - λ1) < ε ? (λ0 + λ1) / 2 : Math.atan2(b, a), - p = project(λ2, φ2), - x2 = p[0], - y2 = p[1], - dx2 = x2 - x0, - dy2 = y2 - y0, - dz = dy * dx2 - dx * dy2; - if (dz * dz / d2 > δ2 // perpendicular projected distance - || abs((dx * dx2 + dy * dy2) / d2 - .5) > .3 // midpoint close to an end - || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { // angular distance - resampleLineTo(x0, y0, λ0, a0, b0, c0, x2, y2, λ2, a /= m, b /= m, c, depth, stream); - stream.point(x2, y2); - resampleLineTo(x2, y2, λ2, a, b, c, x1, y1, λ1, a1, b1, c1, depth, stream); - } - } - } - - resample.precision = function(_) { - if (!arguments.length) return Math.sqrt(δ2); - maxDepth = (δ2 = _ * _) > 0 && 16; - return resample; - }; - - return resample; -} - -d3.geo.path = function() { - var pointRadius = 4.5, - projection, - context, - projectStream, - contextStream, - cacheStream; - - function path(object) { - if (object) { - if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments)); - if (!cacheStream || !cacheStream.valid) cacheStream = projectStream(contextStream); - d3.geo.stream(object, cacheStream); - } - return contextStream.result(); - } - - path.area = function(object) { - d3_geo_pathAreaSum = 0; - d3.geo.stream(object, projectStream(d3_geo_pathArea)); - return d3_geo_pathAreaSum; - }; - - path.centroid = function(object) { - d3_geo_centroidX0 = d3_geo_centroidY0 = d3_geo_centroidZ0 = - d3_geo_centroidX1 = d3_geo_centroidY1 = d3_geo_centroidZ1 = - d3_geo_centroidX2 = d3_geo_centroidY2 = d3_geo_centroidZ2 = 0; - d3.geo.stream(object, projectStream(d3_geo_pathCentroid)); - return d3_geo_centroidZ2 ? [d3_geo_centroidX2 / d3_geo_centroidZ2, d3_geo_centroidY2 / d3_geo_centroidZ2] - : d3_geo_centroidZ1 ? [d3_geo_centroidX1 / d3_geo_centroidZ1, d3_geo_centroidY1 / d3_geo_centroidZ1] - : d3_geo_centroidZ0 ? [d3_geo_centroidX0 / d3_geo_centroidZ0, d3_geo_centroidY0 / d3_geo_centroidZ0] - : [NaN, NaN]; - }; - - path.bounds = function(object) { - d3_geo_pathBoundsX1 = d3_geo_pathBoundsY1 = -(d3_geo_pathBoundsX0 = d3_geo_pathBoundsY0 = Infinity); - d3.geo.stream(object, projectStream(d3_geo_pathBounds)); - return [[d3_geo_pathBoundsX0, d3_geo_pathBoundsY0], [d3_geo_pathBoundsX1, d3_geo_pathBoundsY1]]; - }; - - path.projection = function(_) { - if (!arguments.length) return projection; - projectStream = (projection = _) ? _.stream || d3_geo_pathProjectStream(_) : d3_identity; - return reset(); - }; - - path.context = function(_) { - if (!arguments.length) return context; - contextStream = (context = _) == null ? new d3_geo_pathBuffer : new d3_geo_pathContext(_); - if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius); - return reset(); - }; - - path.pointRadius = function(_) { - if (!arguments.length) return pointRadius; - pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_); - return path; - }; - - function reset() { - cacheStream = null; - return path; - } - - return path.projection(d3.geo.albersUsa()).context(null); -}; - -function d3_geo_pathProjectStream(project) { - var resample = d3_geo_resample(function(x, y) { return project([x * d3_degrees, y * d3_degrees]); }); - return function(stream) { return d3_geo_projectionRadians(resample(stream)); }; -} - -d3.geo.transform = function(methods) { - return { - stream: function(stream) { - var transform = new d3_geo_transform(stream); - for (var k in methods) transform[k] = methods[k]; - return transform; - } - }; -}; - -function d3_geo_transform(stream) { - this.stream = stream; -} - -d3_geo_transform.prototype = { - point: function(x, y) { this.stream.point(x, y); }, - sphere: function() { this.stream.sphere(); }, - lineStart: function() { this.stream.lineStart(); }, - lineEnd: function() { this.stream.lineEnd(); }, - polygonStart: function() { this.stream.polygonStart(); }, - polygonEnd: function() { this.stream.polygonEnd(); } -}; - -function d3_geo_transformPoint(stream, point) { - return { - point: point, - sphere: function() { stream.sphere(); }, - lineStart: function() { stream.lineStart(); }, - lineEnd: function() { stream.lineEnd(); }, - polygonStart: function() { stream.polygonStart(); }, - polygonEnd: function() { stream.polygonEnd(); }, - }; -} - -d3.geo.projection = d3_geo_projection; -d3.geo.projectionMutator = d3_geo_projectionMutator; - -function d3_geo_projection(project) { - return d3_geo_projectionMutator(function() { return project; })(); -} - -function d3_geo_projectionMutator(projectAt) { - var project, - rotate, - projectRotate, - projectResample = d3_geo_resample(function(x, y) { x = project(x, y); return [x[0] * k + δx, δy - x[1] * k]; }), - k = 150, // scale - x = 480, y = 250, // translate - λ = 0, φ = 0, // center - δλ = 0, δφ = 0, δγ = 0, // rotate - δx, δy, // center - preclip = d3_geo_clipAntimeridian, - postclip = d3_identity, - clipAngle = null, - clipExtent = null, - stream; - - function projection(point) { - point = projectRotate(point[0] * d3_radians, point[1] * d3_radians); - return [point[0] * k + δx, δy - point[1] * k]; - } - - function invert(point) { - point = projectRotate.invert((point[0] - δx) / k, (δy - point[1]) / k); - return point && [point[0] * d3_degrees, point[1] * d3_degrees]; - } - - projection.stream = function(output) { - if (stream) stream.valid = false; - stream = d3_geo_projectionRadians(preclip(rotate, projectResample(postclip(output)))); - stream.valid = true; // allow caching by d3.geo.path - return stream; - }; - - projection.clipAngle = function(_) { - if (!arguments.length) return clipAngle; - preclip = _ == null ? (clipAngle = _, d3_geo_clipAntimeridian) : d3_geo_clipCircle((clipAngle = +_) * d3_radians); - return invalidate(); - }; - - projection.clipExtent = function(_) { - if (!arguments.length) return clipExtent; - clipExtent = _; - postclip = _ ? d3_geo_clipExtent(_[0][0], _[0][1], _[1][0], _[1][1]) : d3_identity; - return invalidate(); - }; - - projection.scale = function(_) { - if (!arguments.length) return k; - k = +_; - return reset(); - }; - - projection.translate = function(_) { - if (!arguments.length) return [x, y]; - x = +_[0]; - y = +_[1]; - return reset(); - }; - - projection.center = function(_) { - if (!arguments.length) return [λ * d3_degrees, φ * d3_degrees]; - λ = _[0] % 360 * d3_radians; - φ = _[1] % 360 * d3_radians; - return reset(); - }; - - projection.rotate = function(_) { - if (!arguments.length) return [δλ * d3_degrees, δφ * d3_degrees, δγ * d3_degrees]; - δλ = _[0] % 360 * d3_radians; - δφ = _[1] % 360 * d3_radians; - δγ = _.length > 2 ? _[2] % 360 * d3_radians : 0; - return reset(); - }; - - d3.rebind(projection, projectResample, "precision"); - - function reset() { - projectRotate = d3_geo_compose(rotate = d3_geo_rotation(δλ, δφ, δγ), project); - var center = project(λ, φ); - δx = x - center[0] * k; - δy = y + center[1] * k; - return invalidate(); - } - - function invalidate() { - if (stream) stream.valid = false, stream = null; - return projection; - } - - return function() { - project = projectAt.apply(this, arguments); - projection.invert = project.invert && invert; - return reset(); - }; -} - -function d3_geo_projectionRadians(stream) { - return d3_geo_transformPoint(stream, function(x, y) { - stream.point(x * d3_radians, y * d3_radians); - }); -} - -function d3_geo_mercator(λ, φ) { - return [λ, Math.log(Math.tan(π / 4 + φ / 2))]; -} - -d3_geo_mercator.invert = function(x, y) { - return [x, 2 * Math.atan(Math.exp(y)) - halfπ]; -}; - -function d3_geo_mercatorProjection(project) { - var m = d3_geo_projection(project), - scale = m.scale, - translate = m.translate, - clipExtent = m.clipExtent, - clipAuto; - - m.scale = function() { - var v = scale.apply(m, arguments); - return v === m ? (clipAuto ? m.clipExtent(null) : m) : v; - }; - - m.translate = function() { - var v = translate.apply(m, arguments); - return v === m ? (clipAuto ? m.clipExtent(null) : m) : v; - }; - - m.clipExtent = function(_) { - var v = clipExtent.apply(m, arguments); - if (v === m) { - if (clipAuto = _ == null) { - var k = π * scale(), t = translate(); - clipExtent([[t[0] - k, t[1] - k], [t[0] + k, t[1] + k]]); - } - } else if (clipAuto) { - v = null; - } - return v; - }; - - return m.clipExtent(null); -} - -(d3.geo.mercator = function() { - return d3_geo_mercatorProjection(d3_geo_mercator); -}).raw = d3_geo_mercator; -d3.geom = {}; - -d3.geom.polygon = function(coordinates) { - d3_subclass(coordinates, d3_geom_polygonPrototype); - return coordinates; -}; - -var d3_geom_polygonPrototype = d3.geom.polygon.prototype = []; - -d3_geom_polygonPrototype.area = function() { - var i = -1, - n = this.length, - a, - b = this[n - 1], - area = 0; - - while (++i < n) { - a = b; - b = this[i]; - area += a[1] * b[0] - a[0] * b[1]; - } - - return area * .5; -}; - -d3_geom_polygonPrototype.centroid = function(k) { - var i = -1, - n = this.length, - x = 0, - y = 0, - a, - b = this[n - 1], - c; - - if (!arguments.length) k = -1 / (6 * this.area()); - - while (++i < n) { - a = b; - b = this[i]; - c = a[0] * b[1] - b[0] * a[1]; - x += (a[0] + b[0]) * c; - y += (a[1] + b[1]) * c; - } - - return [x * k, y * k]; -}; - -// The Sutherland-Hodgman clipping algorithm. -// Note: requires the clip polygon to be counterclockwise and convex. -d3_geom_polygonPrototype.clip = function(subject) { - var input, - closed = d3_geom_polygonClosed(subject), - i = -1, - n = this.length - d3_geom_polygonClosed(this), - j, - m, - a = this[n - 1], - b, - c, - d; - - while (++i < n) { - input = subject.slice(); - subject.length = 0; - b = this[i]; - c = input[(m = input.length - closed) - 1]; - j = -1; - while (++j < m) { - d = input[j]; - if (d3_geom_polygonInside(d, a, b)) { - if (!d3_geom_polygonInside(c, a, b)) { - subject.push(d3_geom_polygonIntersect(c, d, a, b)); - } - subject.push(d); - } else if (d3_geom_polygonInside(c, a, b)) { - subject.push(d3_geom_polygonIntersect(c, d, a, b)); - } - c = d; - } - if (closed) subject.push(subject[0]); - a = b; - } - - return subject; -}; - -function d3_geom_polygonInside(p, a, b) { - return (b[0] - a[0]) * (p[1] - a[1]) < (b[1] - a[1]) * (p[0] - a[0]); -} - -// Intersect two infinite lines cd and ab. -function d3_geom_polygonIntersect(c, d, a, b) { - var x1 = c[0], x3 = a[0], x21 = d[0] - x1, x43 = b[0] - x3, - y1 = c[1], y3 = a[1], y21 = d[1] - y1, y43 = b[1] - y3, - ua = (x43 * (y1 - y3) - y43 * (x1 - x3)) / (y43 * x21 - x43 * y21); - return [x1 + ua * x21, y1 + ua * y21]; -} - -// Returns true if the polygon is closed. -function d3_geom_polygonClosed(coordinates) { - var a = coordinates[0], - b = coordinates[coordinates.length - 1]; - return !(a[0] - b[0] || a[1] - b[1]); -} -function d3_geom_pointX(d) { - return d[0]; -} - -function d3_geom_pointY(d) { - return d[1]; -} - -/** - * Computes the 2D convex hull of a set of points using the monotone chain - * algorithm: - * http://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain) - * - * The runtime of this algorithm is O(n log n), where n is the number of input - * points. However in practice it outperforms other O(n log n) hulls. - * - * @param vertices [[x1, y1], [x2, y2], ...] - * @returns polygon [[x1, y1], [x2, y2], ...] - */ -d3.geom.hull = function(vertices) { - var x = d3_geom_pointX, - y = d3_geom_pointY; - - if (arguments.length) return hull(vertices); - - function hull(data) { - // Hull of < 3 points is not well-defined - if (data.length < 3) return []; - - var fx = d3_functor(x), - fy = d3_functor(y), - i, - n = data.length, - points = [], // of the form [[x0, y0, 0], ..., [xn, yn, n]] - flippedPoints = []; - - for (i = 0 ; i < n; i++) { - points.push([+fx.call(this, data[i], i), +fy.call(this, data[i], i), i]); - } - - // sort ascending by x-coord first, y-coord second - points.sort(d3_geom_hullOrder); - - // we flip bottommost points across y axis so we can use the upper hull routine on both - for (i = 0; i < n; i++) flippedPoints.push([points[i][0], -points[i][1]]); - - var upper = d3_geom_hullUpper(points), - lower = d3_geom_hullUpper(flippedPoints); - - // construct the polygon, removing possible duplicate endpoints - var skipLeft = lower[0] === upper[0], - skipRight = lower[lower.length - 1] === upper[upper.length - 1], - polygon = []; - - // add upper hull in r->l order - // then add lower hull in l->r order - for (i = upper.length - 1; i >= 0; --i) polygon.push(data[points[upper[i]][2]]); - for (i = +skipLeft; i < lower.length - skipRight; ++i) polygon.push(data[points[lower[i]][2]]); - - return polygon; - } - - hull.x = function(_) { - return arguments.length ? (x = _, hull) : x; - }; - - hull.y = function(_) { - return arguments.length ? (y = _, hull) : y; - }; - - return hull; -}; - -// finds the 'upper convex hull' (see wiki link above) -// assumes points arg has >=3 elements, is sorted by x, unique in y -// returns array of indices into points in left to right order -function d3_geom_hullUpper(points) { - var n = points.length, - hull = [0, 1], - hs = 2; // hull size - - for (var i = 2; i < n; i++) { - while (hs > 1 && d3_cross2d(points[hull[hs-2]], points[hull[hs-1]], points[i]) <= 0) --hs; - hull[hs++] = i; - } - - // we slice to make sure that the points we 'popped' from hull don't stay behind - return hull.slice(0, hs); -} - -// comparator for ascending sort by x-coord first, y-coord second -function d3_geom_hullOrder(a, b) { - return a[0] - b[0] || a[1] - b[1]; -} -// import "../transition/transition"; - -d3_selectionPrototype.transition = function(name) { - var id = d3_transitionInheritId || ++d3_transitionId, - ns = d3_transitionNamespace(name), - subgroups = [], - subgroup, - node, - transition = d3_transitionInherit || {time: Date.now(), ease: d3_ease_cubicInOut, delay: 0, duration: 250}; - - for (var j = -1, m = this.length; ++j < m;) { - subgroups.push(subgroup = []); - for (var group = this[j], i = -1, n = group.length; ++i < n;) { - if (node = group[i]) d3_transitionNode(node, i, ns, id, transition); - subgroup.push(node); - } - } - - return d3_transition(subgroups, ns, id); -}; -// import "../transition/transition"; - -// TODO Interrupt transitions for all namespaces? -d3_selectionPrototype.interrupt = function(name) { - return this.each(name == null - ? d3_selection_interrupt - : d3_selection_interruptNS(d3_transitionNamespace(name))); -}; - -var d3_selection_interrupt = d3_selection_interruptNS(d3_transitionNamespace()); - -function d3_selection_interruptNS(ns) { - return function() { - var lock, active; - if ((lock = this[ns]) && (active = lock[lock.active])) { - if (--lock.count) delete lock[lock.active]; - else delete this[ns]; - lock.active += .5; - active.event && active.event.interrupt.call(this, this.__data__, active.index); - } - }; -} - -function d3_transition(groups, ns, id) { - d3_subclass(groups, d3_transitionPrototype); - - // Note: read-only! - groups.namespace = ns; - groups.id = id; - - return groups; -} - -var d3_transitionPrototype = [], - d3_transitionId = 0, - d3_transitionInheritId, - d3_transitionInherit; - -d3_transitionPrototype.call = d3_selectionPrototype.call; -d3_transitionPrototype.empty = d3_selectionPrototype.empty; -d3_transitionPrototype.node = d3_selectionPrototype.node; -d3_transitionPrototype.size = d3_selectionPrototype.size; - -d3.transition = function(selection, name) { - return selection && selection.transition - ? (d3_transitionInheritId ? selection.transition(name) : selection) - : d3.selection().transition(selection); -}; - -d3.transition.prototype = d3_transitionPrototype; - - -d3_transitionPrototype.select = function(selector) { - var id = this.id, - ns = this.namespace, - subgroups = [], - subgroup, - subnode, - node; - - selector = d3_selection_selector(selector); - - for (var j = -1, m = this.length; ++j < m;) { - subgroups.push(subgroup = []); - for (var group = this[j], i = -1, n = group.length; ++i < n;) { - if ((node = group[i]) && (subnode = selector.call(node, node.__data__, i, j))) { - if ("__data__" in node) subnode.__data__ = node.__data__; - d3_transitionNode(subnode, i, ns, id, node[ns][id]); - subgroup.push(subnode); - } else { - subgroup.push(null); - } - } - } - - return d3_transition(subgroups, ns, id); -}; - -d3_transitionPrototype.selectAll = function(selector) { - var id = this.id, - ns = this.namespace, - subgroups = [], - subgroup, - subnodes, - node, - subnode, - transition; - - selector = d3_selection_selectorAll(selector); - - for (var j = -1, m = this.length; ++j < m;) { - for (var group = this[j], i = -1, n = group.length; ++i < n;) { - if (node = group[i]) { - transition = node[ns][id]; - subnodes = selector.call(node, node.__data__, i, j); - subgroups.push(subgroup = []); - for (var k = -1, o = subnodes.length; ++k < o;) { - if (subnode = subnodes[k]) d3_transitionNode(subnode, k, ns, id, transition); - subgroup.push(subnode); - } - } - } - } - - return d3_transition(subgroups, ns, id); -}; - -d3_transitionPrototype.filter = function(filter) { - var subgroups = [], - subgroup, - group, - node; - - if (typeof filter !== "function") filter = d3_selection_filter(filter); - - for (var j = 0, m = this.length; j < m; j++) { - subgroups.push(subgroup = []); - for (var group = this[j], i = 0, n = group.length; i < n; i++) { - if ((node = group[i]) && filter.call(node, node.__data__, i, j)) { - subgroup.push(node); - } - } - } - - return d3_transition(subgroups, this.namespace, this.id); -}; -d3.color = d3_color; - -function d3_color() {} - -d3_color.prototype.toString = function() { - return this.rgb() + ""; -}; - -d3.hsl = d3_hsl; - -function d3_hsl(h, s, l) { - return this instanceof d3_hsl ? void (this.h = +h, this.s = +s, this.l = +l) - : arguments.length < 2 ? (h instanceof d3_hsl ? new d3_hsl(h.h, h.s, h.l) - : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl)) - : new d3_hsl(h, s, l); -} - -var d3_hslPrototype = d3_hsl.prototype = new d3_color; - -d3_hslPrototype.brighter = function(k) { - k = Math.pow(0.7, arguments.length ? k : 1); - return new d3_hsl(this.h, this.s, this.l / k); -}; - -d3_hslPrototype.darker = function(k) { - k = Math.pow(0.7, arguments.length ? k : 1); - return new d3_hsl(this.h, this.s, k * this.l); -}; - -d3_hslPrototype.rgb = function() { - return d3_hsl_rgb(this.h, this.s, this.l); -}; - -function d3_hsl_rgb(h, s, l) { - var m1, - m2; - - /* Some simple corrections for h, s and l. */ - h = isNaN(h) ? 0 : (h %= 360) < 0 ? h + 360 : h; - s = isNaN(s) ? 0 : s < 0 ? 0 : s > 1 ? 1 : s; - l = l < 0 ? 0 : l > 1 ? 1 : l; - - /* From FvD 13.37, CSS Color Module Level 3 */ - m2 = l <= .5 ? l * (1 + s) : l + s - l * s; - m1 = 2 * l - m2; - - function v(h) { - if (h > 360) h -= 360; - else if (h < 0) h += 360; - if (h < 60) return m1 + (m2 - m1) * h / 60; - if (h < 180) return m2; - if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60; - return m1; - } - - function vv(h) { - return Math.round(v(h) * 255); - } - - return new d3_rgb(vv(h + 120), vv(h), vv(h - 120)); -} - -d3.hcl = d3_hcl; - -function d3_hcl(h, c, l) { - return this instanceof d3_hcl ? void (this.h = +h, this.c = +c, this.l = +l) - : arguments.length < 2 ? (h instanceof d3_hcl ? new d3_hcl(h.h, h.c, h.l) - : (h instanceof d3_lab ? d3_lab_hcl(h.l, h.a, h.b) - : d3_lab_hcl((h = d3_rgb_lab((h = d3.rgb(h)).r, h.g, h.b)).l, h.a, h.b))) - : new d3_hcl(h, c, l); -} - -var d3_hclPrototype = d3_hcl.prototype = new d3_color; - -d3_hclPrototype.brighter = function(k) { - return new d3_hcl(this.h, this.c, Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1))); -}; - -d3_hclPrototype.darker = function(k) { - return new d3_hcl(this.h, this.c, Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1))); -}; - -d3_hclPrototype.rgb = function() { - return d3_hcl_lab(this.h, this.c, this.l).rgb(); -}; - -function d3_hcl_lab(h, c, l) { - if (isNaN(h)) h = 0; - if (isNaN(c)) c = 0; - return new d3_lab(l, Math.cos(h *= d3_radians) * c, Math.sin(h) * c); -} - -d3.lab = d3_lab; - -function d3_lab(l, a, b) { - return this instanceof d3_lab ? void (this.l = +l, this.a = +a, this.b = +b) - : arguments.length < 2 ? (l instanceof d3_lab ? new d3_lab(l.l, l.a, l.b) - : (l instanceof d3_hcl ? d3_hcl_lab(l.h, l.c, l.l) - : d3_rgb_lab((l = d3_rgb(l)).r, l.g, l.b))) - : new d3_lab(l, a, b); -} - -// Corresponds roughly to RGB brighter/darker -var d3_lab_K = 18; - -// D65 standard referent -var d3_lab_X = 0.950470, - d3_lab_Y = 1, - d3_lab_Z = 1.088830; - -var d3_labPrototype = d3_lab.prototype = new d3_color; - -d3_labPrototype.brighter = function(k) { - return new d3_lab(Math.min(100, this.l + d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); -}; - -d3_labPrototype.darker = function(k) { - return new d3_lab(Math.max(0, this.l - d3_lab_K * (arguments.length ? k : 1)), this.a, this.b); -}; - -d3_labPrototype.rgb = function() { - return d3_lab_rgb(this.l, this.a, this.b); -}; - -function d3_lab_rgb(l, a, b) { - var y = (l + 16) / 116, - x = y + a / 500, - z = y - b / 200; - x = d3_lab_xyz(x) * d3_lab_X; - y = d3_lab_xyz(y) * d3_lab_Y; - z = d3_lab_xyz(z) * d3_lab_Z; - return new d3_rgb( - d3_xyz_rgb( 3.2404542 * x - 1.5371385 * y - 0.4985314 * z), - d3_xyz_rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z), - d3_xyz_rgb( 0.0556434 * x - 0.2040259 * y + 1.0572252 * z) - ); -} - -function d3_lab_hcl(l, a, b) { - return l > 0 - ? new d3_hcl(Math.atan2(b, a) * d3_degrees, Math.sqrt(a * a + b * b), l) - : new d3_hcl(NaN, NaN, l); -} - -function d3_lab_xyz(x) { - return x > 0.206893034 ? x * x * x : (x - 4 / 29) / 7.787037; -} -function d3_xyz_lab(x) { - return x > 0.008856 ? Math.pow(x, 1 / 3) : 7.787037 * x + 4 / 29; -} - -function d3_xyz_rgb(r) { - return Math.round(255 * (r <= 0.00304 ? 12.92 * r : 1.055 * Math.pow(r, 1 / 2.4) - 0.055)); -} - -d3.rgb = d3_rgb; - -function d3_rgb(r, g, b) { - return this instanceof d3_rgb ? void (this.r = ~~r, this.g = ~~g, this.b = ~~b) - : arguments.length < 2 ? (r instanceof d3_rgb ? new d3_rgb(r.r, r.g, r.b) - : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb)) - : new d3_rgb(r, g, b); -} - -function d3_rgbNumber(value) { - return new d3_rgb(value >> 16, value >> 8 & 0xff, value & 0xff); -} - -function d3_rgbString(value) { - return d3_rgbNumber(value) + ""; -} - -var d3_rgbPrototype = d3_rgb.prototype = new d3_color; - -d3_rgbPrototype.brighter = function(k) { - k = Math.pow(0.7, arguments.length ? k : 1); - var r = this.r, - g = this.g, - b = this.b, - i = 30; - if (!r && !g && !b) return new d3_rgb(i, i, i); - if (r && r < i) r = i; - if (g && g < i) g = i; - if (b && b < i) b = i; - return new d3_rgb(Math.min(255, r / k), Math.min(255, g / k), Math.min(255, b / k)); -}; - -d3_rgbPrototype.darker = function(k) { - k = Math.pow(0.7, arguments.length ? k : 1); - return new d3_rgb(k * this.r, k * this.g, k * this.b); -}; - -d3_rgbPrototype.hsl = function() { - return d3_rgb_hsl(this.r, this.g, this.b); -}; - -d3_rgbPrototype.toString = function() { - return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b); -}; - -function d3_rgb_hex(v) { - return v < 0x10 - ? "0" + Math.max(0, v).toString(16) - : Math.min(255, v).toString(16); -} - -function d3_rgb_parse(format, rgb, hsl) { - var r = 0, // red channel; int in [0, 255] - g = 0, // green channel; int in [0, 255] - b = 0, // blue channel; int in [0, 255] - m1, // CSS color specification match - m2, // CSS color specification type (e.g., rgb) - color; - - /* Handle hsl, rgb. */ - m1 = /([a-z]+)\((.*)\)/i.exec(format); - if (m1) { - m2 = m1[2].split(","); - switch (m1[1]) { - case "hsl": { - return hsl( - parseFloat(m2[0]), // degrees - parseFloat(m2[1]) / 100, // percentage - parseFloat(m2[2]) / 100 // percentage - ); - } - case "rgb": { - return rgb( - d3_rgb_parseNumber(m2[0]), - d3_rgb_parseNumber(m2[1]), - d3_rgb_parseNumber(m2[2]) - ); - } - } - } - - /* Named colors. */ - if (color = d3_rgb_names.get(format.toLowerCase())) { - return rgb(color.r, color.g, color.b); - } - - /* Hexadecimal colors: #rgb and #rrggbb. */ - if (format != null && format.charAt(0) === "#" && !isNaN(color = parseInt(format.slice(1), 16))) { - if (format.length === 4) { - r = (color & 0xf00) >> 4; r = (r >> 4) | r; - g = (color & 0xf0); g = (g >> 4) | g; - b = (color & 0xf); b = (b << 4) | b; - } else if (format.length === 7) { - r = (color & 0xff0000) >> 16; - g = (color & 0xff00) >> 8; - b = (color & 0xff); - } - } - - return rgb(r, g, b); -} - -function d3_rgb_hsl(r, g, b) { - var min = Math.min(r /= 255, g /= 255, b /= 255), - max = Math.max(r, g, b), - d = max - min, - h, - s, - l = (max + min) / 2; - if (d) { - s = l < .5 ? d / (max + min) : d / (2 - max - min); - if (r == max) h = (g - b) / d + (g < b ? 6 : 0); - else if (g == max) h = (b - r) / d + 2; - else h = (r - g) / d + 4; - h *= 60; - } else { - h = NaN; - s = l > 0 && l < 1 ? 0 : h; - } - return new d3_hsl(h, s, l); -} - -function d3_rgb_lab(r, g, b) { - r = d3_rgb_xyz(r); - g = d3_rgb_xyz(g); - b = d3_rgb_xyz(b); - var x = d3_xyz_lab((0.4124564 * r + 0.3575761 * g + 0.1804375 * b) / d3_lab_X), - y = d3_xyz_lab((0.2126729 * r + 0.7151522 * g + 0.0721750 * b) / d3_lab_Y), - z = d3_xyz_lab((0.0193339 * r + 0.1191920 * g + 0.9503041 * b) / d3_lab_Z); - return d3_lab(116 * y - 16, 500 * (x - y), 200 * (y - z)); -} - -function d3_rgb_xyz(r) { - return (r /= 255) <= 0.04045 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4); -} - -function d3_rgb_parseNumber(c) { // either integer or percentage - var f = parseFloat(c); - return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f; -} - -var d3_rgb_names = d3.map({ - aliceblue: 0xf0f8ff, - antiquewhite: 0xfaebd7, - aqua: 0x00ffff, - aquamarine: 0x7fffd4, - azure: 0xf0ffff, - beige: 0xf5f5dc, - bisque: 0xffe4c4, - black: 0x000000, - blanchedalmond: 0xffebcd, - blue: 0x0000ff, - blueviolet: 0x8a2be2, - brown: 0xa52a2a, - burlywood: 0xdeb887, - cadetblue: 0x5f9ea0, - chartreuse: 0x7fff00, - chocolate: 0xd2691e, - coral: 0xff7f50, - cornflowerblue: 0x6495ed, - cornsilk: 0xfff8dc, - crimson: 0xdc143c, - cyan: 0x00ffff, - darkblue: 0x00008b, - darkcyan: 0x008b8b, - darkgoldenrod: 0xb8860b, - darkgray: 0xa9a9a9, - darkgreen: 0x006400, - darkgrey: 0xa9a9a9, - darkkhaki: 0xbdb76b, - darkmagenta: 0x8b008b, - darkolivegreen: 0x556b2f, - darkorange: 0xff8c00, - darkorchid: 0x9932cc, - darkred: 0x8b0000, - darksalmon: 0xe9967a, - darkseagreen: 0x8fbc8f, - darkslateblue: 0x483d8b, - darkslategray: 0x2f4f4f, - darkslategrey: 0x2f4f4f, - darkturquoise: 0x00ced1, - darkviolet: 0x9400d3, - deeppink: 0xff1493, - deepskyblue: 0x00bfff, - dimgray: 0x696969, - dimgrey: 0x696969, - dodgerblue: 0x1e90ff, - firebrick: 0xb22222, - floralwhite: 0xfffaf0, - forestgreen: 0x228b22, - fuchsia: 0xff00ff, - gainsboro: 0xdcdcdc, - ghostwhite: 0xf8f8ff, - gold: 0xffd700, - goldenrod: 0xdaa520, - gray: 0x808080, - green: 0x008000, - greenyellow: 0xadff2f, - grey: 0x808080, - honeydew: 0xf0fff0, - hotpink: 0xff69b4, - indianred: 0xcd5c5c, - indigo: 0x4b0082, - ivory: 0xfffff0, - khaki: 0xf0e68c, - lavender: 0xe6e6fa, - lavenderblush: 0xfff0f5, - lawngreen: 0x7cfc00, - lemonchiffon: 0xfffacd, - lightblue: 0xadd8e6, - lightcoral: 0xf08080, - lightcyan: 0xe0ffff, - lightgoldenrodyellow: 0xfafad2, - lightgray: 0xd3d3d3, - lightgreen: 0x90ee90, - lightgrey: 0xd3d3d3, - lightpink: 0xffb6c1, - lightsalmon: 0xffa07a, - lightseagreen: 0x20b2aa, - lightskyblue: 0x87cefa, - lightslategray: 0x778899, - lightslategrey: 0x778899, - lightsteelblue: 0xb0c4de, - lightyellow: 0xffffe0, - lime: 0x00ff00, - limegreen: 0x32cd32, - linen: 0xfaf0e6, - magenta: 0xff00ff, - maroon: 0x800000, - mediumaquamarine: 0x66cdaa, - mediumblue: 0x0000cd, - mediumorchid: 0xba55d3, - mediumpurple: 0x9370db, - mediumseagreen: 0x3cb371, - mediumslateblue: 0x7b68ee, - mediumspringgreen: 0x00fa9a, - mediumturquoise: 0x48d1cc, - mediumvioletred: 0xc71585, - midnightblue: 0x191970, - mintcream: 0xf5fffa, - mistyrose: 0xffe4e1, - moccasin: 0xffe4b5, - navajowhite: 0xffdead, - navy: 0x000080, - oldlace: 0xfdf5e6, - olive: 0x808000, - olivedrab: 0x6b8e23, - orange: 0xffa500, - orangered: 0xff4500, - orchid: 0xda70d6, - palegoldenrod: 0xeee8aa, - palegreen: 0x98fb98, - paleturquoise: 0xafeeee, - palevioletred: 0xdb7093, - papayawhip: 0xffefd5, - peachpuff: 0xffdab9, - peru: 0xcd853f, - pink: 0xffc0cb, - plum: 0xdda0dd, - powderblue: 0xb0e0e6, - purple: 0x800080, - rebeccapurple: 0x663399, - red: 0xff0000, - rosybrown: 0xbc8f8f, - royalblue: 0x4169e1, - saddlebrown: 0x8b4513, - salmon: 0xfa8072, - sandybrown: 0xf4a460, - seagreen: 0x2e8b57, - seashell: 0xfff5ee, - sienna: 0xa0522d, - silver: 0xc0c0c0, - skyblue: 0x87ceeb, - slateblue: 0x6a5acd, - slategray: 0x708090, - slategrey: 0x708090, - snow: 0xfffafa, - springgreen: 0x00ff7f, - steelblue: 0x4682b4, - tan: 0xd2b48c, - teal: 0x008080, - thistle: 0xd8bfd8, - tomato: 0xff6347, - turquoise: 0x40e0d0, - violet: 0xee82ee, - wheat: 0xf5deb3, - white: 0xffffff, - whitesmoke: 0xf5f5f5, - yellow: 0xffff00, - yellowgreen: 0x9acd32 -}); - -d3_rgb_names.forEach(function(key, value) { - d3_rgb_names.set(key, d3_rgbNumber(value)); -}); - -d3.interpolateRgb = d3_interpolateRgb; - -function d3_interpolateRgb(a, b) { - a = d3.rgb(a); - b = d3.rgb(b); - var ar = a.r, - ag = a.g, - ab = a.b, - br = b.r - ar, - bg = b.g - ag, - bb = b.b - ab; - return function(t) { - return "#" - + d3_rgb_hex(Math.round(ar + br * t)) - + d3_rgb_hex(Math.round(ag + bg * t)) - + d3_rgb_hex(Math.round(ab + bb * t)); - }; -} - -d3.interpolateObject = d3_interpolateObject; - -function d3_interpolateObject(a, b) { - var i = {}, - c = {}, - k; - for (k in a) { - if (k in b) { - i[k] = d3_interpolate(a[k], b[k]); - } else { - c[k] = a[k]; - } - } - for (k in b) { - if (!(k in a)) { - c[k] = b[k]; - } - } - return function(t) { - for (k in i) c[k] = i[k](t); - return c; - }; -} - -d3.interpolateArray = d3_interpolateArray; - -function d3_interpolateArray(a, b) { - var x = [], - c = [], - na = a.length, - nb = b.length, - n0 = Math.min(a.length, b.length), - i; - for (i = 0; i < n0; ++i) x.push(d3_interpolate(a[i], b[i])); - for (; i < na; ++i) c[i] = a[i]; - for (; i < nb; ++i) c[i] = b[i]; - return function(t) { - for (i = 0; i < n0; ++i) c[i] = x[i](t); - return c; - }; -} -d3.interpolateNumber = d3_interpolateNumber; - -function d3_interpolateNumber(a, b) { - a = +a, b = +b; - return function(t) { return a * (1 - t) + b * t; }; -} - -d3.interpolateString = d3_interpolateString; - -function d3_interpolateString(a, b) { - var bi = d3_interpolate_numberA.lastIndex = d3_interpolate_numberB.lastIndex = 0, // scan index for next number in b - am, // current match in a - bm, // current match in b - bs, // string preceding current number in b, if any - i = -1, // index in s - s = [], // string constants and placeholders - q = []; // number interpolators - - // Coerce inputs to strings. - a = a + "", b = b + ""; - - // Interpolate pairs of numbers in a & b. - while ((am = d3_interpolate_numberA.exec(a)) - && (bm = d3_interpolate_numberB.exec(b))) { - if ((bs = bm.index) > bi) { // a string precedes the next number in b - bs = b.slice(bi, bs); - if (s[i]) s[i] += bs; // coalesce with previous string - else s[++i] = bs; - } - if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match - if (s[i]) s[i] += bm; // coalesce with previous string - else s[++i] = bm; - } else { // interpolate non-matching numbers - s[++i] = null; - q.push({i: i, x: d3_interpolateNumber(am, bm)}); - } - bi = d3_interpolate_numberB.lastIndex; - } - - // Add remains of b. - if (bi < b.length) { - bs = b.slice(bi); - if (s[i]) s[i] += bs; // coalesce with previous string - else s[++i] = bs; - } - - // Special optimization for only a single match. - // Otherwise, interpolate each of the numbers and rejoin the string. - return s.length < 2 - ? (q[0] ? (b = q[0].x, function(t) { return b(t) + ""; }) - : function() { return b; }) - : (b = q.length, function(t) { - for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t); - return s.join(""); - }); -} - -var d3_interpolate_numberA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g, - d3_interpolate_numberB = new RegExp(d3_interpolate_numberA.source, "g"); - -d3.interpolate = d3_interpolate; - -function d3_interpolate(a, b) { - var i = d3.interpolators.length, f; - while (--i >= 0 && !(f = d3.interpolators[i](a, b))); - return f; -} - -d3.interpolators = [ - function(a, b) { - var t = typeof b; - return (t === "string" ? (d3_rgb_names.has(b) || /^(#|rgb\(|hsl\()/.test(b) ? d3_interpolateRgb : d3_interpolateString) - : b instanceof d3_color ? d3_interpolateRgb - : Array.isArray(b) ? d3_interpolateArray - : t === "object" && isNaN(b) ? d3_interpolateObject - : d3_interpolateNumber)(a, b); - } -]; - -d3.transform = function(string) { - var g = d3_document.createElementNS(d3.ns.prefix.svg, "g"); - return (d3.transform = function(string) { - if (string != null) { - g.setAttribute("transform", string); - var t = g.transform.baseVal.consolidate(); - } - return new d3_transform(t ? t.matrix : d3_transformIdentity); - })(string); -}; - -// Compute x-scale and normalize the first row. -// Compute shear and make second row orthogonal to first. -// Compute y-scale and normalize the second row. -// Finally, compute the rotation. -function d3_transform(m) { - var r0 = [m.a, m.b], - r1 = [m.c, m.d], - kx = d3_transformNormalize(r0), - kz = d3_transformDot(r0, r1), - ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz)) || 0; - if (r0[0] * r1[1] < r1[0] * r0[1]) { - r0[0] *= -1; - r0[1] *= -1; - kx *= -1; - kz *= -1; - } - this.rotate = (kx ? Math.atan2(r0[1], r0[0]) : Math.atan2(-r1[0], r1[1])) * d3_degrees; - this.translate = [m.e, m.f]; - this.scale = [kx, ky]; - this.skew = ky ? Math.atan2(kz, ky) * d3_degrees : 0; -}; - -d3_transform.prototype.toString = function() { - return "translate(" + this.translate - + ")rotate(" + this.rotate - + ")skewX(" + this.skew - + ")scale(" + this.scale - + ")"; -}; - -function d3_transformDot(a, b) { - return a[0] * b[0] + a[1] * b[1]; -} - -function d3_transformNormalize(a) { - var k = Math.sqrt(d3_transformDot(a, a)); - if (k) { - a[0] /= k; - a[1] /= k; - } - return k; -} - -function d3_transformCombine(a, b, k) { - a[0] += k * b[0]; - a[1] += k * b[1]; - return a; -} - -var d3_transformIdentity = {a: 1, b: 0, c: 0, d: 1, e: 0, f: 0}; - -d3.interpolateTransform = d3_interpolateTransform; - -function d3_interpolateTransform(a, b) { - var s = [], // string constants and placeholders - q = [], // number interpolators - n, - A = d3.transform(a), - B = d3.transform(b), - ta = A.translate, - tb = B.translate, - ra = A.rotate, - rb = B.rotate, - wa = A.skew, - wb = B.skew, - ka = A.scale, - kb = B.scale; - - if (ta[0] != tb[0] || ta[1] != tb[1]) { - s.push("translate(", null, ",", null, ")"); - q.push({i: 1, x: d3_interpolateNumber(ta[0], tb[0])}, {i: 3, x: d3_interpolateNumber(ta[1], tb[1])}); - } else if (tb[0] || tb[1]) { - s.push("translate(" + tb + ")"); - } else { - s.push(""); - } - - if (ra != rb) { - if (ra - rb > 180) rb += 360; else if (rb - ra > 180) ra += 360; // shortest path - q.push({i: s.push(s.pop() + "rotate(", null, ")") - 2, x: d3_interpolateNumber(ra, rb)}); - } else if (rb) { - s.push(s.pop() + "rotate(" + rb + ")"); - } - - if (wa != wb) { - q.push({i: s.push(s.pop() + "skewX(", null, ")") - 2, x: d3_interpolateNumber(wa, wb)}); - } else if (wb) { - s.push(s.pop() + "skewX(" + wb + ")"); - } - - if (ka[0] != kb[0] || ka[1] != kb[1]) { - n = s.push(s.pop() + "scale(", null, ",", null, ")"); - q.push({i: n - 4, x: d3_interpolateNumber(ka[0], kb[0])}, {i: n - 2, x: d3_interpolateNumber(ka[1], kb[1])}); - } else if (kb[0] != 1 || kb[1] != 1) { - s.push(s.pop() + "scale(" + kb + ")"); - } - - n = q.length; - return function(t) { - var i = -1, o; - while (++i < n) s[(o = q[i]).i] = o.x(t); - return s.join(""); - }; -} - -d3_transitionPrototype.tween = function(name, tween) { - var id = this.id, ns = this.namespace; - if (arguments.length < 2) return this.node()[ns][id].tween.get(name); - return d3_selection_each(this, tween == null - ? function(node) { node[ns][id].tween.remove(name); } - : function(node) { node[ns][id].tween.set(name, tween); }); -}; - -function d3_transition_tween(groups, name, value, tween) { - var id = groups.id, ns = groups.namespace; - return d3_selection_each(groups, typeof value === "function" - ? function(node, i, j) { node[ns][id].tween.set(name, tween(value.call(node, node.__data__, i, j))); } - : (value = tween(value), function(node) { node[ns][id].tween.set(name, value); })); -} - -d3_transitionPrototype.attr = function(nameNS, value) { - if (arguments.length < 2) { - - // For attr(object), the object specifies the names and values of the - // attributes to transition. The values may be functions that are - // evaluated for each element. - for (value in nameNS) this.attr(value, nameNS[value]); - return this; - } - - var interpolate = nameNS == "transform" ? d3_interpolateTransform : d3_interpolate, - name = d3.ns.qualify(nameNS); - - // For attr(string, null), remove the attribute with the specified name. - function attrNull() { - this.removeAttribute(name); - } - function attrNullNS() { - this.removeAttributeNS(name.space, name.local); - } - - // For attr(string, string), set the attribute with the specified name. - function attrTween(b) { - return b == null ? attrNull : (b += "", function() { - var a = this.getAttribute(name), i; - return a !== b && (i = interpolate(a, b), function(t) { this.setAttribute(name, i(t)); }); - }); - } - function attrTweenNS(b) { - return b == null ? attrNullNS : (b += "", function() { - var a = this.getAttributeNS(name.space, name.local), i; - return a !== b && (i = interpolate(a, b), function(t) { this.setAttributeNS(name.space, name.local, i(t)); }); - }); - } - - return d3_transition_tween(this, "attr." + nameNS, value, name.local ? attrTweenNS : attrTween); -}; - -d3_transitionPrototype.attrTween = function(nameNS, tween) { - var name = d3.ns.qualify(nameNS); - - function attrTween(d, i) { - var f = tween.call(this, d, i, this.getAttribute(name)); - return f && function(t) { this.setAttribute(name, f(t)); }; - } - function attrTweenNS(d, i) { - var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local)); - return f && function(t) { this.setAttributeNS(name.space, name.local, f(t)); }; - } - - return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween); -}; - -d3_transitionPrototype.style = function(name, value, priority) { - var n = arguments.length; - if (n < 3) { - - // For style(object) or style(object, string), the object specifies the - // names and values of the attributes to set or remove. The values may be - // functions that are evaluated for each element. The optional string - // specifies the priority. - if (typeof name !== "string") { - if (n < 2) value = ""; - for (priority in name) this.style(priority, name[priority], value); - return this; - } - - // For style(string, string) or style(string, function), use the default - // priority. The priority is ignored for style(string, null). - priority = ""; - } - - // For style(name, null) or style(name, null, priority), remove the style - // property with the specified name. The priority is ignored. - function styleNull() { - this.style.removeProperty(name); - } - - // For style(name, string) or style(name, string, priority), set the style - // property with the specified name, using the specified priority. - // Otherwise, a name, value and priority are specified, and handled as below. - function styleString(b) { - return b == null ? styleNull : (b += "", function() { - var a = d3_window(this).getComputedStyle(this, null).getPropertyValue(name), i; - return a !== b && (i = d3_interpolate(a, b), function(t) { this.style.setProperty(name, i(t), priority); }); - }); - } - - return d3_transition_tween(this, "style." + name, value, styleString); -}; - -d3_transitionPrototype.styleTween = function(name, tween, priority) { - if (arguments.length < 3) priority = ""; - - function styleTween(d, i) { - var f = tween.call(this, d, i, d3_window(this).getComputedStyle(this, null).getPropertyValue(name)); - return f && function(t) { this.style.setProperty(name, f(t), priority); }; - } - - return this.tween("style." + name, styleTween); -}; - -d3_transitionPrototype.text = function(value) { - return d3_transition_tween(this, "text", value, d3_transition_text); -}; - -function d3_transition_text(b) { - if (b == null) b = ""; - return function() { this.textContent = b; }; -} - -d3_transitionPrototype.remove = function() { - var ns = this.namespace; - return this.each("end.transition", function() { - var p; - if (this[ns].count < 2 && (p = this.parentNode)) p.removeChild(this); - }); -}; - -var d3_ease_default = function() { return d3_identity; }; - -var d3_ease = d3.map({ - linear: d3_ease_default, - poly: d3_ease_poly, - quad: function() { return d3_ease_quad; }, - cubic: function() { return d3_ease_cubic; }, - sin: function() { return d3_ease_sin; }, - exp: function() { return d3_ease_exp; }, - circle: function() { return d3_ease_circle; }, - elastic: d3_ease_elastic, - back: d3_ease_back, - bounce: function() { return d3_ease_bounce; } -}); - -var d3_ease_mode = d3.map({ - "in": d3_identity, - "out": d3_ease_reverse, - "in-out": d3_ease_reflect, - "out-in": function(f) { return d3_ease_reflect(d3_ease_reverse(f)); } -}); - -d3.ease = function(name) { - var i = name.indexOf("-"), - t = i >= 0 ? name.slice(0, i) : name, - m = i >= 0 ? name.slice(i + 1) : "in"; - t = d3_ease.get(t) || d3_ease_default; - m = d3_ease_mode.get(m) || d3_identity; - return d3_ease_clamp(m(t.apply(null, d3_arraySlice.call(arguments, 1)))); -}; - -function d3_ease_clamp(f) { - return function(t) { - return t <= 0 ? 0 : t >= 1 ? 1 : f(t); - }; -} - -function d3_ease_reverse(f) { - return function(t) { - return 1 - f(1 - t); - }; -} - -function d3_ease_reflect(f) { - return function(t) { - return .5 * (t < .5 ? f(2 * t) : (2 - f(2 - 2 * t))); - }; -} - -function d3_ease_quad(t) { - return t * t; -} - -function d3_ease_cubic(t) { - return t * t * t; -} - -// Optimized clamp(reflect(poly(3))). -function d3_ease_cubicInOut(t) { - if (t <= 0) return 0; - if (t >= 1) return 1; - var t2 = t * t, t3 = t2 * t; - return 4 * (t < .5 ? t3 : 3 * (t - t2) + t3 - .75); -} - -function d3_ease_poly(e) { - return function(t) { - return Math.pow(t, e); - }; -} - -function d3_ease_sin(t) { - return 1 - Math.cos(t * halfπ); -} - -function d3_ease_exp(t) { - return Math.pow(2, 10 * (t - 1)); -} - -function d3_ease_circle(t) { - return 1 - Math.sqrt(1 - t * t); -} - -function d3_ease_elastic(a, p) { - var s; - if (arguments.length < 2) p = 0.45; - if (arguments.length) s = p / τ * Math.asin(1 / a); - else a = 1, s = p / 4; - return function(t) { - return 1 + a * Math.pow(2, -10 * t) * Math.sin((t - s) * τ / p); - }; -} - -function d3_ease_back(s) { - if (!s) s = 1.70158; - return function(t) { - return t * t * ((s + 1) * t - s); - }; -} - -function d3_ease_bounce(t) { - return t < 1 / 2.75 ? 7.5625 * t * t - : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75 - : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375 - : 7.5625 * (t -= 2.625 / 2.75) * t + .984375; -} - -d3_transitionPrototype.ease = function(value) { - var id = this.id, ns = this.namespace; - if (arguments.length < 1) return this.node()[ns][id].ease; - if (typeof value !== "function") value = d3.ease.apply(d3, arguments); - return d3_selection_each(this, function(node) { node[ns][id].ease = value; }); -}; - -d3_transitionPrototype.delay = function(value) { - var id = this.id, ns = this.namespace; - if (arguments.length < 1) return this.node()[ns][id].delay; - return d3_selection_each(this, typeof value === "function" - ? function(node, i, j) { node[ns][id].delay = +value.call(node, node.__data__, i, j); } - : (value = +value, function(node) { node[ns][id].delay = value; })); -}; - -d3_transitionPrototype.duration = function(value) { - var id = this.id, ns = this.namespace; - if (arguments.length < 1) return this.node()[ns][id].duration; - return d3_selection_each(this, typeof value === "function" - ? function(node, i, j) { node[ns][id].duration = Math.max(1, value.call(node, node.__data__, i, j)); } - : (value = Math.max(1, value), function(node) { node[ns][id].duration = value; })); -}; - -d3_transitionPrototype.each = function(type, listener) { - var id = this.id, ns = this.namespace; - if (arguments.length < 2) { - var inherit = d3_transitionInherit, - inheritId = d3_transitionInheritId; - try { - d3_transitionInheritId = id; - d3_selection_each(this, function(node, i, j) { - d3_transitionInherit = node[ns][id]; - type.call(node, node.__data__, i, j); - }); - } finally { - d3_transitionInherit = inherit; - d3_transitionInheritId = inheritId; - } - } else { - d3_selection_each(this, function(node) { - var transition = node[ns][id]; - (transition.event || (transition.event = d3.dispatch("start", "end", "interrupt"))).on(type, listener); - }); - } - return this; -}; - -d3_transitionPrototype.transition = function() { - var id0 = this.id, - id1 = ++d3_transitionId, - ns = this.namespace, - subgroups = [], - subgroup, - group, - node, - transition; - - for (var j = 0, m = this.length; j < m; j++) { - subgroups.push(subgroup = []); - for (var group = this[j], i = 0, n = group.length; i < n; i++) { - if (node = group[i]) { - transition = node[ns][id0]; - d3_transitionNode(node, i, ns, id1, {time: transition.time, ease: transition.ease, delay: transition.delay + transition.duration, duration: transition.duration}); - } - subgroup.push(node); - } - } - - return d3_transition(subgroups, ns, id1); -}; - -function d3_transitionNamespace(name) { - return name == null ? "__transition__" : "__transition_" + name + "__"; -} - -function d3_transitionNode(node, i, ns, id, inherit) { - var lock = node[ns] || (node[ns] = {active: 0, count: 0}), - transition = lock[id]; - - if (!transition) { - var time = inherit.time; - - transition = lock[id] = { - tween: new d3_Map, - time: time, - delay: inherit.delay, - duration: inherit.duration, - ease: inherit.ease, - index: i - }; - - inherit = null; // allow gc - - ++lock.count; - - d3.timer(function(elapsed) { - var delay = transition.delay, - duration, - ease, - timer = d3_timer_active, - tweened = []; - - timer.t = delay + time; - if (delay <= elapsed) return start(elapsed - delay); - timer.c = start; - - function start(elapsed) { - if (lock.active > id) return stop(); - - var active = lock[lock.active]; - if (active) { - --lock.count; - delete lock[lock.active]; - active.event && active.event.interrupt.call(node, node.__data__, active.index); - } - - lock.active = id; - - transition.event && transition.event.start.call(node, node.__data__, i); - - transition.tween.forEach(function(key, value) { - if (value = value.call(node, node.__data__, i)) { - tweened.push(value); - } - }); - - // Deferred capture to allow tweens to initialize ease & duration. - ease = transition.ease; - duration = transition.duration; - - d3.timer(function() { // defer to end of current frame - timer.c = tick(elapsed || 1) ? d3_true : tick; - return 1; - }, 0, time); - } - - function tick(elapsed) { - if (lock.active !== id) return 1; - - var t = elapsed / duration, - e = ease(t), - n = tweened.length; - - while (n > 0) { - tweened[--n].call(node, e); - } - - if (t >= 1) { - transition.event && transition.event.end.call(node, node.__data__, i); - return stop(); - } - } - - function stop() { - if (--lock.count) delete lock[id]; - else delete node[ns]; - return 1; - } - }, 0, time); - } -} - -d3.xhr = d3_xhrType(d3_identity); - -function d3_xhrType(response) { - return function(url, mimeType, callback) { - if (arguments.length === 2 && typeof mimeType === "function") callback = mimeType, mimeType = null; - return d3_xhr(url, mimeType, response, callback); - }; -} - -function d3_xhr(url, mimeType, response, callback) { - var xhr = {}, - dispatch = d3.dispatch("beforesend", "progress", "load", "error"), - headers = {}, - request = new XMLHttpRequest, - responseType = null; - - // If IE does not support CORS, use XDomainRequest. - if (this.XDomainRequest - && !("withCredentials" in request) - && /^(http(s)?:)?\/\//.test(url)) request = new XDomainRequest; - - "onload" in request - ? request.onload = request.onerror = respond - : request.onreadystatechange = function() { request.readyState > 3 && respond(); }; - - function respond() { - var status = request.status, result; - if (!status && d3_xhrHasResponse(request) || status >= 200 && status < 300 || status === 304) { - try { - result = response.call(xhr, request); - } catch (e) { - dispatch.error.call(xhr, e); - return; - } - dispatch.load.call(xhr, result); - } else { - dispatch.error.call(xhr, request); - } - } - - request.onprogress = function(event) { - var o = d3.event; - d3.event = event; - try { dispatch.progress.call(xhr, request); } - finally { d3.event = o; } - }; - - xhr.header = function(name, value) { - name = (name + "").toLowerCase(); - if (arguments.length < 2) return headers[name]; - if (value == null) delete headers[name]; - else headers[name] = value + ""; - return xhr; - }; - - // If mimeType is non-null and no Accept header is set, a default is used. - xhr.mimeType = function(value) { - if (!arguments.length) return mimeType; - mimeType = value == null ? null : value + ""; - return xhr; - }; - - // Specifies what type the response value should take; - // for instance, arraybuffer, blob, document, or text. - xhr.responseType = function(value) { - if (!arguments.length) return responseType; - responseType = value; - return xhr; - }; - - // Specify how to convert the response content to a specific type; - // changes the callback value on "load" events. - xhr.response = function(value) { - response = value; - return xhr; - }; - - // Convenience methods. - ["get", "post"].forEach(function(method) { - xhr[method] = function() { - return xhr.send.apply(xhr, [method].concat(d3_array(arguments))); - }; - }); - - // If callback is non-null, it will be used for error and load events. - xhr.send = function(method, data, callback) { - if (arguments.length === 2 && typeof data === "function") callback = data, data = null; - request.open(method, url, true); - if (mimeType != null && !("accept" in headers)) headers["accept"] = mimeType + ",*/*"; - if (request.setRequestHeader) for (var name in headers) request.setRequestHeader(name, headers[name]); - if (mimeType != null && request.overrideMimeType) request.overrideMimeType(mimeType); - if (responseType != null) request.responseType = responseType; - if (callback != null) xhr.on("error", callback).on("load", function(request) { callback(null, request); }); - dispatch.beforesend.call(xhr, request); - request.send(data == null ? null : data); - return xhr; - }; - - xhr.abort = function() { - request.abort(); - return xhr; - }; - - d3.rebind(xhr, dispatch, "on"); - - return callback == null ? xhr : xhr.get(d3_xhr_fixCallback(callback)); -}; - -function d3_xhr_fixCallback(callback) { - return callback.length === 1 - ? function(error, request) { callback(error == null ? request : null); } - : callback; -} - -function d3_xhrHasResponse(request) { - var type = request.responseType; - return type && type !== "text" - ? request.response // null on error - : request.responseText; // "" on error -} - -d3.text = d3_xhrType(function(request) { - return request.responseText; -}); - -d3.json = function(url, callback) { - return d3_xhr(url, "application/json", d3_json, callback); -}; - -function d3_json(request) { - return JSON.parse(request.responseText); -} - -d3.html = function(url, callback) { - return d3_xhr(url, "text/html", d3_html, callback); -}; - -function d3_html(request) { - var range = d3_document.createRange(); - range.selectNode(d3_document.body); - return range.createContextualFragment(request.responseText); -} - -d3.xml = d3_xhrType(function(request) { - return request.responseXML; -}); - if (typeof define === "function" && define.amd) define(d3); - else if (typeof module === "object" && module.exports) module.exports = d3; diff --git a/js/lib/index.js b/js/lib/index.js deleted file mode 100644 index 0e64623e4..000000000 --- a/js/lib/index.js +++ /dev/null @@ -1,9 +0,0 @@ -require('./d3.combobox'); -require('./d3.geo.tile'); -require('./d3.keybinding'); -require('./d3.one'); -require('./d3.dimensions'); -require('./d3.trigger'); -require('./d3.curtain'); -require('./d3.value'); -require('./d3-compat'); diff --git a/modules/actions/circularize.js b/modules/actions/circularize.js index 582baee9e..f4e56098b 100644 --- a/modules/actions/circularize.js +++ b/modules/actions/circularize.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import { euclideanDistance, interp } from '../geo/index'; import { Node } from '../core/index'; import _ from 'lodash'; @@ -17,9 +18,9 @@ export function Circularize(wayId keyNodes = nodes.filter(function(n) { return graph.parentWays(n).length !== 1; }), points = nodes.map(function(n) { return projection(n.loc); }), keyPoints = keyNodes.map(function(n) { return projection(n.loc); }), - centroid = (points.length === 2) ? interp(points[0], points[1], 0.5) : d3.geom.polygon(points).centroid(), + centroid = (points.length === 2) ? interp(points[0], points[1], 0.5) : d3.geoCentroid({ type: 'Polygon', coordinates: points }), radius = d3.median(points, function(p) { return euclideanDistance(centroid, p); }), - sign = d3.geom.polygon(points).area() > 0 ? 1 : -1, + sign = d3.polygonArea(points) > 0 ? 1 : -1, ids; // we need atleast two key nodes for the algorithm to work @@ -151,8 +152,8 @@ export function Circularize(wayId var way = graph.entity(wayId), nodes = _.uniq(graph.childNodes(way)), points = nodes.map(function(n) { return projection(n.loc); }), - sign = d3.geom.polygon(points).area() > 0 ? 1 : -1, - hull = d3.geom.hull(points); + sign = d3.polygonArea(points) > 0 ? 1 : -1, + hull = d3.polygonHull(points); // D3 convex hulls go counterclockwise.. if (sign === -1) { diff --git a/modules/behavior/add_way.js b/modules/behavior/add_way.js index 62cd3544f..1633f5c66 100644 --- a/modules/behavior/add_way.js +++ b/modules/behavior/add_way.js @@ -1,3 +1,5 @@ +import { rebind } from '../util/rebind'; +import * as d3 from 'd3'; import { Browse } from '../modes/index'; import { Draw } from './draw'; @@ -35,5 +37,5 @@ export function AddWay(context) { return addWay; }; - return d3.rebind(addWay, event, 'on'); + return rebind(addWay, event, 'on'); } diff --git a/modules/behavior/breathe.js b/modules/behavior/breathe.js index bf681c7d7..583295c0b 100644 --- a/modules/behavior/breathe.js +++ b/modules/behavior/breathe.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import _ from 'lodash'; export function Breathe(){ var duration = 800, diff --git a/modules/behavior/copy.js b/modules/behavior/copy.js index 225b32c2a..6c5deddbb 100644 --- a/modules/behavior/copy.js +++ b/modules/behavior/copy.js @@ -1,7 +1,9 @@ +import { d3keybinding } from '../../js/lib/d3.keybinding.js'; +import * as d3 from 'd3'; import _ from 'lodash'; import { cmd } from '../ui/index'; export function Copy(context) { - var keybinding = d3.keybinding('copy'); + var keybinding = d3keybinding('copy'); function groupEntities(ids, graph) { var entities = ids.map(function (id) { return graph.entity(id); }); diff --git a/modules/behavior/drag.js b/modules/behavior/drag.js index 6e3665533..5aa661321 100644 --- a/modules/behavior/drag.js +++ b/modules/behavior/drag.js @@ -1,3 +1,5 @@ +import { rebind } from '../util/rebind'; +import * as d3 from 'd3'; import { prefixCSSProperty, prefixDOMProperty } from '../util/index'; /* `iD.behavior.drag` is like `d3.behavior.drag`, with the following differences: @@ -31,11 +33,12 @@ export function drag() { return function(e1) { var e0 = e1.sourceEvent = d3.event; e1.target = drag; - d3.event = e1; + // TODO + // d3.event = e1; try { event[e1.type].apply(thiz, argumentz); } finally { - d3.event = e0; + // d3.event = e0; } }; }; @@ -59,7 +62,7 @@ export function drag() { function mousedown() { target = this; - event_ = event.of(target, arguments); + event_ = event.call("of", target, arguments); var eventTarget = d3.event.target, touchId = d3.event.touches ? d3.event.changedTouches[0].identifier : null, offset, @@ -188,7 +191,7 @@ export function drag() { drag.target = function() { if (!arguments.length) return target; target = arguments[0]; - event_ = event.of(target, Array.prototype.slice.call(arguments, 1)); + event_ = event.call("of", target, Array.prototype.slice.call(arguments, 1)); return drag; }; @@ -198,5 +201,5 @@ export function drag() { return drag; }; - return d3.rebind(drag, event, 'on'); + return rebind(drag, event, 'on'); } diff --git a/modules/behavior/draw.js b/modules/behavior/draw.js index 5e5705429..d599331b3 100644 --- a/modules/behavior/draw.js +++ b/modules/behavior/draw.js @@ -1,3 +1,7 @@ +import { rebind } from '../util/rebind'; +import { getDimensions } from '../util/dimensions'; +import { d3keybinding } from '../../js/lib/d3.keybinding.js'; +import * as d3 from 'd3'; import { chooseEdge, euclideanDistance } from '../geo/index'; import { Edit } from './edit'; import { Hover } from './hover'; @@ -6,7 +10,7 @@ import { Tail } from './tail'; export function Draw(context) { var event = d3.dispatch('move', 'click', 'clickWay', 'clickNode', 'undo', 'cancel', 'finish'), - keybinding = d3.keybinding('draw'), + keybinding = d3keybinding('draw'), hover = Hover(context) .altDisables(true) .on('hover', context.ui().sidebar.hover), @@ -72,7 +76,7 @@ export function Draw(context) { function mousemove() { lastMouse = d3.event; - event.move(datum()); + event.call("move", datum()); } function mouseenter() { @@ -86,7 +90,7 @@ export function Draw(context) { function click() { var d = datum(); if (d.type === 'way') { - var dims = context.map().dimensions(), + var dims = getDimensions(context.map()), mouse = context.mouse(), pad = 5, trySnap = mouse[0] > pad && mouse[0] < dims[0] - pad && @@ -95,16 +99,16 @@ export function Draw(context) { if (trySnap) { var choice = chooseEdge(context.childNodes(d), context.mouse(), context.projection), edge = [d.nodes[choice.index - 1], d.nodes[choice.index]]; - event.clickWay(choice.loc, edge); + event.call("clickWay", choice.loc, edge); } else { - event.click(context.map().mouseCoordinates()); + event.call("click", context.map().mouseCoordinates()); } } else if (d.type === 'node') { - event.clickNode(d); + event.call("clickNode", d); } else { - event.click(context.map().mouseCoordinates()); + event.call("click", context.map().mouseCoordinates()); } } @@ -134,17 +138,17 @@ export function Draw(context) { function backspace() { d3.event.preventDefault(); - event.undo(); + event.call("undo"); } function del() { d3.event.preventDefault(); - event.cancel(); + event.call("cancel"); } function ret() { d3.event.preventDefault(); - event.finish(); + event.call("finish"); } function draw(selection) { @@ -204,7 +208,7 @@ export function Draw(context) { return draw; }; - return d3.rebind(draw, event, 'on'); + return rebind(draw, event, 'on'); } Draw.usedTails = {}; diff --git a/modules/behavior/draw_way.js b/modules/behavior/draw_way.js index 9a7884219..174480295 100644 --- a/modules/behavior/draw_way.js +++ b/modules/behavior/draw_way.js @@ -1,11 +1,13 @@ +import * as d3 from 'd3'; import { t } from '../util/locale'; +import { getDimensions } from '../util/dimensions'; import _ from 'lodash'; import { AddEntity, AddMidpoint, AddVertex, MoveNode } from '../actions/index'; import { Browse, Select } from '../modes/index'; import { Node, Way } from '../core/index'; import { chooseEdge, edgeEqual } from '../geo/index'; import { Draw } from './draw'; -import { entitySelector } from '../util/index'; +import { entitySelector, functor } from '../util/index'; export function DrawWay(context, wayId, index, mode, baseGraph) { var way = context.entity(wayId), @@ -41,7 +43,7 @@ export function DrawWay(context, wayId, index, mode, baseGraph) { loc = datum.loc; } else if (datum.type === 'way' && datum.id !== segment.id) { - var dims = context.map().dimensions(), + var dims = getDimensions(context.map()), mouse = context.mouse(), pad = 5, trySnap = mouse[0] > pad && mouse[0] < dims[0] - pad && @@ -199,7 +201,7 @@ export function DrawWay(context, wayId, index, mode, baseGraph) { // Cancel the draw operation and return to browse, deleting everything drawn. drawWay.cancel = function() { context.perform( - d3.functor(baseGraph), + functor(baseGraph), t('operations.cancel_draw.annotation')); window.setTimeout(function() { diff --git a/modules/behavior/hash.js b/modules/behavior/hash.js index 34908034c..1024a8766 100644 --- a/modules/behavior/hash.js +++ b/modules/behavior/hash.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import _ from 'lodash'; import { qsString, stringQs } from '../util/index'; export function Hash(context) { diff --git a/modules/behavior/hover.js b/modules/behavior/hover.js index 797193eee..1d4fb4533 100644 --- a/modules/behavior/hover.js +++ b/modules/behavior/hover.js @@ -1,3 +1,6 @@ +import { rebind } from '../util/rebind'; +import { d3keybinding } from '../../js/lib/d3.keybinding.js'; +import * as d3 from 'd3'; import { Entity } from '../core/index'; /* The hover behavior adds the `.hover` class on mouseover to all elements to which @@ -15,8 +18,8 @@ export function Hover() { target; function keydown() { - if (altDisables && d3.event.keyCode === d3.keybinding.modifierCodes.alt) { - dispatch.hover(null); + if (altDisables && d3.event.keyCode === d3keybinding.modifierCodes.alt) { + dispatch.call("hover", this, null); selection.selectAll('.hover') .classed('hover-suppressed', true) .classed('hover', false); @@ -24,8 +27,8 @@ export function Hover() { } function keyup() { - if (altDisables && d3.event.keyCode === d3.keybinding.modifierCodes.alt) { - dispatch.hover(target ? target.id : null); + if (altDisables && d3.event.keyCode === d3keybinding.modifierCodes.alt) { + dispatch.call("hover", this, target ? target.id : null); selection.selectAll('.hover-suppressed') .classed('hover-suppressed', false) .classed('hover', true); @@ -59,9 +62,9 @@ export function Hover() { selection.selectAll(selector) .classed(suppressed ? 'hover-suppressed' : 'hover', true); - dispatch.hover(target.id); + dispatch.call("hover", this, target.id); } else { - dispatch.hover(null); + dispatch.call("hover", this, null); } } @@ -124,5 +127,5 @@ export function Hover() { return hover; }; - return d3.rebind(hover, dispatch, 'on'); + return rebind(hover, dispatch, 'on'); } diff --git a/modules/behavior/lasso.js b/modules/behavior/lasso.js index f21fc8e93..9c9ce10f9 100644 --- a/modules/behavior/lasso.js +++ b/modules/behavior/lasso.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import _ from 'lodash'; import { Extent, pointInPolygon } from '../geo/index'; import { Select } from '../modes/index'; diff --git a/modules/behavior/paste.js b/modules/behavior/paste.js index 43a59cce8..1d496e5a5 100644 --- a/modules/behavior/paste.js +++ b/modules/behavior/paste.js @@ -1,3 +1,5 @@ +import { d3keybinding } from '../../js/lib/d3.keybinding.js'; +import * as d3 from 'd3'; import _ from 'lodash'; import { ChangeTags, CopyEntities, Move as MoveAction} from '../actions/index'; import { Extent, pointInPolygon } from '../geo/index'; @@ -5,7 +7,7 @@ import { Move as MoveMode } from '../modes/index'; import { cmd } from '../ui/index'; export function Paste(context) { - var keybinding = d3.keybinding('paste'); + var keybinding = d3keybinding('paste'); function omitTag(v, k) { return ( diff --git a/modules/behavior/select.js b/modules/behavior/select.js index 3dee7aabf..136276903 100644 --- a/modules/behavior/select.js +++ b/modules/behavior/select.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import _ from 'lodash'; import { Browse, Select as SelectMode } from '../modes/index'; import { Entity } from '../core/index'; diff --git a/modules/behavior/tail.js b/modules/behavior/tail.js index c90ce3f03..03dbbb39c 100644 --- a/modules/behavior/tail.js +++ b/modules/behavior/tail.js @@ -1,4 +1,6 @@ +import * as d3 from 'd3'; import { setTransform } from '../util/index'; +import { getDimensions } from '../util/dimensions'; export function Tail() { var text, container, @@ -10,11 +12,11 @@ export function Tail() { if (!text) return; d3.select(window) - .on('resize.tail', function() { selectionSize = selection.dimensions(); }); + .on('resize.tail', function() { selectionSize = getDimensions(selection); }); function show() { container.style('display', 'block'); - tooltipSize = container.dimensions(); + tooltipSize = getDimensions(container); } function mousemove() { @@ -53,8 +55,8 @@ export function Tail() { container .on('mousemove.tail', mousemove); - tooltipSize = container.dimensions(); - selectionSize = selection.dimensions(); + tooltipSize = getDimensions(container); + selectionSize = getDimensions(selection); } tail.off = function(selection) { diff --git a/modules/core/connection.js b/modules/core/connection.js index c3a312867..624aa519d 100644 --- a/modules/core/connection.js +++ b/modules/core/connection.js @@ -1,3 +1,7 @@ +import { rebind } from '../util/rebind'; +import { functor } from '../util/index'; +import { d3geoTile } from '../../js/lib/d3.geo.tile'; +import * as d3 from 'd3'; import _ from 'lodash'; import { Detect } from '../util/detect'; import { Entity } from './entity'; @@ -102,11 +106,11 @@ export function Connection(useHttps) { }; function authenticating() { - event.authenticating(); + event.call("authenticating"); } function authenticated() { - event.authenticated(); + event.call("authenticated"); } function getLoc(attrs) { @@ -298,7 +302,7 @@ export function Connection(useHttps) { method: 'PUT', path: '/api/0.6/changeset/' + changeset_id + '/close', options: { header: { 'Content-Type': 'text/xml' } } - }, d3.functor(true)); + }, functor(true)); }); }); }; @@ -378,7 +382,7 @@ export function Connection(useHttps) { s / 2 - projection.translate()[0], s / 2 - projection.translate()[1]]; - var tiles = d3.geo.tile() + var tiles = d3geoTile() .scaleExtent([tileZoom, tileZoom]) .scale(s) .size(dimensions) @@ -413,7 +417,7 @@ export function Connection(useHttps) { if (loadedTiles[id] || inflight[id]) return; if (_.isEmpty(inflight)) { - event.loading(); + event.call("loading"); } inflight[id] = connection.loadFromURL(bboxUrl(tile), function(err, parsed) { @@ -423,7 +427,7 @@ export function Connection(useHttps) { if (callback) callback(err, _.extend({data: parsed}, tile)); if (_.isEmpty(inflight)) { - event.loaded(); + event.call("loaded"); } }); }); @@ -435,7 +439,7 @@ export function Connection(useHttps) { loading: authenticating, done: authenticated }, options)); - event.auth(); + event.call("auth"); connection.flush(); return connection; }; @@ -462,18 +466,18 @@ export function Connection(useHttps) { connection.logout = function() { userDetails = undefined; oauth.logout(); - event.auth(); + event.call("auth"); return connection; }; connection.authenticate = function(callback) { userDetails = undefined; function done(err, res) { - event.auth(); + event.call("auth"); if (callback) callback(err, res); } return oauth.authenticate(done); }; - return d3.rebind(connection, event, 'on'); + return rebind(connection, event, 'on'); } diff --git a/modules/core/context.js b/modules/core/context.js index d8ede141b..3e27f4f83 100644 --- a/modules/core/context.js +++ b/modules/core/context.js @@ -1,3 +1,5 @@ +import { rebind } from '../util/rebind'; +import * as d3 from 'd3'; import { t, addTranslation, setLocale } from '../util/locale'; import _ from 'lodash'; import { Background } from '../renderer/background'; @@ -170,12 +172,12 @@ export function Context(root) { context.enter = function(newMode) { if (mode) { mode.exit(); - dispatch.exit(mode); + dispatch.call("exit", this, mode); } mode = newMode; mode.enter(); - dispatch.enter(mode); + dispatch.call("enter", this, mode); }; context.selectedIDs = function() { @@ -251,7 +253,7 @@ export function Context(root) { context.setDebug = function(flag, val) { if (arguments.length === 1) val = true; debugFlags[flag] = val; - dispatch.change(); + dispatch.call("change"); return context; }; context.getDebug = function(flag) { @@ -399,6 +401,6 @@ export function Context(root) { presets = presetsInit(); - return d3.rebind(context, dispatch, 'on'); + return rebind(context, dispatch, 'on'); } diff --git a/modules/core/difference.js b/modules/core/difference.js index 9d819879a..a8c3da9b7 100644 --- a/modules/core/difference.js +++ b/modules/core/difference.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import _ from 'lodash'; /* iD.Difference represents the difference between two graphs. diff --git a/modules/core/entity.js b/modules/core/entity.js index 5fc2253d4..ae0d22ecd 100644 --- a/modules/core/entity.js +++ b/modules/core/entity.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import _ from 'lodash'; import { debug } from '../index'; import { interestingTag } from './tags'; diff --git a/modules/core/history.js b/modules/core/history.js index c41e58de1..28f328f72 100644 --- a/modules/core/history.js +++ b/modules/core/history.js @@ -1,3 +1,5 @@ +import { rebind } from '../util/rebind'; +import * as d3 from 'd3'; import _ from 'lodash'; import * as Validations from '../validations/index'; import { Difference } from './difference'; @@ -36,7 +38,7 @@ export function History(context) { function change(previous) { var difference = Difference(previous, history.graph()); - dispatch.change(difference); + dispatch.call("change", this, difference); return difference; } @@ -58,7 +60,7 @@ export function History(context) { stack[0].graph.rebase(entities, _.map(stack, 'graph'), false); tree.rebase(entities, false); - dispatch.change(undefined, extent); + dispatch.call("change", this, undefined, extent); }, perform: function() { @@ -114,7 +116,7 @@ export function History(context) { if (stack[index].annotation) break; } - dispatch.undone(); + dispatch.call("undone"); return change(previous); }, @@ -126,7 +128,7 @@ export function History(context) { if (stack[index].annotation) break; } - dispatch.redone(); + dispatch.call("redone"); return change(previous); }, @@ -202,7 +204,7 @@ export function History(context) { stack = [{graph: Graph()}]; index = 0; tree = Tree(stack[0].graph); - dispatch.change(); + dispatch.call("change"); return history; }, @@ -317,7 +319,7 @@ export function History(context) { if (err || _.isEmpty(missing)) { loading.close(); context.redrawEnable(true); - dispatch.change(); + dispatch.call("change"); } }; @@ -364,7 +366,7 @@ export function History(context) { } if (loadComplete) { - dispatch.change(); + dispatch.call("change"); } return history; @@ -409,5 +411,5 @@ export function History(context) { history.reset(); - return d3.rebind(history, dispatch, 'on'); + return rebind(history, dispatch, 'on'); } diff --git a/modules/core/relation.js b/modules/core/relation.js index dd080863a..972ab8f95 100644 --- a/modules/core/relation.js +++ b/modules/core/relation.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import _ from 'lodash'; import { Extent, joinWays, polygonContainsPolygon, polygonIntersectsPolygon } from '../geo/index'; import { Entity } from './entity'; @@ -191,7 +192,7 @@ _.extend(Relation.prototype, { area: function(resolver) { return resolver.transient(this, 'area', function() { - return d3.geo.area(this.asGeoJSON(resolver)); + return d3.geoArea(this.asGeoJSON(resolver)); }); }, @@ -235,7 +236,7 @@ _.extend(Relation.prototype, { var result = outers.map(function(o) { // Heuristic for detecting counterclockwise winding order. Assumes // that OpenStreetMap polygons are not hemisphere-spanning. - return [d3.geo.area({type: 'Polygon', coordinates: [o]}) > 2 * Math.PI ? o.reverse() : o]; + return [d3.geoArea({type: 'Polygon', coordinates: [o]}) > 2 * Math.PI ? o.reverse() : o]; }); function findOuter(inner) { @@ -257,7 +258,7 @@ _.extend(Relation.prototype, { for (var i = 0; i < inners.length; i++) { var inner = inners[i]; - if (d3.geo.area({type: 'Polygon', coordinates: [inner]}) < 2 * Math.PI) { + if (d3.geoArea({type: 'Polygon', coordinates: [inner]}) < 2 * Math.PI) { inner = inner.reverse(); } diff --git a/modules/core/way.js b/modules/core/way.js index 319e2aefd..419c81027 100644 --- a/modules/core/way.js +++ b/modules/core/way.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import _ from 'lodash'; import { Extent, cross } from '../geo/index'; import { Entity } from './entity'; @@ -336,13 +337,13 @@ _.extend(Way.prototype, { json.coordinates[0].push(nodes[0].loc); } - var area = d3.geo.area(json); + var area = d3.geoArea(json); // Heuristic for detecting counterclockwise winding order. Assumes // that OpenStreetMap polygons are not hemisphere-spanning. if (area > 2 * Math.PI) { json.coordinates[0] = json.coordinates[0].reverse(); - area = d3.geo.area(json); + area = d3.geoArea(json); } return isNaN(area) ? 0 : area; diff --git a/modules/geo/raw_mercator.js b/modules/geo/raw_mercator.js index 5e95019ed..290eae1d6 100644 --- a/modules/geo/raw_mercator.js +++ b/modules/geo/raw_mercator.js @@ -1,3 +1,5 @@ +import * as d3 from 'd3'; + /* Bypasses features of D3's default projection stream pipeline that are unnecessary: * Antimeridian clipping @@ -5,7 +7,7 @@ * Resampling */ export function RawMercator() { - var project = d3.geo.mercator.raw, + var project = d3.geoMercatorRaw, k = 512 / Math.PI, // scale x = 0, y = 0, // translate clipExtent = [[0, 0], [0, 0]]; @@ -39,7 +41,7 @@ export function RawMercator() { return projection; }; - projection.stream = d3.geo.transform({ + projection.stream = d3.geoTransform({ point: function(x, y) { x = projection([x, y]); this.stream.point(x[0], x[1]); diff --git a/modules/id.js b/modules/id.js index 57e8b55cd..ca50e84f9 100644 --- a/modules/id.js +++ b/modules/id.js @@ -1,3 +1,2 @@ -import '../js/lib/index'; import * as iD from './index'; window.iD = iD; diff --git a/modules/modes/drag_node.js b/modules/modes/drag_node.js index 835c0168a..d4c298b20 100644 --- a/modules/modes/drag_node.js +++ b/modules/modes/drag_node.js @@ -1,4 +1,6 @@ +import * as d3 from 'd3'; import { t } from '../util/locale'; +import { getDimensions } from '../util/dimensions'; import _ from 'lodash'; import { AddMidpoint, Connect, MoveNode, Noop } from '../actions/index'; import { Browse, Select } from './index'; @@ -104,7 +106,7 @@ export function DragNode(context) { var nudge = childOf(context.container().node(), d3.event.sourceEvent.toElement) && - edge(d3.event.point, context.map().dimensions()); + edge(d3.event.point, getDimensions(context.map())); if (nudge) startNudge(nudge); else stopNudge(); diff --git a/modules/modes/move.js b/modules/modes/move.js index 1b55ab14b..1ef61c133 100644 --- a/modules/modes/move.js +++ b/modules/modes/move.js @@ -1,4 +1,7 @@ +import { d3keybinding } from '../../js/lib/d3.keybinding.js'; +import * as d3 from 'd3'; import { t } from '../util/locale'; +import { getDimensions } from '../util/dimensions'; import { Browse, Select } from './index'; import { Move as MoveAction, Noop } from '../actions/index'; import { Edit } from '../behavior/index'; @@ -9,7 +12,7 @@ export function Move(context, entityIDs, baseGraph) { button: 'browse' }; - var keybinding = d3.keybinding('move'), + var keybinding = d3keybinding('move'), edit = Edit(context), annotation = entityIDs.length === 1 ? t('operations.move.annotation.' + context.geometry(entityIDs[0])) : @@ -57,7 +60,7 @@ export function Move(context, entityIDs, baseGraph) { context.overwrite(action, annotation); - var nudge = edge(currMouse, context.map().dimensions()); + var nudge = edge(currMouse, getDimensions(context.map())); if (nudge) startNudge(nudge); else stopNudge(); } diff --git a/modules/modes/rotate_way.js b/modules/modes/rotate_way.js index 71338e539..8a3a0044b 100644 --- a/modules/modes/rotate_way.js +++ b/modules/modes/rotate_way.js @@ -1,3 +1,5 @@ +import { d3keybinding } from '../../js/lib/d3.keybinding.js'; +import * as d3 from 'd3'; import { t } from '../util/locale'; import _ from 'lodash'; import { Browse, Select } from './index'; @@ -10,7 +12,7 @@ export function RotateWay(context, wayId) { button: 'browse' }; - var keybinding = d3.keybinding('rotate-way'), + var keybinding = d3keybinding('rotate-way'), edit = Edit(context); mode.enter = function() { @@ -20,7 +22,7 @@ export function RotateWay(context, wayId) { way = context.graph().entity(wayId), nodes = _.uniq(context.graph().childNodes(way)), points = nodes.map(function(n) { return context.projection(n.loc); }), - pivot = d3.geom.polygon(points).centroid(), + pivot = d3.polygonCentroid(points), angle; context.perform( diff --git a/modules/modes/save.js b/modules/modes/save.js index 3ebb34b27..921a566c3 100644 --- a/modules/modes/save.js +++ b/modules/modes/save.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import { t } from '../util/locale'; import _ from 'lodash'; import { Commit, Conflicts, Loading, Success } from '../ui/index'; diff --git a/modules/modes/select.js b/modules/modes/select.js index 28acd43dc..ef736c8f0 100644 --- a/modules/modes/select.js +++ b/modules/modes/select.js @@ -1,3 +1,5 @@ +import { d3keybinding } from '../../js/lib/d3.keybinding.js'; +import * as d3 from 'd3'; import { t } from '../util/locale'; import _ from 'lodash'; import * as Operations from '../operations/index'; @@ -16,7 +18,7 @@ export function Select(context, selectedIDs) { button: 'browse' }; - var keybinding = d3.keybinding('select'), + var keybinding = d3keybinding('select'), timeout = null, behaviors = [ Copy(context), diff --git a/modules/renderer/background.js b/modules/renderer/background.js index 8c384a9b2..f80c09e03 100644 --- a/modules/renderer/background.js +++ b/modules/renderer/background.js @@ -1,3 +1,5 @@ +import { rebind } from '../util/rebind'; +import * as d3 from 'd3'; import _ from 'lodash'; import { Extent, metersToOffset, offsetToMeters} from '../geo/index'; import { qsString, stringQs } from '../util/index'; @@ -112,6 +114,7 @@ export function Background(context) { }; background.dimensions = function(_) { + if (!_) return; baseLayer.dimensions(_); overlayLayers.forEach(function(layer) { @@ -122,7 +125,7 @@ export function Background(context) { background.baseLayerSource = function(d) { if (!arguments.length) return baseLayer.source(); baseLayer.source(d); - dispatch.change(); + dispatch.call("change"); background.updateImagery(); return background; }; @@ -148,7 +151,7 @@ export function Background(context) { layer = overlayLayers[i]; if (layer.source() === d) { overlayLayers.splice(i, 1); - dispatch.change(); + dispatch.call("change"); background.updateImagery(); return; } @@ -160,13 +163,13 @@ export function Background(context) { .dimensions(baseLayer.dimensions()); overlayLayers.push(layer); - dispatch.change(); + dispatch.call("change"); background.updateImagery(); }; background.nudge = function(d, zoom) { baseLayer.source().nudge(d, zoom); - dispatch.change(); + dispatch.call("change"); background.updateImagery(); return background; }; @@ -174,7 +177,7 @@ export function Background(context) { background.offset = function(d) { if (!arguments.length) return baseLayer.source().offset(); baseLayer.source().offset(d); - dispatch.change(); + dispatch.call("change"); background.updateImagery(); return background; }; @@ -246,5 +249,5 @@ export function Background(context) { } }; - return d3.rebind(background, dispatch, 'on'); + return rebind(background, dispatch, 'on'); } diff --git a/modules/renderer/background_source.js b/modules/renderer/background_source.js index cb1396ba0..505256434 100644 --- a/modules/renderer/background_source.js +++ b/modules/renderer/background_source.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import { t } from '../util/locale'; import _ from 'lodash'; import { Extent, polygonIntersectsPolygon } from '../geo/index'; @@ -34,7 +35,7 @@ export function BackgroundSource(data) { source.area = function() { if (!data.polygon) return Number.MAX_VALUE; // worldwide - var area = d3.geo.area({ type: 'MultiPolygon', coordinates: [ data.polygon ] }); + var area = d3.geoArea({ type: 'MultiPolygon', coordinates: [ data.polygon ] }); return isNaN(area) ? 0 : area; }; @@ -111,7 +112,7 @@ BackgroundSource.Bing = function(data, dispatch) { }) }; }); - dispatch.change(); + dispatch.call("change"); }); bing.copyrightNotices = function(zoom, extent) { diff --git a/modules/renderer/features.js b/modules/renderer/features.js index 3b4db372c..3f80044ef 100644 --- a/modules/renderer/features.js +++ b/modules/renderer/features.js @@ -1,3 +1,5 @@ +import { rebind } from '../util/rebind'; +import * as d3 from 'd3'; import _ from 'lodash'; import { Entity } from '../core/index'; export function Features(context) { @@ -54,8 +56,8 @@ export function Features(context) { function update() { _hidden = features.hidden(); - dispatch.change(); - dispatch.redraw(); + dispatch.call("change"); + dispatch.call("redraw"); } function defineFeature(k, filter, max) { @@ -226,7 +228,7 @@ export function Features(context) { features.resetStats = function() { _.each(_features, function(f) { f.count = 0; }); - dispatch.change(); + dispatch.call("change"); }; features.gatherStats = function(d, resolver, dimensions) { @@ -255,7 +257,7 @@ export function Features(context) { if (currHidden !== _hidden) { _hidden = currHidden; needsRedraw = true; - dispatch.change(); + dispatch.call("change"); } return needsRedraw; @@ -418,5 +420,5 @@ export function Features(context) { return result; }; - return d3.rebind(features, dispatch, 'on'); + return rebind(features, dispatch, 'on'); } diff --git a/modules/renderer/map.js b/modules/renderer/map.js index 2d66a89f3..a510bfc7a 100644 --- a/modules/renderer/map.js +++ b/modules/renderer/map.js @@ -1,17 +1,22 @@ +import { rebind } from '../util/rebind'; +import * as d3 from 'd3'; import { t } from '../util/locale'; +import { bindOnce } from '../util/bind_once'; +import { getDimensions, setDimensions } from '../util/dimensions'; import _ from 'lodash'; import { Areas, Labels, Layers, Lines, Midpoints, Points, Vertices } from '../svg/index'; import { Extent, interp } from '../geo/index'; -import { fastMouse, setTransform } from '../util/index'; +import { fastMouse, setTransform, functor } from '../util/index'; import { flash } from '../ui/index'; export function Map(context) { var dimensions = [1, 1], dispatch = d3.dispatch('move', 'drawn'), projection = context.projection, - zoom = d3.behavior.zoom() + initialTransform = d3.zoomIdentity .translate(projection.translate()) - .scale(projection.scale() * 2 * Math.PI) + .scale(projection.scale() * 2 * Math.PI), + zoom = d3.zoom() .scaleExtent([1024, 256 * Math.pow(2, 24)]) .on('zoom', zoomPan), dblclickEnabled = true, @@ -33,7 +38,12 @@ export function Map(context) { mouse, mousemove; + var _selection; + function map(selection) { + + _selection = selection; + context .on('change.map', redraw); context.history() @@ -50,7 +60,7 @@ export function Map(context) { selection .on('dblclick.map', dblClick) - .call(zoom); + .call(zoom, initialTransform); supersurface = selection.append('div') .attr('id', 'supersurface') @@ -83,14 +93,14 @@ export function Map(context) { if (map.editable() && !transformed) { var hover = d3.event.target.__data__; surface.call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom()); - dispatch.drawn({full: false}); + dispatch.call("drawn", this, {full: false}); } }) .on('mouseout.vertices', function() { if (map.editable() && !transformed) { var hover = d3.event.relatedTarget && d3.event.relatedTarget.__data__; surface.call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom()); - dispatch.drawn({full: false}); + dispatch.call("drawn", this, {full: false}); } }); @@ -102,18 +112,18 @@ export function Map(context) { context.on('enter.map', function() { if (map.editable() && !transformed) { var all = context.intersects(map.extent()), - filter = d3.functor(true), + filter = functor(true), graph = context.graph(); all = context.features().filter(all, graph); surface .call(drawVertices, graph, all, filter, map.extent(), map.zoom()) .call(drawMidpoints, graph, all, filter, map.trimmedExtent()); - dispatch.drawn({full: false}); + dispatch.call("drawn", this, {full: false}); } }); - map.dimensions(selection.dimensions()); + map.dimensions(getDimensions(selection)); drawLabels.supersurface(supersurface); } @@ -148,7 +158,7 @@ export function Map(context) { } else { data = all; - filter = d3.functor(true); + filter = functor(true); } } @@ -162,13 +172,13 @@ export function Map(context) { .call(drawLabels, graph, data, filter, dimensions, !difference && !extent) .call(drawPoints, graph, data, filter); - dispatch.drawn({full: true}); + dispatch.call("drawn", this, {full: true}); } function editOff() { context.features().resetStats(); surface.selectAll('.layer-osm *').remove(); - dispatch.drawn({full: true}); + dispatch.call("drawn", this, {full: true}); } function dblClick() { @@ -178,31 +188,34 @@ export function Map(context) { } } - function zoomPan() { - if (Math.log(d3.event.scale) / Math.LN2 - 8 < minzoom) { + function zoomPan(manualEvent) { + + var eventTransform = (manualEvent || d3.event).transform; + + if (Math.log(event) / Math.LN2 - 8 < minzoom) { surface.interrupt(); flash(context.container()) .select('.content') .text(t('cannot_zoom')); setZoom(context.minEditableZoom(), true); queueRedraw(); - dispatch.move(map); + dispatch.call("move", this, map); return; } projection - .translate(d3.event.translate) - .scale(d3.event.scale / (2 * Math.PI)); + .translate([eventTransform.x, eventTransform.y]) + .scale(eventTransform.k / (2 * Math.PI)); - var scale = d3.event.scale / transformStart[0], - tX = (d3.event.translate[0] / scale - transformStart[1][0]) * scale, - tY = (d3.event.translate[1] / scale - transformStart[1][1]) * scale; + var scale = eventTransform.k / transformStart.k, + tX = (eventTransform.x / scale - transformStart.x) * scale, + tY = (eventTransform.y / scale - transformStart.y) * scale; transformed = true; setTransform(supersurface, tX, tY, scale); queueRedraw(); - dispatch.move(map); + dispatch.call("move", this, map); } function resetTransform() { @@ -247,9 +260,11 @@ export function Map(context) { wrapper .call(drawLayers); - transformStart = [ - projection.scale() * 2 * Math.PI, - projection.translate().slice()]; + transformStart = { + k: projection.k * 2 * Math.PI, + x: projection.x, + y: projection + }; return map; } @@ -317,13 +332,15 @@ export function Map(context) { l = pointLocation(center); scale = Math.max(1024, Math.min(256 * Math.pow(2, 24), scale)); projection.scale(scale / (2 * Math.PI)); - zoom.scale(scale); + if (_selection) { + _selection.call(zoom.transform, d3.zoomTransform(_selection).scale(scale)); + } var t = projection.translate(); l = locationPoint(l); t[0] += center[0] - l[0]; t[1] += center[1] - l[1]; projection.translate(t); - zoom.translate(projection.translate()); + // TODO zoom.translate(projection.translate()); return true; } @@ -337,7 +354,9 @@ export function Map(context) { projection.translate([ t[0] - ll[0] + pxC[0], t[1] - ll[1] + pxC[1]]); - zoom.translate(projection.translate()); + if (_selection) { + _selection.call(zoom.transform, d3.zoomTransform(_selection).translate(projection.translate())); + } return true; } @@ -346,8 +365,10 @@ export function Map(context) { t[0] += d[0]; t[1] += d[1]; projection.translate(t); - zoom.translate(projection.translate()); - dispatch.move(map); + if (_selection) { + _selection.call(zoom.transform, d3.zoomTransform(_selection).translate(projection.translate())); + } + dispatch.call("move", this, map); return redraw(); }; @@ -383,7 +404,7 @@ export function Map(context) { } if (setCenter(loc)) { - dispatch.move(map); + dispatch.call("move", this, map); } return redraw(); @@ -403,7 +424,7 @@ export function Map(context) { } if (setZoom(z)) { - dispatch.move(map); + dispatch.call("move", this, map); } return redraw(); @@ -423,7 +444,7 @@ export function Map(context) { zoomed = setZoom(z); if (centered || zoomed) { - dispatch.move(map); + dispatch.call("move", this, map); } return redraw(); @@ -432,7 +453,7 @@ export function Map(context) { map.centerEase = function(loc2, duration) { duration = duration || 250; - surface.one('mousedown.ease', function() { + bindOnce(surface, 'mousedown.ease', function() { map.cancelEase(); }); @@ -443,7 +464,7 @@ export function Map(context) { var t1 = Date.now(), t2 = t1 + duration, loc1 = map.center(), - ease = d3.ease('cubic-in-out'); + ease = d3.easeCubicInOut; easing = true; @@ -459,12 +480,11 @@ export function Map(context) { var locNow = interp(loc1, loc2, ease((tNow - t1) / duration)); setCenter(locNow); - d3.event = { - scale: zoom.scale(), - translate: zoom.translate() - }; + // TODO: fix - zoomPan(); + zoomPan({ + transform: d3.zoomTransform(_selection) + }); return !easing; }); @@ -534,5 +554,5 @@ export function Map(context) { map.layers = drawLayers; - return d3.rebind(map, dispatch, 'on'); + return rebind(map, dispatch, 'on'); } diff --git a/modules/renderer/tile_layer.js b/modules/renderer/tile_layer.js index 1ec21e248..6b3b0c12a 100644 --- a/modules/renderer/tile_layer.js +++ b/modules/renderer/tile_layer.js @@ -1,13 +1,15 @@ -import { prefixCSSProperty } from '../util/index'; +import * as d3 from 'd3'; +import { d3geoTile } from '../../js/lib/d3.geo.tile'; +import { prefixCSSProperty, functor } from '../util/index'; export function TileLayer(context) { var tileSize = 256, - tile = d3.geo.tile(), + tile = d3geoTile(), projection, cache = {}, tileOrigin, z, transformProp = prefixCSSProperty('Transform'), - source = d3.functor(''); + source = functor(''); // blacklist overlay tiles around Null Island.. diff --git a/modules/services/mapillary.js b/modules/services/mapillary.js index 8de822d9c..8e43d1426 100644 --- a/modules/services/mapillary.js +++ b/modules/services/mapillary.js @@ -1,5 +1,8 @@ +import { rebind } from '../util/rebind'; +import * as d3 from 'd3'; /* global Mapillary:false */ import _ from 'lodash'; +import { d3geoTile } from '../../js/lib/d3.geo.tile'; import { Detect } from '../util/detect'; import { Extent } from '../geo/index'; import { Icon } from '../svg/index'; @@ -134,7 +137,7 @@ function getTiles(projection, dimensions) { s / 2 - projection.translate()[0], s / 2 - projection.translate()[1]]; - return d3.geo.tile() + return d3geoTile() .scaleExtent([tileZoom, tileZoom]) .scale(s) .size(dimensions) @@ -207,8 +210,8 @@ function loadTilePage(which, url, tile, page) { cache.rtree.load(features); - if (which === 'images') dispatch.loadedImages(); - if (which === 'signs') dispatch.loadedSigns(); + if (which === 'images') dispatch.call("loadedImages"); + if (which === 'signs') dispatch.call("loadedSigns"); if (data.features.length === maxResults && nextPage < maxPages) { loadTilePage(which, url, tile, nextPage); @@ -403,7 +406,7 @@ export function init() { mapillary.reset(); } - mapillary.event = d3.rebind(mapillary, dispatch, 'on'); + mapillary.event = rebind(mapillary, dispatch, 'on'); return mapillary; } diff --git a/modules/services/nominatim.js b/modules/services/nominatim.js index c5b9d1e4e..d5e9eb792 100644 --- a/modules/services/nominatim.js +++ b/modules/services/nominatim.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import { Extent } from '../geo/index'; import { qsString } from '../util/index'; import rbush from 'rbush'; diff --git a/modules/services/taginfo.js b/modules/services/taginfo.js index d5653ea13..0133bb817 100644 --- a/modules/services/taginfo.js +++ b/modules/services/taginfo.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import _ from 'lodash'; import { qsString } from '../util/index'; diff --git a/modules/svg/areas.js b/modules/svg/areas.js index 57b7495e2..61e83c214 100644 --- a/modules/svg/areas.js +++ b/modules/svg/areas.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import _ from 'lodash'; import { Path, TagClasses } from './index'; import { Entity } from '../core/index'; diff --git a/modules/svg/debug.js b/modules/svg/debug.js index 00d586085..eb408028b 100644 --- a/modules/svg/debug.js +++ b/modules/svg/debug.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import { polygonIntersectsPolygon } from '../geo/index'; import { imperial as imperialData, @@ -22,7 +23,7 @@ export function Debug(projection, context) { showsImagery = context.getDebug('imagery'), showsImperial = context.getDebug('imperial'), showsDriveLeft = context.getDebug('driveLeft'), - path = d3.geo.path().projection(projection); + path = d3.geoPath().projection(projection); var debugData = []; diff --git a/modules/svg/defs.js b/modules/svg/defs.js index 2ab3755f9..e93012738 100644 --- a/modules/svg/defs.js +++ b/modules/svg/defs.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; /* A standalone SVG element that contains only a `defs` sub-element. To be used once globally, since defs IDs must be unique within a document. @@ -6,12 +7,15 @@ export function Defs(context) { function SVGSpriteDefinition(id, href) { return function(defs) { - d3.xml(href, 'image/svg+xml', function(err, svg) { - if (err) return; - defs.node().appendChild( - d3.select(svg.documentElement).attr('id', id).node() - ); - }); + d3.request(href) + .mimeType('image/svg+xml') + .response(function(xhr) { return xhr.responseXML; }) + .get(function(err, svg) { + if (err) return; + defs.node().appendChild( + d3.select(svg.documentElement).attr('id', id).node() + ); + }); }; } @@ -20,16 +24,15 @@ export function Defs(context) { // marker defs.append('marker') - .attr({ - id: 'oneway-marker', - viewBox: '0 0 10 10', - refY: 2.5, - refX: 5, - markerWidth: 2, - markerHeight: 2, - markerUnits: 'strokeWidth', - orient: 'auto' - }) + .attr('id', 'oneway-marker') + .attr('viewBox', '0 0 10 10') + .attr('refY', 2.5) + .attr('refX', 5) + .attr('markerWidth', 2) + .attr('markerHeight', 2) + .attr('markerUnits', 'strokeWidth') + .attr('orient', 'auto') + .append('path') .attr('class', 'oneway') .attr('d', 'M 5 3 L 0 3 L 0 2 L 5 2 L 5 0 L 10 2.5 L 5 5 z') @@ -52,33 +55,27 @@ export function Defs(context) { ]) .enter() .append('pattern') - .attr({ - id: function (d) { - return 'pattern-' + d[0]; - }, - width: 32, - height: 32, - patternUnits: 'userSpaceOnUse' - }); + .attr('id', function (d) { + return 'pattern-' + d[0]; + }) + .attr('width', 32) + .attr('height', 32) + .attr('patternUnits', 'userSpaceOnUse') patterns.append('rect') - .attr({ - x: 0, - y: 0, - width: 32, - height: 32, - 'class': function (d) { + .attr('x', 0) + .attr('y', 0) + .attr('width', 32) + .attr('height', 32) + .attr('class', function (d) { return 'pattern-color-' + d[0]; - } }); patterns.append('image') - .attr({ - x: 0, - y: 0, - width: 32, - height: 32 - }) + .attr('x', 0) + .attr('y', 0) + .attr('width', 32) + .attr('height', 32) .attr('xlink:href', function (d) { return context.imagePath('pattern/' + d[1] + '.png'); }); diff --git a/modules/svg/gpx.js b/modules/svg/gpx.js index f57b59071..9e832f106 100644 --- a/modules/svg/gpx.js +++ b/modules/svg/gpx.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import _ from 'lodash'; import { Extent, polygonIntersectsPolygon } from '../geo/index'; import { Detect } from '../util/detect'; @@ -61,7 +62,7 @@ export function Gpx(projection, context, dispatch) { paths.exit() .remove(); - var path = d3.geo.path() + var path = d3.geoPath() .projection(projection); paths @@ -106,7 +107,7 @@ export function Gpx(projection, context, dispatch) { drawGpx.enabled = function(_) { if (!arguments.length) return Gpx.enabled; Gpx.enabled = _; - dispatch.change(); + dispatch.call("change"); return this; }; @@ -119,7 +120,7 @@ export function Gpx(projection, context, dispatch) { if (!arguments.length) return Gpx.geojson; if (_.isEmpty(gj) || _.isEmpty(gj.features)) return this; Gpx.geojson = gj; - dispatch.change(); + dispatch.call("change"); return this; }; @@ -157,7 +158,7 @@ export function Gpx(projection, context, dispatch) { }, []); if (!polygonIntersectsPolygon(viewport, coords, true)) { - var extent = Extent(d3.geo.bounds(geojson)); + var extent = Extent(d3.geoBounds(geojson)); map.centerZoom(extent.center(), map.trimmedExtentZoom(extent)); } diff --git a/modules/svg/labels.js b/modules/svg/labels.js index 69958772f..f642428ca 100644 --- a/modules/svg/labels.js +++ b/modules/svg/labels.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import _ from 'lodash'; import { displayName, getStyle } from '../util/index'; import { Entity } from '../core/index'; @@ -5,7 +6,7 @@ import { pathLength } from '../geo/index'; import rbush from 'rbush'; export function Labels(projection, context) { - var path = d3.geo.path().projection(projection); + var path = d3.geoPath().projection(projection); // Replace with dict and iterate over entities tags instead? var label_stack = [ @@ -111,10 +112,8 @@ export function Labels(projection, context) { texts.selectAll('.textpath') .filter(filter) .data(entities, Entity.key) - .attr({ - 'startOffset': '50%', - 'xlink:href': function(d) { return '#labelpath-' + d.id; } - }) + .attr('startOffset', '50%') + .attr('xlink:href', function(d) { return '#labelpath-' + d.id; }) .text(displayName); texts.exit().remove(); @@ -462,7 +461,7 @@ export function Labels(projection, context) { .remove(); debugboxes - .attr('d', d3.geo.path().projection(null)); + .attr('d', d3.geoPath().projection(null)); } } diff --git a/modules/svg/layers.js b/modules/svg/layers.js index af120699d..ae7410ec8 100644 --- a/modules/svg/layers.js +++ b/modules/svg/layers.js @@ -1,3 +1,6 @@ +import { rebind } from '../util/rebind'; +import { getDimensions, setDimensions } from '../util/dimensions'; +import * as d3 from 'd3'; import _ from 'lodash'; import { Debug } from './debug'; import { Gpx } from './gpx'; @@ -60,7 +63,7 @@ export function Layers(projection, context) { arr.forEach(function(id) { layers = _.reject(layers, function(o) {return o.id === id;}); }); - dispatch.change(); + dispatch.call("change"); return this; }; @@ -71,13 +74,13 @@ export function Layers(projection, context) { layers.push(obj); } }); - dispatch.change(); + dispatch.call("change"); return this; }; drawLayers.dimensions = function(_) { - if (!arguments.length) return svg.dimensions(); - svg.dimensions(_); + if (!arguments.length) return getDimensions(svg); + setDimensions(svg, _); layers.forEach(function(obj) { if (obj.layer.dimensions) { obj.layer.dimensions(_); @@ -87,5 +90,5 @@ export function Layers(projection, context) { }; - return d3.rebind(drawLayers, dispatch, 'on'); + return rebind(drawLayers, dispatch, 'on'); } diff --git a/modules/svg/lines.js b/modules/svg/lines.js index 51e6bb174..cd99ba9b0 100644 --- a/modules/svg/lines.js +++ b/modules/svg/lines.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import _ from 'lodash'; import { OneWaySegments, Path, RelationMemberTags, TagClasses } from './index'; import { Detect } from '../util/detect'; diff --git a/modules/svg/mapillary_images.js b/modules/svg/mapillary_images.js index 77b466b41..2e0a6b7f1 100644 --- a/modules/svg/mapillary_images.js +++ b/modules/svg/mapillary_images.js @@ -1,9 +1,11 @@ +import * as d3 from 'd3'; import _ from 'lodash'; import { PointTransform } from './point_transform'; +import { getDimensions, setDimensions } from '../util/dimensions'; import { mapillary as mapillaryService } from '../services/index'; export function MapillaryImages(projection, context, dispatch) { - var debouncedRedraw = _.debounce(function () { dispatch.change(); }, 1000), + var debouncedRedraw = _.debounce(function () { dispatch.call("change"); }, 1000), minZoom = 12, layer = d3.select(null), _mapillary; @@ -85,7 +87,7 @@ export function MapillaryImages(projection, context, dispatch) { function update() { var mapillary = getMapillary(), - data = (mapillary ? mapillary.images(projection, layer.dimensions()) : []), + data = (mapillary ? mapillary.images(projection, getDimensions(layer)) : []), imageKey = mapillary ? mapillary.getSelectedImage() : null; var markers = layer.selectAll('.viewfield-group') @@ -136,7 +138,7 @@ export function MapillaryImages(projection, context, dispatch) { if (mapillary && ~~context.map().zoom() >= minZoom) { editOn(); update(); - mapillary.loadImages(projection, layer.dimensions()); + mapillary.loadImages(projection, getDimensions(layer)); } else { editOff(); } @@ -151,7 +153,7 @@ export function MapillaryImages(projection, context, dispatch) { } else { hideLayer(); } - dispatch.change(); + dispatch.call("change"); return this; }; @@ -160,8 +162,8 @@ export function MapillaryImages(projection, context, dispatch) { }; drawImages.dimensions = function(_) { - if (!arguments.length) return layer.dimensions(); - layer.dimensions(_); + if (!arguments.length) return getDimensions(layer); + setDimensions(layer, _); return this; }; diff --git a/modules/svg/mapillary_signs.js b/modules/svg/mapillary_signs.js index a6a19b37d..d477153ef 100644 --- a/modules/svg/mapillary_signs.js +++ b/modules/svg/mapillary_signs.js @@ -1,9 +1,11 @@ +import * as d3 from 'd3'; import _ from 'lodash'; +import { getDimensions, setDimensions } from '../util/dimensions'; import { PointTransform } from './point_transform'; import { mapillary as mapillaryService } from '../services/index'; export function MapillarySigns(projection, context, dispatch) { - var debouncedRedraw = _.debounce(function () { dispatch.change(); }, 1000), + var debouncedRedraw = _.debounce(function () { dispatch.call("change"); }, 1000), minZoom = 12, layer = d3.select(null), _mapillary; @@ -57,7 +59,7 @@ export function MapillarySigns(projection, context, dispatch) { function update() { var mapillary = getMapillary(), - data = (mapillary ? mapillary.signs(projection, layer.dimensions()) : []), + data = (mapillary ? mapillary.signs(projection, getDimensions(layer)) : []), imageKey = mapillary ? mapillary.getSelectedImage() : null; var signs = layer.selectAll('.icon-sign') @@ -105,7 +107,7 @@ export function MapillarySigns(projection, context, dispatch) { if (mapillary && ~~context.map().zoom() >= minZoom) { editOn(); update(); - mapillary.loadSigns(context, projection, layer.dimensions()); + mapillary.loadSigns(context, projection, getDimensions(layer)); } else { editOff(); } @@ -120,7 +122,7 @@ export function MapillarySigns(projection, context, dispatch) { } else { hideLayer(); } - dispatch.change(); + dispatch.call("change"); return this; }; @@ -130,8 +132,8 @@ export function MapillarySigns(projection, context, dispatch) { }; drawSigns.dimensions = function(_) { - if (!arguments.length) return layer.dimensions(); - layer.dimensions(_); + if (!arguments.length) return getDimensions(layer); + setDimensions(layer, _); return this; }; diff --git a/modules/svg/one_way_segments.js b/modules/svg/one_way_segments.js index 8edc13edc..079a17972 100644 --- a/modules/svg/one_way_segments.js +++ b/modules/svg/one_way_segments.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import { euclideanDistance } from '../geo/index'; export function OneWaySegments(projection, graph, dt) { @@ -7,14 +8,14 @@ export function OneWaySegments(projection, graph, dt) { i = 0, offset = dt, segments = [], - clip = d3.geo.clipExtent().extent(projection.clipExtent()).stream, + clip = d3.geoClipExtent().extent(projection.clipExtent()).stream, coordinates = graph.childNodes(entity).map(function(n) { return n.loc; }); if (entity.tags.oneway === '-1') coordinates.reverse(); - d3.geo.stream({ + d3.geoStream({ type: 'LineString', coordinates: coordinates }, projection.stream(clip({ diff --git a/modules/svg/path.js b/modules/svg/path.js index 24365a915..afa9e3e86 100644 --- a/modules/svg/path.js +++ b/modules/svg/path.js @@ -1,8 +1,9 @@ +import * as d3 from 'd3'; export function Path(projection, graph, polygon) { var cache = {}, - clip = d3.geo.clipExtent().extent(projection.clipExtent()).stream, + clip = d3.geoClipExtent().extent(projection.clipExtent()).stream, project = projection.stream, - path = d3.geo.path() + path = d3.geoPath() .projection({stream: function(output) { return polygon ? project(output) : project(clip(output)); }}); return function(entity) { diff --git a/modules/svg/tag_classes.js b/modules/svg/tag_classes.js index 09eeb0cfc..c311f1b0b 100644 --- a/modules/svg/tag_classes.js +++ b/modules/svg/tag_classes.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import { pavedTags } from '../core/tags'; export function TagClasses() { diff --git a/modules/svg/vertices.js b/modules/svg/vertices.js index 33269cac1..49f097d26 100644 --- a/modules/svg/vertices.js +++ b/modules/svg/vertices.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import { Entity } from '../core/index'; import { PointTransform } from './index'; diff --git a/modules/ui/account.js b/modules/ui/account.js index 530a76179..542d79695 100644 --- a/modules/ui/account.js +++ b/modules/ui/account.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import { t } from '../util/locale'; import { Icon } from '../svg/index'; export function Account(context) { diff --git a/modules/ui/attribution.js b/modules/ui/attribution.js index 27bfb20ad..ce99f3f77 100644 --- a/modules/ui/attribution.js +++ b/modules/ui/attribution.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import _ from 'lodash'; export function Attribution(context) { var selection; diff --git a/modules/ui/background.js b/modules/ui/background.js index 1a561e3e2..ae18cddad 100644 --- a/modules/ui/background.js +++ b/modules/ui/background.js @@ -1,3 +1,5 @@ +import { d3keybinding } from '../../js/lib/d3.keybinding.js'; +import * as d3 from 'd3'; import { t } from '../util/locale'; import { tooltip } from '../util/tooltip'; import _ from 'lodash'; @@ -487,7 +489,7 @@ export function Background(context) { update(); setOpacity(opacityDefault); - var keybinding = d3.keybinding('background') + var keybinding = d3keybinding('background') .on(key, toggle) .on(cmd('⌘B'), quickSwitch) .on('F', hide) diff --git a/modules/ui/commit.js b/modules/ui/commit.js index 94b329ecf..3e564f774 100644 --- a/modules/ui/commit.js +++ b/modules/ui/commit.js @@ -1,4 +1,8 @@ +import { rebind } from '../util/rebind'; +import { d3combobox } from '../../js/lib/d3.combobox.js'; +import * as d3 from 'd3'; import { t } from '../util/locale'; +import { triggerEvent } from '../util/trigger_event'; import { tooltip } from '../util/tooltip'; import _ from 'lodash'; import { displayName, entityOrMemberSelector } from '../util/index'; @@ -88,7 +92,7 @@ export function Commit(context) { } } - commentField.call(d3.combobox().caseSensitive(true).data(comments)); + commentField.call(d3combobox().caseSensitive(true).data(comments)); }); var clippyArea = commentSection.append('div') @@ -180,7 +184,7 @@ export function Commit(context) { var cancelButton = buttonSection.append('button') .attr('class', 'secondary-action col5 button cancel-button') - .on('click.cancel', function() { dispatch.cancel(); }); + .on('click.cancel', function() { dispatch.call("cancel"); }); cancelButton.append('span') .attr('class', 'label') @@ -193,7 +197,7 @@ export function Commit(context) { return (n && n.value.length) ? null : true; }) .on('click.save', function() { - dispatch.save({ + dispatch.call('save', this, { comment: commentField.node().value }); }); @@ -278,8 +282,8 @@ export function Commit(context) { // Call checkComment off the bat, in case a changeset // comment is recovered from localStorage - commentField.trigger('input'); + triggerEvent(commentField, 'input'); } - return d3.rebind(commit, dispatch, 'on'); + return rebind(commit, dispatch, 'on'); } diff --git a/modules/ui/conflicts.js b/modules/ui/conflicts.js index b5fa8e194..40734b1cc 100644 --- a/modules/ui/conflicts.js +++ b/modules/ui/conflicts.js @@ -1,3 +1,5 @@ +import { rebind } from '../util/rebind'; +import * as d3 from 'd3'; import { t } from '../util/locale'; import { Extent } from '../geo/index'; import { Icon } from '../svg/index'; @@ -15,7 +17,7 @@ export function Conflicts(context) { header .append('button') .attr('class', 'fr') - .on('click', function() { dispatch.cancel(); }) + .on('click', function() { dispatch.call("cancel"); }) .call(Icon('#icon-close')); header @@ -33,7 +35,7 @@ export function Conflicts(context) { .append('a') .attr('class', 'conflicts-download') .text(t('save.conflict.download_changes')) - .on('click.download', function() { dispatch.download(); }); + .on('click.download', function() { dispatch.call("download"); }); body .append('div') @@ -56,13 +58,13 @@ export function Conflicts(context) { .attr('disabled', list.length > 1) .attr('class', 'action conflicts-button col6') .text(t('save.title')) - .on('click.try_again', function() { dispatch.save(); }); + .on('click.try_again', function() { dispatch.call("save"); }); buttons .append('button') .attr('class', 'secondary-action conflicts-button col6') .text(t('confirm.cancel')) - .on('click.cancel', function() { dispatch.cancel(); }); + .on('click.cancel', function() { dispatch.call("cancel"); }); } @@ -251,5 +253,5 @@ export function Conflicts(context) { return conflicts; }; - return d3.rebind(conflicts, dispatch, 'on'); + return rebind(conflicts, dispatch, 'on'); } diff --git a/modules/ui/contributors.js b/modules/ui/contributors.js index 7469be03b..4a9c2cbf0 100644 --- a/modules/ui/contributors.js +++ b/modules/ui/contributors.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import { t } from '../util/locale'; import _ from 'lodash'; import { Icon } from '../svg/index'; diff --git a/modules/ui/disclosure.js b/modules/ui/disclosure.js index 8ab1d8f2c..e1056b2b2 100644 --- a/modules/ui/disclosure.js +++ b/modules/ui/disclosure.js @@ -1,3 +1,5 @@ +import { rebind } from '../util/rebind'; +import * as d3 from 'd3'; import { Toggle } from './toggle'; export function Disclosure() { @@ -30,7 +32,7 @@ export function Disclosure() { expanded = !expanded; $link.classed('expanded', expanded); $body.call(Toggle(expanded)); - dispatch.toggled(expanded); + dispatch.call("toggled", this, expanded); } }; @@ -52,5 +54,5 @@ export function Disclosure() { return disclosure; }; - return d3.rebind(disclosure, dispatch, 'on'); + return rebind(disclosure, dispatch, 'on'); } diff --git a/modules/ui/entity_editor.js b/modules/ui/entity_editor.js index 52aed39a6..e92e77c3b 100644 --- a/modules/ui/entity_editor.js +++ b/modules/ui/entity_editor.js @@ -1,3 +1,5 @@ +import { rebind } from '../util/rebind'; +import * as d3 from 'd3'; import { t } from '../util/locale'; import { tooltip } from '../util/tooltip'; import _ from 'lodash'; @@ -96,7 +98,7 @@ export function EntityEditor(context) { selection.selectAll('.preset-reset') .on('click', function() { - dispatch.choose(activePreset); + dispatch.call("choose", this, activePreset); }); // Update @@ -245,5 +247,5 @@ export function EntityEditor(context) { return entityEditor; }; - return d3.rebind(entityEditor, dispatch, 'on'); + return rebind(entityEditor, dispatch, 'on'); } diff --git a/modules/ui/feature_info.js b/modules/ui/feature_info.js index 3a82151e0..5158ad6ab 100644 --- a/modules/ui/feature_info.js +++ b/modules/ui/feature_info.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import { t } from '../util/locale'; import { tooltip } from '../util/tooltip'; import _ from 'lodash'; diff --git a/modules/ui/feature_list.js b/modules/ui/feature_list.js index c6ea05264..f408302d5 100644 --- a/modules/ui/feature_list.js +++ b/modules/ui/feature_list.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import { t } from '../util/locale'; import * as sexagesimal from 'sexagesimal'; import { Extent, chooseEdge } from '../geo/index'; diff --git a/modules/ui/fields/access.js b/modules/ui/fields/access.js index c07d0ab9d..9e71d65d6 100644 --- a/modules/ui/fields/access.js +++ b/modules/ui/fields/access.js @@ -1,3 +1,7 @@ +import { rebind } from '../../util/rebind'; +import { getSetValue } from '../../util/get_set_value'; +import { d3combobox } from '../../../js/lib/d3.combobox.js'; +import * as d3 from 'd3'; import _ from 'lodash'; export function access(field) { @@ -33,7 +37,7 @@ export function access(field) { .attr('id', function(d) { return 'preset-input-access-' + d; }) .each(function(d) { d3.select(this) - .call(d3.combobox() + .call(d3combobox() .data(access.options(d))); }); @@ -46,8 +50,8 @@ export function access(field) { function change(d) { var tag = {}; - tag[d] = d3.select(this).value() || undefined; - dispatch.change(tag); + tag[d] = getSetValue(d3.select(this)) || undefined; + dispatch.call("change", this, tag); } access.options = function(type) { @@ -174,8 +178,8 @@ export function access(field) { }; access.tags = function(tags) { - items.selectAll('.preset-input-access') - .value(function(d) { return tags[d] || ''; }) + getSetValue(items.selectAll('.preset-input-access'), + function(d) { return tags[d] || ''; }) .attr('placeholder', function() { return tags.access ? tags.access : field.placeholder(); }); @@ -194,5 +198,5 @@ export function access(field) { .node().focus(); }; - return d3.rebind(access, dispatch, 'on'); + return rebind(access, dispatch, 'on'); } diff --git a/modules/ui/fields/address.js b/modules/ui/fields/address.js index 1a72df367..c35f64efe 100644 --- a/modules/ui/fields/address.js +++ b/modules/ui/fields/address.js @@ -1,3 +1,7 @@ +import { rebind } from '../../util/rebind'; +import { getSetValue } from '../../util/get_set_value'; +import { d3combobox } from '../../../js/lib/d3.combobox.js'; +import * as d3 from 'd3'; import _ from 'lodash'; import { Extent, chooseEdge, sphericalDistance } from '../../geo/index'; import { nominatim } from '../../services/index'; @@ -150,19 +154,19 @@ export function address(field, context) { // Update wrap.selectAll('.addr-street') - .call(d3.combobox() + .call(d3combobox() .fetcher(function(value, callback) { callback(getStreets()); })); wrap.selectAll('.addr-city') - .call(d3.combobox() + .call(d3combobox() .fetcher(function(value, callback) { callback(getCities()); })); wrap.selectAll('.addr-postcode') - .call(d3.combobox() + .call(d3combobox() .fetcher(function(value, callback) { callback(getPostCodes()); })); @@ -174,7 +178,7 @@ export function address(field, context) { wrap.selectAll('input:not(.combobox-input)') .on('input', change(true)); - dispatch.init(); + dispatch.call("init"); isInitialized = true; }); } @@ -188,15 +192,14 @@ export function address(field, context) { tags['addr:' + field.id] = this.value || undefined; }); - dispatch.change(tags, onInput); + dispatch.call("change", this, tags, onInput); }; } function updateTags(tags) { - wrap.selectAll('input') - .value(function (field) { - return tags['addr:' + field.id] || ''; - }); + getSetValue(wrap.selectAll('input'), function (field) { + return tags['addr:' + field.id] || ''; + }); } address.entity = function(_) { @@ -209,7 +212,7 @@ export function address(field, context) { if (isInitialized) { updateTags(tags); } else { - dispatch.on('init', function () { + dispatch.call("on", this, 'init', function () { updateTags(tags); }); } @@ -220,5 +223,5 @@ export function address(field, context) { if (node) node.focus(); }; - return d3.rebind(address, dispatch, 'on'); + return rebind(address, dispatch, 'on'); } diff --git a/modules/ui/fields/check.js b/modules/ui/fields/check.js index 95769bcba..37b8f8892 100644 --- a/modules/ui/fields/check.js +++ b/modules/ui/fields/check.js @@ -1,3 +1,5 @@ +import { rebind } from '../../util/rebind'; +import * as d3 from 'd3'; import { t } from '../../util/locale'; import { oneWayTags } from '../../core/index'; @@ -56,7 +58,7 @@ export function check(field) { .on('click', function() { var t = {}; t[field.key] = values[(values.indexOf(value) + 1) % values.length]; - dispatch.change(t); + dispatch.call("change", this, t); d3.event.stopPropagation(); }); @@ -81,5 +83,5 @@ export function check(field) { box.node().focus(); }; - return d3.rebind(check, dispatch, 'on'); + return rebind(check, dispatch, 'on'); } diff --git a/modules/ui/fields/combo.js b/modules/ui/fields/combo.js index fffdd5a1d..5efa5875f 100644 --- a/modules/ui/fields/combo.js +++ b/modules/ui/fields/combo.js @@ -1,3 +1,7 @@ +import { rebind } from '../../util/rebind'; +import { getSetValue } from '../../util/get_set_value'; +import { d3combobox } from '../../../js/lib/d3.combobox.js'; +import * as d3 from 'd3'; import _ from 'lodash'; import { t } from '../../util/locale'; @@ -15,7 +19,7 @@ export function combo(field, context) { optstrings = field.strings && field.strings.options, optarray = field.options, snake_case = (field.snake_case || (field.snake_case === undefined)), - combobox = d3.combobox().minItems(isMulti ? 1 : 2), + combobox = d3combobox().minItems(isMulti ? 1 : 2), comboData = [], multiData = [], container, @@ -189,13 +193,13 @@ export function combo(field, context) { function change() { - var val = tagValue(input.value()), + var val = tagValue(getSetValue(input)), t = {}; if (isMulti) { if (!val) return; container.classed('active', false); - input.value(''); + getSetValue(input, ''); field.keys.push(field.key + val); t[field.key + val] = 'yes'; window.setTimeout(function() { input.node().focus(); }, 10); @@ -204,7 +208,7 @@ export function combo(field, context) { t[field.key] = val; } - dispatch.change(t); + dispatch.call("change", this, t); } @@ -212,7 +216,7 @@ export function combo(field, context) { d3.event.stopPropagation(); var t = {}; t[d.key] = undefined; - dispatch.change(t); + dispatch.call("change", this, t); } @@ -315,7 +319,7 @@ export function combo(field, context) { .remove(); } else { - input.value(displayValue(tags[field.key])); + getSetValue(input, displayValue(tags[field.key])); } }; @@ -332,5 +336,5 @@ export function combo(field, context) { }; - return d3.rebind(combo, dispatch, 'on'); + return rebind(combo, dispatch, 'on'); } diff --git a/modules/ui/fields/cycleway.js b/modules/ui/fields/cycleway.js index 24af9e893..34eab5c73 100644 --- a/modules/ui/fields/cycleway.js +++ b/modules/ui/fields/cycleway.js @@ -1,3 +1,7 @@ +import { rebind } from '../../util/rebind'; +import { getSetValue } from '../../util/get_set_value'; +import { d3combobox } from '../../../js/lib/d3.combobox.js'; +import * as d3 from 'd3'; export function cycleway(field) { var dispatch = d3.dispatch('change'), items; @@ -31,7 +35,7 @@ export function cycleway(field) { .attr('id', function(d) { return 'preset-input-cycleway-' + d; }) .each(function(d) { d3.select(this) - .call(d3.combobox() + .call(d3combobox() .data(cycleway.options(d))); }); @@ -44,8 +48,8 @@ export function cycleway(field) { function change() { var inputs = d3.selectAll('.preset-input-cycleway')[0], - left = d3.select(inputs[0]).value(), - right = d3.select(inputs[1]).value(), + left = getSetValue(d3.select(inputs[0])), + right = getSetValue(d3.select(inputs[1])), tag = {}; if (left === 'none' || left === '') { left = undefined; } if (right === 'none' || right === '') { right = undefined; } @@ -67,7 +71,7 @@ export function cycleway(field) { }; } - dispatch.change(tag); + dispatch.call("change", this, tag); } cycleway.options = function() { @@ -80,8 +84,7 @@ export function cycleway(field) { }; cycleway.tags = function(tags) { - items.selectAll('.preset-input-cycleway') - .value(function(d) { + getSetValue(items.selectAll('.preset-input-cycleway'), function(d) { // If cycleway is set, always return that if (tags.cycleway) { return tags.cycleway; @@ -96,5 +99,5 @@ export function cycleway(field) { .node().focus(); }; - return d3.rebind(cycleway, dispatch, 'on'); + return rebind(cycleway, dispatch, 'on'); } diff --git a/modules/ui/fields/input.js b/modules/ui/fields/input.js index 64cbf4bcb..5015aa117 100644 --- a/modules/ui/fields/input.js +++ b/modules/ui/fields/input.js @@ -1,3 +1,6 @@ +import { rebind } from '../../util/rebind'; +import { getSetValue } from '../../util/get_set_value'; +import * as d3 from 'd3'; import { t } from '../../util/locale'; import { nominatim as nominatimService } from '../../services/index'; import { phoneFormats } from '../../../data/index'; @@ -71,8 +74,8 @@ export function url(field, context) { function change(onInput) { return function() { var t = {}; - t[field.key] = input.value() || undefined; - dispatch.change(t, onInput); + t[field.key] = getSetValue(input) || undefined; + dispatch.call("change", this, t, onInput); }; } @@ -83,7 +86,7 @@ export function url(field, context) { }; i.tags = function(tags) { - input.value(tags[field.key] || ''); + getSetValue(input, tags[field.key] || ''); }; i.focus = function() { @@ -91,5 +94,5 @@ export function url(field, context) { if (node) node.focus(); }; - return d3.rebind(i, dispatch, 'on'); + return rebind(i, dispatch, 'on'); } diff --git a/modules/ui/fields/lanes.js b/modules/ui/fields/lanes.js index 3542b80df..857a7fc51 100644 --- a/modules/ui/fields/lanes.js +++ b/modules/ui/fields/lanes.js @@ -1,3 +1,5 @@ +import { rebind } from '../../util/rebind'; +import * as d3 from 'd3'; export function lanes(field, context) { var dispatch = d3.dispatch('change'), LANE_WIDTH = 40, @@ -23,7 +25,7 @@ export function lanes(field, context) { var surface = wrap.selectAll('.surface') .data([0]); - var d = wrap.dimensions(); + var d = getDimensions(wrap); var freeSpace = d[0] - lanesData.lanes.length * LANE_WIDTH * 1.5 + LANE_WIDTH * 0.5; surface.enter() @@ -116,5 +118,5 @@ export function lanes(field, context) { lanes.focus = function() {}; lanes.off = function() {}; - return d3.rebind(lanes, dispatch, 'on'); + return rebind(lanes, dispatch, 'on'); } diff --git a/modules/ui/fields/localized.js b/modules/ui/fields/localized.js index 6b5dcf56b..59895eae8 100644 --- a/modules/ui/fields/localized.js +++ b/modules/ui/fields/localized.js @@ -1,3 +1,7 @@ +import { rebind } from '../../util/rebind'; +import { d3combobox } from '../../../js/lib/d3.combobox.js'; +import { getSetValue } from '../../util/get_set_value'; +import * as d3 from 'd3'; import { t } from '../../util/locale'; import { tooltip } from '../../util/tooltip'; import _ from 'lodash'; @@ -25,7 +29,7 @@ export function localized(field, context) { if (field.id === 'name') { var preset = context.presets().match(entity, context.graph()); - input.call(d3.combobox().fetcher( + input.call(d3combobox().fetcher( SuggestNames(preset, suggestions) )); } @@ -73,15 +77,15 @@ export function localized(field, context) { function change(onInput) { return function() { var t = {}; - t[field.key] = d3.select(this).value() || undefined; - dispatch.change(t, onInput); + t[field.key] = getSetValue(d3.select(this)) || undefined; + dispatch.call("change", this, t, onInput); }; } function key(lang) { return field.key + ':' + lang; } function changeLang(d) { - var lang = d3.select(this).value(), + var lang = getSetValue(d3.select(this)), t = {}, language = _.find(wikipediaData, function(d) { return d[0].toLowerCase() === lang.toLowerCase() || @@ -94,9 +98,8 @@ export function localized(field, context) { t[key(d.lang)] = undefined; } - var value = d3.select(this.parentNode) - .selectAll('.localized-value') - .value(); + var value = getSetValue(d3.select(this.parentNode) + .selectAll('.localized-value')); if (lang && value) { t[key(lang)] = value; @@ -105,14 +108,14 @@ export function localized(field, context) { } d.lang = lang; - dispatch.change(t); + dispatch.call("change", this, t); } function changeValue(d) { if (!d.lang) return; var t = {}; - t[key(d.lang)] = d3.select(this).value() || undefined; - dispatch.change(t); + t[key(d.lang)] = getSetValue(d3.select(this)) || undefined; + dispatch.call("change", this, t); } function fetcher(value, cb) { @@ -137,7 +140,7 @@ export function localized(field, context) { innerWrap.attr('class', 'entry') .each(function() { var wrap = d3.select(this); - var langcombo = d3.combobox().fetcher(fetcher).minItems(0); + var langcombo = d3combobox().fetcher(fetcher).minItems(0); var label = wrap.append('label') .attr('class','form-label') @@ -150,7 +153,7 @@ export function localized(field, context) { d3.event.preventDefault(); var t = {}; t[key(d.lang)] = undefined; - dispatch.change(t); + dispatch.call("change", this, t); d3.select(this.parentNode.parentNode) .style('top','0') .style('max-height','240px') @@ -202,14 +205,13 @@ export function localized(field, context) { var entry = selection.selectAll('.entry'); - entry.select('.localized-lang') - .value(function(d) { + getSetValue(entry.select('.localized-lang'), function(d) { var lang = _.find(wikipediaData, function(lang) { return lang[2] === d.lang; }); return lang ? lang[1] : d.lang; }); - entry.select('.localized-value') - .value(function(d) { return d.value; }); + getSetValue(entry.select('.localized-value'), + function(d) { return d.value; }); } localized.tags = function(tags) { @@ -224,7 +226,7 @@ export function localized(field, context) { } } - input.value(tags[field.key] || ''); + getSetValue(input, tags[field.key] || ''); var postfixed = [], k, m; for (k in tags) { @@ -247,5 +249,5 @@ export function localized(field, context) { return localized; }; - return d3.rebind(localized, dispatch, 'on'); + return rebind(localized, dispatch, 'on'); } diff --git a/modules/ui/fields/maxspeed.js b/modules/ui/fields/maxspeed.js index e7850863e..1e48bbe47 100644 --- a/modules/ui/fields/maxspeed.js +++ b/modules/ui/fields/maxspeed.js @@ -1,3 +1,7 @@ +import { rebind } from '../../util/rebind'; +import { getSetValue } from '../../util/get_set_value'; +import { d3combobox } from '../../../js/lib/d3.combobox.js'; +import * as d3 from 'd3'; import _ from 'lodash'; import { pointInPolygon } from '../../geo/index'; import { imperial as imperialData } from '../../../data/index'; @@ -14,8 +18,8 @@ export function maxspeed(field, context) { imperialValues = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80]; function maxspeed(selection) { - combobox = d3.combobox(); - var unitCombobox = d3.combobox().data(['km/h', 'mph'].map(comboValues)); + combobox = d3combobox(); + var unitCombobox = d3combobox().data(['km/h', 'mph'].map(comboValues)); input = selection.selectAll('#preset-input-' + field.id) .data([0]); @@ -52,8 +56,8 @@ export function maxspeed(field, context) { .call(unitCombobox); function changeUnits() { - imperial = unitInput.value() === 'mph'; - unitInput.value(imperial ? 'mph' : 'km/h'); + imperial = getSetValue(unitInput) === 'mph'; + getSetValue(unitInput, imperial ? 'mph' : 'km/h'); setSuggestions(); change(); } @@ -62,7 +66,7 @@ export function maxspeed(field, context) { function setSuggestions() { combobox.data((imperial ? imperialValues : metricValues).map(comboValues)); - unitInput.value(imperial ? 'mph' : 'km/h'); + getSetValue(unitInput, imperial ? 'mph' : 'km/h'); } function comboValues(d) { @@ -74,7 +78,7 @@ export function maxspeed(field, context) { function change() { var tag = {}, - value = input.value(); + value = getSetValue(input); if (!value) { tag[field.key] = undefined; @@ -84,7 +88,7 @@ export function maxspeed(field, context) { tag[field.key] = value + ' mph'; } - dispatch.change(tag); + dispatch.call("change", this, tag); } maxspeed.tags = function(tags) { @@ -99,7 +103,7 @@ export function maxspeed(field, context) { setSuggestions(); - input.value(value || ''); + getSetValue(input, value || ''); }; maxspeed.focus = function() { @@ -110,5 +114,5 @@ export function maxspeed(field, context) { entity = _; }; - return d3.rebind(maxspeed, dispatch, 'on'); + return rebind(maxspeed, dispatch, 'on'); } diff --git a/modules/ui/fields/radio.js b/modules/ui/fields/radio.js index 62baf1d9b..27f8e88d2 100644 --- a/modules/ui/fields/radio.js +++ b/modules/ui/fields/radio.js @@ -1,3 +1,5 @@ +import { rebind } from '../../util/rebind'; +import * as d3 from 'd3'; import { t } from '../../util/locale'; export function radio(field) { @@ -47,7 +49,7 @@ export function radio(field) { t[d] = active ? 'yes' : undefined; } }); - dispatch.change(t); + dispatch.call("change", this, t); } radio.tags = function(tags) { @@ -73,5 +75,5 @@ export function radio(field) { radios.node().focus(); }; - return d3.rebind(radio, dispatch, 'on'); + return rebind(radio, dispatch, 'on'); } diff --git a/modules/ui/fields/restrictions.js b/modules/ui/fields/restrictions.js index d52e5759f..bdf084c25 100644 --- a/modules/ui/fields/restrictions.js +++ b/modules/ui/fields/restrictions.js @@ -1,3 +1,7 @@ +import { rebind } from '../../util/rebind'; +import { functor } from '../../util/index'; +import { getDimensions, setDimensions } from '../../util/dimensions'; +import * as d3 from 'd3'; import { t } from '../../util/locale'; import { Extent, Intersection, RawMercator, Turn, inferRestriction } from '../../geo/index'; import { Layers, Lines, Turns, Vertices } from '../../svg/index'; @@ -33,11 +37,11 @@ export function restrictions(field, context) { var intersection = Intersection(context.graph(), vertexID), graph = intersection.graph, vertex = graph.entity(vertexID), - filter = d3.functor(true), + filter = functor(true), extent = Extent(), projection = RawMercator(); - var d = wrap.dimensions(), + var d = getDimensions(wrap), c = [d[0] / 2, d[1] / 2], z = 24; @@ -50,7 +54,7 @@ export function restrictions(field, context) { .translate([c[0] - s[0], c[1] - s[1]]) .clipExtent([[0, 0], d]); - var drawLayers = Layers(projection, context).only('osm').dimensions(d), + var drawLayers = setDimensions(Layers(projection, context).only('osm'), d), drawVertices = Vertices(projection, context), drawLines = Lines(projection, context), drawTurns = Turns(projection, context); @@ -63,8 +67,7 @@ export function restrictions(field, context) { var surface = wrap.selectAll('.surface'); - surface - .dimensions(d) + setDimensions(surface, d) .call(drawVertices, graph, [vertex], filter, extent, z) .call(drawLines, graph, intersection.ways, filter) .call(drawTurns, graph, intersection.turns(fromNodeID)); @@ -91,7 +94,7 @@ export function restrictions(field, context) { d3.select(window) .on('resize.restrictions', function() { - wrap.dimensions(null); + setDimensions(wrap, null); render(); }); @@ -176,5 +179,5 @@ export function restrictions(field, context) { .on('resize.restrictions', null); }; - return d3.rebind(restrictions, dispatch, 'on'); + return rebind(restrictions, dispatch, 'on'); } diff --git a/modules/ui/fields/textarea.js b/modules/ui/fields/textarea.js index 7e9a7942f..2eaff2164 100644 --- a/modules/ui/fields/textarea.js +++ b/modules/ui/fields/textarea.js @@ -1,3 +1,5 @@ +import { rebind } from '../../util/rebind'; +import * as d3 from 'd3'; import { t } from '../../util/locale'; export function textarea(field) { @@ -22,18 +24,18 @@ export function textarea(field) { function change(onInput) { return function() { var t = {}; - t[field.key] = input.value() || undefined; - dispatch.change(t, onInput); + t[field.key] = getSetValue(input) || undefined; + dispatch.call("change", this, t, onInput); }; } textarea.tags = function(tags) { - input.value(tags[field.key] || ''); + getSetValue(input, tags[field.key] || ''); }; textarea.focus = function() { input.node().focus(); }; - return d3.rebind(textarea, dispatch, 'on'); + return rebind(textarea, dispatch, 'on'); } diff --git a/modules/ui/fields/wikipedia.js b/modules/ui/fields/wikipedia.js index 9265f0098..11e1a59fb 100644 --- a/modules/ui/fields/wikipedia.js +++ b/modules/ui/fields/wikipedia.js @@ -1,3 +1,6 @@ +import { rebind } from '../../util/rebind'; +import { d3combobox } from '../../../js/lib/d3.combobox.js'; +import * as d3 from 'd3'; import { t } from '../../util/locale'; import _ from 'lodash'; import { ChangeTags } from '../../actions/index'; @@ -16,7 +19,7 @@ export function wikipedia(field, context) { link, entity, lang, title; function wiki(selection) { - var langcombo = d3.combobox() + var langcombo = d3combobox() .fetcher(function(value, cb) { var v = value.toLowerCase(); @@ -29,7 +32,7 @@ export function wikipedia(field, context) { })); }); - var titlecombo = d3.combobox() + var titlecombo = d3combobox() .fetcher(function(value, cb) { if (!value) value = context.entity(entity.id).tags.name || ''; @@ -45,11 +48,11 @@ export function wikipedia(field, context) { lang = selection.selectAll('input.wiki-lang') .data([0]); - lang.enter().append('input') + getSetValue(lang.enter().append('input') .attr('type', 'text') .attr('class', 'wiki-lang') - .attr('placeholder', t('translate.localized_translation_language')) - .value(language()[1]); + .attr('placeholder', t('translate.localized_translation_language')), + language()[1]); lang .call(langcombo) @@ -80,7 +83,7 @@ export function wikipedia(field, context) { } function language() { - var value = lang.value().toLowerCase(); + var value = getSetValue(lang).toLowerCase(); var locale = Detect().locale.toLowerCase(); var localeLanguage; return _.find(wikipediaData, function(d) { @@ -92,7 +95,7 @@ export function wikipedia(field, context) { } function changeLang() { - lang.value(language()[1]); + getSetValue(lang, language()[1]); change(true); } @@ -101,7 +104,7 @@ export function wikipedia(field, context) { } function change(skipWikidata) { - var value = title.value(), + var value = getSetValue(title), m = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/), l = m && _.find(wikipediaData, function(d) { return m[1] === d[2]; }), anchor, @@ -120,8 +123,8 @@ export function wikipedia(field, context) { value += '#' + anchor.replace(/_/g, ' '); } value = value.slice(0, 1).toUpperCase() + value.slice(1); - lang.value(l[1]); - title.value(value); + getSetValue(lang, l[1]); + getSetValue(title, value); } syncTags.wikipedia = value ? language()[2] + ':' + value : undefined; @@ -129,7 +132,7 @@ export function wikipedia(field, context) { syncTags.wikidata = undefined; } - dispatch.change(syncTags); + dispatch.call("change", this, syncTags); if (skipWikidata || !value || !language()[2]) return; @@ -160,7 +163,7 @@ export function wikipedia(field, context) { }); context.overwrite(ChangeTags(currEntityId, currTags), annotation); - dispatch.change(currTags); + dispatch.call("change", this, currTags); }); } @@ -172,8 +175,8 @@ export function wikipedia(field, context) { // value in correct format if (l) { - lang.value(l[1]); - title.value(m[2] + (anchor ? ('#' + anchor) : '')); + getSetValue(lang, l[1]); + getSetValue(title, m[2] + (anchor ? ('#' + anchor) : '')); if (anchor) { try { // Best-effort `anchorencode:` implementation @@ -187,9 +190,9 @@ export function wikipedia(field, context) { // unrecognized value format } else { - title.value(value); + getSetValue(title, value); if (value && value !== '') { - lang.value(''); + getSetValue(lang, ''); } link.attr('href', 'https://en.wikipedia.org/wiki/Special:Search?search=' + value); } @@ -205,5 +208,5 @@ export function wikipedia(field, context) { title.node().focus(); }; - return d3.rebind(wiki, dispatch, 'on'); + return rebind(wiki, dispatch, 'on'); } diff --git a/modules/ui/full_screen.js b/modules/ui/full_screen.js index a73dc108e..13d4285e9 100644 --- a/modules/ui/full_screen.js +++ b/modules/ui/full_screen.js @@ -1,8 +1,10 @@ +import { d3keybinding } from '../../js/lib/d3.keybinding.js'; +import * as d3 from 'd3'; import { cmd } from './cmd'; export function FullScreen(context) { var element = context.container().node(), - keybinding = d3.keybinding('full-screen'); + keybinding = d3keybinding('full-screen'); // button; function getFullScreenFn() { diff --git a/modules/ui/help.js b/modules/ui/help.js index 630c3b1d3..6fdcb3b25 100644 --- a/modules/ui/help.js +++ b/modules/ui/help.js @@ -1,3 +1,5 @@ +import { d3keybinding } from '../../js/lib/d3.keybinding.js'; +import * as d3 from 'd3'; import { t } from '../util/locale'; import { tooltip } from '../util/tooltip'; import { Icon } from '../svg/index'; @@ -147,7 +149,7 @@ export function Help(context) { clickHelp(docs[0], 0); - var keybinding = d3.keybinding('help') + var keybinding = d3keybinding('help') .on(key, toggle) .on('B', hide) .on('F', hide); diff --git a/modules/ui/info.js b/modules/ui/info.js index 92406930a..508648ea2 100644 --- a/modules/ui/info.js +++ b/modules/ui/info.js @@ -1,3 +1,5 @@ +import { d3keybinding } from '../../js/lib/d3.keybinding.js'; +import * as d3 from 'd3'; import { t } from '../util/locale'; import _ from 'lodash'; import { Detect } from '../util/detect'; @@ -141,9 +143,9 @@ export function Info(context) { if (geometry === 'line' || geometry === 'area') { var closed = (entity.type === 'relation') || (entity.isClosed() && !entity.isDegenerate()), feature = entity.asGeoJSON(resolver), - length = radiansToMeters(d3.geo.length(toLineString(feature))), + length = radiansToMeters(d3.geoLength(toLineString(feature))), lengthLabel = t('infobox.' + (closed ? 'perimeter' : 'length')), - centroid = d3.geo.centroid(feature); + centroid = d3.geoCentroid(feature); list.append('li') .text(t('infobox.geometry') + ': ' + @@ -226,7 +228,7 @@ export function Info(context) { redraw(); - var keybinding = d3.keybinding('info') + var keybinding = d3keybinding('info') .on(key, toggle); d3.select(document) diff --git a/modules/ui/init.js b/modules/ui/init.js index d71a42c39..809373eda 100644 --- a/modules/ui/init.js +++ b/modules/ui/init.js @@ -1,4 +1,7 @@ +import { d3keybinding } from '../../js/lib/d3.keybinding.js'; +import * as d3 from 'd3'; import { t } from '../util/locale'; +import { getDimensions, setDimensions } from '../util/dimensions'; import { tooltip } from '../util/tooltip'; import { Defs, Icon } from '../svg/index'; import { Account } from './account'; @@ -195,7 +198,7 @@ export function init(context) { var mapDimensions = map.dimensions(); d3.select(window).on('resize.editor', function() { - mapDimensions = content.dimensions(null); + mapDimensions = setDimensions(content, null); map.dimensions(mapDimensions); }); @@ -209,7 +212,7 @@ export function init(context) { // pan amount var pa = 10; - var keybinding = d3.keybinding('main') + var keybinding = d3keybinding('main') .on('⌫', function() { d3.event.preventDefault(); }) .on('←', pan([pa, 0])) .on('↑', pan([0, pa])) @@ -246,7 +249,8 @@ export function init(context) { }); } - function ui(container) { + function ui(node) { + var container = d3.select(node); context.container(container); context.loadLocale(function() { render(container); diff --git a/modules/ui/inspector.js b/modules/ui/inspector.js index 8f4a13d60..cfc24ef05 100644 --- a/modules/ui/inspector.js +++ b/modules/ui/inspector.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import { EntityEditor } from './entity_editor'; import { PresetList } from './preset_list'; import { ViewOnOSM } from './view_on_osm'; diff --git a/modules/ui/intro/area.js b/modules/ui/intro/area.js index 7d6fd1cbd..b7ab1b2d0 100644 --- a/modules/ui/intro/area.js +++ b/modules/ui/intro/area.js @@ -1,3 +1,5 @@ +import { rebind } from '../../util/rebind'; +import * as d3 from 'd3'; import { t } from '../../util/locale'; import { icon, pad } from './helper'; @@ -87,5 +89,5 @@ export function area(context, reveal) { d3.select('.preset-search-input').on('keyup.intro', null); }; - return d3.rebind(step, event, 'on'); + return rebind(step, event, 'on'); } diff --git a/modules/ui/intro/intro.js b/modules/ui/intro/intro.js index 93ba12580..367929902 100644 --- a/modules/ui/intro/intro.js +++ b/modules/ui/intro/intro.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import { t } from '../../util/locale'; import { Entity, Graph } from '../../core/index'; import { Browse } from '../../modes/index'; @@ -6,6 +7,7 @@ import { line } from './line'; import { navigation } from './navigation'; import { point } from './point'; import { startEditing } from './start_editing'; +import { d3curtain } from '../../util/curtain'; import { default as introGraphRaw } from '../../../data/intro_graph.json'; var sampleIntros = { @@ -104,7 +106,7 @@ export function intro(context) { d3.selectAll('#map .layer-background').style('opacity', 1); - var curtain = d3.curtain(); + var curtain = d3curtain(); selection.call(curtain); function reveal(box, text, options) { diff --git a/modules/ui/intro/line.js b/modules/ui/intro/line.js index 825afd451..0a65073cf 100644 --- a/modules/ui/intro/line.js +++ b/modules/ui/intro/line.js @@ -1,3 +1,6 @@ +import { rebind } from '../../util/rebind'; +import { bindOnce } from '../../util/bind_once'; +import * as d3 from 'd3'; import { t } from '../../util/locale'; import _ from 'lodash'; import { icon, pad } from './helper'; @@ -113,7 +116,7 @@ export function line(context, reveal) { d3.select('#curtain').style('pointer-events', 'none'); var road = d3.select('.preset-category-road .preset-list-button'); reveal(road.node(), t('intro.lines.road')); - road.one('click.intro', roadCategory); + bindOnce(road, 'click.intro', roadCategory); }, 500); } @@ -121,10 +124,10 @@ export function line(context, reveal) { timeout(function() { var grid = d3.select('.subgrid'); reveal(grid.node(), t('intro.lines.residential')); - grid.selectAll(':not(.preset-highway-residential) .preset-list-button') - .one('click.intro', retryPreset); - grid.selectAll('.preset-highway-residential .preset-list-button') - .one('click.intro', roadDetails); + bindOnce(grid.selectAll(':not(.preset-highway-residential) .preset-list-button'), + 'click.intro', retryPreset); + bindOnce(grid.selectAll('.preset-highway-residential .preset-list-button'), + 'click.intro', roadDetails); }, 500); } @@ -133,7 +136,7 @@ export function line(context, reveal) { timeout(function() { var preset = d3.select('.entity-editor-pane .preset-list-button'); reveal(preset.node(), t('intro.lines.wrong_preset')); - preset.one('click.intro', presetCategory); + bindOnce(preset, 'click.intro', presetCategory); }, 500); } @@ -155,5 +158,5 @@ export function line(context, reveal) { context.history().on('change.intro', null); }; - return d3.rebind(step, event, 'on'); + return rebind(step, event, 'on'); } diff --git a/modules/ui/intro/navigation.js b/modules/ui/intro/navigation.js index 8306d0db9..d5fc52d75 100644 --- a/modules/ui/intro/navigation.js +++ b/modules/ui/intro/navigation.js @@ -1,3 +1,5 @@ +import { rebind } from '../../util/rebind'; +import * as d3 from 'd3'; import { t } from '../../util/locale'; import _ from 'lodash'; import { icon, pointBox } from './helper'; @@ -112,5 +114,5 @@ export function navigation(context, reveal) { .on('keyup.intro', null); }; - return d3.rebind(step, event, 'on'); + return rebind(step, event, 'on'); } diff --git a/modules/ui/intro/point.js b/modules/ui/intro/point.js index 2c79dad23..d106afdbc 100644 --- a/modules/ui/intro/point.js +++ b/modules/ui/intro/point.js @@ -1,3 +1,5 @@ +import { rebind } from '../../util/rebind'; +import * as d3 from 'd3'; import { t } from '../../util/locale'; import { icon, pad } from './helper'; @@ -135,7 +137,7 @@ export function point(context, reveal) { } function deleted(changed) { - if (changed.deleted().length) event.done(); + if (changed.deleted().length) event.call("done"); } }; @@ -151,5 +153,5 @@ export function point(context, reveal) { .on('keydown.intro', null); }; - return d3.rebind(step, event, 'on'); + return rebind(step, event, 'on'); } diff --git a/modules/ui/intro/start_editing.js b/modules/ui/intro/start_editing.js index 4146c2078..6ddac4958 100644 --- a/modules/ui/intro/start_editing.js +++ b/modules/ui/intro/start_editing.js @@ -1,3 +1,5 @@ +import { rebind } from '../../util/rebind'; +import * as d3 from 'd3'; import { t } from '../../util/locale'; import { icon } from './helper'; import { modal } from '../modal'; @@ -48,7 +50,7 @@ export function startEditing(context, reveal) { startbutton.append('h2') .text(t('intro.startediting.start')); - event.startEditing(); + event.call("startEditing"); }, 10500); }; @@ -57,5 +59,5 @@ export function startEditing(context, reveal) { timeouts.forEach(window.clearTimeout); }; - return d3.rebind(step, event, 'on'); + return rebind(step, event, 'on'); } diff --git a/modules/ui/lasso.js b/modules/ui/lasso.js index 3eb96b7ef..11bf90173 100644 --- a/modules/ui/lasso.js +++ b/modules/ui/lasso.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import { Extent } from '../geo/index'; import { Toggle } from './toggle'; diff --git a/modules/ui/map_data.js b/modules/ui/map_data.js index fc561af6e..85bbe3305 100644 --- a/modules/ui/map_data.js +++ b/modules/ui/map_data.js @@ -1,3 +1,5 @@ +import { d3keybinding } from '../../js/lib/d3.keybinding.js'; +import * as d3 from 'd3'; import { t } from '../util/locale'; import { tooltip } from '../util/tooltip'; import { Icon } from '../svg/index'; @@ -423,7 +425,7 @@ export function MapData(context) { setFill(fillDefault); - var keybinding = d3.keybinding('features') + var keybinding = d3keybinding('features') .on(key, togglePanel) .on('W', toggleWireframe) .on('B', hidePanel) diff --git a/modules/ui/map_in_map.js b/modules/ui/map_in_map.js index 3105ce6a9..5d1df3f97 100644 --- a/modules/ui/map_in_map.js +++ b/modules/ui/map_in_map.js @@ -1,7 +1,10 @@ +import { d3keybinding } from '../../js/lib/d3.keybinding.js'; +import * as d3 from 'd3'; import { Debug, Gpx } from '../svg/index'; import { RawMercator } from '../geo/index'; import { TileLayer } from '../renderer/index'; import { setTransform } from '../util/index'; +import { getDimensions, setDimensions } from '../util/dimensions'; export function MapInMap(context) { var key = '/'; @@ -12,7 +15,7 @@ export function MapInMap(context) { projection = RawMercator(), gpxLayer = Gpx(projection, context).showLabels(false), debugLayer = Debug(projection, context), - zoom = d3.behavior.zoom() + zoom = d3.zoom() .scaleExtent([ztok(0.5), ztok(24)]) .on('zoom', zoomPan), transformed = false, @@ -75,7 +78,7 @@ export function MapInMap(context) { panning = false; if (tCurr[0] !== tStart[0] && tCurr[1] !== tStart[1]) { - var dMini = wrap.dimensions(), + var dMini = getDimensions(wrap), cMini = [ dMini[0] / 2, dMini[1] / 2 ]; context.map().center(projection.invert(cMini)); @@ -85,7 +88,7 @@ export function MapInMap(context) { function updateProjection() { var loc = context.map().center(), - dMini = wrap.dimensions(), + dMini = getDimensions(wrap), cMini = [ dMini[0] / 2, dMini[1] / 2 ], tMain = context.projection.translate(), kMain = context.projection.scale(), @@ -129,7 +132,7 @@ export function MapInMap(context) { updateProjection(); - var dMini = wrap.dimensions(), + var dMini = getDimensions(wrap), zMini = ktoz(projection.scale() * 2 * Math.PI); // setup tile container @@ -212,7 +215,7 @@ export function MapInMap(context) { // redraw viewport bounding box if (!panning) { - var getPath = d3.geo.path().projection(projection), + var getPath = d3.geoPath().projection(projection), bbox = { type: 'Polygon', coordinates: [context.map().extent().polygon()] }; viewport = wrap.selectAll('.map-in-map-viewport') @@ -294,7 +297,7 @@ export function MapInMap(context) { redraw(); - var keybinding = d3.keybinding('map-in-map') + var keybinding = d3keybinding('map-in-map') .on(key, toggle); d3.select(document) diff --git a/modules/ui/modal.js b/modules/ui/modal.js index d6c4cf892..962ea84c1 100644 --- a/modules/ui/modal.js +++ b/modules/ui/modal.js @@ -1,6 +1,8 @@ +import { d3keybinding } from '../../js/lib/d3.keybinding.js'; +import * as d3 from 'd3'; import { Icon } from '../svg/index'; export function modal(selection, blocking) { - var keybinding = d3.keybinding('modal'); + var keybinding = d3keybinding('modal'); var previous = selection.select('div.modal'); var animate = previous.empty(); diff --git a/modules/ui/modes.js b/modules/ui/modes.js index 40b16d030..bbb28aa74 100644 --- a/modules/ui/modes.js +++ b/modules/ui/modes.js @@ -1,3 +1,5 @@ +import { d3keybinding } from '../../js/lib/d3.keybinding.js'; +import * as d3 from 'd3'; import _ from 'lodash'; import { tooltip } from '../util/tooltip'; import { AddArea, AddLine, AddPoint, Browse } from '../modes/index'; @@ -61,7 +63,7 @@ export function Modes(context) { .classed('mode-' + exited.id, false); }); - var keybinding = d3.keybinding('mode-buttons'); + var keybinding = d3keybinding('mode-buttons'); modes.forEach(function(m) { keybinding.on(m.key, function() { if (editable()) context.enter(m); }); diff --git a/modules/ui/preset.js b/modules/ui/preset.js index 7172f7377..15c92e52a 100644 --- a/modules/ui/preset.js +++ b/modules/ui/preset.js @@ -1,3 +1,7 @@ +import { rebind } from '../util/rebind'; +import { getSetValue } from '../util/get_set_value'; +import { d3combobox } from '../../js/lib/d3.combobox.js'; +import * as d3 from 'd3'; import { t } from '../util/locale'; import _ from 'lodash'; import { Browse } from '../modes/index'; @@ -206,7 +210,7 @@ export function preset(context) { .attr('class', 'value') .attr('type', 'text'); - $input.value('') + getSetValue($input, '') .attr('placeholder', function() { var placeholder = []; for (var field in notShown) { @@ -214,7 +218,7 @@ export function preset(context) { } return placeholder.slice(0,3).join(', ') + ((placeholder.length > 3) ? '…' : ''); }) - .call(d3.combobox().data(notShown) + .call(d3combobox().data(notShown) .minItems(1) .on('accept', show)); @@ -234,13 +238,13 @@ export function preset(context) { function revert(field) { d3.event.stopPropagation(); d3.event.preventDefault(); - event.change(field.revert()); + event.call("change", field.revert()); } function remove(field) { d3.event.stopPropagation(); d3.event.preventDefault(); - event.change(field.remove()); + event.call("change", field.remove()); } } @@ -273,5 +277,5 @@ export function preset(context) { return presets; }; - return d3.rebind(presets, event, 'on'); + return rebind(presets, event, 'on'); } diff --git a/modules/ui/preset_icon.js b/modules/ui/preset_icon.js index 6eb3fac5f..4ec29ce61 100644 --- a/modules/ui/preset_icon.js +++ b/modules/ui/preset_icon.js @@ -1,3 +1,5 @@ +import { functor } from '../util/index'; +import * as d3 from 'd3'; import { Icon } from '../svg/index'; import { featureIcons } from '../../data/index'; @@ -71,13 +73,13 @@ export function PresetIcon() { presetIcon.preset = function(_) { if (!arguments.length) return preset; - preset = d3.functor(_); + preset = functor(_); return presetIcon; }; presetIcon.geometry = function(_) { if (!arguments.length) return geometry; - geometry = d3.functor(_); + geometry = functor(_); return presetIcon; }; diff --git a/modules/ui/preset_list.js b/modules/ui/preset_list.js index 3d85700c8..278925b7b 100644 --- a/modules/ui/preset_list.js +++ b/modules/ui/preset_list.js @@ -1,3 +1,6 @@ +import { rebind } from '../util/rebind'; +import { d3keybinding } from '../../js/lib/d3.keybinding.js'; +import * as d3 from 'd3'; import { t } from '../util/locale'; import { Browse } from '../modes/index'; import { ChangePreset } from '../actions/index'; @@ -34,7 +37,7 @@ export function PresetList(context) { if (context.entity(id).isUsed(context.graph())) { messagewrap.append('button') .attr('class', 'preset-choose') - .on('click', function() { dispatch.choose(currentPreset); }) + .on('click', function() { dispatch.call("choose", this, currentPreset); }) .append('span') .html('►'); } else { @@ -49,14 +52,14 @@ export function PresetList(context) { function keydown() { // hack to let delete shortcut work when search is autofocused if (search.property('value').length === 0 && - (d3.event.keyCode === d3.keybinding.keyCodes['⌫'] || - d3.event.keyCode === d3.keybinding.keyCodes['⌦'])) { + (d3.event.keyCode === d3keybinding.keyCodes['⌫'] || + d3.event.keyCode === d3keybinding.keyCodes['⌦'])) { d3.event.preventDefault(); d3.event.stopPropagation(); Delete([id], context)(); } else if (search.property('value').length === 0 && (d3.event.ctrlKey || d3.event.metaKey) && - d3.event.keyCode === d3.keybinding.keyCodes.z) { + d3.event.keyCode === d3keybinding.keyCodes.z) { d3.event.preventDefault(); d3.event.stopPropagation(); context.undo(); @@ -229,7 +232,7 @@ export function PresetList(context) { ChangePreset(id, currentPreset, preset), t('operations.change_tags.annotation')); - dispatch.choose(preset); + dispatch.call("choose", this, preset); }; item.help = function() { @@ -262,5 +265,5 @@ export function PresetList(context) { return presetList; }; - return d3.rebind(presetList, dispatch, 'on'); + return rebind(presetList, dispatch, 'on'); } diff --git a/modules/ui/radial_menu.js b/modules/ui/radial_menu.js index 675fe254e..546b5fb19 100644 --- a/modules/ui/radial_menu.js +++ b/modules/ui/radial_menu.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import { roundCoords } from '../geo/index'; import { tooltipHtml } from './tooltipHtml'; diff --git a/modules/ui/raw_member_editor.js b/modules/ui/raw_member_editor.js index 5e5e45830..9d3229a41 100644 --- a/modules/ui/raw_member_editor.js +++ b/modules/ui/raw_member_editor.js @@ -1,3 +1,5 @@ +import { d3combobox } from '../../js/lib/d3.combobox.js'; +import * as d3 from 'd3'; import { t } from '../util/locale'; import { Browse, Select } from '../modes/index'; import { ChangeMember, DeleteMember } from '../actions/index'; @@ -138,7 +140,7 @@ export function RawMemberEditor(context) { return sameletter.concat(other); } - role.call(d3.combobox() + role.call(d3combobox() .fetcher(function(role, callback) { var rtype = entity.tags.type; context.taginfo().roles({ @@ -156,7 +158,7 @@ export function RawMemberEditor(context) { var row = d3.select(this); row.selectAll('input.member-role') - .call(d3.combobox.off); + .call(d3combobox.off); } } } diff --git a/modules/ui/raw_membership_editor.js b/modules/ui/raw_membership_editor.js index d4cc1b25f..2d72f4971 100644 --- a/modules/ui/raw_membership_editor.js +++ b/modules/ui/raw_membership_editor.js @@ -1,3 +1,5 @@ +import { d3combobox } from '../../js/lib/d3.combobox.js'; +import * as d3 from 'd3'; import { t } from '../util/locale'; import _ from 'lodash'; import { AddEntity, AddMember, ChangeMember, DeleteMember } from '../actions/index'; @@ -177,7 +179,7 @@ export function RawMembershipEditor(context) { $enter.append('input') .attr('type', 'text') .attr('class', 'member-entity-input') - .call(d3.combobox() + .call(d3combobox() .minItems(1) .fetcher(function(value, callback) { callback(relations(value)); @@ -236,7 +238,7 @@ export function RawMembershipEditor(context) { return sameletter.concat(other); } - role.call(d3.combobox() + role.call(d3combobox() .fetcher(function(role, callback) { var rtype = d.relation.tags.type; context.taginfo().roles({ @@ -254,7 +256,7 @@ export function RawMembershipEditor(context) { var row = d3.select(this); row.selectAll('input.member-role') - .call(d3.combobox.off); + .call(d3combobox.off); } } } diff --git a/modules/ui/raw_tag_editor.js b/modules/ui/raw_tag_editor.js index a5a491d43..d3317c4e2 100644 --- a/modules/ui/raw_tag_editor.js +++ b/modules/ui/raw_tag_editor.js @@ -1,3 +1,7 @@ +import { rebind } from '../util/rebind'; +import { getSetValue } from '../util/get_set_value'; +import { d3combobox } from '../../js/lib/d3.combobox.js'; +import * as d3 from 'd3'; import { t } from '../util/locale'; import { Disclosure } from './disclosure'; import { Icon } from '../svg/index'; @@ -104,18 +108,18 @@ export function RawTagEditor(context) { .call(reference.body); }); - $items.select('input.key') + getSetValue($items.select('input.key') .attr('title', function(d) { return d.key; }) - .value(function(d) { return d.key; }) .on('blur', keyChange) - .on('change', keyChange); + .on('change', keyChange), + function(d) { return d.key; }) - $items.select('input.value') + getSetValue($items.select('input.value') .attr('title', function(d) { return d.value; }) - .value(function(d) { return d.value; }) .on('blur', valueChange) .on('change', valueChange) - .on('keydown.push-more', pushMore); + .on('keydown.push-more', pushMore), + function(d) { return d.value; }) $items.select('button.remove') .on('click', removeTag); @@ -149,7 +153,7 @@ export function RawTagEditor(context) { return sameletter.concat(other); } - key.call(d3.combobox() + key.call(d3combobox() .fetcher(function(value, callback) { context.taginfo().keys({ debounce: true, @@ -160,11 +164,11 @@ export function RawTagEditor(context) { }); })); - value.call(d3.combobox() + value.call(d3combobox() .fetcher(function(value, callback) { context.taginfo().values({ debounce: true, - key: key.value(), + key: getSetValue(key), geometry: context.geometry(id), query: value }, function(err, data) { @@ -177,10 +181,10 @@ export function RawTagEditor(context) { var row = d3.select(this); row.selectAll('input.key') - .call(d3.combobox.off); + .call(d3combobox.off); row.selectAll('input.value') - .call(d3.combobox.off); + .call(d3combobox.off); } function keyChange(d) { @@ -200,19 +204,19 @@ export function RawTagEditor(context) { tag[kNew] = d.value; d.key = kNew; // Maintain DOM identity through the subsequent update. this.value = kNew; - event.change(tag); + event.call("change", tag); } function valueChange(d) { var tag = {}; tag[d.key] = this.value; - event.change(tag); + event.call("change", tag); } function removeTag(d) { var tag = {}; tag[d.key] = undefined; - event.change(tag); + event.call("change", tag); d3.select(this.parentNode).remove(); } @@ -252,5 +256,5 @@ export function RawTagEditor(context) { return rawTagEditor; }; - return d3.rebind(rawTagEditor, event, 'on'); + return rebind(rawTagEditor, event, 'on'); } diff --git a/modules/ui/save.js b/modules/ui/save.js index 1158aea06..5c5365bb8 100644 --- a/modules/ui/save.js +++ b/modules/ui/save.js @@ -1,3 +1,5 @@ +import { d3keybinding } from '../../js/lib/d3.keybinding.js'; +import * as d3 from 'd3'; import { t } from '../util/locale'; import { tooltip } from '../util/tooltip'; import { Save as SaveMode } from '../modes/index'; @@ -53,7 +55,7 @@ export function Save(context) { .attr('class', 'count') .text('0'); - var keybinding = d3.keybinding('undo-redo') + var keybinding = d3keybinding('undo-redo') .on(key, save, true); d3.select(document) diff --git a/modules/ui/scale.js b/modules/ui/scale.js index 179a4f4f8..bda008f90 100644 --- a/modules/ui/scale.js +++ b/modules/ui/scale.js @@ -1,5 +1,6 @@ import { lonToMeters, metersToLon } from '../geo/index'; import { Detect } from '../util/detect'; +import { getDimensions, setDimensions } from '../util/dimensions'; export function Scale(context) { var projection = context.projection, diff --git a/modules/ui/selection_list.js b/modules/ui/selection_list.js index 4c3b02d7a..71ea703b5 100644 --- a/modules/ui/selection_list.js +++ b/modules/ui/selection_list.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import { t } from '../util/locale'; import { Entity } from '../core/index'; import { Icon } from '../svg/index'; diff --git a/modules/ui/source_switch.js b/modules/ui/source_switch.js index 792d5589d..3d5544314 100644 --- a/modules/ui/source_switch.js +++ b/modules/ui/source_switch.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import { t } from '../util/locale'; import { Browse } from '../modes/index'; export function SourceSwitch(context) { diff --git a/modules/ui/splash.js b/modules/ui/splash.js index 991928006..4774668dd 100644 --- a/modules/ui/splash.js +++ b/modules/ui/splash.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import { t } from '../util/locale'; import { intro } from './intro/index'; import { modal } from './modal'; diff --git a/modules/ui/success.js b/modules/ui/success.js index 79050f698..1d709b9b1 100644 --- a/modules/ui/success.js +++ b/modules/ui/success.js @@ -1,3 +1,5 @@ +import { rebind } from '../util/rebind'; +import * as d3 from 'd3'; import { t } from '../util/locale'; import { tooltip } from '../util/tooltip'; import { Icon } from '../svg/index'; @@ -14,7 +16,7 @@ export function Success(context) { header.append('button') .attr('class', 'fr') - .on('click', function() { dispatch.cancel(); }) + .on('click', function() { dispatch.call("cancel"); }) .call(Icon('#icon-close')); header.append('h3') @@ -68,5 +70,5 @@ export function Success(context) { return success; }; - return d3.rebind(success, dispatch, 'on'); + return rebind(success, dispatch, 'on'); } diff --git a/modules/ui/tag_reference.js b/modules/ui/tag_reference.js index 063467b9d..ab8cb9872 100644 --- a/modules/ui/tag_reference.js +++ b/modules/ui/tag_reference.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; import { t } from '../util/locale'; import _ from 'lodash'; import { Detect } from '../util/detect'; diff --git a/modules/ui/toggle.js b/modules/ui/toggle.js index 9e06ecf8e..0d96933de 100644 --- a/modules/ui/toggle.js +++ b/modules/ui/toggle.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; // toggles the visibility of ui elements, using a combination of the // hide class, which sets display=none, and a d3 transition for opacity. // this will cause blinking when called repeatedly, so check that the diff --git a/modules/ui/undo_redo.js b/modules/ui/undo_redo.js index 132e9ddfd..9736a0d54 100644 --- a/modules/ui/undo_redo.js +++ b/modules/ui/undo_redo.js @@ -1,3 +1,5 @@ +import { d3keybinding } from '../../js/lib/d3.keybinding.js'; +import * as d3 from 'd3'; import { t } from '../util/locale'; import { tooltip } from '../util/tooltip'; import { Icon } from '../svg/index'; @@ -43,7 +45,7 @@ export function UndoRedo(context) { .call(Icon('#icon-' + d.id)); }); - var keybinding = d3.keybinding('undo') + var keybinding = d3keybinding('undo') .on(commands[0].cmd, function() { d3.event.preventDefault(); commands[0].action(); }) .on(commands[1].cmd, function() { d3.event.preventDefault(); commands[1].action(); }); diff --git a/modules/ui/zoom.js b/modules/ui/zoom.js index ac780b415..27dbf6c9a 100644 --- a/modules/ui/zoom.js +++ b/modules/ui/zoom.js @@ -1,3 +1,5 @@ +import { d3keybinding } from '../../js/lib/d3.keybinding.js'; +import * as d3 from 'd3'; import { t } from '../util/locale'; import { tooltip } from '../util/tooltip'; import { Icon } from '../svg/index'; @@ -60,7 +62,7 @@ export function Zoom(context) { .call(Icon('#icon-' + d.icon, 'light')); }); - var keybinding = d3.keybinding('zoom'); + var keybinding = d3keybinding('zoom'); _.each(['=','ffequals','plus','ffplus'], function(key) { keybinding.on(key, zoomIn); diff --git a/js/lib/d3.one.js b/modules/util/bind_once.js similarity index 58% rename from js/lib/d3.one.js rename to modules/util/bind_once.js index b28bd2c58..14d345f9c 100644 --- a/js/lib/d3.one.js +++ b/modules/util/bind_once.js @@ -1,5 +1,5 @@ -d3.selection.prototype.one = function (type, listener, capture) { - var target = this, typeOnce = type + ".once"; +export function bindOnce(target, type, listener, capture) { + var typeOnce = type + ".once"; function one() { target.on(typeOnce, null); listener.apply(this, arguments); diff --git a/js/lib/d3.curtain.js b/modules/util/curtain.js similarity index 87% rename from js/lib/d3.curtain.js rename to modules/util/curtain.js index 61e7aee67..863ea75e7 100644 --- a/js/lib/d3.curtain.js +++ b/modules/util/curtain.js @@ -1,5 +1,9 @@ +import { getDimensions } from './dimensions'; +import { rebind } from '../../modules/util/rebind'; +import * as d3 from 'd3'; + // Tooltips and svg mask used to highlight certain features -d3.curtain = function() { +export function d3curtain() { var event = d3.dispatch(), surface, @@ -19,11 +23,9 @@ d3.curtain = function() { }); darkness = surface.append('path') - .attr({ - x: 0, - y: 0, - 'class': 'curtain-darkness' - }); + .attr('x', 0) + .attr('y', 0) + .attr('class', 'curtain-darkness') d3.select(window).on('resize.curtain', resize); @@ -37,10 +39,9 @@ d3.curtain = function() { resize(); function resize() { - surface.attr({ - width: window.innerWidth, - height: window.innerHeight - }); + surface + .attr('width', window.innerWidth) + .attr('height', window.innerHeight); curtain.cut(darkness.datum()); } } @@ -57,10 +58,9 @@ d3.curtain = function() { var html = parts[0] ? '' + parts[0] + '' : ''; if (parts[1]) html += '' + parts[1] + ''; - var dimensions = tooltip.classed('in', true) + var dimensions = getDimensions(tooltip.classed('in', true) .select('.tooltip-inner') - .html(html) - .dimensions(); + .html(html)); var pos; @@ -127,5 +127,5 @@ d3.curtain = function() { tooltip.remove(); }; - return d3.rebind(curtain, event, 'on'); + return rebind(curtain, event, 'on'); }; diff --git a/modules/util/dimensions.js b/modules/util/dimensions.js new file mode 100644 index 000000000..e9c4b9c9f --- /dev/null +++ b/modules/util/dimensions.js @@ -0,0 +1,24 @@ +function refresh(target, node) { + var cr = node.getBoundingClientRect(); + var prop = [cr.width, cr.height]; + target.property('__dimensions__', prop); + return prop; +} + +export function getDimensions (target) { + if (!target) return [0, 0]; + var node = target.node(); + return target.property('__dimensions__') || refresh(target, node); +} + +export function setDimensions (target, dimensions) { + var node = target.node(); + if (dimensions === null) { + if (!node) return [0,0]; + return refresh(target, node); + } + return target + .property('__dimensions__', [dimensions[0], dimensions[1]]) + .attr('width', dimensions[0]) + .attr('height', dimensions[1]) +} diff --git a/js/lib/d3.value.js b/modules/util/get_set_value.js similarity index 52% rename from js/lib/d3.value.js rename to modules/util/get_set_value.js index 1261034e5..5e2150874 100644 --- a/js/lib/d3.value.js +++ b/modules/util/get_set_value.js @@ -1,19 +1,19 @@ // Like selection.property('value', ...), but avoids no-op value sets, // which can result in layout/repaint thrashing in some situations. -d3.selection.prototype.value = function(value) { +export function getSetValue (target, value) { function d3_selection_value(value) { function valueNull() { - delete this.value; + delete target.value; } function valueConstant() { - if (this.value !== value) this.value = value; + if (target.value !== value) target.value = value; } function valueFunction() { - var x = value.apply(this, arguments); - if (x == null) delete this.value; - else if (this.value !== x) this.value = x; + var x = value.apply(target, arguments); + if (x == null) delete target.value; + else if (target.value !== x) target.value = x; } return value == null @@ -21,6 +21,6 @@ d3.selection.prototype.value = function(value) { ? valueFunction : valueConstant); } - if (!arguments.length) return this.property('value'); - return this.each(d3_selection_value(value)); -}; + if (!arguments.length) return target.property('value'); + return target.each(d3_selection_value(value)); +} diff --git a/modules/util/index.js b/modules/util/index.js index 92780dffa..906623f17 100644 --- a/modules/util/index.js +++ b/modules/util/index.js @@ -14,5 +14,6 @@ export { fastMouse } from './util'; export { getPrototypeOf } from './util'; export { asyncMap } from './util'; export { wrap } from './util'; +export { functor } from './util'; export { SessionMutex } from './session_mutex'; export { SuggestNames } from './suggest_names'; diff --git a/modules/util/jsonp_request.js b/modules/util/jsonp_request.js index 3ed47b677..c740b6caf 100644 --- a/modules/util/jsonp_request.js +++ b/modules/util/jsonp_request.js @@ -1,3 +1,4 @@ +import * as d3 from 'd3'; var jsonpCache = {}; window.jsonpCache = jsonpCache; diff --git a/modules/util/rebind.js b/modules/util/rebind.js new file mode 100644 index 000000000..a9c78a8b2 --- /dev/null +++ b/modules/util/rebind.js @@ -0,0 +1,16 @@ +// Copies a variable number of methods from source to target. +export function rebind(target, source) { + var i = 1, n = arguments.length, method; + while (++i < n) target[method = arguments[i]] = d3_rebind(target, source, source[method]); + return target; +}; + +// Method is assumed to be a standard D3 getter-setter: +// If passed with no arguments, gets the value. +// If passed with arguments, sets the value and returns the target. +function d3_rebind(target, source, method) { + return function() { + var value = method.apply(source, arguments); + return value === source ? target : value; + }; +} diff --git a/modules/util/tooltip.js b/modules/util/tooltip.js index 498089e97..1267a78f7 100644 --- a/modules/util/tooltip.js +++ b/modules/util/tooltip.js @@ -1,10 +1,12 @@ +import { functor } from './index'; +import * as d3 from 'd3'; export function tooltip() { var tooltip = function(selection) { selection.each(setup); }, - animation = d3.functor(false), - html = d3.functor(false), + animation = functor(false), + html = functor(false), title = function() { var title = this.getAttribute('data-original-title'); if (title) { @@ -18,11 +20,11 @@ export function tooltip() { }, over = 'mouseenter.tooltip', out = 'mouseleave.tooltip', - placement = d3.functor('top'); + placement = functor('top'); tooltip.title = function(_) { if (arguments.length) { - title = d3.functor(_); + title = functor(_); return tooltip; } else { return title; @@ -31,7 +33,7 @@ export function tooltip() { tooltip.html = function(_) { if (arguments.length) { - html = d3.functor(_); + html = functor(_); return tooltip; } else { return html; @@ -40,7 +42,7 @@ export function tooltip() { tooltip.placement = function(_) { if (arguments.length) { - placement = d3.functor(_); + placement = functor(_); return tooltip; } else { return placement; diff --git a/js/lib/d3.trigger.js b/modules/util/trigger_event.js similarity index 64% rename from js/lib/d3.trigger.js rename to modules/util/trigger_event.js index 59b7cd5a5..676add372 100644 --- a/js/lib/d3.trigger.js +++ b/modules/util/trigger_event.js @@ -1,5 +1,5 @@ -d3.selection.prototype.trigger = function (type) { - this.each(function() { +export function triggerEvent(target, type) { + target.each(function() { var evt = document.createEvent('HTMLEvents'); evt.initEvent(type, true, true); this.dispatchEvent(evt); diff --git a/modules/util/util.js b/modules/util/util.js index 62550a198..dff1c982a 100644 --- a/modules/util/util.js +++ b/modules/util/util.js @@ -1,3 +1,5 @@ +import { functor } from '../index'; +import * as d3 from 'd3'; import { t } from './locale'; import { Detect } from './detect'; import { remove as removeDiacritics } from 'diacritics'; @@ -193,3 +195,16 @@ export function wrap(index, length) { index += Math.ceil(-index/length)*length; return index % length; } + +/** + * a replacement for functor + * + * @param {*} value any value + * @returns {Function} a function that returns that value or the value if it's a function + */ +export function functor(value) { + if (typeof value === 'function') return value; + return function() { + return value; + }; +} diff --git a/package.json b/package.json index 1f92ddd0e..126f938a6 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ }, "scripts": { "test": "npm run lint && make && phantomjs node_modules/mocha-phantomjs-core/mocha-phantomjs-core.js test/index.html dot", - "start": "rollup --config=./rollup.config.js -w --input ./modules/id.js --output dist/iD.js", + "start": "rollup --config=./rollup.config.js -f iife --input ./modules/id.js --output dist/iD.js -w", "web": "http-server", "build": "rollup --config=./rollup.config.js -f iife --input ./modules/id.js --output dist/iD.js && uglifyjs dist/iD.js -c -m -o dist/iD.min.js", "lint": "eslint js/id test/spec modules" @@ -36,7 +36,7 @@ "devDependencies": { "chai": "~3.5.0", "brfs": "1.4.3", - "d3": "3.5.5", + "d3": "4.2.1", "editor-layer-index": "git://github.com/osmlab/editor-layer-index.git#gh-pages", "eslint": "~3.3.1", "glob": "~7.0.5", diff --git a/rollup.config.js b/rollup.config.js index 6b01750c9..322fcc37a 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -4,7 +4,7 @@ import json from 'rollup-plugin-json'; export default { plugins: [ - nodeResolve({ jsnext: true, main: true, browser: true }), + nodeResolve({ jsnext: true, main: true, browser: false }), commonjs(), json() ] diff --git a/test/bench/event-binding-cost.html b/test/bench/event-binding-cost.html index 595104fa3..c6b20a814 100644 --- a/test/bench/event-binding-cost.html +++ b/test/bench/event-binding-cost.html @@ -24,7 +24,6 @@

-    
     
     
     
     
 
     
-    
     
 
     
diff --git a/test/rendering.html b/test/rendering.html
index e5856534d..ffe74022b 100644
--- a/test/rendering.html
+++ b/test/rendering.html
@@ -8,7 +8,6 @@
 
     
     
-    
 
     
     
diff --git a/test/spec/actions/circularize.js b/test/spec/actions/circularize.js
index 430b4cf9c..6c6331019 100644
--- a/test/spec/actions/circularize.js
+++ b/test/spec/actions/circularize.js
@@ -1,5 +1,5 @@
 describe('iD.actions.Circularize', function () {
-    var projection = d3.geo.mercator();
+    var projection = d3.geoMercator();
 
     function isCircular(id, graph) {
         var points = _.map(graph.childNodes(graph.entity(id)), 'loc').map(projection),
diff --git a/test/spec/actions/move.js b/test/spec/actions/move.js
index a7c48861d..7e085adaf 100644
--- a/test/spec/actions/move.js
+++ b/test/spec/actions/move.js
@@ -1,5 +1,5 @@
 describe('iD.actions.Move', function() {
-    var projection = d3.geo.mercator().scale(250 / Math.PI);
+    var projection = d3.geoMercator().scale(250 / Math.PI);
 
     describe('#disabled', function() {
         it('returns falsy by default', function() {
diff --git a/test/spec/actions/orthogonalize.js b/test/spec/actions/orthogonalize.js
index 982838103..050cddd9f 100644
--- a/test/spec/actions/orthogonalize.js
+++ b/test/spec/actions/orthogonalize.js
@@ -1,5 +1,5 @@
 describe('iD.actions.Orthogonalize', function () {
-    var projection = d3.geo.mercator();
+    var projection = d3.geoMercator();
 
     it('orthogonalizes a perfect quad', function () {
         var graph = iD.Graph([
diff --git a/test/spec/actions/restrict_turn.js b/test/spec/actions/restrict_turn.js
index 4650e1cbe..d3c643d7f 100644
--- a/test/spec/actions/restrict_turn.js
+++ b/test/spec/actions/restrict_turn.js
@@ -1,5 +1,5 @@
 describe('iD.actions.RestrictTurn', function() {
-    var projection = d3.geo.mercator().scale(250 / Math.PI);
+    var projection = d3.geoMercator().scale(250 / Math.PI);
 
     it('adds a restriction to an unrestricted turn', function() {
         // u====*--->w
diff --git a/test/spec/actions/straighten.js b/test/spec/actions/straighten.js
index 85c4f5a95..9a50693fb 100644
--- a/test/spec/actions/straighten.js
+++ b/test/spec/actions/straighten.js
@@ -1,5 +1,5 @@
 describe('iD.actions.Straighten', function () {
-    var projection = d3.geo.mercator();
+    var projection = d3.geoMercator();
 
     describe('#disabled', function () {
         it('returns falsy for ways with internal nodes near centerline', function () {
diff --git a/test/spec/renderer/tile_layer.js b/test/spec/renderer/tile_layer.js
index f937deea9..9b3fa2083 100644
--- a/test/spec/renderer/tile_layer.js
+++ b/test/spec/renderer/tile_layer.js
@@ -4,7 +4,7 @@ describe('iD.TileLayer', function() {
     beforeEach(function() {
         context = iD.Context(window);
         d = d3.select(document.createElement('div'));
-        c = iD.TileLayer(context).projection(d3.geo.mercator());
+        c = iD.TileLayer(context).projection(d3.geoMercator());
     });
 
     afterEach(function() {
diff --git a/test/spec/svg/areas.js b/test/spec/svg/areas.js
index 880ec0b88..c2717f423 100644
--- a/test/spec/svg/areas.js
+++ b/test/spec/svg/areas.js
@@ -1,6 +1,6 @@
 describe('iD.svg.Areas', function () {
     var surface,
-        projection = d3.geo.projection(function(x, y) { return [x, y]; })
+        projection = d3.geoProjection(function(x, y) { return [x, y]; })
             .clipExtent([[0, 0], [Infinity, Infinity]]),
         all = d3.functor(true),
         none = d3.functor(false);
diff --git a/test/spec/svg/lines.js b/test/spec/svg/lines.js
index d1b914b03..f7a92a179 100644
--- a/test/spec/svg/lines.js
+++ b/test/spec/svg/lines.js
@@ -1,6 +1,6 @@
 describe('iD.svg.Lines', function () {
     var surface,
-        projection = d3.geo.projection(function(x, y) { return [x, y]; })
+        projection = d3.geoProjection(function(x, y) { return [x, y]; })
             .clipExtent([[0, 0], [Infinity, Infinity]]),
         all = d3.functor(true),
         none = d3.functor(false);