diff --git a/css/60_photos.css b/css/60_photos.css index ea5692bdc..4984abf3f 100644 --- a/css/60_photos.css +++ b/css/60_photos.css @@ -621,3 +621,8 @@ label.streetside-hires { border-radius: 4px; cursor: pointer; } + +datalist { + display: inline-block; + vertical-align: middle; + } \ No newline at end of file diff --git a/data/core.yaml b/data/core.yaml index 35787f935..2035f27aa 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -893,6 +893,9 @@ en: all: "Show all" title: "Photo age" tooltip: "Select maximum photo age" + age_slider_filter: + title: "Year Slider" + tooltip: "Select oldest photo year" feature: points: description: Points diff --git a/modules/renderer/photos.js b/modules/renderer/photos.js index cf26982b1..3b0646b4b 100644 --- a/modules/renderer/photos.js +++ b/modules/renderer/photos.js @@ -14,6 +14,7 @@ export function rendererPhotos(context) { var _fromDate; var _toDate; var _maxPhotoAge; + var _maxPhotoYear; var _usernames; function photos() {} @@ -51,6 +52,10 @@ export function rendererPhotos(context) { return _maxPhotoAge; }; + photos.maxPhotoYear = function() { + return _maxPhotoYear; + }; + photos.dateFilterValue = function(val) { return val === _dateFilters[0] ? _fromDate : _toDate; }; @@ -101,6 +106,19 @@ export function rendererPhotos(context) { photos.setDateFilter('fromDate', null) } + photos.setMaxPhotoYear = function(maxPhotoYear){ + if(maxPhotoYear != null){ + var fromDate = new Date(); + fromDate = '01/01/' + maxPhotoYear; + photos.setDateFilter('fromDate', fromDate); + _maxPhotoYear = maxPhotoYear; + } + else{ + photos.setDateFilter('fromDate', null); + } + } + + photos.setUsernameFilter = function(val, updateUrl) { if (val && typeof val === 'string') val = val.replace(/;/g, ',').split(','); if (val) { @@ -144,6 +162,10 @@ export function rendererPhotos(context) { }; photos.shouldFilterByMaxAge = function(){ + return false; + } + + photos.shouldFilterDateBySlider = function(){ return showsLayer('panoramax'); } diff --git a/modules/services/panoramax.js b/modules/services/panoramax.js index d465adb99..b68b47507 100644 --- a/modules/services/panoramax.js +++ b/modules/services/panoramax.js @@ -39,6 +39,8 @@ let _planeFrame; let _pannellumFrame; let _currentFrame; +let _oldestDate; + let _currentScene = { currentImage : null, nextImage : null, @@ -162,6 +164,14 @@ function loadTileDataToCache(data, tile) { features.push({ minX: loc[0], minY: loc[1], maxX: loc[0], maxY: loc[1], data: d }); + + if(_oldestDate){ + if(d.capture_time < _oldestDate) + _oldestDate = d.capture_time; + } + else{ + _oldestDate = d.capture_time; + } } if (cache.rtree) { cache.rtree.load(features); @@ -179,6 +189,13 @@ function loadTileDataToCache(data, tile) { } else { cache.lineString[feature.properties.id] = [feature]; } + if(_oldestDate){ + if(feature.properties.date < _oldestDate) + _oldestDate = feature.properties.date; + } + else{ + _oldestDate = feature.properties.date; + } } } @@ -271,6 +288,11 @@ export default { return data.features[0].id; }, + getOldestDate: function(){ + if(_oldestDate) + return _oldestDate.substr(0, 4); + }, + // Get visible sequences sequences: function(projection, zoom) { const viewport = projection.clipExtent(); diff --git a/modules/svg/panoramax_images.js b/modules/svg/panoramax_images.js index 14d0c5cf6..e5ccdff50 100644 --- a/modules/svg/panoramax_images.js +++ b/modules/svg/panoramax_images.js @@ -185,6 +185,31 @@ export function svgPanoramaxImages(projection, context, dispatch) { if (service) service.setStyles(context, null); } + function updateSlider(oldestDate){ + let currYear = new Date(); + let slider = d3_select('.list-option-date-slider'); + + let label = slider.select(function() { return this.parentNode; }) + + label.selectAll('datalist').remove(); + + let datalist = label.append('datalist').attr('id', 'dateValues'); + + datalist + .append('option') + .attr('value', currYear.getFullYear()) + .attr('label', currYear.getFullYear()) + + if(oldestDate){ + slider.attr('min', oldestDate); + + datalist + .append('option') + .attr('value', oldestDate) + .attr('label', oldestDate) + } + } + async function update() { const zoom = ~~context.map().zoom(); const showViewfields = (zoom >= viewFieldZoomLevel); @@ -192,6 +217,9 @@ export function svgPanoramaxImages(projection, context, dispatch) { const service = getService(); let sequences = (service ? service.sequences(projection, zoom) : []); let images = (service ? service.images(projection) : []); + let oldestDate = service.getOldestDate(); + + updateSlider(oldestDate); images = await filterImages(images); sequences = await filterSequences(sequences, service); @@ -266,7 +294,6 @@ export function svgPanoramaxImages(projection, context, dispatch) { return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z'; } } - } function viewerChanged() { diff --git a/modules/ui/sections/photo_overlays.js b/modules/ui/sections/photo_overlays.js index e9da0af76..cbb9bfc87 100644 --- a/modules/ui/sections/photo_overlays.js +++ b/modules/ui/sections/photo_overlays.js @@ -30,7 +30,7 @@ export function uiSectionPhotoOverlays(context) { .merge(container) .call(drawPhotoItems) .call(drawPhotoTypeItems) - .call(drawMaxAgeFilter) + .call(drawDateSlider) .call(drawDateFilter) .call(drawUsernameFilter) .call(drawLocalPhotos); @@ -338,6 +338,78 @@ export function uiSectionPhotoOverlays(context) { .classed('active', filterEnabled); } + function drawDateSlider(selection){ + + function filterEnabled(d) { + return context.photos().maxPhotoYear(d); + } + + var currYear = new Date(); + currYear = currYear.getFullYear(); + + var ul = selection + .selectAll('.layer-list-date-slider') + .data([0]); + + ul.exit() + .remove(); + + ul = ul.enter() + .append('ul') + .attr('class', 'layer-list layer-list-date-slider') + .merge(ul); + + var li = ul.selectAll('.list-item-date-slider') + .data(context.photos().shouldFilterDateBySlider() ? ['date-slider'] : []); + + li.exit() + .remove(); + + var liEnter = li.enter() + .append('li') + .attr('class', 'list-item-date-slider'); + + var labelEnter = liEnter + .append('label') + .each(function() { + d3_select(this) + .call(uiTooltip() + .title(() => t.append('photo_overlays.age_slider_filter.tooltip')) + .placement('top') + ); + }); + + labelEnter + .append('span') + .call(t.append('photo_overlays.age_slider_filter.title')); + + labelEnter + .append('input') + .attr('type', 'range') + .attr('max', currYear) + .attr('min', currYear) + .attr('list', 'dateValues') + .attr('class', 'list-option-date-slider') + .call(utilNoAuto) + .on('change', function() { + var value = d3_select(this).property('value'); + context.photos().setMaxPhotoYear(parseInt(value)); + }); + + let datalist = labelEnter + .append('datalist') + .attr('id', 'dateValues') + + datalist + .append('option') + .attr('value', currYear) + .attr('label', currYear) + + li + .merge(liEnter) + .classed('active', filterEnabled); + } + function drawUsernameFilter(selection) { function filterEnabled() { return context.photos().usernames();