Add existing to tracked
This commit is contained in:
+233
@@ -0,0 +1,233 @@
|
||||
import {
|
||||
defined,
|
||||
destroyObject,
|
||||
DeveloperError,
|
||||
FeatureDetection,
|
||||
getElement,
|
||||
} from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import GeocoderViewModel from "./GeocoderViewModel.js";
|
||||
|
||||
const startSearchPath =
|
||||
"M29.772,26.433l-7.126-7.126c0.96-1.583,1.523-3.435,1.524-5.421C24.169,8.093,19.478,3.401,13.688,3.399C7.897,3.401,3.204,8.093,3.204,13.885c0,5.789,4.693,10.481,10.484,10.481c1.987,0,3.839-0.563,5.422-1.523l7.128,7.127L29.772,26.433zM7.203,13.885c0.006-3.582,2.903-6.478,6.484-6.486c3.579,0.008,6.478,2.904,6.484,6.486c-0.007,3.58-2.905,6.476-6.484,6.484C10.106,20.361,7.209,17.465,7.203,13.885z";
|
||||
const stopSearchPath =
|
||||
"M24.778,21.419 19.276,15.917 24.777,10.415 21.949,7.585 16.447,13.087 10.945,7.585 8.117,10.415 13.618,15.917 8.116,21.419 10.946,24.248 16.447,18.746 21.948,24.248z";
|
||||
|
||||
/**
|
||||
* A widget for finding addresses and landmarks, and flying the camera to them. Geocoding is
|
||||
* performed using {@link https://cesium.com/cesium-ion/|Cesium ion}.
|
||||
*
|
||||
* @alias Geocoder
|
||||
* @constructor
|
||||
*
|
||||
* @param {object} options Object with the following properties:
|
||||
* @param {Element|string} options.container The DOM element or ID that will contain the widget.
|
||||
* @param {Scene} options.scene The Scene instance to use.
|
||||
* @param {GeocoderService[]} [options.geocoderServices] The geocoder services to be used
|
||||
* @param {boolean} [options.autoComplete = true] True if the geocoder should query as the user types to autocomplete
|
||||
* @param {number} [options.flightDuration=1.5] The duration of the camera flight to an entered location, in seconds.
|
||||
* @param {Geocoder.DestinationFoundFunction} [options.destinationFound=GeocoderViewModel.flyToDestination] A callback function that is called after a successful geocode. If not supplied, the default behavior is to fly the camera to the result destination.
|
||||
*/
|
||||
function Geocoder(options) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(options) || !defined(options.container)) {
|
||||
throw new DeveloperError("options.container is required.");
|
||||
}
|
||||
if (!defined(options.scene)) {
|
||||
throw new DeveloperError("options.scene is required.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
const container = getElement(options.container);
|
||||
const viewModel = new GeocoderViewModel(options);
|
||||
|
||||
viewModel._startSearchPath = startSearchPath;
|
||||
viewModel._stopSearchPath = stopSearchPath;
|
||||
|
||||
const form = document.createElement("form");
|
||||
form.setAttribute("data-bind", "submit: search");
|
||||
|
||||
const textBox = document.createElement("input");
|
||||
textBox.type = "search";
|
||||
textBox.className = "cesium-geocoder-input";
|
||||
textBox.setAttribute("placeholder", "Enter an address or landmark...");
|
||||
textBox.setAttribute(
|
||||
"data-bind",
|
||||
'\
|
||||
textInput: searchText,\
|
||||
disable: isSearchInProgress,\
|
||||
event: { keyup: handleKeyUp, keydown: handleKeyDown, mouseover: deselectSuggestion },\
|
||||
css: { "cesium-geocoder-input-wide" : keepExpanded || searchText.length > 0 },\
|
||||
hasFocus: _focusTextbox',
|
||||
);
|
||||
|
||||
this._onTextBoxFocus = function () {
|
||||
// as of 2016-10-19, setTimeout is required to ensure that the
|
||||
// text is focused on Safari 10
|
||||
setTimeout(function () {
|
||||
textBox.select();
|
||||
}, 0);
|
||||
};
|
||||
|
||||
textBox.addEventListener("focus", this._onTextBoxFocus, false);
|
||||
form.appendChild(textBox);
|
||||
this._textBox = textBox;
|
||||
|
||||
const searchButton = document.createElement("span");
|
||||
searchButton.className = "cesium-geocoder-searchButton";
|
||||
searchButton.setAttribute(
|
||||
"data-bind",
|
||||
"\
|
||||
click: search,\
|
||||
cesiumSvgPath: { path: isSearchInProgress ? _stopSearchPath : _startSearchPath, width: 32, height: 32 }",
|
||||
);
|
||||
form.appendChild(searchButton);
|
||||
|
||||
container.appendChild(form);
|
||||
|
||||
const searchSuggestionsContainer = document.createElement("div");
|
||||
searchSuggestionsContainer.className = "search-results";
|
||||
searchSuggestionsContainer.setAttribute(
|
||||
"data-bind",
|
||||
"visible: _suggestionsVisible",
|
||||
);
|
||||
|
||||
const suggestionsList = document.createElement("ul");
|
||||
suggestionsList.setAttribute("data-bind", "foreach: _suggestions");
|
||||
const suggestions = document.createElement("li");
|
||||
suggestionsList.appendChild(suggestions);
|
||||
suggestions.setAttribute(
|
||||
"data-bind",
|
||||
"text: $data.displayName, \
|
||||
click: $parent.activateSuggestion, \
|
||||
event: { mouseover: $parent.handleMouseover}, \
|
||||
css: { active: $data === $parent._selectedSuggestion }",
|
||||
);
|
||||
|
||||
searchSuggestionsContainer.appendChild(suggestionsList);
|
||||
container.appendChild(searchSuggestionsContainer);
|
||||
|
||||
knockout.applyBindings(viewModel, form);
|
||||
knockout.applyBindings(viewModel, searchSuggestionsContainer);
|
||||
|
||||
this._container = container;
|
||||
this._searchSuggestionsContainer = searchSuggestionsContainer;
|
||||
this._viewModel = viewModel;
|
||||
this._form = form;
|
||||
|
||||
this._onInputBegin = function (e) {
|
||||
// e.target will not be correct if we are inside of the Shadow DOM
|
||||
// and contains will always fail. To retrieve the correct target,
|
||||
// we need to access the first element of the composedPath.
|
||||
// This allows us to use shadow DOM if it exists and fall
|
||||
// back to legacy behavior if its not being used.
|
||||
|
||||
let target = e.target;
|
||||
if (typeof e.composedPath === "function") {
|
||||
target = e.composedPath()[0];
|
||||
}
|
||||
|
||||
if (!container.contains(target)) {
|
||||
viewModel._focusTextbox = false;
|
||||
viewModel.hideSuggestions();
|
||||
}
|
||||
};
|
||||
|
||||
this._onInputEnd = function (e) {
|
||||
viewModel._focusTextbox = true;
|
||||
viewModel.showSuggestions();
|
||||
};
|
||||
|
||||
//We subscribe to both begin and end events in order to give the text box
|
||||
//focus no matter where on the widget is clicked.
|
||||
|
||||
if (FeatureDetection.supportsPointerEvents()) {
|
||||
document.addEventListener("pointerdown", this._onInputBegin, true);
|
||||
container.addEventListener("pointerup", this._onInputEnd, true);
|
||||
container.addEventListener("pointercancel", this._onInputEnd, true);
|
||||
} else {
|
||||
document.addEventListener("mousedown", this._onInputBegin, true);
|
||||
container.addEventListener("mouseup", this._onInputEnd, true);
|
||||
document.addEventListener("touchstart", this._onInputBegin, true);
|
||||
container.addEventListener("touchend", this._onInputEnd, true);
|
||||
container.addEventListener("touchcancel", this._onInputEnd, true);
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperties(Geocoder.prototype, {
|
||||
/**
|
||||
* Gets the parent container.
|
||||
* @memberof Geocoder.prototype
|
||||
*
|
||||
* @type {Element}
|
||||
*/
|
||||
container: {
|
||||
get: function () {
|
||||
return this._container;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the parent container.
|
||||
* @memberof Geocoder.prototype
|
||||
*
|
||||
* @type {Element}
|
||||
*/
|
||||
searchSuggestionsContainer: {
|
||||
get: function () {
|
||||
return this._searchSuggestionsContainer;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the view model.
|
||||
* @memberof Geocoder.prototype
|
||||
*
|
||||
* @type {GeocoderViewModel}
|
||||
*/
|
||||
viewModel: {
|
||||
get: function () {
|
||||
return this._viewModel;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @returns {boolean} true if the object has been destroyed, false otherwise.
|
||||
*/
|
||||
Geocoder.prototype.isDestroyed = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys the widget. Should be called if permanently
|
||||
* removing the widget from layout.
|
||||
*/
|
||||
Geocoder.prototype.destroy = function () {
|
||||
const container = this._container;
|
||||
if (FeatureDetection.supportsPointerEvents()) {
|
||||
document.removeEventListener("pointerdown", this._onInputBegin, true);
|
||||
container.removeEventListener("pointerup", this._onInputEnd, true);
|
||||
} else {
|
||||
document.removeEventListener("mousedown", this._onInputBegin, true);
|
||||
container.removeEventListener("mouseup", this._onInputEnd, true);
|
||||
document.removeEventListener("touchstart", this._onInputBegin, true);
|
||||
container.removeEventListener("touchend", this._onInputEnd, true);
|
||||
}
|
||||
this._viewModel.destroy();
|
||||
knockout.cleanNode(this._form);
|
||||
knockout.cleanNode(this._searchSuggestionsContainer);
|
||||
container.removeChild(this._form);
|
||||
container.removeChild(this._searchSuggestionsContainer);
|
||||
this._textBox.removeEventListener("focus", this._onTextBoxFocus, false);
|
||||
|
||||
return destroyObject(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* A function that handles the result of a successful geocode.
|
||||
* @callback Geocoder.DestinationFoundFunction
|
||||
* @param {GeocoderViewModel} viewModel The view model.
|
||||
* @param {Cartesian3|Rectangle} destination The destination result of the geocode.
|
||||
*/
|
||||
export default Geocoder;
|
||||
Reference in New Issue
Block a user