diff options
author | Zarino Zappia <mail@zarino.co.uk> | 2016-01-15 15:55:13 +0000 |
---|---|---|
committer | Matthew Somerville <matthew@mysociety.org> | 2016-02-09 14:49:18 +0000 |
commit | b71d042e933ba03e3c737d8630d4e3d4ca3eb9d1 (patch) | |
tree | d8df5240a51e048b8418ca99a7ed41ec848d0c87 /web/js/map-OpenLayers.js | |
parent | cf80773fa925f36a7c43b5f7eb1bcf7f56593796 (diff) |
Clearer relationship between map pins/list items.
Hovering over map pins highlights the relevant item from the
sidebar beside the map. And hovering a sidebar item highlights
the relevant map pin.
Clicking a map pin takes you directly to the relevant report
page, just like clicking an item in the sidebar.
This means the OpenLayers popup "balloon" no longer appears on
clicking a pin, and has been removed entirely.
To make customisation of the list item hover colour easier,
it has been abstracted out into a SCSS variable that cobrand
authors should override (as the fixmystreet.com cobrand does)
or leave at its default light grey colour.
Fixes #1094.
Diffstat (limited to 'web/js/map-OpenLayers.js')
-rw-r--r-- | web/js/map-OpenLayers.js | 145 |
1 files changed, 116 insertions, 29 deletions
diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index 3cd54bc23..2d119e8d0 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -88,6 +88,7 @@ function fms_markers_list(pins, transform) { var marker = new OpenLayers.Feature.Vector(loc, { colour: pin[2], size: pin[5] || size, + faded: 0, id: pin[3], title: pin[4] || '' }); @@ -114,6 +115,69 @@ function fms_markers_resize() { fixmystreet.markers.redraw(); } +// `markers.redraw()` in fms_markers_highlight will trigger an +// `overFeature` event if the mouse cursor is still over the same +// marker on the map, which would then run fms_markers_highlight +// again, causing an infinite flicker while the cursor remains over +// the same marker. We really only want to redraw the markers when +// the cursor moves from one marker to another (ie: when there is an +// overFeature followed by an outFeature followed by an overFeature). +// Therefore, we keep track of the previous event in +// fixmystreet.latest_map_hover_event and only call fms_markers_highlight +// if we know the previous event was different to the current one. +// (See the `overFeature` and `outFeature` callbacks inside of +// fixmystreet.select_feature). + +function fms_markers_highlight(problem_id) { + for (var i = 0; i < fixmystreet.markers.features.length; i++) { + if (typeof problem_id == 'undefined') { + // There is no highlighted marker, so unfade this marker + fixmystreet.markers.features[i].attributes.faded = 0; + } else if (problem_id == fixmystreet.markers.features[i].attributes.id) { + // This is the highlighted marker, unfade it + fixmystreet.markers.features[i].attributes.faded = 0; + } else { + // This is not the hightlighted marker, fade it + fixmystreet.markers.features[i].attributes.faded = 1; + } + } + fixmystreet.markers.redraw(); +} + +function fms_sidebar_highlight(problem_id) { + if (typeof problem_id !== 'undefined') { + var $a = $('.item-list--reports a[href$="' + problem_id + '"]'); + $a.parent().addClass('hovered'); + + var a_top = $a.offset().top; + var a_height = $a.outerHeight(); + var viewport_top = $(window).scrollTop(); + var viewport_height = $(window).height(); + var header_height = $('.nav-wrapper-2').outerHeight(); + var shadow_height = $('.shadow-wrap').outerHeight(); + var shadow_top = $('.shadow-wrap').offset().top; + + if (a_top < viewport_top + header_height) { + // Top of item (at least) is above the bottom edge of the header + $('html, body').animate({ + scrollTop: a_top - header_height - 20 // little bit extra below header + }, 100); + } else if (a_top + a_height > shadow_top) { + // Bottom of item (at least) is below the top edge of the shadow + $('html, body').animate({ + scrollTop: a_top + a_height - viewport_height + shadow_height + }, 100); + } + } else { + $('.item-list--reports .hovered').removeClass('hovered'); + } +} + +function fms_marker_click(problem_id) { + var $a = $('.item-list--reports a[href$="' + problem_id + '"]'); + $a[0] && $a[0].click(); +} + function fms_categories_or_status_changed() { // If the category or status has changed we need to re-fetch map markers fixmystreet.markers.refresh({force: true}); @@ -197,6 +261,14 @@ function fixmystreet_onload() { popupYOffset: -10 } }); + pin_layer_style_map.addUniqueValueRules('default', 'faded', { + 0: { + graphicOpacity: 1 + }, + 1: { + graphicOpacity: 0.15 + } + }); var pin_layer_options = { rendererOptions: { yOrdering: true @@ -221,32 +293,35 @@ function fixmystreet_onload() { var markers = fms_markers_list( fixmystreet.pins, true ); fixmystreet.markers.addFeatures( markers ); - function onPopupClose(evt) { - fixmystreet.select_feature.unselect(selectedFeature); - OpenLayers.Event.stop(evt); - } + if (fixmystreet.page == 'around' || fixmystreet.page == 'reports' || fixmystreet.page == 'my') { - fixmystreet.select_feature = new OpenLayers.Control.SelectFeature( fixmystreet.markers ); - var selectedFeature; - fixmystreet.markers.events.register( 'featureunselected', fixmystreet.markers, function(evt) { - var feature = evt.feature, popup = feature.popup; - fixmystreet.map.removePopup(popup); - popup.destroy(); - feature.popup = null; - }); - fixmystreet.markers.events.register( 'featureselected', fixmystreet.markers, function(evt) { - var feature = evt.feature; - selectedFeature = feature; - var popupYOffset = feature.layer.styleMap.createSymbolizer(feature).popupYOffset || -40; - var popup = new OpenLayers.Popup.FramedCloud("popup", - feature.geometry.getBounds().getCenterLonLat(), - null, - feature.attributes.title + "<br><a href=/report/" + feature.attributes.id + ">" + translation_strings.more_details + "</a>", - { size: new OpenLayers.Size(0, 0), offset: new OpenLayers.Pixel(0, popupYOffset) }, - true, onPopupClose); - feature.popup = popup; - fixmystreet.map.addPopup(popup); - }); + fixmystreet.select_feature = new OpenLayers.Control.SelectFeature( + fixmystreet.markers, + { + hover: true, + // Override clickFeature so that we can use it even though + // hover is true. http://gis.stackexchange.com/a/155675 + clickFeature: function (feature) { + fms_marker_click(feature.attributes.id); + }, + overFeature: function (feature) { + if (fixmystreet.latest_map_hover_event != 'overFeature') { + document.getElementById('map').style.cursor = 'pointer'; + fms_markers_highlight(feature.attributes.id); + fms_sidebar_highlight(feature.attributes.id); + fixmystreet.latest_map_hover_event = 'overFeature'; + } + }, + outFeature: function (feature) { + if (fixmystreet.latest_map_hover_event != 'outFeature') { + document.getElementById('map').style.cursor = ''; + fms_markers_highlight(); + fms_sidebar_highlight(); + fixmystreet.latest_map_hover_event = 'outFeature'; + } + } + } + ); fixmystreet.map.addControl( fixmystreet.select_feature ); fixmystreet.select_feature.activate(); fixmystreet.map.events.register( 'zoomend', null, fms_markers_resize ); @@ -326,7 +401,7 @@ $(function(){ // Set specific map config - some other JS included in the // template should define this - set_map_config(); + set_map_config(); // Create the basics of the map fixmystreet.map = new OpenLayers.Map( @@ -433,6 +508,18 @@ $(function(){ } else { fixmystreet_onload(); } + + (function() { + var timeout; + $('.item-list--reports').on('mouseenter', '.item-list--reports__item', function(){ + var href = $('a', this).attr('href'); + var id = parseInt(href.replace(/^.*[/]([0-9]+)$/, '$1')); + clearTimeout(timeout); + fms_markers_highlight(id); + }).on('mouseleave', '.item-list--reports__item', function(){ + timeout = setTimeout(fms_markers_highlight, 50); + }); + })(); }); /* Overridding the buttonDown function of PanZoom so that it does @@ -562,7 +649,7 @@ OpenLayers.Format.FixMyStreet = OpenLayers.Class(OpenLayers.Format.JSON, { }); /* Click handler */ -OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control, { +OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control, { defaultHandlerOptions: { 'single': true, 'double': false, @@ -576,12 +663,12 @@ OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control, { {}, this.defaultHandlerOptions); OpenLayers.Control.prototype.initialize.apply( this, arguments - ); + ); this.handler = new OpenLayers.Handler.Click( this, { 'click': this.trigger }, this.handlerOptions); - }, + }, trigger: function(e) { var cobrand = $('meta[name="cobrand"]').attr('content'); |