From e439ea406a43a199c8da98db16275954a3318a20 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Mon, 6 Nov 2017 15:48:44 -0500 Subject: [PATCH] Cache sequence info, draw sequence linestrings --- css/60_photos.css | 14 ++++++- modules/services/openstreetcam.js | 61 ++++++++++++++++++++++++----- modules/svg/openstreetcam_images.js | 57 ++++++++++++++++++++++----- 3 files changed, 113 insertions(+), 19 deletions(-) diff --git a/css/60_photos.css b/css/60_photos.css index 637e1ae70..a251a2658 100644 --- a/css/60_photos.css +++ b/css/60_photos.css @@ -24,7 +24,6 @@ overflow: hidden; } - .viewfield-group { pointer-events: visible; cursor: pointer; @@ -57,6 +56,11 @@ fill-opacity: 0.6; } +.sequence { + stroke-width: 2; + fill: none; +} + /* Mapillary Image Layer */ .layer-mapillary-images { @@ -67,6 +71,10 @@ fill: #55ff22; } +.layer-mapillary-images .sequence { + stroke: #55ff22; +} + /* Mapillary Sign Layer */ .layer-mapillary-signs { @@ -105,6 +113,10 @@ fill: #77ddff; } +.layer-openstreetcam-images .sequence { + stroke: #77ddff; +} + /* Mapillary viewer */ #mly .domRenderer .TagSymbol { diff --git a/modules/services/openstreetcam.js b/modules/services/openstreetcam.js index 0bc1f6d86..e12dcec6a 100644 --- a/modules/services/openstreetcam.js +++ b/modules/services/openstreetcam.js @@ -150,10 +150,19 @@ function loadNextTilePage(which, currZoom, url, tile) { captured_at: localeDateString(item.shot_date || item.date_added), captured_by: item.username, imagePath: item.lth_name, - sequence_id: item.sequence_id, - sequence_index: item.sequence_index + sequence_id: +item.sequence_id, + sequence_index: +item.sequence_index }; + + // cache sequence info + var seq = openstreetcamCache.sequences[d.sequence_id]; + if (!seq) { + seq = { rotation: 0, images: [] }; + openstreetcamCache.sequences[d.sequence_id] = seq; + } + seq.images[d.sequence_index] = d; } + return { minX: loc[0], minY: loc[1], maxX: loc[0], maxY: loc[1], data: d }; @@ -234,7 +243,7 @@ export default { openstreetcamCache = { images: { inflight: {}, loaded: {}, nextPage: {}, rtree: rbush() }, - sequences: { rotation: {} } + sequences: {} }; openstreetcamImage = null; @@ -247,6 +256,33 @@ export default { }, + sequences: function(projection) { + 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(); + var seq_ids = {}; + + // all sequences for images in viewport + openstreetcamCache.images.rtree.search(bbox) + .forEach(function(d) { seq_ids[d.data.sequence_id] = true; }); + + // make linestrings from those sequences + var lineStrings = []; + Object.keys(seq_ids).forEach(function(seq_id) { + var seq = openstreetcamCache.sequences[seq_id]; + var images = seq && seq.images; + if (images) { + lineStrings.push({ + type: 'LineString', + coordinates: images.map(function (d) { return d.loc; }).filter(Boolean) + }); + } + }); + return lineStrings; + }, + + loadImages: function(projection) { var url = apibase + '/1.0/list/nearby-photos/'; loadTiles('images', url, projection); @@ -275,7 +311,7 @@ export default { controlsEnter .append('button') - .text('◅'); + .text('◄'); controlsEnter .append('button') @@ -289,17 +325,23 @@ export default { controlsEnter .append('button') - .text('▻'); + .text('►'); function rotate(deg) { return function() { if (!openstreetcamImage) return; - var seq = openstreetcamImage.sequence_id; - var r = openstreetcamCache.sequences.rotation[seq] || 0; + var seq_id = openstreetcamImage.sequence_id; + var seq = openstreetcamCache.sequences[seq_id]; + if (!seq) { + seq = { rotation: 0, coords: [] }; + openstreetcamCache.sequences[seq_id] = seq; + } + + var r = seq.rotation || 0; r += deg; - openstreetcamCache.sequences.rotation[seq] = r; + seq.rotation = r; d3_select('#photoviewer .osc-wrapper .osc-image') .transition() @@ -351,7 +393,8 @@ export default { .remove(); if (d) { - var r = openstreetcamCache.sequences.rotation[d.sequence_id] || 0; + var seq = openstreetcamCache.sequences[d.sequence_id]; + var r = (seq && seq.rotation) || 0; wrap.append('img') .attr('class', 'osc-image') diff --git a/modules/svg/openstreetcam_images.js b/modules/svg/openstreetcam_images.js index e17f073d2..458bec47c 100644 --- a/modules/svg/openstreetcam_images.js +++ b/modules/svg/openstreetcam_images.js @@ -1,5 +1,11 @@ import _throttle from 'lodash-es/throttle'; + import { select as d3_select } from 'd3-selection'; +import { + geoIdentity as d3_geoIdentity, + geoPath as d3_geoPath +} from 'd3-geo'; + import { svgPointTransform } from './point_transform'; import { services } from '../services'; @@ -95,13 +101,36 @@ export function svgOpenstreetcamImages(projection, context, dispatch) { function update() { - var openstreetcam = getOpenstreetcam(), - data = (openstreetcam ? openstreetcam.images(projection) : []), - image = openstreetcam && openstreetcam.selectedImage(), - imageKey = image && image.key; + var highZoom = ~~context.map().zoom() >= minViewfieldZoom; + var openstreetcam = getOpenstreetcam(); + var sequences = (openstreetcam && highZoom ? openstreetcam.sequences(projection) : []); + var images = (openstreetcam ? openstreetcam.images(projection) : []); + var selectedImage = openstreetcam && openstreetcam.selectedImage(); + var imageKey = selectedImage && selectedImage.key; - var markers = layer.selectAll('.viewfield-group') - .data(data, function(d) { return d.key; }); + var clip = d3_geoIdentity().clipExtent(projection.clipExtent()).stream; + var project = projection.stream; + var makePath = d3_geoPath().projection({ stream: function(output) { + return project(clip(output)); + }}); + + var lineStrings = layer.selectAll('.sequences').selectAll('.sequence') + .data(sequences); + + lineStrings.exit() + .remove(); + + lineStrings = lineStrings.enter() + .append('path') + .attr('class', 'sequence') + .merge(lineStrings); + + lineStrings + .attr('d', makePath); + + + var markers = layer.selectAll('.markers').selectAll('.viewfield-group') + .data(images, function(d) { return d.key; }); markers.exit() .remove(); @@ -118,7 +147,7 @@ export function svgOpenstreetcamImages(projection, context, dispatch) { var viewfields = markers.selectAll('.viewfield') - .data(~~context.map().zoom() >= minViewfieldZoom ? [0] : []); + .data(highZoom ? [0] : []); viewfields.exit() .remove(); @@ -149,10 +178,20 @@ export function svgOpenstreetcamImages(projection, context, dispatch) { layer.exit() .remove(); - layer = layer.enter() + var layerEnter = layer.enter() .append('g') .attr('class', 'layer-openstreetcam-images') - .style('display', enabled ? 'block' : 'none') + .style('display', enabled ? 'block' : 'none'); + + layerEnter + .append('g') + .attr('class', 'sequences'); + + layerEnter + .append('g') + .attr('class', 'markers'); + + layer = layerEnter .merge(layer); if (enabled) {