mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-15 21:48:20 +02:00
add point and line
This commit is contained in:
@@ -244,6 +244,18 @@
|
||||
stroke: #20c4ff;
|
||||
}
|
||||
|
||||
/* Mapilio Image Layer */
|
||||
.layer-mapilio {
|
||||
pointer-events: none;
|
||||
}
|
||||
.layer-mapilio .viewfield-group * {
|
||||
fill: #0056f1;
|
||||
stroke: #ffffff;
|
||||
fill-opacity: .7;
|
||||
}
|
||||
.layer-mapilio .sequence {
|
||||
stroke: #0056f1;
|
||||
}
|
||||
|
||||
/* Streetside Viewer (pannellum) */
|
||||
.ms-wrapper .photo-attribution .image-link {
|
||||
|
||||
+73
-32
@@ -5,9 +5,12 @@ import RBush from 'rbush';
|
||||
import { VectorTile } from '@mapbox/vector-tile';
|
||||
|
||||
import { utilRebind, utilTiler } from '../util';
|
||||
import {geoExtent, geoScaleToZoom} from '../geo';
|
||||
|
||||
const baseTileUrl = 'https://geo.mapilio.com/geoserver/gwc/service/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&LAYER=mapilio:';
|
||||
const pointsTileUrl = `${baseTileUrl}points_mapilio_map&STYLE=&TILEMATRIX=EPSG:900913:{z}&TILEMATRIXSET=EPSG:900913&FORMAT=application/vnd.mapbox-vector-tile&TILECOL={x}&TILEROW={y}`;
|
||||
const pointLayer = 'points_mapilio_map';
|
||||
const lineLayer = 'captured_roads_line';
|
||||
const tileStyle = '&STYLE=&TILEMATRIX=EPSG:900913:{z}&TILEMATRIXSET=EPSG:900913&FORMAT=application/vnd.mapbox-vector-tile&TILECOL={x}&TILEROW={y}';
|
||||
|
||||
const minZoom = 14;
|
||||
const dispatch = d3_dispatch('change', 'loadedImages', 'loadedSigns', 'loadedMapFeatures', 'bearingChanged', 'imageChanged');
|
||||
@@ -16,6 +19,31 @@ let _mlyActiveImage;
|
||||
let _mlyCache;
|
||||
|
||||
|
||||
// Partition viewport into higher zoom tiles
|
||||
function partitionViewport(projection) {
|
||||
const z = geoScaleToZoom(projection.scale());
|
||||
const z2 = (Math.ceil(z * 2) / 2) + 2.5; // round to next 0.5 and add 2.5
|
||||
const tiler = utilTiler().zoomExtent([z2, z2]);
|
||||
|
||||
return tiler.getTiles(projection)
|
||||
.map(function(tile) { return tile.extent; });
|
||||
}
|
||||
|
||||
|
||||
// Return no more than `limit` results per partition.
|
||||
function searchLimited(limit, projection, rtree) {
|
||||
limit = limit || 5;
|
||||
|
||||
return partitionViewport(projection)
|
||||
.reduce(function(result, extent) {
|
||||
const found = rtree.search(extent.bbox())
|
||||
.slice(0, limit)
|
||||
.map(function(d) { return d.data; });
|
||||
|
||||
return (found.length ? result.concat(found) : result);
|
||||
}, []);
|
||||
}
|
||||
|
||||
// Load all data for the specified type from Mapilio vector tiles
|
||||
function loadTiles(which, url, maxZoom, projection) {
|
||||
const tiler = utilTiler().zoomExtent([minZoom, maxZoom]).skipNullIsland(true);
|
||||
@@ -100,46 +128,21 @@ function loadTileDataToCache(data, tile, which) {
|
||||
}
|
||||
}
|
||||
|
||||
if (vectorTile.layers.hasOwnProperty('sequence')) {
|
||||
if (vectorTile.layers.hasOwnProperty('captured_roads_line')) {
|
||||
features = [];
|
||||
cache = _mlyCache.sequences;
|
||||
layer = vectorTile.layers.sequence;
|
||||
layer = vectorTile.layers.captured_roads_line;
|
||||
|
||||
for (i = 0; i < layer.length; i++) {
|
||||
feature = layer.feature(i).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
|
||||
if (cache.lineString[feature.properties.id]) {
|
||||
cache.lineString[feature.properties.id].push(feature);
|
||||
if (cache.lineString[feature.properties.sequence_uuid]) {
|
||||
cache.lineString[feature.properties.sequence_uuid].push(feature);
|
||||
} else {
|
||||
cache.lineString[feature.properties.id] = [feature];
|
||||
cache.lineString[feature.properties.sequence_uuid] = [feature];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vectorTile.layers.hasOwnProperty('point')) {
|
||||
features = [];
|
||||
cache = _mlyCache[which];
|
||||
layer = vectorTile.layers.point;
|
||||
|
||||
for (i = 0; i < layer.length; i++) {
|
||||
feature = layer.feature(i).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
|
||||
loc = feature.geometry.coordinates;
|
||||
|
||||
d = {
|
||||
loc: loc,
|
||||
id: feature.properties.id,
|
||||
first_seen_at: feature.properties.first_seen_at,
|
||||
last_seen_at: feature.properties.last_seen_at,
|
||||
value: feature.properties.value
|
||||
};
|
||||
features.push({
|
||||
minX: loc[0], minY: loc[1], maxX: loc[0], maxY: loc[1], data: d
|
||||
});
|
||||
}
|
||||
if (cache.rtree) {
|
||||
cache.rtree.load(features);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -168,10 +171,48 @@ export default {
|
||||
_mlyActiveImage = null;
|
||||
},
|
||||
|
||||
// Get visible images
|
||||
images: function(projection) {
|
||||
const limit = 5;
|
||||
return searchLimited(limit, projection, _mlyCache.images.rtree);
|
||||
},
|
||||
|
||||
|
||||
// Load images in the visible area
|
||||
loadImages: function(projection) {
|
||||
loadTiles('images', pointsTileUrl, 14, projection);
|
||||
let url = baseTileUrl + pointLayer + tileStyle;
|
||||
loadTiles('images', url, 14, projection);
|
||||
},
|
||||
|
||||
// Load line in the visible area
|
||||
loadLines: function(projection) {
|
||||
let url = baseTileUrl + lineLayer + tileStyle;
|
||||
loadTiles('line', url, 14, projection);
|
||||
},
|
||||
|
||||
// Get visible sequences
|
||||
sequences: function(projection) {
|
||||
const viewport = projection.clipExtent();
|
||||
const min = [viewport[0][0], viewport[1][1]];
|
||||
const max = [viewport[1][0], viewport[0][1]];
|
||||
const bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
|
||||
const sequenceIds = {};
|
||||
let lineStrings = [];
|
||||
|
||||
_mlyCache.images.rtree.search(bbox)
|
||||
.forEach(function(d) {
|
||||
if (d.data.sequence_id) {
|
||||
sequenceIds[d.data.sequence_id] = true;
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(sequenceIds).forEach(function(sequenceId) {
|
||||
if (_mlyCache.sequences.lineString[sequenceId]) {
|
||||
lineStrings = lineStrings.concat(_mlyCache.sequences.lineString[sequenceId]);
|
||||
}
|
||||
});
|
||||
|
||||
return lineStrings;
|
||||
},
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import _throttle from 'lodash-es/throttle';
|
||||
|
||||
import { select as d3_select } from 'd3-selection';
|
||||
import { services } from '../services';
|
||||
import {svgPath, svgPointTransform} from './helpers';
|
||||
|
||||
|
||||
export function svgMapilioImages(projection, context, dispatch) {
|
||||
@@ -55,6 +56,14 @@ export function svgMapilioImages(projection, context, dispatch) {
|
||||
.on('end', editOff);
|
||||
}
|
||||
|
||||
function transform(d) {
|
||||
let t = svgPointTransform(projection)(d);
|
||||
if (d.ca) {
|
||||
t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
function editOn() {
|
||||
layer.style('display', 'block');
|
||||
@@ -66,6 +75,79 @@ export function svgMapilioImages(projection, context, dispatch) {
|
||||
layer.style('display', 'none');
|
||||
}
|
||||
|
||||
function update() {
|
||||
|
||||
const z = ~~context.map().zoom();
|
||||
|
||||
const service = getService();
|
||||
let sequences = (service ? service.sequences(projection) : []);
|
||||
let images = (service ? service.images(projection) : []);
|
||||
|
||||
|
||||
// service.filterViewer(context);
|
||||
|
||||
let traces = layer.selectAll('.sequences').selectAll('.sequence')
|
||||
.data(sequences, function(d) { return d.properties.id; });
|
||||
|
||||
// exit
|
||||
traces.exit()
|
||||
.remove();
|
||||
//
|
||||
// // enter/update
|
||||
traces = traces.enter()
|
||||
.append('path')
|
||||
.attr('class', 'sequence')
|
||||
.merge(traces)
|
||||
.attr('d', svgPath(projection).geojson);
|
||||
|
||||
|
||||
const groups = layer.selectAll('.markers').selectAll('.viewfield-group')
|
||||
.data(images, function(d) { return d.id; });
|
||||
|
||||
// exit
|
||||
groups.exit()
|
||||
.remove();
|
||||
|
||||
// enter
|
||||
const groupsEnter = groups.enter()
|
||||
.append('g')
|
||||
.attr('class', 'viewfield-group');
|
||||
|
||||
groupsEnter
|
||||
.append('g')
|
||||
.attr('class', 'viewfield-scale');
|
||||
|
||||
// update
|
||||
const markers = groups
|
||||
.merge(groupsEnter)
|
||||
.sort(function(a, b) {
|
||||
return b.loc[1] - a.loc[1]; // sort Y
|
||||
})
|
||||
.attr('transform', transform)
|
||||
.select('.viewfield-scale');
|
||||
|
||||
|
||||
markers.selectAll('circle')
|
||||
.data([0])
|
||||
.enter()
|
||||
.append('circle')
|
||||
.attr('dx', '0')
|
||||
.attr('dy', '0')
|
||||
.attr('r', '6');
|
||||
|
||||
const viewfields = markers.selectAll('.viewfield')
|
||||
.data([0]);
|
||||
|
||||
viewfields.exit()
|
||||
.remove();
|
||||
|
||||
viewfields.enter() // viewfields may or may not be drawn...
|
||||
.insert('path', 'circle') // but if they are, draw below the circles
|
||||
.attr('class', 'viewfield')
|
||||
.attr('transform', 'scale(1.5,1.5),translate(-8, -13)')
|
||||
|
||||
}
|
||||
|
||||
|
||||
function drawImages(selection) {
|
||||
const enabled = svgMapilioImages.enabled;
|
||||
@@ -96,7 +178,9 @@ export function svgMapilioImages(projection, context, dispatch) {
|
||||
if (enabled) {
|
||||
if (service && ~~context.map().zoom() >= minZoom) {
|
||||
editOn();
|
||||
update();
|
||||
service.loadImages(projection);
|
||||
service.loadLines(projection);
|
||||
} else {
|
||||
editOff();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user