Use live bound object for imagery array, remove context.imagery() accessor

Also update documentation, closes #3359
This commit is contained in:
Bryan Housel
2016-11-14 11:15:03 -05:00
parent 9c8037ca4e
commit 93d50b4e87
12 changed files with 97 additions and 42 deletions

89
API.md
View File

@@ -137,9 +137,79 @@ class.
Elements that are currently selected shall have the `.selected` class.
## Customized Deployments
iD is used to edit data outside of the OpenStreetMap environment. There are some basic configuration steps to introduce custom presets, imagery and tag information.
iD may be used to edit maps in a non-OpenStreetMap environment. This requires
certain parts of the iD code to be replaced at runtime by custom code or data.
iD is written in a modular style and bundled with [rollup.js](http://rollupjs.org/),
which makes hot code replacement tricky. (ES6 module exports are
[immutable bindings](http://www.2ality.com/2015/07/es6-module-exports.html)).
Because of this, the parts of iD which are designed for customization are exported
as live bound objects that can be overriden at runtime _before initializing the iD context_.
### Services
The `iD.services` object includes code that talks to other web services.
To replace the OSM service with a custom service that exactly mimics the default OSM service:
```js
iD.services.osm = serviceMyOSM;
```
Some services may be removed entirely. For example, to remove the Mapillary service:
```js
iD.services.mapillary = undefined;
// or
delete iD.services.mapillary;
```
### Background Imagery
iD's background imagery database is stored in the `iD.data.imagery` array and can be
overridden. (Note that the "None" and "Custom" options will always be shown in the list)
To remove all imagery from iD:
```js
iD.data.imagery = [];
```
To replace all imagery with a single source:
```js
iD.data.imagery = [{
"id": "ExampleImagery",
"name": "My Imagery",
"type": "tms",
"template": "http://{switch:a,b,c}.tiles.example.com/{z}/{x}/{y}.png"
}];
```
Each imagery source should have the following properties:
* `id` - Unique identifier for this source (also used as a url paramater)
* `name` - Display name for the source
* `type` - Source type, currently only `tms` is supported
* `template` - Url template, valid replacement tokens include:
* `{z}`, `{x}`, `{y}` - for Z/X/Y scheme
* `{-y}` or `{ty}` - for flipped Y
* `{u}` - for quadtile scheme
* `{switch:a,b,c}` - for parts of the url that can be cycled for connection parallelization
Optional properties:
* `description` - A longer source description which, if included, will be displayed in a popup when viewing the background imagery list
* `overlay` - If `true`, this is an overlay layer (a transparent layer rendered above base imagery layer). Defaults to `false`
* `scaleExtent` - Allowable min and max zoom levels, defaults to `[0, 20]`
* `polygon` - Array of coordinate rings within which imagery is valid. If omitted, imagery is assumed to be valid worldwide
* `overzoom` - Can this imagery be scaled up when zooming in beyond the max zoom? Defaults to `true`
* `terms_url` - Url to link to when displaying the imagery terms
* `terms_html` - Html content to display in the imagery terms
* `terms_text` - Text content to display in the imagery terms
* `best` - If set to `true`, this imagery is considered "better than Bing" and may be chosen by default when iD starts. Will display with a star in the background imagery list. Defaults to `false`
For more details about the `iD.data.imagery` structure, see
[`update_imagery.js`](https://github.com/openstreetmap/iD/blob/master/data/update_imagery.js).
### Presets
@@ -148,27 +218,12 @@ iD can use external presets exclusively or along with the default OpenStreetMap
```js
var id = iD.Context()
.presets(customPresets)
.imagery(iD.dataImagery);
.presets(customPresets);
```
The format of the Preset object is [documented here](https://github.com/openstreetmap/iD/tree/master/data/presets#custom-presets).
### Imagery
Just like Presets, Imagery can be configured using the `context.imagery` accessor:
```js
var id = iD.Context()
.presets(customPresets)
.imagery(customImagery);
```
The Imagery object should follow the structure defined by [editor-layer-index](https://github.com/osmlab/editor-layer-index/blob/gh-pages/schema.json)
### Minimum Editable Zoom

View File

@@ -5,7 +5,6 @@ export { default as dataSuggestions } from 'name-suggestion-index/name-suggestio
export { dataAddressFormats } from './address-formats.json';
export { dataDeprecated } from './deprecated.json';
export { dataDiscarded } from './discarded.json';
export { dataImagery } from './imagery.json';
export { dataLocales } from './locales.json';
export { dataPhoneFormats } from './phone-formats.json';
@@ -24,3 +23,8 @@ export var dataPresets = {
categories: categories,
fields: fields
};
import { dataImagery } from './imagery.json';
export var data = {
imagery: dataImagery
};

5
dist/index.html vendored
View File

@@ -37,9 +37,8 @@
document.getElementById('id-container').innerHTML = 'Sorry, your browser is not currently supported. Please use Potlatch 2 to edit the map.';
document.getElementById('id-container').className = 'unsupported';
} else {
var id = iD.Context(window)
.presets(iD.dataPresets)
.imagery(iD.dataImagery);
var id = iD.Context()
.presets(iD.dataPresets);
id.ui()(document.getElementById('id-container'));
}

View File

@@ -17,9 +17,9 @@
<body>
<div id='id-container'></div>
<script>
id = iD.Context()
.presets(iD.dataPresets)
.imagery(iD.dataImagery)
.assetPath('dist/');
id.ui()(document.getElementById('id-container'), function() {

View File

@@ -259,13 +259,6 @@ export function coreContext() {
};
/* Imagery */
context.imagery = function(_) {
background.load(_);
return context;
};
/* Container */
var container, embed;
context.container = function(_) {
@@ -347,7 +340,7 @@ export function coreContext() {
context.reset = context.flush = function() {
context.debouncedSave.cancel();
_.each(services, function(service) {
if (typeof service.reset === 'function') {
if (service && typeof service.reset === 'function') {
service.reset(context);
}
});
@@ -407,10 +400,11 @@ export function coreContext() {
context.zoomOutFurther = map.zoomOutFurther;
context.redrawEnable = map.redrawEnable;
background.init();
presets = presetInit();
_.each(services, function(service) {
if (typeof service.init === 'function') {
if (service && typeof service.init === 'function') {
service.init(context);
}
});

View File

@@ -1,10 +1,11 @@
import * as d3 from 'd3';
import _ from 'lodash';
import { utilRebind } from '../util/rebind';
import { data } from '../../data/index';
import { geoExtent, geoMetersToOffset, geoOffsetToMeters} from '../geo/index';
import { utilQsString, utilStringQs } from '../util/index';
import { rendererBackgroundSource } from './background_source';
import { rendererTileLayer } from './tile_layer';
import { utilQsString, utilStringQs } from '../util/index';
import { utilRebind } from '../util/rebind';
export function rendererBackground(context) {
@@ -191,7 +192,7 @@ export function rendererBackground(context) {
};
background.load = function(imagery) {
background.init = function() {
function parseMap(qmap) {
if (!qmap) return false;
var args = qmap.split('/').map(Number);
@@ -199,12 +200,13 @@ export function rendererBackground(context) {
return geoExtent([args[1], args[2]]);
}
var q = utilStringQs(window.location.hash.substring(1)),
var dataImagery = data.imagery || [],
q = utilStringQs(window.location.hash.substring(1)),
chosen = q.background || q.layer,
extent = parseMap(q.map),
best;
backgroundSources = imagery.map(function(source) {
backgroundSources = dataImagery.map(function(source) {
if (source.type === 'bing') {
return rendererBackgroundSource.Bing(source, dispatch);
} else {

View File

@@ -1,9 +1,9 @@
import * as d3 from 'd3';
import { geoPolygonIntersectsPolygon } from '../geo/index';
import {
data,
dataImperial,
dataDriveLeft,
dataImagery
dataDriveLeft
} from '../../data/index';
@@ -83,6 +83,7 @@ export function svgDebug(projection, context) {
var extent = context.map().extent(),
dataImagery = data.imagery || [],
availableImagery = showsImagery && multipolygons(dataImagery.filter(function(source) {
if (!source.polygon) return false;
return source.polygon.some(function(polygon) {

View File

@@ -2,7 +2,7 @@ describe('iD.behaviorLasso', function () {
var lasso, context;
beforeEach(function () {
context = iD.Context().imagery(iD.dataImagery);
context = iD.Context();
context.container(d3.select(document.createElement('div')));
// Neuter connection

View File

@@ -3,7 +3,7 @@ describe('iD.behaviorSelect', function() {
beforeEach(function() {
container = d3.select('body').append('div');
context = iD.Context().imagery(iD.dataImagery).container(container);
context = iD.Context().container(container);
a = iD.Node({loc: [0, 0]});
b = iD.Node({loc: [0, 0]});

View File

@@ -6,7 +6,6 @@ describe.skip('iD.modeAddPoint', function() {
context = iD.Context()
.presets(iD.dataPresets)
.imagery([])
.container(container);
context.loadTiles = function () {};

View File

@@ -2,7 +2,7 @@ describe('iD.Map', function() {
var context, map;
beforeEach(function() {
context = iD.Context().imagery(iD.dataImagery);
context = iD.Context();
context.container(d3.select(document.createElement('div')));
map = context.map();
d3.select(document.createElement('div'))

View File

@@ -1,6 +1,7 @@
/* globals chai:false */
iD.debug = true;
iD.data.imagery = [];
mocha.setup({
ui: 'bdd',