Skip to content

Commit

Permalink
Turn on spatial filter after 1st user interaction
Browse files Browse the repository at this point in the history
In new Cesium-based catalog search view

Issue #2160
  • Loading branch information
robyngit committed Jul 21, 2023
1 parent c9aae3b commit aa7ba09
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 70 deletions.
2 changes: 1 addition & 1 deletion src/js/templates/search/catalogSearch.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
id="toggle-spatial-filter"
type="checkbox"
name="map"
checked="true"
<% if (mapFilterOn) { %> checked="true" <% } %>
class="map-filter-toggle__checkbox" />
</div>
</div>
191 changes: 127 additions & 64 deletions src/js/views/maps/CesiumWidgetView.js
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,6 @@ define(
// raised.
view.camera.percentChanged = 0.1

// Zoom functions executed after each scene render
view.scene.postRender.addEventListener(function () {
view.postRender();
});

// Disable HDR lighting for better performance and to avoid changing imagery colors.
view.scene.highDynamicRange = false;
Expand All @@ -224,81 +220,148 @@ define(
view.updateDataSourceDisplay.call(view)
})

view.setListeners();
view.addLayers();

// Go to the home position, if one is set.
view.flyHome(0)

// If users are allowed to click on features for more details, initialize
// picking behavior on the map.
// If users are allowed to click on features for more details,
// initialize picking behavior on the map.
if (view.model.get('showFeatureInfo')) {
view.initializePicking()
}

// Set listeners for when the Cesium camera changes a significant amount.
view.camera.changed.addEventListener(function () {
view.trigger('moved')
view.model.trigger('moved')
// Update the bounding box for the visible area in the Map model
view.updateViewExtent()
// If the scale bar is showing, update the pixel to meter scale on the map
// model when the camera angle/zoom level changes
if (view.model.get('showScaleBar')) {
view.updateCurrentScale()
}
})
return this

view.camera.moveEnd.addEventListener(function () {
view.trigger('moveEnd')
view.model.trigger('moveEnd')
})
view.camera.moveStart.addEventListener(function () {
view.trigger('moveStart')
view.model.trigger('moveStart')
})
}
catch (error) {
console.log(
'Failed to render a CesiumWidgetView. Error details: ' + error
);
}
},

// Sets listeners for when the mouse moves, depending on the value of the map
// model's showScaleBar and showFeatureInfo attributes
view.setMouseMoveListeners()

// When the appearance of a layer has been updated, then tell Cesium to
// re-render the scene. Each layer model triggers the 'appearanceChanged'
// function whenever the color, opacity, etc. has been updated in the
// associated Cesium model.
view.stopListening(view.model.get('layers'), 'appearanceChanged')
view.listenTo(view.model.get('layers'), 'appearanceChanged', view.requestRender)

// Other views may trigger an event on the layer/asset model that indicates
// that the map should navigate to the extent of the data, or on the Map model
// to navigate to the home position.
view.stopListening(view.model.get('layers'), 'flyToExtent')
view.listenTo(view.model.get('layers'), 'flyToExtent', view.flyTo)
view.stopListening(view.model, 'flyHome')
view.listenTo(view.model, 'flyHome', view.flyHome)

// Add each layer from the Map model to the Cesium widget. Render using the
// function configured in the View's mapAssetRenderFunctions property. Add in
// reverse order for layers to appear in the correct order on the map.
const layers = view.model.get('layers')
_.each(layers.last(layers.length).reverse(), function (mapAsset) {
view.addAsset(mapAsset)
});
/**
* Set all of the listeners for the CesiumWidgetView. This function is
* called during the render function.
* @since x.x.x
*/
setListeners: function () {

const view = this;

// The Cesium Widget will support just one terrain option to start. Later,
// we'll allow users to switch between terrains if there is more than one.
var terrains = view.model.get('terrains')
var terrainModel = terrains ? terrains.first() : false;
if (terrainModel) {
view.addAsset(terrainModel)
// Zoom functions executed after each scene render
view.scene.postRender.addEventListener(function () {
view.postRender();
});

// When the user first interacts with the map, update the model.
// Ignore the event where the user just moves the mouse over the map.
view.listenOnceForInteraction(function () {
view.model.set('firstInteraction', true);
}, ["MOUSE_MOVE"]);

// Set listeners for when the Cesium camera changes a significant
// amount.
view.camera.changed.addEventListener(function () {
view.trigger('moved')
view.model.trigger('moved')
// Update the bounding box for the visible area in the Map model
view.updateViewExtent()
// If the scale bar is showing, update the pixel to meter scale on
// the map model when the camera angle/zoom level changes
if (view.model.get('showScaleBar')) {
view.updateCurrentScale()
}
})

view.camera.moveEnd.addEventListener(function () {
view.trigger('moveEnd')
view.model.trigger('moveEnd')
})
view.camera.moveStart.addEventListener(function () {
view.trigger('moveStart')
view.model.trigger('moveStart')
})

// Sets listeners for when the mouse moves, depending on the value
// of the map model's showScaleBar and showFeatureInfo attributes
view.setMouseMoveListeners()

// When the appearance of a layer has been updated, then tell Cesium
// to re-render the scene. Each layer model triggers the
// 'appearanceChanged' function whenever the color, opacity, etc.
// has been updated in the associated Cesium model.
view.stopListening(view.model.get('layers'), 'appearanceChanged')
view.listenTo(view.model.get('layers'), 'appearanceChanged', view.requestRender)

// Other views may trigger an event on the layer/asset model that
// indicates that the map should navigate to the extent of the data,
// or on the Map model to navigate to the home position.
view.stopListening(view.model.get('layers'), 'flyToExtent')
view.listenTo(view.model.get('layers'), 'flyToExtent', view.flyTo)
view.stopListening(view.model, 'flyHome')
view.listenTo(view.model, 'flyHome', view.flyHome)
},

/**
* Listen for any user interaction with the map. Once an interaction has
* occurred, run the callback function and stop listening for
* interactions. Useful for detecting the first user interaction with the
* map.
* @param {function} callback - The function to run once the interaction
* has occurred.
* @param {string[]} ignore - An array of Cesium.ScreenSpaceEventType
* labels to ignore. See
* {@link https://cesium.com/learn/cesiumjs/ref-doc/ScreenSpaceEventType.html}
* @since x.x.x
*/
listenOnceForInteraction: function (
callback,
ignore = []
) {
const view = this;
const events = Cesium.ScreenSpaceEventType;
const inputHandler = new Cesium.ScreenSpaceEventHandler(
view.scene.canvas
);
if (!ignore || !Array.isArray(ignore)) ignore = [];

Object.entries(events).forEach(function ([label, value]) {
if (ignore.includes(label)) return;
inputHandler.setInputAction(function () {
callback();
inputHandler.destroy();
}, value);
});
},

/**
* Add all of the model's layers to the map. This function is called
* during the render function.
* @since x.x.x
*/
addLayers: function () {

return this
const view = this;

}
catch (error) {
console.log(
'Failed to render a CesiumWidgetView. Error details: ' + error
);
// Add each layer from the Map model to the Cesium widget. Render
// using the function configured in the View's mapAssetRenderFunctions
// property. Add in reverse order for layers to appear in the correct
// order on the map.
const layers = view.model.get('layers')
_.each(layers.last(layers.length).reverse(), function (mapAsset) {
view.addAsset(mapAsset)
});

// The Cesium Widget will support just one terrain option to start.
// Later, we'll allow users to switch between terrains if there is
// more than one.
var terrains = view.model.get('terrains')
var terrainModel = terrains ? terrains.first() : false;
if (terrainModel) {
view.addAsset(terrainModel)
}
},

Expand Down
64 changes: 59 additions & 5 deletions src/js/views/search/CatalogSearchView.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,25 @@ define([
filtersVisible: true,

/**
* Whether to limit the search to the extent of the map. If true, the
* search will update when the user pans or zooms the map.
* Whether to limit the search to the extent of the map. When true, the
* search will update when the user pans or zooms the map. This property
* will be updated when the user clicks the map filter toggle. Whatever is
* set during the initial render will be the default.
* @type {boolean}
* @since 2.25.0
* @default false
*/
limitSearchToMapArea: false,

/**
* Whether to limit the search to the extent the first time the user
* interacts with the map. This only applies if limitSearchToMapArea is
* initially set to false.
* @type {boolean}
* @since x.x.x
* @default true
*/
limitSearchToMapArea: true,
limitSearchToMapOnInteraction: true,

/**
* The View that displays the search results. The render method will be
Expand Down Expand Up @@ -300,8 +312,9 @@ define([
addSpatialFilter: options.addSpatialFilter !== false,
});
}
model.connect();

this.model = model;
this.model.connect();
},

/**
Expand All @@ -317,6 +330,9 @@ define([

// Render the search components
this.renderComponents();

// Set up the initial map toggle state
this.setMapToggleState();
},

/**
Expand Down Expand Up @@ -354,6 +370,27 @@ define([
this.toggleMapVisibility(this.mapVisible);
},

/**
* Sets the initial state of the map filter toggle. Optionally listens
* for the first user interaction with the map before turning on the
* spatial filter.
* @since x.x.x
*/
setMapToggleState: function () {
// Set the initial state of the spatial filter
this.toggleMapFilter(this.limitSearchToMapArea);

if (this.limitSearchToMapOnInteraction && !this.limitSearchToMapArea) {
this.listenToOnce(
this.model.get("map"),
"change:firstInteraction",
function () {
this.toggleMapFilter(true);
}
);
}
},

/**
* Sets up the basic components of this view
* @since 2.22.0
Expand All @@ -373,7 +410,11 @@ define([
this.addLinkedData();

// Render the template
this.$el.html(this.template({}));
this.$el.html(
this.template({
mapFilterOn: this.limitSearchToMapArea === true,
})
);
} catch (e) {
console.log(
"There was an error setting up the CatalogSearchView:" + e
Expand Down Expand Up @@ -817,12 +858,25 @@ define([
? !this.limitSearchToMapArea // the opposite of the current mode
: newSetting; // the provided new mode if it is a boolean

// Select the map filter toggle checkbox so that we can keep it in sync
// with the new setting
let mapFilterToggle = this.el.querySelector(this.mapFilterToggle);
// If it's not a checkbox input, find the child checkbox input
if (mapFilterToggle && mapFilterToggle.tagName != "INPUT") {
mapFilterToggle = mapFilterToggle.querySelector("input");
}
if (newSetting) {
// If true, then the filter should be ON
this.model.connectFiltersMap();
if (mapFilterToggle) {
mapFilterToggle.checked = true;
}
} else {
// If false, then the filter should be OFF
this.model.disconnectFiltersMap(true);
if (mapFilterToggle) {
mapFilterToggle.checked = false;
}
}
this.limitSearchToMapArea = newSetting;
},
Expand Down

0 comments on commit aa7ba09

Please sign in to comment.