mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-21 15:56:56 +02:00
updated: notes rendering
This commit is contained in:
+4
-1
@@ -61,7 +61,10 @@ module.exports = function buildData() {
|
||||
};
|
||||
|
||||
// Font Awesome icons used
|
||||
var faIcons = {};
|
||||
var faIcons = {
|
||||
'fas-comment-alt': {},
|
||||
'far-comment-alt': {}
|
||||
};
|
||||
|
||||
// Start clean
|
||||
shell.rm('-f', [
|
||||
|
||||
+1
-1
@@ -118,7 +118,7 @@
|
||||
pointer-events: none;
|
||||
}
|
||||
.layer-notes .notes * {
|
||||
fill: #20c4ff;
|
||||
color: #eebb00;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ export var services = {
|
||||
export {
|
||||
serviceMapillary,
|
||||
serviceNominatim,
|
||||
serviceNotes,
|
||||
serviceOpenstreetcam,
|
||||
serviceOsm,
|
||||
serviceStreetside,
|
||||
|
||||
+44
-85
@@ -1,10 +1,8 @@
|
||||
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';
|
||||
|
||||
@@ -12,7 +10,6 @@ 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';
|
||||
|
||||
@@ -33,10 +30,11 @@ var urlroot = 'https://api.openstreetmap.org',
|
||||
dispatch = d3_dispatch('loadedNotes', 'loading'),
|
||||
tileZoom = 14;
|
||||
|
||||
// TODO: complete authentication
|
||||
var oauth = osmAuth({
|
||||
url: urlroot,
|
||||
oauth_consumer_key: '5A043yRSEugj4DJ5TljuapfnrflWDte8jTOcWLlT',
|
||||
oauth_secret: 'aB3jKq1TRsCOUrfOIZ6oQMEDmv2ptV76PA54NGLL',
|
||||
oauth_consumer_key: '',
|
||||
oauth_secret: '',
|
||||
loading: authLoading,
|
||||
done: authDone
|
||||
});
|
||||
@@ -49,6 +47,10 @@ function authDone() {
|
||||
dispatch.call('authDone');
|
||||
}
|
||||
|
||||
function authenticated() {
|
||||
return oauth.authenticated();
|
||||
}
|
||||
|
||||
function abortRequest(i) {
|
||||
i.abort();
|
||||
}
|
||||
@@ -81,52 +83,6 @@ function getTiles(projection) {
|
||||
});
|
||||
}
|
||||
|
||||
function nearNullIsland(x, y, z) {
|
||||
if (z >= 7) {
|
||||
var center = Math.pow(2, z - 1),
|
||||
width = Math.pow(2, z - 6),
|
||||
min = center - (width / 2),
|
||||
max = center + (width / 2) - 1;
|
||||
return x >= min && x <= max && y >= min && y <= max;
|
||||
}
|
||||
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;
|
||||
@@ -137,23 +93,20 @@ 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;
|
||||
_forEach(comments, function(comment) {
|
||||
if (comment.nodeName === 'comment') {
|
||||
var childNodes = comment.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;
|
||||
_forEach(childNodes, function(node) {
|
||||
if (node.nodeName !== '#text') {
|
||||
var nodeName = node.nodeName;
|
||||
parsedComment[nodeName] = node.innerHTML;
|
||||
}
|
||||
}
|
||||
parsedComments.push(parsedComment);
|
||||
});
|
||||
if (parsedComment) { parsedComments.push(parsedComment); }
|
||||
}
|
||||
}
|
||||
});
|
||||
return parsedComments;
|
||||
}
|
||||
|
||||
@@ -165,19 +118,18 @@ var parsers = {
|
||||
|
||||
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;
|
||||
_forEach(childNodes, function(node) {
|
||||
if (node.nodeName !== '#text') {
|
||||
var nodeName = node.nodeName;
|
||||
// if the element is comments, parse the comments
|
||||
if (nodeName === 'comments') {
|
||||
parsedNote[nodeName] = parseComments(childNodes[i].childNodes);
|
||||
parsedNote[nodeName] = parseComments(node.childNodes);
|
||||
} else {
|
||||
parsedNote[nodeName] = childNodes[i].innerHTML;
|
||||
parsedNote[nodeName] = node.innerHTML;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
minX: parsedNote.loc[0],
|
||||
minY: parsedNote.loc[1],
|
||||
@@ -198,7 +150,8 @@ function parse(xml, callback, options) {
|
||||
function parseChild(child) {
|
||||
var parser = parsers[child.nodeName];
|
||||
if (parser) {
|
||||
// TODO: change how a note uid is parsed. Nodes also share 'n' + id
|
||||
|
||||
// TODO: change how a note uid is parsed. Nodes & notes share 'n' + id combination
|
||||
var childNodes = child.childNodes;
|
||||
var id;
|
||||
var i;
|
||||
@@ -236,10 +189,6 @@ export default {
|
||||
_notesCache = { notes: { inflight: {}, loaded: {}, rtree: rbush() } };
|
||||
},
|
||||
|
||||
authenticated: function() {
|
||||
return oauth.authenticated();
|
||||
},
|
||||
|
||||
loadFromAPI: function(path, callback, options) {
|
||||
options = _extend({ cache: true }, options);
|
||||
|
||||
@@ -261,14 +210,16 @@ export default {
|
||||
);
|
||||
}
|
||||
|
||||
if (this.authenticated()) {
|
||||
if (authenticated()) {
|
||||
return oauth.xhr({ method: 'GET', path: path }, done);
|
||||
} else {
|
||||
return d3_xml(path).get(done);
|
||||
}
|
||||
},
|
||||
|
||||
// TODO: refactor /services for consistency by splitting or joining loadTiles & loadTile
|
||||
loadTile: function(which, currZoom, url, tile) {
|
||||
var that = this;
|
||||
var cache = _notesCache[which];
|
||||
var bbox = tile.extent.toParam();
|
||||
var fullUrl = url + bbox;
|
||||
@@ -281,7 +232,7 @@ export default {
|
||||
dispatch.call('loading');
|
||||
}
|
||||
|
||||
cache.inflight[id] = this.loadFromAPI(
|
||||
cache.inflight[id] = that.loadFromAPI(
|
||||
fullUrl,
|
||||
function (err, parsed) {
|
||||
delete cache.inflight[id];
|
||||
@@ -304,9 +255,7 @@ export default {
|
||||
var s = projection.scale() * 2 * Math.PI,
|
||||
currZoom = Math.floor(Math.max(Math.log(s) / Math.log(2) - 8, 0));
|
||||
|
||||
var tiles = getTiles(projection).filter(function(t) {
|
||||
return !nearNullIsland(t.xyz[0], t.xyz[1], t.xyz[2]);
|
||||
});
|
||||
var tiles = getTiles(projection);
|
||||
|
||||
_filter(which.inflight, function(v, k) {
|
||||
var wanted = _find(tiles, function(tile) { return k === (tile.id + ',0'); });
|
||||
@@ -320,12 +269,22 @@ export default {
|
||||
},
|
||||
|
||||
loadNotes: function(projection) {
|
||||
var that = this;
|
||||
var url = urlroot + '/api/0.6/notes?bbox=';
|
||||
this.loadTiles('notes', url, projection);
|
||||
that.loadTiles('notes', url, projection);
|
||||
},
|
||||
|
||||
notes: function(projection) {
|
||||
var psize = 32, limit = 3;
|
||||
return searchLimited(psize, limit, projection, _notesCache.notes.rtree);
|
||||
var viewport = projection.clipExtent();
|
||||
var min = [viewport[0][0], viewport[1][1]];
|
||||
var max = [viewport[1][0], viewport[0][1]];
|
||||
var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
|
||||
|
||||
return _notesCache.notes.rtree.search(bbox)
|
||||
.map(function(d) { return d.data; });
|
||||
},
|
||||
|
||||
cache: function() {
|
||||
return _notesCache;
|
||||
}
|
||||
};
|
||||
+7
-14
@@ -21,7 +21,7 @@ export function svgNotes(projection, context, dispatch) {
|
||||
|
||||
|
||||
function editOff() {
|
||||
layer.selectAll('.viewfield-group').remove();
|
||||
layer.selectAll('.note').remove();
|
||||
layer.style('display', 'none');
|
||||
}
|
||||
|
||||
@@ -37,10 +37,6 @@ export function svgNotes(projection, context, dispatch) {
|
||||
}
|
||||
|
||||
function showLayer() {
|
||||
var service = getService();
|
||||
if (!service) return;
|
||||
|
||||
// service.loadViewer(context);
|
||||
editOn();
|
||||
|
||||
layer
|
||||
@@ -52,11 +48,6 @@ export function svgNotes(projection, context, dispatch) {
|
||||
}
|
||||
|
||||
function hideLayer() {
|
||||
var service = getService();
|
||||
if (service) {
|
||||
// service.hideViewer();
|
||||
}
|
||||
|
||||
throttledRedraw.cancel();
|
||||
|
||||
layer
|
||||
@@ -90,10 +81,12 @@ export function svgNotes(projection, context, dispatch) {
|
||||
markers.selectAll('circle')
|
||||
.data([0])
|
||||
.enter()
|
||||
.append('circle')
|
||||
.attr('dx', '0')
|
||||
.attr('dy', '0')
|
||||
.attr('r', '6');
|
||||
.append('use')
|
||||
.attr('width', '24px')
|
||||
.attr('height', '24px')
|
||||
.attr('x', '-12px')
|
||||
.attr('y', '-12px')
|
||||
.attr('xlink:href', '#far-comment-alt');
|
||||
}
|
||||
|
||||
function drawNotes(selection) {
|
||||
|
||||
@@ -120,6 +120,7 @@ export function svgOpenstreetcamImages(projection, context, dispatch) {
|
||||
var service = getService();
|
||||
var sequences = (service ? service.sequences(projection) : []);
|
||||
var images = (service && showMarkers ? service.images(projection) : []);
|
||||
// console.log('images: ', images);
|
||||
|
||||
var traces = layer.selectAll('.sequences').selectAll('.sequence')
|
||||
.data(sequences, function(d) { return d.properties.key; });
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg aria-hidden="true" data-prefix="far" data-icon="comment-alt" class="svg-inline--fa fa-comment-alt fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M448 0H64C28.7 0 0 28.7 0 64v288c0 35.3 28.7 64 64 64h96v84c0 7.1 5.8 12 12 12 2.4 0 4.9-.7 7.1-2.4L304 416h144c35.3 0 64-28.7 64-64V64c0-35.3-28.7-64-64-64zm16 352c0 8.8-7.2 16-16 16H288l-12.8 9.6L208 428v-60H64c-8.8 0-16-7.2-16-16V64c0-8.8 7.2-16 16-16h384c8.8 0 16 7.2 16 16v288z"></path></svg>
|
||||
|
After Width: | Height: | Size: 506 B |
@@ -0,0 +1 @@
|
||||
<svg aria-hidden="true" data-prefix="fas" data-icon="comment-alt" class="svg-inline--fa fa-comment-alt fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M448 0H64C28.7 0 0 28.7 0 64v288c0 35.3 28.7 64 64 64h96v84c0 9.8 11.2 15.5 19.1 9.7L304 416h144c35.3 0 64-28.7 64-64V64c0-35.3-28.7-64-64-64z"></path></svg>
|
||||
|
After Width: | Height: | Size: 366 B |
+50
-22
@@ -1,9 +1,6 @@
|
||||
describe('iD.serviceNotes', function () {
|
||||
var dimensions = [64, 64],
|
||||
ua = navigator.userAgent,
|
||||
isPhantom = (navigator.userAgent.match(/PhantomJS/) !== null),
|
||||
uaMock = function () { return ua; },
|
||||
context, server, notes, orig;
|
||||
context, server, notes;
|
||||
|
||||
|
||||
before(function() {
|
||||
@@ -24,28 +21,10 @@ describe('iD.serviceNotes', function () {
|
||||
server = sinon.fakeServer.create();
|
||||
notes = iD.services.notes;
|
||||
notes.reset();
|
||||
|
||||
/* eslint-disable no-global-assign */
|
||||
/* mock userAgent */
|
||||
if (isPhantom) {
|
||||
orig = navigator;
|
||||
navigator = Object.create(orig, { userAgent: { get: uaMock }});
|
||||
} else {
|
||||
orig = navigator.__lookupGetter__('userAgent');
|
||||
navigator.__defineGetter__('userAgent', uaMock);
|
||||
}
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
server.restore();
|
||||
|
||||
/* restore userAgent */
|
||||
if (isPhantom) {
|
||||
navigator = orig;
|
||||
} else {
|
||||
navigator.__defineGetter__('userAgent', orig);
|
||||
}
|
||||
/* eslint-enable no-global-assign */
|
||||
});
|
||||
|
||||
describe('#init', function () {
|
||||
@@ -59,4 +38,53 @@ describe('iD.serviceNotes', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('#reset', function () {
|
||||
it('resets cache', function () {
|
||||
notes.cache.foo = 'bar';
|
||||
notes.reset();
|
||||
expect(notes.cache()).to.not.have.property('foo');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#loadFromAPI', function () {
|
||||
var path = '/api/0.6/notes?bbox=-0.65094,51.312159,0.374908,51.3125',
|
||||
response = '<?xml version="1.0" encoding="UTF-8"?>' +
|
||||
'<osm version="0.6" generator="OpenStreetMap server">' +
|
||||
'<note lon="0.1979819" lat="51.3122986">' +
|
||||
'<id>814798</id>' +
|
||||
'<url>https://api.openstreetmap.org/api/0.6/notes/814798</url>' +
|
||||
'<comment_url>https://api.openstreetmap.org/api/0.6/notes/814798/comment</comment_url>' +
|
||||
'<close_url>https://api.openstreetmap.org/api/0.6/notes/814798/close</close_url>' +
|
||||
'<date_created>2016-12-13 11:02:44 UTC</date_created>' +
|
||||
'<status>open</status>' +
|
||||
'<comments>' +
|
||||
'<comment>' +
|
||||
'<date>2016-12-13 11:02:44 UTC</date>' +
|
||||
'<action>opened</action>' +
|
||||
'<text>Otford Scout Hut</text>' +
|
||||
'<html><p>Otford Scout Hut</p></html>' +
|
||||
'</comment>' +
|
||||
'</comments>' +
|
||||
'</note>' +
|
||||
'</osm>';
|
||||
|
||||
it('returns an object', function (done) {
|
||||
var result = notes.loadFromAPI(
|
||||
'https://www.openstreetmap.org' + path,
|
||||
function (err, xml) {
|
||||
expect(err).to.not.be.ok;
|
||||
expect(typeof xml).to.eql('object');
|
||||
done();
|
||||
},
|
||||
[]);
|
||||
|
||||
// TODO: clarify why this throws an error
|
||||
// server.respondWith('GET', 'http://www.openstreetmap.org' + path,
|
||||
// [200, { 'Content-Type': 'text/xml' }, response]);
|
||||
// server.respond();
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user