devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
332 lines (331 loc) • 11.6 kB
JavaScript
/**
* DevExtreme (esm/ui/map.js)
* Version: 21.1.4
* Build date: Mon Jun 21 2021
*
* Copyright (c) 2012 - 2021 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
import $ from "../core/renderer";
import eventsEngine from "../events/core/events_engine";
import Promise from "../core/polyfills/promise";
import {
fromPromise
} from "../core/utils/deferred";
import registerComponent from "../core/component_registrator";
import errors from "./widget/ui.errors";
import devices from "../core/devices";
import Widget from "./widget/ui.widget";
import {
titleize
} from "../core/utils/inflector";
import {
each
} from "../core/utils/iterator";
import {
extend
} from "../core/utils/extend";
import {
inArray,
wrapToArray
} from "../core/utils/array";
import {
isNumeric
} from "../core/utils/type";
import {
addNamespace
} from "../events/utils/index";
import pointerEvents from "../events/pointer";
import googleStatic from "./map/provider.google_static";
import google from "./map/provider.dynamic.google";
import bing from "./map/provider.dynamic.bing";
var PROVIDERS = {
googleStatic: googleStatic,
google: google,
bing: bing
};
var MAP_CLASS = "dx-map";
var MAP_CONTAINER_CLASS = "dx-map-container";
var MAP_SHIELD_CLASS = "dx-map-shield";
var NATIVE_CLICK_CLASS = "dx-native-click";
var Map = Widget.inherit({
_getDefaultOptions: function() {
return extend(this.callBase(), {
bounds: {
northEast: null,
southWest: null
},
center: {
lat: 0,
lng: 0
},
zoom: 1,
width: 300,
height: 300,
type: "roadmap",
provider: "google",
autoAdjust: true,
markers: [],
markerIconSrc: null,
onMarkerAdded: null,
onMarkerRemoved: null,
routes: [],
onRouteAdded: null,
onRouteRemoved: null,
key: {
bing: "",
google: "",
googleStatic: ""
},
apiKey: {
bing: "",
google: "",
googleStatic: ""
},
controls: false,
onReady: null,
onUpdated: null,
onClick: null
})
},
_defaultOptionsRules: function() {
return this.callBase().concat([{
device: function() {
return "desktop" === devices.real().deviceType && !devices.isSimulator()
},
options: {
focusStateEnabled: true
}
}])
},
_setDeprecatedOptions: function() {
this.callBase();
extend(this._deprecatedOptions, {
key: {
since: "20.2",
alias: "apiKey"
}
})
},
_init: function() {
this.callBase();
this.$element().addClass(MAP_CLASS).addClass(NATIVE_CLICK_CLASS);
this._lastAsyncAction = Promise.resolve();
this._checkOption("provider");
this._checkOption("markers");
this._checkOption("routes");
this._initContainer();
this._grabEvents();
this._rendered = {}
},
_useTemplates: function() {
return false
},
_checkOption: function(option) {
var value = this.option(option);
if ("markers" === option && !Array.isArray(value)) {
throw errors.Error("E1022")
}
if ("routes" === option && !Array.isArray(value)) {
throw errors.Error("E1023")
}
},
_initContainer: function() {
this._$container = $("<div>").addClass(MAP_CONTAINER_CLASS);
this.$element().append(this._$container)
},
_grabEvents: function() {
var eventName = addNamespace(pointerEvents.down, this.NAME);
eventsEngine.on(this.$element(), eventName, this._cancelEvent.bind(this))
},
_cancelEvent: function(e) {
var cancelByProvider = this._provider && this._provider.isEventsCanceled(e) && !this.option("disabled");
if (cancelByProvider) {
e.stopPropagation()
}
},
_saveRendered: function(option) {
var value = this.option(option);
this._rendered[option] = value.slice()
},
_render: function() {
this.callBase();
this._renderShield();
this._saveRendered("markers");
this._saveRendered("routes");
this._provider = new(PROVIDERS[this.option("provider")])(this, this._$container);
this._queueAsyncAction("render", this._rendered.markers, this._rendered.routes)
},
_renderShield: function() {
var $shield;
if (this.option("disabled")) {
$shield = $("<div>").addClass(MAP_SHIELD_CLASS);
this.$element().append($shield)
} else {
$shield = this.$element().find("." + MAP_SHIELD_CLASS);
$shield.remove()
}
},
_clean: function() {
this._cleanFocusState();
if (this._provider) {
this._provider.clean()
}
this._provider = null;
this._lastAsyncAction = Promise.resolve();
this.setOptionSilent("bounds", {
northEast: null,
southWest: null
});
delete this._suppressAsyncAction
},
_optionChanged: function(args) {
var name = args.name;
var changeBag = this._optionChangeBag;
this._optionChangeBag = null;
switch (name) {
case "disabled":
this._renderShield();
this.callBase(args);
break;
case "width":
case "height":
this.callBase(args);
this._dimensionChanged();
break;
case "provider":
this._suppressAsyncAction = true;
this._invalidate();
break;
case "key":
case "apiKey":
errors.log("W1001");
break;
case "bounds":
this._queueAsyncAction("updateBounds");
break;
case "center":
this._queueAsyncAction("updateCenter");
break;
case "zoom":
this._queueAsyncAction("updateZoom");
break;
case "type":
this._queueAsyncAction("updateMapType");
break;
case "controls":
this._queueAsyncAction("updateControls", this._rendered.markers, this._rendered.routes);
break;
case "autoAdjust":
this._queueAsyncAction("adjustViewport");
break;
case "markers":
case "routes":
this._checkOption(name);
var prevValue = this._rendered[name];
this._saveRendered(name);
this._queueAsyncAction("update" + titleize(name), changeBag ? changeBag.removed : prevValue, changeBag ? changeBag.added : this._rendered[name]).then((function(result) {
if (changeBag) {
changeBag.resolve(result)
}
}));
break;
case "markerIconSrc":
this._queueAsyncAction("updateMarkers", this._rendered.markers, this._rendered.markers);
break;
case "onReady":
case "onUpdated":
case "onMarkerAdded":
case "onMarkerRemoved":
case "onRouteAdded":
case "onRouteRemoved":
case "onClick":
break;
default:
this.callBase.apply(this, arguments)
}
},
_visibilityChanged: function(visible) {
if (visible) {
this._dimensionChanged()
}
},
_dimensionChanged: function() {
this._queueAsyncAction("updateDimensions")
},
_queueAsyncAction: function(name) {
var options = [].slice.call(arguments).slice(1);
var isActionSuppressed = this._suppressAsyncAction;
this._lastAsyncAction = this._lastAsyncAction.then(function() {
if (!this._provider || isActionSuppressed) {
return Promise.resolve()
}
return this._provider[name].apply(this._provider, options).then(function(result) {
result = wrapToArray(result);
var mapRefreshed = result[0];
if (mapRefreshed && !this._disposed) {
this._triggerReadyAction()
}
return result[1]
}.bind(this))
}.bind(this));
return this._lastAsyncAction
},
_triggerReadyAction: function() {
this._createActionByOption("onReady")({
originalMap: this._provider.map()
})
},
_triggerUpdateAction: function() {
this._createActionByOption("onUpdated")()
},
setOptionSilent: function(name, value) {
this._setOptionWithoutOptionChange(name, value)
},
addMarker: function(marker) {
return this._addFunction("markers", marker)
},
removeMarker: function(marker) {
return this._removeFunction("markers", marker)
},
addRoute: function(route) {
return this._addFunction("routes", route)
},
removeRoute: function(route) {
return this._removeFunction("routes", route)
},
_addFunction: function(optionName, addingValue) {
var optionValue = this.option(optionName);
var addingValues = wrapToArray(addingValue);
optionValue.push.apply(optionValue, addingValues);
return this._partialArrayOptionChange(optionName, optionValue, addingValues, [])
},
_removeFunction: function(optionName, removingValue) {
var optionValue = this.option(optionName);
var removingValues = wrapToArray(removingValue);
each(removingValues, (function(removingIndex, removingValue) {
var index = isNumeric(removingValue) ? removingValue : inArray(removingValue, optionValue);
if (-1 !== index) {
var removing = optionValue.splice(index, 1)[0];
removingValues.splice(removingIndex, 1, removing)
} else {
throw errors.log("E1021", titleize(optionName.substring(0, optionName.length - 1)), removingValue)
}
}));
return this._partialArrayOptionChange(optionName, optionValue, [], removingValues)
},
_partialArrayOptionChange: function(optionName, optionValue, addingValues, removingValues) {
return fromPromise(new Promise(function(resolve) {
this._optionChangeBag = {
resolve: resolve,
added: addingValues,
removed: removingValues
};
this.option(optionName, optionValue)
}.bind(this)).then((function(result) {
return result && 1 === result.length ? result[0] : result
})), this)
}
});
registerComponent("dxMap", Map);
export default Map;