cdb
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
(function() {
|
||||
|
||||
/**
|
||||
* this module implements all the features related to overlay geometries
|
||||
* in leaflet: markers, polygons, lines and so on
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* view for markers
|
||||
*/
|
||||
function PointView(geometryModel) {
|
||||
var self = this;
|
||||
// events to link
|
||||
var events = [
|
||||
'click',
|
||||
'dblclick',
|
||||
'mousedown',
|
||||
'mouseover',
|
||||
'mouseout',
|
||||
'dragstart',
|
||||
'drag',
|
||||
'dragend'
|
||||
];
|
||||
|
||||
this._eventHandlers = {};
|
||||
this.model = geometryModel;
|
||||
this.points = [];
|
||||
|
||||
var icon = {
|
||||
iconUrl: this.model.get('iconUrl') || cdb.config.get('assets_url') + '/images/layout/default_marker.png',
|
||||
iconAnchor: this.model.get('iconAnchor') || [11, 11]
|
||||
};
|
||||
|
||||
this.geom = L.GeoJSON.geometryToLayer(geometryModel.get('geojson'), function(geojson, latLng) {
|
||||
//TODO: create marker depending on the visualizacion options
|
||||
var p = L.marker(latLng, {
|
||||
icon: L.icon(icon)
|
||||
});
|
||||
|
||||
var i;
|
||||
for(i = 0; i < events.length; ++i) {
|
||||
var e = events[i];
|
||||
p.on(e, self._eventHandler(e));
|
||||
}
|
||||
return p;
|
||||
});
|
||||
|
||||
this.bind('dragend', function(e, pos) {
|
||||
geometryModel.set({
|
||||
geojson: {
|
||||
type: 'Point',
|
||||
//geojson is lng,lat
|
||||
coordinates: [pos[1], pos[0]]
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
PointView.prototype = new GeometryView();
|
||||
|
||||
PointView.prototype.edit = function() {
|
||||
this.geom.dragging.enable();
|
||||
};
|
||||
|
||||
/**
|
||||
* returns a function to handle events fot evtType
|
||||
*/
|
||||
PointView.prototype._eventHandler = function(evtType) {
|
||||
var self = this;
|
||||
var h = this._eventHandlers[evtType];
|
||||
if(!h) {
|
||||
h = function(e) {
|
||||
var latlng = e.target.getLatLng();
|
||||
var s = [latlng.lat, latlng.lng];
|
||||
self.trigger(evtType, e.originalEvent, s);
|
||||
};
|
||||
this._eventHandlers[evtType] = h;
|
||||
}
|
||||
return h;
|
||||
};
|
||||
|
||||
/**
|
||||
* view for other geometries (polygons/lines)
|
||||
*/
|
||||
function PathView(geometryModel) {
|
||||
var self = this;
|
||||
// events to link
|
||||
var events = [
|
||||
'click',
|
||||
'dblclick',
|
||||
'mousedown',
|
||||
'mouseover',
|
||||
'mouseout',
|
||||
];
|
||||
|
||||
this._eventHandlers = {};
|
||||
this.model = geometryModel;
|
||||
this.points = [];
|
||||
|
||||
|
||||
this.geom = L.GeoJSON.geometryToLayer(geometryModel.get('geojson'));
|
||||
this.geom.setStyle(geometryModel.get('style'));
|
||||
|
||||
|
||||
/*for(var i = 0; i < events.length; ++i) {
|
||||
var e = events[i];
|
||||
this.geom.on(e, self._eventHandler(e));
|
||||
}*/
|
||||
|
||||
}
|
||||
|
||||
PathView.prototype = new GeometryView();
|
||||
|
||||
PathView.prototype._leafletLayers = function() {
|
||||
// check if this is a multi-feature or single-feature
|
||||
if (this.geom.getLayers) {
|
||||
return this.geom.getLayers();
|
||||
}
|
||||
return [this.geom];
|
||||
};
|
||||
|
||||
|
||||
PathView.prototype.enableEdit = function() {
|
||||
var self = this;
|
||||
var layers = this._leafletLayers();
|
||||
_.each(layers, function(g) {
|
||||
g.setStyle(self.model.get('style'));
|
||||
g.on('edit', function() {
|
||||
self.model.set('geojson', self.geom.toGeoJSON().geometry);
|
||||
}, self);
|
||||
});
|
||||
};
|
||||
|
||||
PathView.prototype.disableEdit = function() {
|
||||
var self = this;
|
||||
var layers = this._leafletLayers();
|
||||
_.each(layers, function(g) {
|
||||
g.off('edit', null, self);
|
||||
});
|
||||
};
|
||||
|
||||
PathView.prototype.edit = function(enable) {
|
||||
var self = this;
|
||||
var fn = enable ? 'enable': 'disable';
|
||||
var layers = this._leafletLayers();
|
||||
_.each(layers, function(g) {
|
||||
g.editing[fn]();
|
||||
enable ? self.enableEdit(): self.disableEdit();
|
||||
});
|
||||
};
|
||||
|
||||
cdb.geo.leaflet = cdb.geo.leaflet || {};
|
||||
|
||||
cdb.geo.leaflet.PointView = PointView;
|
||||
cdb.geo.leaflet.PathView = PathView;
|
||||
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,426 @@
|
||||
/**
|
||||
* leaflet implementation of a map
|
||||
*/
|
||||
(function() {
|
||||
|
||||
if(typeof(L) == "undefined")
|
||||
return;
|
||||
|
||||
/**
|
||||
* leatlef impl
|
||||
*/
|
||||
cdb.geo.LeafletMapView = cdb.geo.MapView.extend({
|
||||
|
||||
|
||||
initialize: function() {
|
||||
|
||||
_.bindAll(this, '_addLayer', '_removeLayer', '_setZoom', '_setCenter', '_setView');
|
||||
|
||||
cdb.geo.MapView.prototype.initialize.call(this);
|
||||
|
||||
var self = this;
|
||||
|
||||
var center = this.map.get('center');
|
||||
|
||||
var mapConfig = {
|
||||
zoomControl: false,
|
||||
center: new L.LatLng(center[0], center[1]),
|
||||
zoom: this.map.get('zoom'),
|
||||
minZoom: this.map.get('minZoom'),
|
||||
maxZoom: this.map.get('maxZoom')
|
||||
};
|
||||
|
||||
|
||||
if (this.map.get('bounding_box_ne')) {
|
||||
//mapConfig.maxBounds = [this.map.get('bounding_box_ne'), this.map.get('bounding_box_sw')];
|
||||
}
|
||||
|
||||
if (!this.options.map_object) {
|
||||
|
||||
this.map_leaflet = new L.Map(this.el, mapConfig);
|
||||
|
||||
// remove the "powered by leaflet"
|
||||
this.map_leaflet.attributionControl.setPrefix('');
|
||||
|
||||
// Disable scrollwheel
|
||||
if (this.map.get("scrollwheel") == false) this.map_leaflet.scrollWheelZoom.disable();
|
||||
// Disable keyboard
|
||||
if (this.map.get("keyboard") == false) this.map_leaflet.keyboard.disable();
|
||||
// Disable dragging (also doubleClickZoom)
|
||||
if (this.map.get("drag") == false) {
|
||||
this.map_leaflet.dragging.disable();
|
||||
this.map_leaflet.doubleClickZoom.disable();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
this.map_leaflet = this.options.map_object;
|
||||
this.setElement(this.map_leaflet.getContainer());
|
||||
|
||||
var c = self.map_leaflet.getCenter();
|
||||
|
||||
self._setModelProperty({ center: [c.lat, c.lng] });
|
||||
self._setModelProperty({ zoom: self.map_leaflet.getZoom() });
|
||||
|
||||
// unset bounds to not change mapbounds
|
||||
self.map.unset('view_bounds_sw', { silent: true });
|
||||
self.map.unset('view_bounds_ne', { silent: true });
|
||||
}
|
||||
|
||||
this.map.bind('set_view', this._setView, this);
|
||||
this.map.layers.bind('add', this._addLayer, this);
|
||||
this.map.layers.bind('remove', this._removeLayer, this);
|
||||
this.map.layers.bind('reset', this._addLayers, this);
|
||||
this.map.layers.bind('change:type', this._swicthLayerView, this);
|
||||
|
||||
this.map.geometries.bind('add', this._addGeometry, this);
|
||||
this.map.geometries.bind('remove', this._removeGeometry, this);
|
||||
|
||||
this._bindModel();
|
||||
this._addLayers();
|
||||
this.setAttribution();
|
||||
|
||||
this.map_leaflet.on('layeradd', function(lyr) {
|
||||
this.trigger('layeradd', lyr, self);
|
||||
}, this);
|
||||
|
||||
this.map_leaflet.on('zoomstart', function() {
|
||||
self.trigger('zoomstart');
|
||||
});
|
||||
|
||||
this.map_leaflet.on('click', function(e) {
|
||||
self.trigger('click', e.originalEvent, [e.latlng.lat, e.latlng.lng]);
|
||||
});
|
||||
|
||||
this.map_leaflet.on('dblclick', function(e) {
|
||||
self.trigger('dblclick', e.originalEvent);
|
||||
});
|
||||
|
||||
this.map_leaflet.on('zoomend', function() {
|
||||
self._setModelProperty({
|
||||
zoom: self.map_leaflet.getZoom()
|
||||
});
|
||||
self.trigger('zoomend');
|
||||
}, this);
|
||||
|
||||
this.map_leaflet.on('move', function() {
|
||||
var c = self.map_leaflet.getCenter();
|
||||
self._setModelProperty({ center: [c.lat, c.lng] });
|
||||
});
|
||||
|
||||
this.map_leaflet.on('dragend', function() {
|
||||
var c = self.map_leaflet.getCenter();
|
||||
this.trigger('dragend', [c.lat, c.lng]);
|
||||
}, this);
|
||||
|
||||
this.map_leaflet.on('drag', function() {
|
||||
var c = self.map_leaflet.getCenter();
|
||||
self._setModelProperty({
|
||||
center: [c.lat, c.lng]
|
||||
});
|
||||
self.trigger('drag');
|
||||
}, this);
|
||||
|
||||
this.map.bind('change:maxZoom', function() {
|
||||
L.Util.setOptions(self.map_leaflet, { maxZoom: self.map.get('maxZoom') });
|
||||
}, this);
|
||||
|
||||
this.map.bind('change:minZoom', function() {
|
||||
L.Util.setOptions(self.map_leaflet, { minZoom: self.map.get('minZoom') });
|
||||
}, this);
|
||||
|
||||
this.trigger('ready');
|
||||
|
||||
// looks like leaflet dont like to change the bounds just after the inicialization
|
||||
var bounds = this.map.getViewBounds();
|
||||
|
||||
if (bounds) {
|
||||
this.showBounds(bounds);
|
||||
}
|
||||
},
|
||||
|
||||
// this replaces the default functionality to search for
|
||||
// already added views so they are not replaced
|
||||
_addLayers: function() {
|
||||
var self = this;
|
||||
|
||||
var oldLayers = this.layers;
|
||||
this.layers = {};
|
||||
|
||||
function findLayerView(layer) {
|
||||
var lv = _.find(oldLayers, function(layer_view) {
|
||||
var m = layer_view.model;
|
||||
return m.isEqual(layer);
|
||||
});
|
||||
return lv;
|
||||
}
|
||||
|
||||
function canReused(layer) {
|
||||
return self.map.layers.find(function(m) {
|
||||
return m.isEqual(layer);
|
||||
});
|
||||
}
|
||||
|
||||
// remove all
|
||||
for(var layer in oldLayers) {
|
||||
var layer_view = oldLayers[layer];
|
||||
if (!canReused(layer_view.model)) {
|
||||
layer_view.remove();
|
||||
}
|
||||
}
|
||||
|
||||
this.map.layers.each(function(lyr) {
|
||||
var lv = findLayerView(lyr);
|
||||
if (!lv) {
|
||||
self._addLayer(lyr);
|
||||
} else {
|
||||
lv.setModel(lyr);
|
||||
self.layers[lyr.cid] = lv;
|
||||
self.trigger('newLayerView', lv, lv.model, self);
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
clean: function() {
|
||||
//see https://github.com/CloudMade/Leaflet/issues/1101
|
||||
L.DomEvent.off(window, 'resize', this.map_leaflet._onResize, this.map_leaflet);
|
||||
|
||||
// remove layer views
|
||||
for(var layer in this.layers) {
|
||||
var layer_view = this.layers[layer];
|
||||
layer_view.remove();
|
||||
delete this.layers[layer];
|
||||
}
|
||||
|
||||
// do not change by elder
|
||||
cdb.core.View.prototype.clean.call(this);
|
||||
},
|
||||
|
||||
_setKeyboard: function(model, z) {
|
||||
if (z) {
|
||||
this.map_leaflet.keyboard.enable();
|
||||
} else {
|
||||
this.map_leaflet.keyboard.disable();
|
||||
}
|
||||
},
|
||||
|
||||
_setScrollWheel: function(model, z) {
|
||||
if (z) {
|
||||
this.map_leaflet.scrollWheelZoom.enable();
|
||||
} else {
|
||||
this.map_leaflet.scrollWheelZoom.disable();
|
||||
}
|
||||
},
|
||||
|
||||
_setZoom: function(model, z) {
|
||||
this._setView();
|
||||
},
|
||||
|
||||
_setCenter: function(model, center) {
|
||||
this._setView();
|
||||
},
|
||||
|
||||
_setView: function() {
|
||||
this.map_leaflet.setView(this.map.get("center"), this.map.get("zoom") || 0 );
|
||||
},
|
||||
|
||||
_addGeomToMap: function(geom) {
|
||||
var geo = cdb.geo.LeafletMapView.createGeometry(geom);
|
||||
geo.geom.addTo(this.map_leaflet);
|
||||
return geo;
|
||||
},
|
||||
|
||||
_removeGeomFromMap: function(geo) {
|
||||
this.map_leaflet.removeLayer(geo.geom);
|
||||
},
|
||||
|
||||
createLayer: function(layer) {
|
||||
return cdb.geo.LeafletMapView.createLayer(layer, this.map_leaflet);
|
||||
},
|
||||
|
||||
_addLayer: function(layer, layers, opts) {
|
||||
var self = this;
|
||||
var lyr, layer_view;
|
||||
layer_view = cdb.geo.LeafletMapView.createLayer(layer, this.map_leaflet);
|
||||
if (!layer_view) {
|
||||
return;
|
||||
}
|
||||
return this._addLayerToMap(layer_view, opts);
|
||||
},
|
||||
|
||||
_addLayerToMap: function(layer_view, opts) {
|
||||
var layer = layer_view.model;
|
||||
|
||||
this.layers[layer.cid] = layer_view;
|
||||
cdb.geo.LeafletMapView.addLayerToMap(layer_view, this.map_leaflet);
|
||||
|
||||
// reorder layers
|
||||
for(var i in this.layers) {
|
||||
var lv = this.layers[i];
|
||||
lv.setZIndex(lv.model.get('order'));
|
||||
}
|
||||
|
||||
if(opts === undefined || !opts.silent) {
|
||||
this.trigger('newLayerView', layer_view, layer_view.model, this);
|
||||
}
|
||||
return layer_view;
|
||||
},
|
||||
|
||||
pixelToLatLon: function(pos) {
|
||||
var point = this.map_leaflet.containerPointToLatLng([pos[0], pos[1]]);
|
||||
return point;
|
||||
},
|
||||
|
||||
latLonToPixel: function(latlon) {
|
||||
var point = this.map_leaflet.latLngToLayerPoint(new L.LatLng(latlon[0], latlon[1]));
|
||||
return this.map_leaflet.layerPointToContainerPoint(point);
|
||||
},
|
||||
|
||||
// return the current bounds of the map view
|
||||
getBounds: function() {
|
||||
var b = this.map_leaflet.getBounds();
|
||||
var sw = b.getSouthWest();
|
||||
var ne = b.getNorthEast();
|
||||
return [
|
||||
[sw.lat, sw.lng],
|
||||
[ne.lat, ne.lng]
|
||||
];
|
||||
},
|
||||
|
||||
setAttribution: function() {
|
||||
var attributionControl = this._getAttributionControl();
|
||||
|
||||
// Save the attributions that were in the map the first time a new layer
|
||||
// is added and the attributions of the map have changed
|
||||
if (!this._originalAttributions) {
|
||||
this._originalAttributions = Object.keys(attributionControl._attributions);
|
||||
}
|
||||
|
||||
// Clear the attributions and re-add the original and custom attributions in
|
||||
// the order we want
|
||||
attributionControl._attributions = {};
|
||||
var newAttributions = this._originalAttributions.concat(this.map.get('attribution'));
|
||||
_.each(newAttributions, function(attribution) {
|
||||
attributionControl.addAttribution(cdb.core.sanitize.html(attribution));
|
||||
});
|
||||
},
|
||||
|
||||
_getAttributionControl: function() {
|
||||
if (this._attributionControl) {
|
||||
return this._attributionControl;
|
||||
}
|
||||
|
||||
this._attributionControl = this.map_leaflet.attributionControl;
|
||||
if (!this._attributionControl) {
|
||||
this._attributionControl = L.control.attribution({ prefix: '' });
|
||||
this.map_leaflet.addControl(this._attributionControl);
|
||||
}
|
||||
|
||||
return this._attributionControl;
|
||||
},
|
||||
|
||||
getSize: function() {
|
||||
return this.map_leaflet.getSize();
|
||||
},
|
||||
|
||||
panBy: function(p) {
|
||||
this.map_leaflet.panBy(new L.Point(p.x, p.y));
|
||||
},
|
||||
|
||||
setCursor: function(cursor) {
|
||||
$(this.map_leaflet.getContainer()).css('cursor', cursor);
|
||||
},
|
||||
|
||||
getNativeMap: function() {
|
||||
return this.map_leaflet;
|
||||
},
|
||||
|
||||
invalidateSize: function() {
|
||||
// there is a race condition in leaflet. If size is invalidated
|
||||
// and at the same time the center is set the final center is displaced
|
||||
// so set pan to false so the map is not moved and then force the map
|
||||
// to be at the place it should be
|
||||
this.map_leaflet.invalidateSize({ pan: false })//, animate: false });
|
||||
this.map_leaflet.setView(this.map.get("center"), this.map.get("zoom") || 0, {
|
||||
animate: false
|
||||
});
|
||||
}
|
||||
|
||||
}, {
|
||||
|
||||
layerTypeMap: {
|
||||
"tiled": cdb.geo.LeafLetTiledLayerView,
|
||||
"wms": cdb.geo.LeafLetWMSLayerView,
|
||||
"cartodb": cdb.geo.LeafLetLayerCartoDBView,
|
||||
"carto": cdb.geo.LeafLetLayerCartoDBView,
|
||||
"plain": cdb.geo.LeafLetPlainLayerView,
|
||||
|
||||
// Substitutes the GMaps baselayer w/ an equivalent Leaflet tiled layer, since not supporting Gmaps anymore
|
||||
"gmapsbase": cdb.geo.LeafLetGmapsTiledLayerView,
|
||||
|
||||
"layergroup": cdb.geo.LeafLetCartoDBLayerGroupView,
|
||||
"namedmap": cdb.geo.LeafLetCartoDBNamedMapView,
|
||||
"torque": function(layer, map) {
|
||||
return new cdb.geo.LeafLetTorqueLayer(layer, map);
|
||||
}
|
||||
},
|
||||
|
||||
createLayer: function(layer, map) {
|
||||
var layer_view = null;
|
||||
var layerClass = this.layerTypeMap[layer.get('type').toLowerCase()];
|
||||
|
||||
if (layerClass) {
|
||||
try {
|
||||
layer_view = new layerClass(layer, map);
|
||||
} catch(e) {
|
||||
cdb.log.error("MAP: error creating '" + layer.get('type') + "' layer -> " + e.message);
|
||||
}
|
||||
} else {
|
||||
cdb.log.error("MAP: " + layer.get('type') + " can't be created");
|
||||
}
|
||||
return layer_view;
|
||||
},
|
||||
|
||||
addLayerToMap: function(layer_view, map, pos) {
|
||||
map.addLayer(layer_view.leafletLayer);
|
||||
if(pos !== undefined) {
|
||||
if (layer_view.setZIndex) {
|
||||
layer_view.setZIndex(pos);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* create the view for the geometry model
|
||||
*/
|
||||
createGeometry: function(geometryModel) {
|
||||
if(geometryModel.isPoint()) {
|
||||
return new cdb.geo.leaflet.PointView(geometryModel);
|
||||
}
|
||||
return new cdb.geo.leaflet.PathView(geometryModel);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// set the image path in order to be able to get leaflet icons
|
||||
// code adapted from leaflet
|
||||
L.Icon.Default.imagePath = (function () {
|
||||
var scripts = document.getElementsByTagName('script'),
|
||||
leafletRe = /\/?cartodb[\-\._]?([\w\-\._]*)\.js\??/;
|
||||
|
||||
var i, len, src, matches;
|
||||
|
||||
for (i = 0, len = scripts.length; i < len; i++) {
|
||||
src = scripts[i].src;
|
||||
matches = src.match(leafletRe);
|
||||
|
||||
if (matches) {
|
||||
var bits = src.split('/')
|
||||
delete bits[bits.length - 1];
|
||||
return bits.join('/') + 'themes/css/images';
|
||||
}
|
||||
}
|
||||
}());
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,61 @@
|
||||
|
||||
(function() {
|
||||
/**
|
||||
* base layer for all leaflet layers
|
||||
*/
|
||||
var LeafLetLayerView = function(layerModel, leafletLayer, leafletMap) {
|
||||
this.leafletLayer = leafletLayer;
|
||||
this.leafletMap = leafletMap;
|
||||
this.model = layerModel;
|
||||
|
||||
this.setModel(layerModel);
|
||||
|
||||
this.type = layerModel.get('type') || layerModel.get('kind');
|
||||
this.type = this.type.toLowerCase();
|
||||
};
|
||||
|
||||
_.extend(LeafLetLayerView.prototype, Backbone.Events);
|
||||
_.extend(LeafLetLayerView.prototype, {
|
||||
|
||||
setModel: function(model) {
|
||||
if (this.model) {
|
||||
this.model.unbind('change', this._modelUpdated, this);
|
||||
}
|
||||
this.model = model;
|
||||
this.model.bind('change', this._modelUpdated, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* remove layer from the map and unbind events
|
||||
*/
|
||||
remove: function() {
|
||||
this.leafletMap.removeLayer(this.leafletLayer);
|
||||
this.trigger('remove', this);
|
||||
this.model.unbind(null, null, this);
|
||||
this.unbind();
|
||||
},
|
||||
/*
|
||||
|
||||
show: function() {
|
||||
this.leafletLayer.setOpacity(1.0);
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
this.leafletLayer.setOpacity(0.0);
|
||||
},
|
||||
*/
|
||||
|
||||
/**
|
||||
* reload the tiles
|
||||
*/
|
||||
reload: function() {
|
||||
this.leafletLayer.redraw();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
cdb.geo.LeafLetLayerView = LeafLetLayerView;
|
||||
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,163 @@
|
||||
|
||||
(function() {
|
||||
|
||||
if(typeof(L) == "undefined")
|
||||
return;
|
||||
|
||||
L.CartoDBLayer = L.CartoDBGroupLayer.extend({
|
||||
|
||||
options: {
|
||||
query: "SELECT * FROM {{table_name}}",
|
||||
opacity: 0.99,
|
||||
attribution: cdb.config.get('cartodb_attributions'),
|
||||
debug: false,
|
||||
visible: true,
|
||||
added: false,
|
||||
extra_params: {},
|
||||
layer_definition_version: '1.0.0'
|
||||
},
|
||||
|
||||
|
||||
initialize: function (options) {
|
||||
L.Util.setOptions(this, options);
|
||||
|
||||
if (!options.table_name || !options.user_name || !options.tile_style) {
|
||||
throw ('cartodb-leaflet needs at least a CartoDB table name, user_name and tile_style');
|
||||
}
|
||||
|
||||
L.CartoDBGroupLayer.prototype.initialize.call(this, {
|
||||
layer_definition: {
|
||||
version: this.options.layer_definition_version,
|
||||
layers: [{
|
||||
type: 'cartodb',
|
||||
options: this._getLayerDefinition(),
|
||||
infowindow: this.options.infowindow
|
||||
}]
|
||||
}
|
||||
});
|
||||
|
||||
this.setOptions(this.options);
|
||||
},
|
||||
|
||||
setQuery: function(layer, sql) {
|
||||
if(sql === undefined) {
|
||||
sql = layer;
|
||||
layer = 0;
|
||||
}
|
||||
sql = sql || 'select * from ' + this.options.table_name;
|
||||
LayerDefinition.prototype.setQuery.call(this, layer, sql);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns if the layer is visible or not
|
||||
*/
|
||||
isVisible: function() {
|
||||
return this.visible;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Returns if the layer belongs to the map
|
||||
*/
|
||||
isAdded: function() {
|
||||
return this.options.added;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* leatlet cartodb layer
|
||||
*/
|
||||
|
||||
var LeafLetLayerCartoDBView = L.CartoDBLayer.extend({
|
||||
//var LeafLetLayerCartoDBView = function(layerModel, leafletMap) {
|
||||
initialize: function(layerModel, leafletMap) {
|
||||
var self = this;
|
||||
|
||||
_.bindAll(this, 'featureOut', 'featureOver', 'featureClick');
|
||||
|
||||
var opts = _.clone(layerModel.attributes);
|
||||
|
||||
opts.map = leafletMap;
|
||||
|
||||
var // preserve the user's callbacks
|
||||
_featureOver = opts.featureOver,
|
||||
_featureOut = opts.featureOut,
|
||||
_featureClick = opts.featureClick;
|
||||
|
||||
opts.featureOver = function() {
|
||||
_featureOver && _featureOver.apply(this, arguments);
|
||||
self.featureOver && self.featureOver.apply(this, arguments);
|
||||
};
|
||||
|
||||
opts.featureOut = function() {
|
||||
_featureOut && _featureOut.apply(this, arguments);
|
||||
self.featureOut && self.featureOut.apply(this, arguments);
|
||||
};
|
||||
|
||||
opts.featureClick = function() {
|
||||
_featureClick && _featureClick.apply(this, arguments);
|
||||
self.featureClick && self.featureClick.apply(opts, arguments);
|
||||
};
|
||||
|
||||
layerModel.bind('change:visible', function() {
|
||||
self.model.get('visible') ? self.show(): self.hide();
|
||||
}, this);
|
||||
|
||||
L.CartoDBLayer.prototype.initialize.call(this, opts);
|
||||
cdb.geo.LeafLetLayerView.call(this, layerModel, this, leafletMap);
|
||||
|
||||
},
|
||||
|
||||
_modelUpdated: function() {
|
||||
var attrs = _.clone(this.model.attributes);
|
||||
this.leafletLayer.setOptions(attrs);
|
||||
},
|
||||
|
||||
featureOver: function(e, latlon, pixelPos, data) {
|
||||
// dont pass leaflet lat/lon
|
||||
this.trigger('featureOver', e, [latlon.lat, latlon.lng], pixelPos, data, 0);
|
||||
},
|
||||
|
||||
featureOut: function(e) {
|
||||
this.trigger('featureOut', e, 0);
|
||||
},
|
||||
|
||||
featureClick: function(e, latlon, pixelPos, data) {
|
||||
// dont pass leaflet lat/lon
|
||||
this.trigger('featureClick', e, [latlon.lat, latlon.lng], pixelPos, data, 0);
|
||||
},
|
||||
|
||||
reload: function() {
|
||||
this.model.invalidate();
|
||||
//this.redraw();
|
||||
},
|
||||
|
||||
error: function(e) {
|
||||
this.trigger('error', e?e.error:'unknown error');
|
||||
this.model.trigger('tileError', e?e.error:'unknown error');
|
||||
},
|
||||
|
||||
tilesOk: function(e) {
|
||||
this.model.trigger('tileOk');
|
||||
},
|
||||
|
||||
includes: [
|
||||
cdb.geo.LeafLetLayerView.prototype,
|
||||
Backbone.Events
|
||||
]
|
||||
|
||||
});
|
||||
|
||||
/*_.extend(L.CartoDBLayer.prototype, CartoDBLayerCommon.prototype);
|
||||
|
||||
_.extend(
|
||||
LeafLetLayerCartoDBView.prototype,
|
||||
cdb.geo.LeafLetLayerView.prototype,
|
||||
L.CartoDBLayer.prototype,
|
||||
Backbone.Events, // be sure this is here to not use the on/off from leaflet
|
||||
|
||||
*/
|
||||
cdb.geo.LeafLetLayerCartoDBView = LeafLetLayerCartoDBView;
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,455 @@
|
||||
|
||||
(function() {
|
||||
|
||||
if(typeof(L) == "undefined")
|
||||
return;
|
||||
|
||||
|
||||
L.CartoDBGroupLayerBase = L.TileLayer.extend({
|
||||
|
||||
interactionClass: wax.leaf.interaction,
|
||||
|
||||
includes: [
|
||||
cdb.geo.LeafLetLayerView.prototype,
|
||||
//LayerDefinition.prototype,
|
||||
CartoDBLayerCommon.prototype
|
||||
],
|
||||
|
||||
options: {
|
||||
opacity: 0.99,
|
||||
attribution: cdb.config.get('cartodb_attributions'),
|
||||
debug: false,
|
||||
visible: true,
|
||||
added: false,
|
||||
tiler_domain: "carto.com",
|
||||
tiler_port: "80",
|
||||
tiler_protocol: "http",
|
||||
sql_api_domain: "carto.com",
|
||||
sql_api_port: "80",
|
||||
sql_api_protocol: "http",
|
||||
maxZoom: 30, // default leaflet zoom level for a layers is 18, raise it
|
||||
extra_params: {
|
||||
},
|
||||
cdn_url: null,
|
||||
subdomains: null
|
||||
},
|
||||
|
||||
|
||||
initialize: function (options) {
|
||||
options = options || {};
|
||||
// Set options
|
||||
L.Util.setOptions(this, options);
|
||||
|
||||
// Some checks
|
||||
if (!options.layer_definition && !options.sublayers) {
|
||||
throw new Error('cartodb-leaflet needs at least the layer_definition or sublayer list');
|
||||
}
|
||||
|
||||
if(!options.layer_definition) {
|
||||
this.options.layer_definition = LayerDefinition.layerDefFromSubLayers(options.sublayers);
|
||||
}
|
||||
|
||||
LayerDefinition.call(this, this.options.layer_definition, this.options);
|
||||
|
||||
this.fire = this.trigger;
|
||||
|
||||
CartoDBLayerCommon.call(this);
|
||||
L.TileLayer.prototype.initialize.call(this);
|
||||
this.interaction = [];
|
||||
this.addProfiling();
|
||||
},
|
||||
|
||||
addProfiling: function() {
|
||||
this.bind('tileloadstart', function(e) {
|
||||
var s = this.tileStats || (this.tileStats = {});
|
||||
s[e.tile.src] = cartodb.core.Profiler.metric('cartodb-js.tile.png.load.time').start();
|
||||
});
|
||||
var finish = function(e) {
|
||||
var s = this.tileStats && this.tileStats[e.tile.src];
|
||||
s && s.end();
|
||||
};
|
||||
this.bind('tileload', finish);
|
||||
this.bind('tileerror', function(e) {
|
||||
cartodb.core.Profiler.metric('cartodb-js.tile.png.error').inc();
|
||||
finish(e);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
// overwrite getTileUrl in order to
|
||||
// support different tiles subdomains in tilejson way
|
||||
getTileUrl: function (tilePoint) {
|
||||
var EMPTY_GIF = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
|
||||
this._adjustTilePoint(tilePoint);
|
||||
|
||||
var tiles = [EMPTY_GIF];
|
||||
if(this.tilejson) {
|
||||
tiles = this.tilejson.tiles;
|
||||
}
|
||||
|
||||
var index = (tilePoint.x + tilePoint.y) % tiles.length;
|
||||
|
||||
return L.Util.template(tiles[index], L.Util.extend({
|
||||
z: this._getZoomForUrl(),
|
||||
x: tilePoint.x,
|
||||
y: tilePoint.y
|
||||
}, this.options));
|
||||
},
|
||||
|
||||
/**
|
||||
* Change opacity of the layer
|
||||
* @params {Integer} New opacity
|
||||
*/
|
||||
setOpacity: function(opacity) {
|
||||
|
||||
if (isNaN(opacity) || opacity>1 || opacity<0) {
|
||||
throw new Error(opacity + ' is not a valid value');
|
||||
}
|
||||
|
||||
// Leaflet only accepts 0-0.99... Weird!
|
||||
this.options.opacity = Math.min(opacity, 0.99);
|
||||
|
||||
if (this.options.visible) {
|
||||
L.TileLayer.prototype.setOpacity.call(this, this.options.opacity);
|
||||
this.fire('updated');
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* When Leaflet adds the layer... go!
|
||||
* @params {map}
|
||||
*/
|
||||
onAdd: function(map) {
|
||||
var self = this;
|
||||
this.options.map = map;
|
||||
|
||||
// Add cartodb logo
|
||||
if (this.options.cartodb_logo != false)
|
||||
cdb.geo.common.CartoDBLogo.addWadus({ left:8, bottom:8 }, 0, map._container);
|
||||
|
||||
this.__update(function() {
|
||||
// if while the layer was processed in the server is removed
|
||||
// it should not be added to the map
|
||||
var id = L.stamp(self);
|
||||
if (!map._layers[id]) {
|
||||
return;
|
||||
}
|
||||
|
||||
L.TileLayer.prototype.onAdd.call(self, map);
|
||||
self.fire('added');
|
||||
self.options.added = true;
|
||||
});
|
||||
},
|
||||
|
||||
getAttribution: function() {
|
||||
return cdb.core.sanitize.html(this.options.attribution);
|
||||
},
|
||||
|
||||
/**
|
||||
* When removes the layer, destroy interactivity if exist
|
||||
*/
|
||||
onRemove: function(map) {
|
||||
if(this.options.added) {
|
||||
this.options.added = false;
|
||||
L.TileLayer.prototype.onRemove.call(this, map);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update CartoDB layer
|
||||
* generates a new url for tiles and refresh leaflet layer
|
||||
* do not collide with leaflet _update
|
||||
*/
|
||||
__update: function(done) {
|
||||
var self = this;
|
||||
this.fire('updated');
|
||||
this.fire('loading');
|
||||
var map = this.options.map;
|
||||
|
||||
this.getTiles(function(urls, err) {
|
||||
if(urls) {
|
||||
self.tilejson = urls;
|
||||
self.setUrl(self.tilejson.tiles[0]);
|
||||
// manage interaction
|
||||
self._reloadInteraction();
|
||||
self.ok && self.ok();
|
||||
done && done();
|
||||
} else {
|
||||
self.error && self.error(err);
|
||||
done && done();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
_checkLayer: function() {
|
||||
if (!this.options.added) {
|
||||
throw new Error('the layer is not still added to the map');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a new layer attribution
|
||||
* @params {String} New attribution string
|
||||
*/
|
||||
setAttribution: function(attribution) {
|
||||
this._checkLayer();
|
||||
// Remove old one
|
||||
this.map.attributionControl.removeAttribution(
|
||||
cdb.core.sanitize.html(this.options.attribution)
|
||||
);
|
||||
// Change text
|
||||
this.map.attributionControl.addAttribution(
|
||||
cdb.core.sanitize.html(attribution)
|
||||
);
|
||||
// Set new attribution in the options
|
||||
this.options.attribution = attribution;
|
||||
// Change in the layer
|
||||
this.tilejson.attribution = this.options.attribution;
|
||||
|
||||
this.fire('updated');
|
||||
},
|
||||
|
||||
/**
|
||||
* Bind events for wax interaction
|
||||
* @param {Object} Layer map object
|
||||
* @param {Event} Wax event
|
||||
*/
|
||||
_manageOnEvents: function(map, o) {
|
||||
var layer_point = this._findPos(map,o);
|
||||
|
||||
if (!layer_point || isNaN(layer_point.x) || isNaN(layer_point.y)) {
|
||||
// If layer_point doesn't contain x and y,
|
||||
// we can't calculate event map position
|
||||
return false;
|
||||
}
|
||||
|
||||
var latlng = map.layerPointToLatLng(layer_point);
|
||||
var event_type = o.e.type.toLowerCase();
|
||||
var screenPos = map.layerPointToContainerPoint(layer_point);
|
||||
|
||||
switch (event_type) {
|
||||
case 'mousemove':
|
||||
if (this.options.featureOver) {
|
||||
return this.options.featureOver(o.e,latlng, screenPos, o.data, o.layer);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'click':
|
||||
case 'touchend':
|
||||
case 'touchmove': // for some reason android browser does not send touchend
|
||||
case 'mspointerup':
|
||||
case 'pointerup':
|
||||
case 'pointermove':
|
||||
if (this.options.featureClick) {
|
||||
this.options.featureClick(o.e,latlng, screenPos, o.data, o.layer);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Bind off event for wax interaction
|
||||
*/
|
||||
_manageOffEvents: function(map, o) {
|
||||
if (this.options.featureOut) {
|
||||
return this.options.featureOut && this.options.featureOut(o.e, o.layer);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the Leaflet Point of the event
|
||||
* @params {Object} Map object
|
||||
* @params {Object} Wax event object
|
||||
*/
|
||||
_findPos: function (map, o) {
|
||||
var curleft = 0;
|
||||
var curtop = 0;
|
||||
var obj = map.getContainer();
|
||||
|
||||
var x, y;
|
||||
if (o.e.changedTouches && o.e.changedTouches.length > 0) {
|
||||
x = o.e.changedTouches[0].clientX + window.scrollX;
|
||||
y = o.e.changedTouches[0].clientY + window.scrollY;
|
||||
} else {
|
||||
x = o.e.clientX;
|
||||
y = o.e.clientY;
|
||||
}
|
||||
|
||||
// If the map is fixed at the top of the window, we can't use offsetParent
|
||||
// cause there might be some scrolling that we need to take into account.
|
||||
if (obj.offsetParent && obj.offsetTop > 0) {
|
||||
do {
|
||||
curleft += obj.offsetLeft;
|
||||
curtop += obj.offsetTop;
|
||||
} while (obj = obj.offsetParent);
|
||||
var point = this._newPoint(
|
||||
x - curleft, y - curtop);
|
||||
} else {
|
||||
var rect = obj.getBoundingClientRect();
|
||||
var scrollX = (window.scrollX || window.pageXOffset);
|
||||
var scrollY = (window.scrollY || window.pageYOffset);
|
||||
var point = this._newPoint(
|
||||
(o.e.clientX? o.e.clientX: x) - rect.left - obj.clientLeft - scrollX,
|
||||
(o.e.clientY? o.e.clientY: y) - rect.top - obj.clientTop - scrollY);
|
||||
}
|
||||
return map.containerPointToLayerPoint(point);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates an instance of a Leaflet Point
|
||||
*/
|
||||
_newPoint: function(x, y) {
|
||||
return new L.Point(x, y);
|
||||
}
|
||||
});
|
||||
|
||||
L.CartoDBGroupLayer = L.CartoDBGroupLayerBase.extend({
|
||||
includes: [
|
||||
LayerDefinition.prototype,
|
||||
],
|
||||
|
||||
_modelUpdated: function() {
|
||||
this.setLayerDefinition(this.model.get('layer_definition'));
|
||||
}
|
||||
});
|
||||
|
||||
function layerView(base) {
|
||||
var layerViewClass = base.extend({
|
||||
|
||||
includes: [
|
||||
cdb.geo.LeafLetLayerView.prototype,
|
||||
Backbone.Events
|
||||
],
|
||||
|
||||
initialize: function(layerModel, leafletMap) {
|
||||
var self = this;
|
||||
var hovers = [];
|
||||
|
||||
var opts = _.clone(layerModel.attributes);
|
||||
|
||||
opts.map = leafletMap;
|
||||
|
||||
var // preserve the user's callbacks
|
||||
_featureOver = opts.featureOver,
|
||||
_featureOut = opts.featureOut,
|
||||
_featureClick = opts.featureClick;
|
||||
|
||||
var previousEvent;
|
||||
var eventTimeout = -1;
|
||||
|
||||
opts.featureOver = function(e, latlon, pxPos, data, layer) {
|
||||
if (!hovers[layer]) {
|
||||
self.trigger('layerenter', e, latlon, pxPos, data, layer);
|
||||
}
|
||||
hovers[layer] = 1;
|
||||
_featureOver && _featureOver.apply(this, arguments);
|
||||
self.featureOver && self.featureOver.apply(self, arguments);
|
||||
// if the event is the same than before just cancel the event
|
||||
// firing because there is a layer on top of it
|
||||
if (e.timeStamp === previousEvent) {
|
||||
clearTimeout(eventTimeout);
|
||||
}
|
||||
eventTimeout = setTimeout(function() {
|
||||
self.trigger('mouseover', e, latlon, pxPos, data, layer);
|
||||
self.trigger('layermouseover', e, latlon, pxPos, data, layer);
|
||||
}, 0);
|
||||
previousEvent = e.timeStamp;
|
||||
|
||||
};
|
||||
|
||||
opts.featureOut = function(m, layer) {
|
||||
if (hovers[layer]) {
|
||||
self.trigger('layermouseout', layer);
|
||||
}
|
||||
hovers[layer] = 0;
|
||||
if(!_.any(hovers)) {
|
||||
self.trigger('mouseout');
|
||||
}
|
||||
_featureOut && _featureOut.apply(this, arguments);
|
||||
self.featureOut && self.featureOut.apply(self, arguments);
|
||||
};
|
||||
|
||||
opts.featureClick = _.debounce(function() {
|
||||
_featureClick && _featureClick.apply(self, arguments);
|
||||
self.featureClick && self.featureClick.apply(self, arguments);
|
||||
}, 10);
|
||||
|
||||
|
||||
base.prototype.initialize.call(this, opts);
|
||||
cdb.geo.LeafLetLayerView.call(this, layerModel, this, leafletMap);
|
||||
|
||||
},
|
||||
|
||||
featureOver: function(e, latlon, pixelPos, data, layer) {
|
||||
// dont pass leaflet lat/lon
|
||||
this.trigger('featureOver', e, [latlon.lat, latlon.lng], pixelPos, data, layer);
|
||||
},
|
||||
|
||||
featureOut: function(e, layer) {
|
||||
this.trigger('featureOut', e, layer);
|
||||
},
|
||||
|
||||
featureClick: function(e, latlon, pixelPos, data, layer) {
|
||||
// dont pass leaflet lat/lon
|
||||
this.trigger('featureClick', e, [latlon.lat, latlon.lng], pixelPos, data, layer);
|
||||
},
|
||||
|
||||
error: function(e) {
|
||||
this.trigger('error', e ? (e.errors || e) : 'unknown error');
|
||||
this.model.trigger('error', e?e.errors:'unknown error');
|
||||
},
|
||||
|
||||
ok: function(e) {
|
||||
this.model.trigger('tileOk');
|
||||
},
|
||||
|
||||
onLayerDefinitionUpdated: function() {
|
||||
this.__update();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return layerViewClass;
|
||||
}
|
||||
|
||||
L.NamedMap = L.CartoDBGroupLayerBase.extend({
|
||||
includes: [
|
||||
cdb.geo.LeafLetLayerView.prototype,
|
||||
NamedMap.prototype,
|
||||
CartoDBLayerCommon.prototype
|
||||
],
|
||||
|
||||
initialize: function (options) {
|
||||
options = options || {};
|
||||
// Set options
|
||||
L.Util.setOptions(this, options);
|
||||
|
||||
// Some checks
|
||||
if (!options.named_map && !options.sublayers) {
|
||||
throw new Error('cartodb-leaflet needs at least the named_map');
|
||||
}
|
||||
|
||||
NamedMap.call(this, this.options.named_map, this.options);
|
||||
|
||||
this.fire = this.trigger;
|
||||
|
||||
CartoDBLayerCommon.call(this);
|
||||
L.TileLayer.prototype.initialize.call(this);
|
||||
this.interaction = [];
|
||||
this.addProfiling();
|
||||
},
|
||||
|
||||
_modelUpdated: function() {
|
||||
this.setLayerDefinition(this.model.get('named_map'));
|
||||
}
|
||||
});
|
||||
|
||||
cdb.geo.LeafLetCartoDBLayerGroupView = layerView(L.CartoDBGroupLayer);
|
||||
cdb.geo.LeafLetCartoDBNamedMapView = layerView(L.NamedMap);
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
(function() {
|
||||
|
||||
if(typeof(L) == "undefined")
|
||||
return;
|
||||
|
||||
var stamenSubstitute = function stamenSubstitute(type) {
|
||||
return {
|
||||
url: 'http://{s}.basemaps.cartocdn.com/'+ type +'_all/{z}/{x}/{y}.png',
|
||||
subdomains: 'abcd',
|
||||
minZoom: 0,
|
||||
maxZoom: 18,
|
||||
attribution: 'Map designs by <a href="http://stamen.com/">Stamen</a>. Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, Provided by <a href="https://carto.com">CARTO</a>'
|
||||
};
|
||||
};
|
||||
|
||||
var nokiaSubstitute = function nokiaSubstitute(type) {
|
||||
return {
|
||||
url: 'https://{s}.maps.nlp.nokia.com/maptile/2.1/maptile/newest/'+ type +'.day/{z}/{x}/{y}/256/png8?lg=eng&token=A7tBPacePg9Mj_zghvKt9Q&app_id=KuYppsdXZznpffJsKT24',
|
||||
subdomains: '1234',
|
||||
minZoom: 0,
|
||||
maxZoom: 21,
|
||||
attribution: '©2012 Nokia <a href="http://here.net/services/terms" target="_blank">Terms of use</a>'
|
||||
};
|
||||
};
|
||||
|
||||
var substitutes = {
|
||||
roadmap: nokiaSubstitute('normal'),
|
||||
gray_roadmap: stamenSubstitute('light'),
|
||||
dark_roadmap: stamenSubstitute('dark'),
|
||||
hybrid: nokiaSubstitute('hybrid'),
|
||||
terrain: nokiaSubstitute('terrain'),
|
||||
satellite: nokiaSubstitute('satellite')
|
||||
};
|
||||
|
||||
var LeafLetGmapsTiledLayerView = L.TileLayer.extend({
|
||||
initialize: function(layerModel, leafletMap) {
|
||||
var substitute = substitutes[layerModel.get('base_type')];
|
||||
L.TileLayer.prototype.initialize.call(this, substitute.url, {
|
||||
tms: false,
|
||||
attribution: substitute.attribution,
|
||||
minZoom: substitute.minZoom,
|
||||
maxZoom: substitute.maxZoom,
|
||||
subdomains: substitute.subdomains,
|
||||
errorTileUrl: '',
|
||||
opacity: 1
|
||||
});
|
||||
cdb.geo.LeafLetLayerView.call(this, layerModel, this, leafletMap);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
_.extend(LeafLetGmapsTiledLayerView.prototype, cdb.geo.LeafLetLayerView.prototype, {
|
||||
|
||||
_modelUpdated: function() {
|
||||
// do nothing, this map type does not support updating
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
cdb.geo.LeafLetGmapsTiledLayerView = LeafLetGmapsTiledLayerView;
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,51 @@
|
||||
|
||||
(function() {
|
||||
|
||||
if(typeof(L) == "undefined")
|
||||
return;
|
||||
|
||||
/**
|
||||
* this is a dummy layer class that modifies the leaflet DOM element background
|
||||
* instead of creating a layer with div
|
||||
*/
|
||||
var LeafLetPlainLayerView = L.Class.extend({
|
||||
includes: L.Mixin.Events,
|
||||
|
||||
initialize: function(layerModel, leafletMap) {
|
||||
cdb.geo.LeafLetLayerView.call(this, layerModel, this, leafletMap);
|
||||
},
|
||||
|
||||
onAdd: function() {
|
||||
this.redraw();
|
||||
},
|
||||
|
||||
onRemove: function() {
|
||||
var div = this.leafletMap.getContainer()
|
||||
div.style.background = 'none';
|
||||
},
|
||||
|
||||
_modelUpdated: function() {
|
||||
this.redraw();
|
||||
},
|
||||
|
||||
redraw: function() {
|
||||
var div = this.leafletMap.getContainer()
|
||||
div.style.backgroundColor = this.model.get('color') || '#FFF';
|
||||
|
||||
if (this.model.get('image')) {
|
||||
var st = 'transparent url(' + this.model.get('image') + ') repeat center center';
|
||||
div.style.background = st
|
||||
}
|
||||
},
|
||||
|
||||
// this method
|
||||
setZIndex: function() {
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
_.extend(LeafLetPlainLayerView.prototype, cdb.geo.LeafLetLayerView.prototype);
|
||||
|
||||
cdb.geo.LeafLetPlainLayerView = LeafLetPlainLayerView;
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,50 @@
|
||||
|
||||
(function() {
|
||||
|
||||
if(typeof(L) == "undefined")
|
||||
return;
|
||||
|
||||
var LeafLetTiledLayerView = L.TileLayer.extend({
|
||||
initialize: function(layerModel, leafletMap) {
|
||||
|
||||
var tmpLayer = {
|
||||
tms: layerModel.get('tms'),
|
||||
attribution: layerModel.get('attribution'),
|
||||
minZoom: layerModel.get('minZoom'),
|
||||
maxZoom: layerModel.get('maxZoom'),
|
||||
subdomains: layerModel.get('subdomains') || 'abc',
|
||||
errorTileUrl: layerModel.get('errorTileUrl'),
|
||||
opacity: layerModel.get('opacity')
|
||||
};
|
||||
|
||||
if ( layerModel.get('tileSize') ) {
|
||||
tmpLayer.tileSize = layerModel.get('tileSize');
|
||||
}
|
||||
|
||||
if ( layerModel.get('zoomOffset') ) {
|
||||
tmpLayer.zoomOffset = layerModel.get('zoomOffset');
|
||||
}
|
||||
|
||||
L.TileLayer.prototype.initialize.call(this, layerModel.get('urlTemplate'), tmpLayer);
|
||||
cdb.geo.LeafLetLayerView.call(this, layerModel, this, leafletMap);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
_.extend(LeafLetTiledLayerView.prototype, cdb.geo.LeafLetLayerView.prototype, {
|
||||
|
||||
_modelUpdated: function() {
|
||||
_.defaults(this.leafletLayer.options, _.clone(this.model.attributes));
|
||||
this.leafletLayer.options.subdomains = this.model.get('subdomains') || 'abc';
|
||||
this.leafletLayer.options.attribution = this.model.get('attribution');
|
||||
this.leafletLayer.options.maxZoom = this.model.get('maxZoom');
|
||||
this.leafletLayer.options.minZoom = this.model.get('minZoom');
|
||||
// set url and reload
|
||||
this.leafletLayer.setUrl(this.model.get('urlTemplate'));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
cdb.geo.LeafLetTiledLayerView = LeafLetTiledLayerView;
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,48 @@
|
||||
|
||||
(function() {
|
||||
|
||||
if(typeof(L) == "undefined")
|
||||
return;
|
||||
|
||||
var LeafLetWMSLayerView = L.TileLayer.WMS.extend({
|
||||
initialize: function(layerModel, leafletMap) {
|
||||
|
||||
var tmpLayer = {
|
||||
attribution: layerModel.get('attribution'),
|
||||
layers: layerModel.get('layers'),
|
||||
format: layerModel.get('format'),
|
||||
transparent: layerModel.get('transparent'),
|
||||
minZoom: layerModel.get('minZomm'),
|
||||
maxZoom: layerModel.get('maxZoom'),
|
||||
subdomains: layerModel.get('subdomains') || 'abc',
|
||||
errorTileUrl: layerModel.get('errorTileUrl'),
|
||||
opacity: layerModel.get('opacity')
|
||||
};
|
||||
|
||||
if ( layerModel.get('tileSize') ) {
|
||||
tmpLayer.tileSize = layerModel.get('tileSize');
|
||||
}
|
||||
|
||||
if ( layerModel.get('zoomOffset') ) {
|
||||
tmpLayer.zoomOffset = layerModel.get('zoomOffset');
|
||||
}
|
||||
|
||||
L.TileLayer.WMS.prototype.initialize.call(this, layerModel.get('urlTemplate'), tmpLayer);
|
||||
|
||||
cdb.geo.LeafLetLayerView.call(this, layerModel, this, leafletMap);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
_.extend(LeafLetWMSLayerView.prototype, cdb.geo.LeafLetLayerView.prototype, {
|
||||
|
||||
_modelUpdated: function() {
|
||||
_.defaults(this.leafletLayer.options, _.clone(this.model.attributes));
|
||||
this.leafletLayer.setUrl(this.model.get('urlTemplate'));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
cdb.geo.LeafLetWMSLayerView = LeafLetWMSLayerView;
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,110 @@
|
||||
|
||||
(function() {
|
||||
|
||||
if(typeof(L) === "undefined")
|
||||
return;
|
||||
|
||||
/**
|
||||
* leaflet torque layer
|
||||
*/
|
||||
var LeafLetTorqueLayer = L.TorqueLayer.extend({
|
||||
|
||||
initialize: function(layerModel, leafletMap) {
|
||||
var extra = layerModel.get('extra_params');
|
||||
|
||||
var query = this._getQuery(layerModel);
|
||||
|
||||
// initialize the base layers
|
||||
L.TorqueLayer.prototype.initialize.call(this, {
|
||||
table: layerModel.get('table_name'),
|
||||
user: layerModel.get('user_name'),
|
||||
column: layerModel.get('property'),
|
||||
blendmode: layerModel.get('torque-blend-mode'),
|
||||
resolution: 1,
|
||||
//TODO: manage time columns
|
||||
countby: 'count(cartodb_id)',
|
||||
sql_api_domain: layerModel.get('sql_api_domain'),
|
||||
sql_api_protocol: layerModel.get('sql_api_protocol'),
|
||||
sql_api_port: layerModel.get('sql_api_port'),
|
||||
tiler_protocol: layerModel.get('tiler_protocol'),
|
||||
tiler_domain: layerModel.get('tiler_domain'),
|
||||
tiler_port: layerModel.get('tiler_port'),
|
||||
maps_api_template: layerModel.get('maps_api_template'),
|
||||
stat_tag: layerModel.get('stat_tag'),
|
||||
animationDuration: layerModel.get('torque-duration'),
|
||||
steps: layerModel.get('torque-steps'),
|
||||
sql: query,
|
||||
visible: layerModel.get('visible'),
|
||||
extra_params: {
|
||||
api_key: extra ? extra.map_key: ''
|
||||
},
|
||||
cartodb_logo: layerModel.get('cartodb_logo'),
|
||||
attribution: layerModel.get('attribution'),
|
||||
cartocss: layerModel.get('cartocss') || layerModel.get('tile_style'),
|
||||
named_map: layerModel.get('named_map'),
|
||||
auth_token: layerModel.get('auth_token'),
|
||||
no_cdn: layerModel.get('no_cdn'),
|
||||
dynamic_cdn: layerModel.get('dynamic_cdn'),
|
||||
loop: layerModel.get('loop') === false? false: true,
|
||||
instanciateCallback: function() {
|
||||
var cartocss = layerModel.get('cartocss') || layerModel.get('tile_style');
|
||||
|
||||
return '_cdbct_' + cdb.core.util.uniqueCallbackName(cartocss + query);
|
||||
}
|
||||
});
|
||||
|
||||
cdb.geo.LeafLetLayerView.call(this, layerModel, this, leafletMap);
|
||||
|
||||
// match leaflet events with backbone events
|
||||
this.fire = this.trigger;
|
||||
|
||||
//this.setCartoCSS(layerModel.get('tile_style'));
|
||||
if (layerModel.get('visible')) {
|
||||
this.play();
|
||||
}
|
||||
|
||||
this.bind('tilesLoaded', function() {
|
||||
this.trigger('load');
|
||||
}, this);
|
||||
|
||||
this.bind('tilesLoading', function() {
|
||||
this.trigger('loading');
|
||||
}, this);
|
||||
|
||||
},
|
||||
|
||||
onAdd: function(map) {
|
||||
L.TorqueLayer.prototype.onAdd.apply(this, [map]);
|
||||
// Add CartoDB logo
|
||||
if (this.options.cartodb_logo != false)
|
||||
cdb.geo.common.CartoDBLogo.addWadus({ left:8, bottom:8 }, 0, map._container)
|
||||
},
|
||||
|
||||
_getQuery: function(layerModel) {
|
||||
var query = layerModel.get('query');
|
||||
var qw = layerModel.get('query_wrapper');
|
||||
if(qw) {
|
||||
query = _.template(qw)({ sql: query || ('select * from ' + layerModel.get('table_name')) });
|
||||
}
|
||||
return query;
|
||||
},
|
||||
|
||||
_modelUpdated: function(model) {
|
||||
var changed = this.model.changedAttributes();
|
||||
if(changed === false) return;
|
||||
changed.tile_style && this.setCartoCSS(this.model.get('tile_style'));
|
||||
if ('query' in changed || 'query_wrapper' in changed) {
|
||||
this.setSQL(this._getQuery(this.model));
|
||||
}
|
||||
|
||||
if ('visible' in changed)
|
||||
this.model.get('visible') ? this.show(): this.hide();
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
_.extend(LeafLetTorqueLayer.prototype, cdb.geo.LeafLetLayerView.prototype);
|
||||
|
||||
cdb.geo.LeafLetTorqueLayer = LeafLetTorqueLayer;
|
||||
|
||||
})();
|
||||
Reference in New Issue
Block a user