cartodb-4.42/lib/assets/javascripts/cartodb/table/overlays/map_overlays.js
2024-04-06 05:25:13 +00:00

795 lines
20 KiB
JavaScript

//
// manages overlays on the map
//
cdb.admin.MapOverlays = cdb.core.View.extend({
initialize: function() {
this.overlayViews = [];
this.horizontal_overlays = ["share", "layer_selector", "search"];
this.vertical_overlays = ["zoom", "fullscreen", "loader"];
this.vis = this.options.vis;
this.master_vis = this.options.master_vis;
this.canvas = this.options.canvas;
this.mapView = this.options.mapView;
this.map = this.mapView.map;
this.mapToolbar = this.options.mapToolbar;
this.headerMessageIsVisible = this.options.headerMessageIsVisible;
this._bindOverlays();
},
setHeaderMessageIsVisible: function(visible) {
this.headerMessageIsVisible = visible;
this._positionOverlaysVertically();
},
_cleanOverlays: function() {
if (this.overlays) {
_.each(this.overlayViews, function(overlay) {
overlay.clean();
});
this.overlayViews = [];
this.zoom = null;
this.loader = null;
this.fullscreen = null;
this.search = null;
}
},
getOverlay: function(type) {
if (!this.overlays) return;
return this.overlays.filter(function(m) { return m.get("type") == type })[0];
},
getHeaderOverlay: function() {
return this.getOverlay("header");
},
_hideOverlays: function(mode) {
if (!this.overlays) return;
var hideOverlays = ["search"];
this.overlays.each(function(overlay) {
var device = overlay.get("device");
if (device === mode) overlay.set("display", false);
}, this);
},
_showOverlays: function(mode) {
this.overlays.each(function(overlay) {
var device = overlay.get("device");
if (device === mode) overlay.set("display", true);
}, this);
},
_bindOverlays: function() {
var self = this;
this.overlays = this.vis.overlays;
this.add_related_model(this.vis.overlays);
this.overlays.unbind("reset", this._onResetOverlays);
this.overlays.unbind("remove");
this.overlays.unbind("add");
this.overlays.bind("reset", this._onResetOverlays, this);
this.overlays.bind("remove", function(overlay) {
overlay.destroy();
});
this.overlays.bind("add", function(overlay) {
self._renderOverlay(false, overlay);
self._reloadDraggable();
});
this._onResetOverlays(this.overlays);
},
_onResetOverlays: function(overlays) {
this._cleanOverlays();
if (overlays.models.length > 0) {
overlays.each(this._setupOverlay, this);
}
},
_setupOverlay: function(overlay) {
this._renderOverlay(false, overlay);
},
_renderOverlay: function(delayed_animation, model) {
// FIXME - delayed_animation never used ???
var type = this._getOverlayType(model);
var device = model.get("device");
var vis_overlays = ["Header", "Fullscreen", "Share", "LayerSelector"];
if (_.contains(vis_overlays, type) && this.vis.get("type") === "table") {
return;
}
var display = (device && device != this.canvas.get("mode")) ? false : true;
model.set("display", display);
var overlay = this._configureOverlay(model);
if (!overlay) return;
this.overlayViews.push(overlay);
this.mapView.$el.append(overlay.render().$el);
this._bindOverlay(overlay);
if (type === "Text" || type === "Image") {
this._toggleOverlay(overlay);
} else if (type === "Annotation") {
this._reloadDraggable();
}
},
//TODO: move to overlay list
_configureOverlay: function(model) {
var type = this._getOverlayType(model);
var overlay;
switch(type) {
case 'Loader': overlay = this._setupLoaderOverlay(type, model); break;
case 'Zoom': overlay = this._setupZoomOverlay(type, model); break;
case 'Share': overlay = this._setupShareOverlay(type, model); break;
case 'Header': overlay = this._setupHeaderOverlay(type, model); break;
case 'Search': overlay = this._setupSearchOverlay(type, model); break;
case 'Logo': overlay = this._setupCartoDBLogo(type, model); break;
case 'LayerSelector': overlay = this._setupLayerSelectorOverlay(type, model); break;
case 'Fullscreen': overlay = this._setupFullScreenOverlay(type, model); break;
// Default
case 'Text': overlay = new cdb.admin.overlays[type]({ model: model }); break;
case 'Image': overlay = new cdb.admin.overlays[type]({ model: model }); break;
case 'Annotation': overlay = new cdb.admin.overlays[type]({
vis: this.vis,
canvas: this.canvas,
model: model,
mapView: this.mapView
}); break;
}
return overlay;
},
_getOverlayType: function(data) {
var type = data.get("type");
if (!type) type = "text";
return _.map(type.split("_"), function(word) {
return word.slice(0, 1).toUpperCase() + word.slice(1);
}).join("");
},
_positionOverlaysHorizontally: function() {
_.each(this.horizontal_overlays, function(type) {
var overlay_model = this.getOverlay(type);
if (overlay_model) this._positionOverlay(overlay_model)
}, this);
},
_positionOverlaysVertically: function(move_header) {
if (!this.overlays) return;
if (move_header) {
var header = this.getHeaderOverlay();
this._positionOverlay(header);
}
_.each(this.horizontal_overlays, function(type) {
var overlay_model = this.getOverlay(type);
if (overlay_model) this._positionOverlay(overlay_model)
}, this);
_.each(this.vertical_overlays, function(type) {
var overlay_model = this.getOverlay(type);
if (overlay_model) this._positionOverlay(overlay_model);
}, this);
},
_duplicate: function(model) {
var m = model.cloneAttributes();
var extra = m.extra;
var canvas_mode = this.options.canvas.get("mode");
var indexes = this.overlays.getOverlaysZIndex(canvas_mode);
var zIndex = _.max(indexes);
var style = m.style;
style['z-index'] = zIndex + 1;
if (model.get('type') === 'annotation') {
var latlng = this._getRandomCenter(model.get('extra').latlng);
extra.latlng = [latlng.lat, latlng.lng];
} else {
var point = this._getRandomPoint(model.get('x'), model.get('y'));
m.x = point.x;
m.y = point.y;
}
var overlay = new cdb.admin.models.Overlay(_.extend(m, { id: null, style: style, extra: extra }));
this.overlays.add(overlay);
overlay.save();
},
paste: function() {
if (!this._copiedOverlay || this._editing) {
return;
}
var model = this._copiedOverlay;
this._duplicate(model);
},
_getRandomPoint: function(x, y) {
return { x: x + 50 + Math.round(Math.random() * 50), y: y + 50 + Math.round(Math.random() * 50) };
},
_getRandomCenter: function(latlng) {
var center = this.mapView.latLonToPixel(latlng);
var xR = center.x + 50 + Math.round(Math.random() * 50);
var yR = center.y + 50 + Math.round(Math.random() * 50);
return this.mapView.pixelToLatLon([xR, yR]);
},
_bindOverlay: function(overlay) {
if (overlay.model && overlay.model.get("type") === "header") {
this._positionOverlaysVertically();
}
if (overlay.model && overlay.model.get("type") === 'search') {
this._positionSearchOverlay(overlay.model);
}
overlay.bind("editing", function(editing) {
this._editing = editing;
}, this);
overlay.bind("duplicate", function(model) {
this.editing = true;
this._copiedOverlay = model;
}, this);
overlay.bind("remove", function(overlay) {
this.overlays.remove(overlay.model);
this._removeOverlayPropertiesBar(true);
}, this);
overlay.bind("clickEdit", function(model, form_data) {
this._addOverlayPropertiesBar(model, form_data);
}, this);
},
_hideToobarOptions: function(model) {
if (this.overlayPropertiesBar) {
if (this.overlayPropertiesBar.compareModel(model)) { // if the model is the same as the current one, hide the options bar
this.mapToolbar.find("ul.options").animate({ top: -100 }, { duration: 200, easing: "easeInOutQuad" } );
} else { // otherwise, deselect the overlay
this.overlayPropertiesBar.deselectOverlay();
}
} else {
this.mapToolbar.find("ul.options").animate({ top: -100 }, { duration: 200, easing: "easeInOutQuad" });
}
},
_removeOverlayPropertiesBar: function(show_toolbar, model) {
// Abort the removal if we are clicking in the same overlay to edit
if (model && this.overlayPropertiesBar && this.overlayPropertiesBar.compareModel(model)) return;
if (show_toolbar) this._showToolbarOptions();
// Attempt to destroy the bar
if (this.overlayPropertiesBar) {
var self = this;
if (!model) { // if there's no current model, animate the bar
this.overlayPropertiesBar.$el.animate({ top: 100 }, { duration: 150, complete: function() {
self.overlayPropertiesBar.clean();
delete self.overlayPropertiesBar;
}});
return false;
} else { // otherwise, just remove the bar
this.overlayPropertiesBar.clean();
delete this.overlayPropertiesBar;
return true;
}
}
},
_showToolbarOptions: function() {
var self = this;
this.mapToolbar.find("ul.options").animate({ top: 0 }, { duration: 250, easing: "easeInOutQuad", complete: function() {
self.mapToolbar.removeClass("animated");
}});
},
_addOverlayPropertiesBar: function(model, form_data) {
if (this.overlaysDropdown) this.overlaysDropdown.hide();
this.mapToolbar.addClass("animated");
this._hideToobarOptions(model);
var animatedRemoval = this._removeOverlayPropertiesBar(false, model);
if (!this.overlayPropertiesBar) {
this.overlayPropertiesBar = new cdb.admin.OverlayPropertiesBar({
model: model,
mapView: this.mapView,
overlays: this.overlays,
canvas: this.canvas,
vis: this.vis,
form_data: form_data
});
this.addView(this.overlayPropertiesBar);
this.overlayPropertiesBar.bind("remove", this._removeOverlayPropertiesBar, this);
this.overlayPropertiesBar.bind("copy-overlay", this._duplicate, this);
this.mapToolbar.append(this.overlayPropertiesBar.render().el);
if (!animatedRemoval) {
this.overlayPropertiesBar.$el.animate({ top: 0 }, { duration: 200, easing: "easeInOutQuad" });
} else {
this.overlayPropertiesBar.$el.css({ top: 0 });
}
}
},
/* Show or hide an overlay */
_toggleOverlay: function(overlay, delayed_animation) {
this._reloadDraggable();
if (delayed_animation) { // Random animation
var randomTime = 100 + Math.random() * 900;
setTimeout(function() {
if (overlay.model.get("display")) overlay.show();
}, randomTime);
} else { // Show the overlay right away
if (overlay.model.get("display")) overlay.show();
}
},
_reloadDraggable: function() {
$(".overlay").draggableOverlay({
container: $(".cartodb-map"),
stickiness: 10
});
},
// SHARE
_setupShareOverlay: function(type, data) {
var overlay = this.share = new cdb.admin.overlays[type]({
model: data,
map: this.map
});
overlay.show();
this._bindShareOverlay(overlay);
return overlay;
},
_bindShareOverlay: function(overlay) {
var self = this;
this._positionShareOverlay(overlay.model);
this._positionOverlaysHorizontally();
var onDestroy = function() {
if (self.share) {
self.share.clean();
delete self.share;
}
self._positionOverlaysHorizontally();
};
overlay.model.bind("destroy", onDestroy, this);
},
// LOADER
_setupLoaderOverlay: function(type, data) {
if (this.loader) return;
var overlay = this.loader = new cdb.admin.overlays[type]({
model: data,
map: this.vis.map
});
this._bindLoaderOverlay(overlay);
return overlay;
},
_bindLoaderOverlay: function(overlay) {
this._positionLoaderOverlay(overlay.model);
},
// FULLSCREEN
_setupFullScreenOverlay: function(type, data) {
if (this.fullscreen) return;
var overlay = this.fullscreen = new cdb.admin.overlays[type]({
model: data,
mapView: this.mapView
});
this._bindFullScreenOverlay(overlay);
return overlay;
},
_bindFullScreenOverlay: function(overlay) {
var self = this;
this._positionOverlay(overlay.model);
var onDestroy = function() {
if (self.fullscreen) {
self.fullscreen.clean();
delete self.fullscreen;
}
};
overlay.show();
overlay.model.bind("destroy", onDestroy, this);
},
_setupLayerSelectorOverlay: function(type, data) {
if (this.layer_selector) return;
var overlay = this.layer_selector = new cdb.admin.overlays[type]({
model: data,
mapView: this.mapView,
template: this.getTemplate("table/views/layer_selector"),
dropdown_template: this.getTemplate("table/views/layer_dropdown")
});
overlay.show();
this._bindLayerSelectorOverlay(overlay);
return overlay;
},
_bindLayerSelectorOverlay: function(overlay) {
var self = this;
this._positionOverlay(overlay.model);
var onDestroy = function() {
if (self.layer_selector) {
self.layer_selector.clean();
delete self.layer_selector;
}
};
overlay.model.bind("destroy", onDestroy, this);
},
// ZOOM
_setupZoomOverlay: function(type, data) {
if (this.zoom) return;
var overlay = this.zoom = new cdb.admin.overlays[type]({
model: data,
map: this.vis.map
});
overlay.show();
this._bindZoomOverlay(overlay);
return overlay;
},
_bindZoomOverlay: function(overlay) {
var self = this;
var n = this.vertical_overlays.indexOf(overlay.model.get("type"));
for (var i = n ; i< this.vertical_overlays.length; i++) {
var type = this.vertical_overlays[i];
var overlay_model = this.getOverlay(type);
if (overlay_model) this._positionOverlay(overlay_model)
}
var onDestroy = function() {
if (self.zoom) {
self.zoom.clean();
delete self.zoom;
}
var n = this.vertical_overlays.indexOf(overlay.model.get("type"));
for (var i = n + 1; i< this.vertical_overlays.length; i++) {
var type = this.vertical_overlays[i];
var overlay_model = this.getOverlay(type);
if (overlay_model) this._positionOverlay(overlay_model)
}
};
overlay.model.bind("destroy", onDestroy, this);
},
_setupCartoDBLogo: function(type, data) {
var overlay = this.cartodb_logo = new cdb.admin.overlays[type]({
model: data,
map: this.map
});
return overlay;
},
_setupSearchOverlay: function(type, data) {
if (this.search) {
return;
}
var overlay = this.search = new cdb.admin.overlays[type]({
model: data,
relative_position: this.vis.get("type") === "table",
mapView: this.options.mapView,
map: this.map,
vis: this.vis,
canvas: this.canvas,
});
this._bindSearchOverlay(overlay);
return overlay;
},
_bindSearchOverlay: function(overlay) {
var self = this;
this._positionSearchOverlay(overlay.model);
this._positionOverlaysHorizontally();
var onDestroy = function() {
if (self.search) {
self.search.clean();
delete self.search;
}
self._positionOverlaysHorizontally();
};
overlay.model.bind("destroy", onDestroy, this);
},
_setupHeaderOverlay: function(type, data) {
var overlay = this.header = new cdb.admin.overlays[type]({
model: data,
map: this.map
});
this._bindHeaderOverlay(overlay);
return overlay;
},
_bindHeaderOverlay: function(overlay) {
var self = this;
var onDestroy = function() {
if (self.header) {
self.header.clean();
delete self.header;
}
self._positionOverlaysVertically();
};
overlay.bind("change_y", this._positionOverlaysVertically, this);
overlay.model.bind("destroy", onDestroy, this);
},
_getHeaderHeight: function() {
return $(".header.overlay-static").outerHeight(true) || 20;
},
_positionOverlay: function(overlay_model) {
if (!overlay_model) return;
var type = overlay_model.get("type");
if (type === 'header') this._positionHeaderOverlay(overlay_model);
else if (type === 'zoom') this._positionZoomOverlay(overlay_model);
else if (type === 'fullscreen') this._positionFullScreenOverlay(overlay_model);
else if (type === 'share') this._positionShareOverlay(overlay_model);
else if (type === 'loader') this._positionLoaderOverlay(overlay_model);
else if (type === 'search') this._positionSearchOverlay(overlay_model);
else if (type === 'layer_selector') this._positionLayerSelectorOverlay(overlay_model);
},
_positionHeaderOverlay: function(overlay_model) {
if (this.headerMessageIsVisible && this.canvas.get("mode") === 'desktop') overlay_model.set("y", 20);
else overlay_model.set("y", 0);
},
_positionSearchOverlay: function(overlay_model) {
var y = this.header ? this._getHeaderHeight() + 20 : 20;
var x = this.share ? 60 : 20;
if (this.headerMessageIsVisible && this.canvas.get("mode") === 'desktop') overlay_model.set("y", this._getHeaderHeight() + 40);
else overlay_model.set("y", y);
overlay_model.set("x", x);
},
_positionLayerSelectorOverlay: function(overlay_model) {
var y = 20;
var x = 20;
if (this.header) y = this._getHeaderHeight() + 20;
if (this.search && this.share) x = 220;
else if (this.search) x = 180;
else if (this.share) x = 60;
overlay_model.set("x", x);
if (this.headerMessageIsVisible && this.canvas.get("mode") === 'desktop') overlay_model.set("y", this._getHeaderHeight() + 40);
else overlay_model.set("y", y);
},
_positionShareOverlay: function(overlay_model) {
var y = this.header ? this._getHeaderHeight() + 20 : 20;
if (this.headerMessageIsVisible && this.canvas.get("mode") === 'desktop') overlay_model.set("y", this._getHeaderHeight() + 40);
else overlay_model.set("y", y);
},
_positionLoaderOverlay: function(overlay_model) {
var hasSQLHeader = this.headerMessageIsVisible && this.canvas.get("mode") === 'desktop';
var y = 20;
if (this.canvas.get("mode") === 'mobile' && this.header) {
y = this._getHeaderHeight() + 20;
}
else if (this.fullscreen) y = this.fullscreen.model.get("y") + 40;
else if (this.zoom) y = this.zoom.model.get("y") + 120;
else if (this.header) y = this._getHeaderHeight() + 20;
else if (hasSQLHeader) y = this._getHeaderHeight() + 40;
overlay_model.set("y", y);
},
_positionZoomOverlay: function(overlay_model) {
var y = this.header ? this._getHeaderHeight() + 20 : 20;
if ( this.headerMessageIsVisible) overlay_model.set("y", this._getHeaderHeight() + 40);
else overlay_model.set("y", y);
},
_positionFullScreenOverlay: function(overlay_model) {
if (this.zoom) overlay_model.set("y", this.zoom.model.get("y") + 120);
else if (this.header) overlay_model.set("y", this._getHeaderHeight() + 20);
else if (this.headerMessageIsVisible && this.canvas.get("mode") === 'desktop') overlay_model.set("y", this._getHeaderHeight() + 40);
else overlay_model.set("y", 20);
}
});