mirror of
https://github.com/FoggedLens/iD.git
synced 2026-02-13 01:02:58 +00:00
added: svg notes, TODO: add icon, test
This commit is contained in:
@@ -113,6 +113,14 @@
|
||||
stroke-opacity: 1;
|
||||
}
|
||||
|
||||
/* Notes Layer */
|
||||
.layer-notes {
|
||||
pointer-events: none;
|
||||
}
|
||||
.layer-notes .notes * {
|
||||
fill: #20c4ff;
|
||||
}
|
||||
|
||||
|
||||
/* Streetside Image Layer */
|
||||
.layer-streetside-images {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export { osmChangeset } from './changeset';
|
||||
export { osmEntity } from './entity';
|
||||
export { osmNode } from './node';
|
||||
export { osmNote } from './note';
|
||||
export { osmRelation } from './relation';
|
||||
export { osmWay } from './way';
|
||||
|
||||
|
||||
34
modules/osm/note.js
Normal file
34
modules/osm/note.js
Normal file
@@ -0,0 +1,34 @@
|
||||
import _extend from 'lodash-es/extend';
|
||||
|
||||
import { osmEntity } from './entity';
|
||||
import { geoExtent } from '../geo';
|
||||
|
||||
|
||||
export function osmNote() {
|
||||
if (!(this instanceof osmNote)) {
|
||||
return (new osmNote()).initialize(arguments);
|
||||
} else if (arguments.length) {
|
||||
this.initialize(arguments);
|
||||
}
|
||||
}
|
||||
|
||||
osmEntity.note = osmNote;
|
||||
|
||||
osmNote.prototype = Object.create(osmEntity.prototype);
|
||||
|
||||
_extend(osmNote.prototype, {
|
||||
|
||||
type: 'note',
|
||||
|
||||
|
||||
extent: function() {
|
||||
return new geoExtent(this.loc);
|
||||
},
|
||||
|
||||
|
||||
geometry: function(graph) {
|
||||
return graph.transient(this, 'geometry', function() {
|
||||
return graph.isPoi(this) ? 'point' : 'vertex';
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -1,8 +1,10 @@
|
||||
import _extend from 'lodash-es/extend';
|
||||
import _filter from 'lodash-es/filter';
|
||||
import _flatten from 'lodash-es/flatten';
|
||||
import _find from 'lodash-es/find';
|
||||
import _forEach from 'lodash-es/forEach';
|
||||
import _isEmpty from 'lodash-es/isEmpty';
|
||||
import _map from 'lodash-es/map';
|
||||
|
||||
import osmAuth from 'osm-auth';
|
||||
|
||||
@@ -10,19 +12,25 @@ import rbush from 'rbush';
|
||||
|
||||
var _entityCache = {};
|
||||
|
||||
import { range as d3_range } from 'd3-array';
|
||||
import { dispatch as d3_dispatch } from 'd3-dispatch';
|
||||
import { xml as d3_xml } from 'd3-request';
|
||||
|
||||
import { d3geoTile as d3_geoTile } from '../lib/d3.geo.tile';
|
||||
import { geoExtent } from '../geo';
|
||||
|
||||
import {
|
||||
osmNote,
|
||||
osmEntity,
|
||||
} from '../osm';
|
||||
|
||||
import {
|
||||
utilRebind,
|
||||
utilIdleWorker
|
||||
} from '../util';
|
||||
|
||||
var urlroot = 'https://api.openstreetmap.org',
|
||||
_notesCache = { notes: { inflight: {}, loaded: {} } },
|
||||
_notesCache,
|
||||
__notesSelectedNote,
|
||||
dispatch = d3_dispatch('loadedNotes', 'loading'),
|
||||
tileZoom = 14;
|
||||
@@ -87,6 +95,130 @@ function nearNullIsland(x, y, z) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// no more than `limit` results per partition.
|
||||
function searchLimited(psize, limit, projection, rtree) {
|
||||
limit = limit || 3;
|
||||
|
||||
var partitions = partitionViewport(psize, projection);
|
||||
var results;
|
||||
|
||||
results = _flatten(_map(partitions, function(extent) {
|
||||
return rtree.search(extent.bbox())
|
||||
.slice(0, limit)
|
||||
.map(function(d) { return d.data; });
|
||||
}));
|
||||
return results;
|
||||
}
|
||||
|
||||
// partition viewport into `psize` x `psize` regions
|
||||
function partitionViewport(psize, projection) {
|
||||
var dimensions = projection.clipExtent()[1];
|
||||
psize = psize || 16;
|
||||
var cols = d3_range(0, dimensions[0], psize);
|
||||
var rows = d3_range(0, dimensions[1], psize);
|
||||
var partitions = [];
|
||||
|
||||
rows.forEach(function(y) {
|
||||
cols.forEach(function(x) {
|
||||
var min = [x, y + psize];
|
||||
var max = [x + psize, y];
|
||||
partitions.push(
|
||||
geoExtent(projection.invert(min), projection.invert(max)));
|
||||
});
|
||||
});
|
||||
|
||||
return partitions;
|
||||
}
|
||||
|
||||
function getLoc(attrs) {
|
||||
var lon = attrs.lon && attrs.lon.value;
|
||||
var lat = attrs.lat && attrs.lat.value;
|
||||
return [parseFloat(lon), parseFloat(lat)];
|
||||
}
|
||||
|
||||
function parseComments(comments) {
|
||||
var parsedComments = [];
|
||||
|
||||
// for each comment
|
||||
var i;
|
||||
for (i = 0; i < comments.length; i++) {
|
||||
if (comments[i].nodeName === 'comment') {
|
||||
var childNodes = comments[i].childNodes;
|
||||
var parsedComment = {};
|
||||
|
||||
// for each comment element
|
||||
var j;
|
||||
for (j = 0; j < childNodes.length; j++) {
|
||||
if (childNodes[j].nodeName !== '#text') {
|
||||
var nodeName = childNodes[j].nodeName;
|
||||
parsedComment[nodeName] = childNodes[j].innerHTML;
|
||||
}
|
||||
}
|
||||
parsedComments.push(parsedComment);
|
||||
}
|
||||
}
|
||||
return parsedComments;
|
||||
}
|
||||
|
||||
var parsers = {
|
||||
note: function parseNote(obj, uid) {
|
||||
var attrs = obj.attributes;
|
||||
var childNodes = obj.childNodes;
|
||||
var parsedNote = {};
|
||||
|
||||
parsedNote.loc = getLoc(attrs);
|
||||
|
||||
// for each element in a note
|
||||
var i;
|
||||
for (i = 0; i < childNodes.length; i++) {
|
||||
if (childNodes[i].nodeName !== '#text') {
|
||||
var nodeName = childNodes[i].nodeName;
|
||||
// if the element is comments, parse the comments
|
||||
if (nodeName === 'comments') {
|
||||
parsedNote[nodeName] = parseComments(childNodes[i].childNodes);
|
||||
} else {
|
||||
parsedNote[nodeName] = childNodes[i].innerHTML;
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
minX: parsedNote.loc[0],
|
||||
minY: parsedNote.loc[1],
|
||||
maxX: parsedNote.loc[0],
|
||||
maxY: parsedNote.loc[1],
|
||||
data: new osmNote(parsedNote)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
function parse(xml, callback, options) {
|
||||
options = _extend({ cache: true }, options);
|
||||
if (!xml || !xml.childNodes) return;
|
||||
|
||||
var root = xml.childNodes[0];
|
||||
var children = root.childNodes;
|
||||
|
||||
function parseChild(child) {
|
||||
var parser = parsers[child.nodeName];
|
||||
if (parser) {
|
||||
// TODO: change how a note uid is parsed. Nodes also share 'n' + id
|
||||
// var uid = osmEntity.id.fromOSM(child.nodeName, child.childNodes[1].innerHTML);
|
||||
var childNodes = child.childNodes;
|
||||
var id;
|
||||
var i;
|
||||
|
||||
for (i = 0; i < childNodes.length; i++) {
|
||||
if (childNodes[i].nodeName === 'id') { id = childNodes[i].nodeName; }
|
||||
}
|
||||
if (options.cache && _entityCache[id]) {
|
||||
return null;
|
||||
}
|
||||
return parser(child);
|
||||
}
|
||||
}
|
||||
utilIdleWorker(children, parseChild, callback);
|
||||
}
|
||||
|
||||
export default {
|
||||
|
||||
init: function() {
|
||||
@@ -106,7 +238,7 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
_notesCache = { notes: { inflight: {}, loaded: {} } };
|
||||
_notesCache = { notes: { inflight: {}, loaded: {}, rtree: rbush() } };
|
||||
|
||||
__notesSelectedNote = null;
|
||||
},
|
||||
@@ -118,7 +250,21 @@ export default {
|
||||
loadFromAPI(path, callback, options) {
|
||||
options = _extend({ cache: true }, options);
|
||||
|
||||
function done(err, xml) {}
|
||||
function done(err, xml) {
|
||||
if (err) { console.log ('error: ', err); }
|
||||
parse(
|
||||
xml,
|
||||
function(entities) {
|
||||
if (options.cache) {
|
||||
for (var i in entities) {
|
||||
_entityCache[entities[i].id] = true;
|
||||
}
|
||||
}
|
||||
callback(null, entities);
|
||||
},
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
if (this.authenticated()) {
|
||||
return oauth.xhr({ method: 'GET', path: path }, done);
|
||||
@@ -130,6 +276,7 @@ export default {
|
||||
loadTile(which, currZoom, url, tile) {
|
||||
var cache = _notesCache[which];
|
||||
var bbox = tile.extent.toParam();
|
||||
var fullUrl = url + bbox;
|
||||
|
||||
var id = tile.id;
|
||||
|
||||
@@ -140,9 +287,18 @@ export default {
|
||||
}
|
||||
|
||||
cache.inflight[id] = this.loadFromAPI(
|
||||
url + bbox,
|
||||
function () {
|
||||
fullUrl,
|
||||
function (err, parsed) {
|
||||
delete cache.inflight[id];
|
||||
if (!err) {
|
||||
cache.loaded[id] = true;
|
||||
}
|
||||
|
||||
cache.rtree.load(parsed);
|
||||
|
||||
if (_isEmpty(cache.inflight)) {
|
||||
dispatch.call('loadedNotes');
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
@@ -171,5 +327,10 @@ export default {
|
||||
loadNotes: function(projection) {
|
||||
var url = urlroot + '/api/0.6/notes?bbox=';
|
||||
this.loadTiles('notes', url, projection);
|
||||
}
|
||||
},
|
||||
|
||||
notes: function(projection) {
|
||||
var psize = 32, limit = 3;
|
||||
return searchLimited(psize, limit, projection, _notesCache.notes.rtree);
|
||||
},
|
||||
};
|
||||
@@ -1,5 +1,7 @@
|
||||
import _some from 'lodash-es/some';
|
||||
import _throttle from 'lodash-es/throttle';
|
||||
import { select as d3_select } from 'd3-selection';
|
||||
import { svgPointTransform } from './index';
|
||||
import { services } from '../services';
|
||||
|
||||
export function svgNotes(projection, context, dispatch) {
|
||||
@@ -67,6 +69,36 @@ export function svgNotes(projection, context, dispatch) {
|
||||
.on('end', editOff);
|
||||
}
|
||||
|
||||
function update() {
|
||||
var service = getService();
|
||||
var data = (service ? service.notes(projection) : []);
|
||||
var transform = svgPointTransform(projection);
|
||||
var notes = layer.selectAll('.notes').selectAll('.note')
|
||||
.data(data, function(d) { return d.key; });
|
||||
|
||||
// exit
|
||||
notes.exit()
|
||||
.remove();
|
||||
|
||||
// enter
|
||||
var notesEnter = notes.enter()
|
||||
.append('g')
|
||||
.attr('class', 'note');
|
||||
|
||||
// update
|
||||
var markers = notes
|
||||
.merge(notesEnter)
|
||||
.attr('transform', transform);
|
||||
|
||||
markers.selectAll('circle')
|
||||
.data([0])
|
||||
.enter()
|
||||
.append('circle')
|
||||
.attr('dx', '0')
|
||||
.attr('dy', '0')
|
||||
.attr('r', '6');
|
||||
}
|
||||
|
||||
function drawNotes(selection) {
|
||||
var enabled = svgNotes.enabled,
|
||||
service = getService();
|
||||
@@ -82,10 +114,6 @@ export function svgNotes(projection, context, dispatch) {
|
||||
.attr('class', 'layer-notes')
|
||||
.style('display', enabled ? 'block' : 'none');
|
||||
|
||||
// layerEnter
|
||||
// .append('g')
|
||||
// .attr('class', 'sequences');
|
||||
|
||||
layerEnter
|
||||
.append('g')
|
||||
.attr('class', 'notes');
|
||||
@@ -96,7 +124,7 @@ export function svgNotes(projection, context, dispatch) {
|
||||
if (enabled) {
|
||||
if (service && ~~context.map().zoom() >= minZoom) {
|
||||
editOn();
|
||||
// update();
|
||||
update();
|
||||
service.loadNotes(projection);
|
||||
} else {
|
||||
editOff();
|
||||
|
||||
Reference in New Issue
Block a user