889 lines
23 KiB
JavaScript
889 lines
23 KiB
JavaScript
|
/*
|
||
|
Leaflet.print, implements the Mapfish print protocol allowing a Leaflet map to be printed using either the Mapfish or GeoServer print module.
|
||
|
(c) 2013, Adam Ratcliffe, GeoSmart Maps Limited
|
||
|
*/
|
||
|
(function (window, document, undefined) {
|
||
|
/* global L:false, $:false */
|
||
|
|
||
|
L.print = L.print || {};
|
||
|
|
||
|
L.print.Provider = L.Class.extend({
|
||
|
|
||
|
includes: L.Mixin.Events,
|
||
|
|
||
|
statics: {
|
||
|
MAX_RESOLUTION: 156543.03390625,
|
||
|
MAX_EXTENT: [-20037508.34, -20037508.34, 20037508.34, 20037508.34],
|
||
|
SRS: 'EPSG:3857',
|
||
|
INCHES_PER_METER: 39.3701,
|
||
|
DPI: 72,
|
||
|
UNITS: 'm'
|
||
|
},
|
||
|
|
||
|
options: {
|
||
|
autoLoad: false,
|
||
|
autoOpen: true,
|
||
|
outputFormat: 'pdf',
|
||
|
outputFilename: 'leaflet-map',
|
||
|
method: 'POST',
|
||
|
rotation: 0,
|
||
|
customParams: {},
|
||
|
legends: false
|
||
|
},
|
||
|
|
||
|
initialize: function (options) {
|
||
|
if (L.version <= '0.5.1') {
|
||
|
throw 'Leaflet.print requires Leaflet 0.6.0+. Download latest from https://github.com/Leaflet/Leaflet/';
|
||
|
}
|
||
|
|
||
|
var context;
|
||
|
|
||
|
options = L.setOptions(this, options);
|
||
|
|
||
|
if (options.map) {
|
||
|
this.setMap(options.map);
|
||
|
}
|
||
|
|
||
|
if (options.capabilities) {
|
||
|
this._capabilities = options.capabilities;
|
||
|
} else if (this.options.autoLoad) {
|
||
|
this.loadCapabilities();
|
||
|
}
|
||
|
|
||
|
if (options.listeners) {
|
||
|
if (options.listeners.context) {
|
||
|
context = options.listeners.context;
|
||
|
delete options.listeners.context;
|
||
|
}
|
||
|
this.addEventListener(options.listeners, context);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
loadCapabilities: function () {
|
||
|
if (!this.options.url) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var url;
|
||
|
|
||
|
url = this.options.url + '/info.json';
|
||
|
if (this.options.proxy) {
|
||
|
url = this.options.proxy + url;
|
||
|
}
|
||
|
|
||
|
$.ajax({
|
||
|
type: 'GET',
|
||
|
dataType: 'json',
|
||
|
url: url,
|
||
|
success: L.Util.bind(this.onCapabilitiesLoad, this)
|
||
|
});
|
||
|
},
|
||
|
|
||
|
print: function (options) {
|
||
|
options = L.extend(L.extend({}, this.options), options);
|
||
|
|
||
|
if (!options.layout || !options.dpi) {
|
||
|
throw 'Must provide a layout name and dpi value to print';
|
||
|
}
|
||
|
|
||
|
this.fire('beforeprint', {
|
||
|
provider: this,
|
||
|
map: this._map
|
||
|
});
|
||
|
|
||
|
var jsonData = JSON.stringify(L.extend({
|
||
|
units: L.print.Provider.UNITS,
|
||
|
srs: L.print.Provider.SRS,
|
||
|
layout: options.layout,
|
||
|
dpi: options.dpi,
|
||
|
outputFormat: options.outputFormat,
|
||
|
outputFilename: options.outputFilename,
|
||
|
layers: this._encodeLayers(this._map),
|
||
|
pages: [{
|
||
|
center: this._projectCoords(L.print.Provider.SRS, this._map.getCenter()),
|
||
|
scale: this._getScale(),
|
||
|
rotation: options.rotation
|
||
|
}]
|
||
|
}, this.options.customParams, options.customParams, this._makeLegends(this._map))),
|
||
|
url;
|
||
|
|
||
|
if (options.method === 'GET') {
|
||
|
url = this._capabilities.printURL + '?spec=' + encodeURIComponent(jsonData);
|
||
|
|
||
|
if (options.proxy) {
|
||
|
url = options.proxy + encodeURIComponent(url);
|
||
|
}
|
||
|
|
||
|
window.open(url);
|
||
|
|
||
|
this.fire('print', {
|
||
|
provider: this,
|
||
|
map: this._map
|
||
|
});
|
||
|
} else {
|
||
|
url = this._capabilities.createURL;
|
||
|
|
||
|
if (options.proxy) {
|
||
|
url = options.proxy + url;
|
||
|
}
|
||
|
|
||
|
if (this._xhr) {
|
||
|
this._xhr.abort();
|
||
|
}
|
||
|
|
||
|
this._xhr = $.ajax({
|
||
|
type: 'POST',
|
||
|
contentType: 'application/json; charset=UTF-8',
|
||
|
processData: false,
|
||
|
dataType: 'json',
|
||
|
url: url,
|
||
|
data: jsonData,
|
||
|
success: L.Util.bind(this.onPrintSuccess, this),
|
||
|
error: L.Util.bind(this.onPrintError, this)
|
||
|
});
|
||
|
}
|
||
|
|
||
|
},
|
||
|
|
||
|
getCapabilities: function () {
|
||
|
return this._capabilities;
|
||
|
},
|
||
|
|
||
|
setMap: function (map) {
|
||
|
this._map = map;
|
||
|
},
|
||
|
|
||
|
setDpi: function (dpi) {
|
||
|
var oldDpi = this.options.dpi;
|
||
|
|
||
|
if (oldDpi !== dpi) {
|
||
|
this.options.dpi = dpi;
|
||
|
this.fire('dpichange', {
|
||
|
provider: this,
|
||
|
dpi: dpi
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
|
||
|
setLayout: function (name) {
|
||
|
var oldName = this.options.layout;
|
||
|
|
||
|
if (oldName !== name) {
|
||
|
this.options.layout = name;
|
||
|
this.fire('layoutchange', {
|
||
|
provider: this,
|
||
|
layout: name
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
|
||
|
setRotation: function (rotation) {
|
||
|
var oldRotation = this.options.rotation;
|
||
|
|
||
|
if (oldRotation !== this.options.rotation) {
|
||
|
this.options.rotation = rotation;
|
||
|
this.fire('rotationchange', {
|
||
|
provider: this,
|
||
|
rotation: rotation
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_getLayers: function (map) {
|
||
|
var markers = [],
|
||
|
vectors = [],
|
||
|
tiles = [],
|
||
|
imageOverlays = [],
|
||
|
imageNodes,
|
||
|
pathNodes,
|
||
|
id;
|
||
|
|
||
|
for (id in map._layers) {
|
||
|
if (map._layers.hasOwnProperty(id)) {
|
||
|
if (!map._layers.hasOwnProperty(id)) { continue; }
|
||
|
var lyr = map._layers[id];
|
||
|
|
||
|
if (lyr instanceof L.TileLayer.WMS || lyr instanceof L.TileLayer) {
|
||
|
tiles.push(lyr);
|
||
|
} else if (lyr instanceof L.ImageOverlay) {
|
||
|
imageOverlays.push(lyr);
|
||
|
} else if (lyr instanceof L.Marker) {
|
||
|
markers.push(lyr);
|
||
|
} else if (lyr instanceof L.Path && lyr.toGeoJSON) {
|
||
|
vectors.push(lyr);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
markers.sort(function (a, b) {
|
||
|
return a._icon.style.zIndex - b._icon.style.zIndex;
|
||
|
});
|
||
|
|
||
|
var i;
|
||
|
// Layers with equal zIndexes can cause problems with mapfish print
|
||
|
for (i = 1; i < markers.length; i++) {
|
||
|
if (markers[i]._icon.style.zIndex <= markers[i - 1]._icon.style.zIndex) {
|
||
|
markers[i]._icon.style.zIndex = markers[i - 1].icons.style.zIndex + 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
tiles.sort(function (a, b) {
|
||
|
return a._container.style.zIndex - b._container.style.zIndex;
|
||
|
});
|
||
|
|
||
|
// Layers with equal zIndexes can cause problems with mapfish print
|
||
|
for (i = 1; i < tiles.length; i++) {
|
||
|
if (tiles[i]._container.style.zIndex <= tiles[i - 1]._container.style.zIndex) {
|
||
|
tiles[i]._container.style.zIndex = tiles[i - 1]._container.style.zIndex + 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
imageNodes = [].slice.call(this, map._panes.overlayPane.childNodes);
|
||
|
imageOverlays.sort(function (a, b) {
|
||
|
return imageNodes.indexOf(a._image) - imageNodes.indexOf(b._image);
|
||
|
});
|
||
|
|
||
|
if (map._pathRoot) {
|
||
|
pathNodes = [].slice.call(this, map._pathRoot.childNodes);
|
||
|
vectors.sort(function (a, b) {
|
||
|
return pathNodes.indexOf(a._container) - pathNodes.indexOf(b._container);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
return tiles.concat(vectors).concat(imageOverlays).concat(markers);
|
||
|
},
|
||
|
|
||
|
_getScale: function () {
|
||
|
var map = this._map,
|
||
|
bounds = map.getBounds(),
|
||
|
inchesKm = L.print.Provider.INCHES_PER_METER * 1000,
|
||
|
scales = this._capabilities.scales,
|
||
|
sw = bounds.getSouthWest(),
|
||
|
ne = bounds.getNorthEast(),
|
||
|
halfLat = (sw.lat + ne.lat) / 2,
|
||
|
midLeft = L.latLng(halfLat, sw.lng),
|
||
|
midRight = L.latLng(halfLat, ne.lng),
|
||
|
mwidth = midLeft.distanceTo(midRight),
|
||
|
pxwidth = map.getSize().x,
|
||
|
kmPx = mwidth / pxwidth / 1000,
|
||
|
mscale = (kmPx || 0.000001) * inchesKm * L.print.Provider.DPI,
|
||
|
closest = Number.POSITIVE_INFINITY,
|
||
|
i = scales.length,
|
||
|
diff,
|
||
|
scale;
|
||
|
|
||
|
while (i--) {
|
||
|
diff = Math.abs(mscale - scales[i].value);
|
||
|
if (diff < closest) {
|
||
|
closest = diff;
|
||
|
scale = parseInt(scales[i].value, 10);
|
||
|
}
|
||
|
}
|
||
|
return scale;
|
||
|
},
|
||
|
|
||
|
_getLayoutByName: function (name) {
|
||
|
var layout, i, l;
|
||
|
|
||
|
for (i = 0, l = this._capabilities.layouts.length; i < l; i++) {
|
||
|
if (this._capabilities.layouts[i].name === name) {
|
||
|
layout = this._capabilities.layouts[i];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return layout;
|
||
|
},
|
||
|
|
||
|
_encodeLayers: function (map) {
|
||
|
var enc = [],
|
||
|
vectors = [],
|
||
|
layer,
|
||
|
i;
|
||
|
|
||
|
var layers = this._getLayers(map);
|
||
|
for (i = 0; i < layers.length; i++) {
|
||
|
layer = layers[i];
|
||
|
if (layer instanceof L.TileLayer.WMS) {
|
||
|
enc.push(this._encoders.layers.tilelayerwms.call(this, layer));
|
||
|
} else if (L.mapbox && layer instanceof L.mapbox.TileLayer) {
|
||
|
enc.push(this._encoders.layers.tilelayermapbox.call(this, layer));
|
||
|
} else if (layer instanceof L.TileLayer) {
|
||
|
enc.push(this._encoders.layers.tilelayer.call(this, layer));
|
||
|
} else if (layer instanceof L.ImageOverlay) {
|
||
|
enc.push(this._encoders.layers.image.call(this, layer));
|
||
|
} else if (layer instanceof L.Marker || (layer instanceof L.Path && layer.toGeoJSON)) {
|
||
|
vectors.push(layer);
|
||
|
}
|
||
|
}
|
||
|
if (vectors.length) {
|
||
|
enc.push(this._encoders.layers.vector.call(this, vectors));
|
||
|
}
|
||
|
return enc;
|
||
|
},
|
||
|
|
||
|
_makeLegends: function (map, options) {
|
||
|
if (!this.options.legends) {
|
||
|
return [];
|
||
|
}
|
||
|
|
||
|
var legends = [], legendReq, singlelayers, url, i;
|
||
|
|
||
|
var layers = this._getLayers(map);
|
||
|
var layer, oneLegend;
|
||
|
for (i = 0; i < layers.length; i++) {
|
||
|
layer = layers[i];
|
||
|
if (layer instanceof L.TileLayer.WMS) {
|
||
|
|
||
|
oneLegend = {
|
||
|
name: layer.options.title || layer.wmsParams.layers,
|
||
|
classes: []
|
||
|
};
|
||
|
|
||
|
// defaults
|
||
|
legendReq = {
|
||
|
'SERVICE' : 'WMS',
|
||
|
'LAYER' : layer.wmsParams.layers,
|
||
|
'REQUEST' : 'GetLegendGraphic',
|
||
|
'VERSION' : layer.wmsParams.version,
|
||
|
'FORMAT' : layer.wmsParams.format,
|
||
|
'STYLE' : layer.wmsParams.styles,
|
||
|
'WIDTH' : 15,
|
||
|
'HEIGHT' : 15
|
||
|
};
|
||
|
|
||
|
legendReq = L.extend(legendReq, options);
|
||
|
url = L.Util.template(layer._url);
|
||
|
|
||
|
singlelayers = layer.wmsParams.layers.split(',');
|
||
|
|
||
|
// If a WMS layer doesn't have multiple server layers, only show one graphic
|
||
|
if (singlelayers.length === 1) {
|
||
|
oneLegend.icons = [this._getAbsoluteUrl(url + L.Util.getParamString(legendReq, url, true))];
|
||
|
} else {
|
||
|
for (i = 0; i < singlelayers.length; i++) {
|
||
|
legendReq.LAYER = singlelayers[i];
|
||
|
oneLegend.classes.push({
|
||
|
name: singlelayers[i],
|
||
|
icons: [this._getAbsoluteUrl(url + L.Util.getParamString(legendReq, url, true))]
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
legends.push(oneLegend);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return {legends: legends};
|
||
|
},
|
||
|
|
||
|
_encoders: {
|
||
|
layers: {
|
||
|
httprequest: function (layer) {
|
||
|
var baseUrl = layer._url;
|
||
|
|
||
|
if (baseUrl.indexOf('{s}') !== -1) {
|
||
|
baseUrl = baseUrl.replace('{s}', layer.options.subdomains[0]);
|
||
|
}
|
||
|
baseUrl = this._getAbsoluteUrl(baseUrl);
|
||
|
|
||
|
return {
|
||
|
baseURL: baseUrl,
|
||
|
opacity: layer.options.opacity
|
||
|
};
|
||
|
},
|
||
|
tilelayer: function (layer) {
|
||
|
var enc = this._encoders.layers.httprequest.call(this, layer),
|
||
|
baseUrl = layer._url.substring(0, layer._url.indexOf('{z}')),
|
||
|
resolutions = [],
|
||
|
zoom;
|
||
|
|
||
|
// If using multiple subdomains, replace the subdomain placeholder
|
||
|
if (baseUrl.indexOf('{s}') !== -1) {
|
||
|
baseUrl = baseUrl.replace('{s}', layer.options.subdomains[0]);
|
||
|
}
|
||
|
|
||
|
for (zoom = 0; zoom <= layer.options.maxZoom; ++zoom) {
|
||
|
resolutions.push(L.print.Provider.MAX_RESOLUTION / Math.pow(2, zoom));
|
||
|
}
|
||
|
|
||
|
return L.extend(enc, {
|
||
|
// XYZ layer type would be a better fit but is not supported in mapfish plugin for GeoServer
|
||
|
// See https://github.com/mapfish/mapfish-print/pull/38
|
||
|
type: 'OSM',
|
||
|
baseURL: baseUrl,
|
||
|
extension: 'png',
|
||
|
tileSize: [layer.options.tileSize, layer.options.tileSize],
|
||
|
maxExtent: L.print.Provider.MAX_EXTENT,
|
||
|
resolutions: resolutions,
|
||
|
singleTile: false
|
||
|
});
|
||
|
},
|
||
|
tilelayerwms: function (layer) {
|
||
|
var enc = this._encoders.layers.httprequest.call(this, layer),
|
||
|
layerOpts = layer.options,
|
||
|
p;
|
||
|
|
||
|
L.extend(enc, {
|
||
|
type: 'WMS',
|
||
|
layers: [layerOpts.layers].join(',').split(',').filter(function (x) {return x !== ""; }), //filter out empty strings from the array
|
||
|
format: layerOpts.format,
|
||
|
styles: [layerOpts.styles].join(',').split(',').filter(function (x) {return x !== ""; }),
|
||
|
singleTile: true
|
||
|
});
|
||
|
|
||
|
for (p in layer.wmsParams) {
|
||
|
if (layer.wmsParams.hasOwnProperty(p)) {
|
||
|
if ('detectretina,format,height,layers,request,service,srs,styles,version,width'.indexOf(p.toLowerCase()) === -1) {
|
||
|
if (!enc.customParams) {
|
||
|
enc.customParams = {};
|
||
|
}
|
||
|
enc.customParams[p] = layer.wmsParams[p];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return enc;
|
||
|
},
|
||
|
tilelayermapbox: function (layer) {
|
||
|
var resolutions = [], zoom;
|
||
|
|
||
|
for (zoom = 0; zoom <= layer.options.maxZoom; ++zoom) {
|
||
|
resolutions.push(L.print.Provider.MAX_RESOLUTION / Math.pow(2, zoom));
|
||
|
}
|
||
|
|
||
|
var customParams = {};
|
||
|
if (typeof layer.options.access_token === 'string' && layer.options.access_token.length > 0) {
|
||
|
customParams.access_token = layer.options.access_token;
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
// XYZ layer type would be a better fit but is not supported in mapfish plugin for GeoServer
|
||
|
// See https://github.com/mapfish/mapfish-print/pull/38
|
||
|
type: 'OSM',
|
||
|
baseURL: layer.options.tiles[0].substring(0, layer.options.tiles[0].indexOf('{z}')),
|
||
|
opacity: layer.options.opacity,
|
||
|
extension: 'png',
|
||
|
tileSize: [layer.options.tileSize, layer.options.tileSize],
|
||
|
maxExtent: L.print.Provider.MAX_EXTENT,
|
||
|
resolutions: resolutions,
|
||
|
singleTile: false,
|
||
|
customParams: customParams
|
||
|
};
|
||
|
},
|
||
|
image: function (layer) {
|
||
|
return {
|
||
|
type: 'Image',
|
||
|
opacity: layer.options.opacity,
|
||
|
name: 'image',
|
||
|
baseURL: this._getAbsoluteUrl(layer._url),
|
||
|
extent: this._projectBounds(L.print.Provider.SRS, layer._bounds)
|
||
|
};
|
||
|
},
|
||
|
vector: function (features) {
|
||
|
var encFeatures = [],
|
||
|
encStyles = {},
|
||
|
opacity,
|
||
|
feature,
|
||
|
style,
|
||
|
dictKey,
|
||
|
dictItem = {},
|
||
|
styleDict = {},
|
||
|
styleName,
|
||
|
nextId = 1,
|
||
|
featureGeoJson,
|
||
|
i, l;
|
||
|
|
||
|
for (i = 0, l = features.length; i < l; i++) {
|
||
|
feature = features[i];
|
||
|
|
||
|
if (feature instanceof L.Marker) {
|
||
|
var icon = feature.options.icon,
|
||
|
iconUrl = icon.options.iconUrl || L.Icon.Default.imagePath + '/marker-icon.png',
|
||
|
iconSize = L.Util.isArray(icon.options.iconSize) ? new L.Point(icon.options.iconSize[0], icon.options.iconSize[1]) : icon.options.iconSize,
|
||
|
iconAnchor = L.Util.isArray(icon.options.iconAnchor) ? new L.Point(icon.options.iconAnchor[0], icon.options.iconAnchor[1]) : icon.options.iconAnchor,
|
||
|
scaleFactor = (this.options.dpi / L.print.Provider.DPI);
|
||
|
|
||
|
style = {
|
||
|
externalGraphic: this._getAbsoluteUrl(iconUrl),
|
||
|
graphicWidth: (iconSize.x / scaleFactor),
|
||
|
graphicHeight: (iconSize.y / scaleFactor),
|
||
|
graphicXOffset: (-iconAnchor.x / scaleFactor),
|
||
|
graphicYOffset: (-iconAnchor.y / scaleFactor)
|
||
|
};
|
||
|
} else {
|
||
|
style = this._extractFeatureStyle(feature);
|
||
|
}
|
||
|
|
||
|
dictKey = JSON.stringify(style);
|
||
|
dictItem = styleDict[dictKey];
|
||
|
if (dictItem) {
|
||
|
styleName = dictItem;
|
||
|
} else {
|
||
|
styleDict[dictKey] = styleName = nextId++;
|
||
|
encStyles[styleName] = style;
|
||
|
}
|
||
|
|
||
|
featureGeoJson = (feature instanceof L.Circle) ? this._circleGeoJSON(feature) : feature.toGeoJSON();
|
||
|
featureGeoJson.geometry.coordinates = this._projectCoords(L.print.Provider.SRS, featureGeoJson.geometry.coordinates);
|
||
|
featureGeoJson.properties._leaflet_style = styleName;
|
||
|
|
||
|
// All markers will use the same opacity as the first marker found
|
||
|
if (opacity === null) {
|
||
|
opacity = feature.options.opacity || 1.0;
|
||
|
}
|
||
|
|
||
|
encFeatures.push(featureGeoJson);
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
type: 'Vector',
|
||
|
styles: encStyles,
|
||
|
opacity: opacity,
|
||
|
styleProperty: '_leaflet_style',
|
||
|
geoJson: {
|
||
|
type: 'FeatureCollection',
|
||
|
features: encFeatures
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
|
||
|
_circleGeoJSON: function (circle) {
|
||
|
var projection = circle._map.options.crs.projection;
|
||
|
var earthRadius = 1, i;
|
||
|
|
||
|
if (projection === L.Projection.SphericalMercator) {
|
||
|
earthRadius = 6378137;
|
||
|
} else if (projection === L.Projection.Mercator) {
|
||
|
earthRadius = projection.R_MAJOR;
|
||
|
}
|
||
|
var cnt = projection.project(circle.getLatLng());
|
||
|
var scale = 1.0 / Math.cos(circle.getLatLng().lat * Math.PI / 180.0);
|
||
|
var points = [];
|
||
|
for (i = 0; i < 64; i++) {
|
||
|
var radian = i * 2.0 * Math.PI / 64.0;
|
||
|
var shift = L.point(Math.cos(radian), Math.sin(radian));
|
||
|
points.push(projection.unproject(cnt.add(shift.multiplyBy(circle.getRadius() * scale / earthRadius))));
|
||
|
}
|
||
|
return L.polygon(points).toGeoJSON();
|
||
|
},
|
||
|
|
||
|
_extractFeatureStyle: function (feature) {
|
||
|
var options = feature.options;
|
||
|
|
||
|
return {
|
||
|
stroke: options.stroke,
|
||
|
strokeColor: options.color,
|
||
|
strokeWidth: options.weight,
|
||
|
strokeOpacity: options.opacity,
|
||
|
strokeLinecap: 'round',
|
||
|
fill: options.fill,
|
||
|
fillColor: options.fillColor || options.color,
|
||
|
fillOpacity: options.fillOpacity
|
||
|
};
|
||
|
},
|
||
|
|
||
|
_getAbsoluteUrl: function (url) {
|
||
|
var a;
|
||
|
|
||
|
if (L.Browser.ie) {
|
||
|
a = document.createElement('a');
|
||
|
a.style.display = 'none';
|
||
|
document.body.appendChild(a);
|
||
|
a.href = url;
|
||
|
document.body.removeChild(a);
|
||
|
} else {
|
||
|
a = document.createElement('a');
|
||
|
a.href = url;
|
||
|
}
|
||
|
return a.href;
|
||
|
},
|
||
|
|
||
|
_projectBounds: function (crs, bounds) {
|
||
|
var sw = bounds.getSouthWest(),
|
||
|
ne = bounds.getNorthEast();
|
||
|
|
||
|
return this._projectCoords(crs, sw).concat(this._projectCoords(crs, ne));
|
||
|
},
|
||
|
|
||
|
_projectCoords: function (crs, coords) {
|
||
|
var crsKey = crs.toUpperCase().replace(':', ''),
|
||
|
crsClass = L.CRS[crsKey];
|
||
|
|
||
|
if (!crsClass) {
|
||
|
throw 'Unsupported coordinate reference system: ' + crs;
|
||
|
}
|
||
|
|
||
|
return this._project(crsClass, coords);
|
||
|
},
|
||
|
|
||
|
_project: function (crsClass, coords) {
|
||
|
var projected,
|
||
|
pt,
|
||
|
i, l;
|
||
|
|
||
|
if (typeof coords[0] === 'number') {
|
||
|
coords = new L.LatLng(coords[1], coords[0]);
|
||
|
}
|
||
|
|
||
|
if (coords instanceof L.LatLng) {
|
||
|
pt = crsClass.project(coords);
|
||
|
return [pt.x, pt.y];
|
||
|
} else {
|
||
|
projected = [];
|
||
|
for (i = 0, l = coords.length; i < l; i++) {
|
||
|
projected.push(this._project(crsClass, coords[i]));
|
||
|
}
|
||
|
return projected;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
// --------------------------------------------------
|
||
|
// Event handlers
|
||
|
// --------------------------------------------------
|
||
|
|
||
|
onCapabilitiesLoad: function (response) {
|
||
|
this._capabilities = response;
|
||
|
|
||
|
if (!this.options.layout) {
|
||
|
this.options.layout = this._capabilities.layouts[0].name;
|
||
|
}
|
||
|
|
||
|
if (!this.options.dpi) {
|
||
|
this.options.dpi = this._capabilities.dpis[0].value;
|
||
|
}
|
||
|
|
||
|
this.fire('capabilitiesload', {
|
||
|
provider: this,
|
||
|
capabilities: this._capabilities
|
||
|
});
|
||
|
},
|
||
|
|
||
|
onPrintSuccess: function (response) {
|
||
|
var url = response.getURL + (L.Browser.ie ? '?inline=true' : '');
|
||
|
|
||
|
if (this.options.autoOpen) {
|
||
|
if (L.Browser.ie) {
|
||
|
window.open(url);
|
||
|
} else {
|
||
|
window.location.href = url;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this._xhr = null;
|
||
|
|
||
|
this.fire('print', {
|
||
|
provider: this,
|
||
|
response: response
|
||
|
});
|
||
|
},
|
||
|
|
||
|
onPrintError: function (jqXHR) {
|
||
|
this._xhr = null;
|
||
|
|
||
|
this.fire('printexception', {
|
||
|
provider: this,
|
||
|
response: jqXHR
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
L.print.provider = function (options) {
|
||
|
return new L.print.Provider(options);
|
||
|
};
|
||
|
|
||
|
|
||
|
/*global L:false*/
|
||
|
|
||
|
L.Control.Print = L.Control.extend({
|
||
|
|
||
|
options: {
|
||
|
position: 'topleft',
|
||
|
showLayouts: true
|
||
|
},
|
||
|
|
||
|
initialize: function (options) {
|
||
|
L.Control.prototype.initialize.call(this, options);
|
||
|
|
||
|
this._actionButtons = {};
|
||
|
this._actionsVisible = false;
|
||
|
|
||
|
if (this.options.provider && this.options.provider instanceof L.print.Provider) {
|
||
|
this._provider = this.options.provider;
|
||
|
} else {
|
||
|
this._provider = L.print.Provider(this.options.provider || {});
|
||
|
}
|
||
|
},
|
||
|
|
||
|
onAdd: function (map) {
|
||
|
var capabilities,
|
||
|
container = L.DomUtil.create('div', 'leaflet-control-print'),
|
||
|
toolbarContainer = L.DomUtil.create('div', 'leaflet-bar', container),
|
||
|
link;
|
||
|
|
||
|
this._toolbarContainer = toolbarContainer;
|
||
|
|
||
|
link = L.DomUtil.create('a', 'leaflet-print-print', toolbarContainer);
|
||
|
link.href = '#';
|
||
|
link.title = 'Print map';
|
||
|
|
||
|
L.DomEvent
|
||
|
.on(link, 'click', L.DomEvent.stopPropagation)
|
||
|
.on(link, 'mousedown', L.DomEvent.stopPropagation)
|
||
|
.on(link, 'dblclick', L.DomEvent.stopPropagation)
|
||
|
.on(link, 'click', L.DomEvent.preventDefault)
|
||
|
.on(link, 'click', this.onPrint, this);
|
||
|
|
||
|
if (this.options.showLayouts) {
|
||
|
capabilities = this._provider.getCapabilities();
|
||
|
if (!capabilities) {
|
||
|
this._provider.once('capabilitiesload', this.onCapabilitiesLoad, this);
|
||
|
} else {
|
||
|
this._createActions(container, capabilities);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this._provider.setMap(map);
|
||
|
|
||
|
return container;
|
||
|
},
|
||
|
|
||
|
onRemove: function () {
|
||
|
var buttonId,
|
||
|
button;
|
||
|
|
||
|
for (buttonId in this._actionButtons) {
|
||
|
if (this._actionButtons.hasOwnProperty(buttonId)) {
|
||
|
button = this._actionButtons[buttonId];
|
||
|
this._disposeButton(button.button, button.callback, button.scope);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this._actionButtons = {};
|
||
|
this._actionsContainer = null;
|
||
|
},
|
||
|
|
||
|
getProvider: function () {
|
||
|
return this._provider;
|
||
|
},
|
||
|
|
||
|
_createActions: function (container, capabilities) {
|
||
|
var layouts = capabilities.layouts,
|
||
|
l = layouts.length,
|
||
|
actionsContainer = L.DomUtil.create('ul', 'leaflet-print-actions', container),
|
||
|
buttonWidth = 100,
|
||
|
containerWidth = (l * buttonWidth) + (l - 1),
|
||
|
button,
|
||
|
li,
|
||
|
i;
|
||
|
|
||
|
actionsContainer.style.width = containerWidth + 'px';
|
||
|
|
||
|
for (i = 0; i < l; i++) {
|
||
|
li = L.DomUtil.create('li', '', actionsContainer);
|
||
|
|
||
|
button = this._createButton({
|
||
|
title: 'Print map using the ' + layouts[i].name + ' layout',
|
||
|
text: this._ellipsis(layouts[i].name, 16),
|
||
|
container: li,
|
||
|
callback: this.onActionClick,
|
||
|
context: this
|
||
|
});
|
||
|
|
||
|
this._actionButtons[L.stamp(button)] = {
|
||
|
name: layouts[i].name,
|
||
|
button: button,
|
||
|
callback: this.onActionClick,
|
||
|
context: this
|
||
|
};
|
||
|
}
|
||
|
|
||
|
this._actionsContainer = actionsContainer;
|
||
|
},
|
||
|
|
||
|
_createButton: function (options) {
|
||
|
var link = L.DomUtil.create('a', options.className || '', options.container);
|
||
|
link.href = '#';
|
||
|
|
||
|
if (options.text) {
|
||
|
link.innerHTML = options.text;
|
||
|
}
|
||
|
|
||
|
if (options.title) {
|
||
|
link.title = options.title;
|
||
|
}
|
||
|
|
||
|
L.DomEvent
|
||
|
.on(link, 'click', L.DomEvent.stopPropagation)
|
||
|
.on(link, 'mousedown', L.DomEvent.stopPropagation)
|
||
|
.on(link, 'dblclick', L.DomEvent.stopPropagation)
|
||
|
.on(link, 'click', L.DomEvent.preventDefault)
|
||
|
.on(link, 'click', options.callback, options.context);
|
||
|
|
||
|
return link;
|
||
|
},
|
||
|
|
||
|
_showActionsToolbar: function () {
|
||
|
L.DomUtil.addClass(this._toolbarContainer, 'leaflet-print-actions-visible');
|
||
|
this._actionsContainer.style.display = 'block';
|
||
|
|
||
|
this._actionsVisible = true;
|
||
|
},
|
||
|
|
||
|
_hideActionsToolbar: function () {
|
||
|
this._actionsContainer.style.display = 'none';
|
||
|
L.DomUtil.removeClass(this._toolbarContainer, 'leaflet-print-actions-visible');
|
||
|
|
||
|
this._actionsVisible = false;
|
||
|
},
|
||
|
|
||
|
_ellipsis: function (value, len) {
|
||
|
if (value && value.length > len) {
|
||
|
value = value.substr(0, len - 3) + '...';
|
||
|
}
|
||
|
return value;
|
||
|
},
|
||
|
|
||
|
// --------------------------------------------------
|
||
|
// Event Handlers
|
||
|
// --------------------------------------------------
|
||
|
|
||
|
onCapabilitiesLoad: function (event) {
|
||
|
this._createActions(this._container, event.capabilities);
|
||
|
},
|
||
|
|
||
|
onActionClick: function (event) {
|
||
|
var id = '' + L.stamp(event.target),
|
||
|
button,
|
||
|
buttonId;
|
||
|
|
||
|
for (buttonId in this._actionButtons) {
|
||
|
if (this._actionButtons.hasOwnProperty(buttonId) && buttonId === id) {
|
||
|
button = this._actionButtons[buttonId];
|
||
|
this._provider.print({
|
||
|
layout: button.name
|
||
|
});
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
this._hideActionsToolbar();
|
||
|
},
|
||
|
|
||
|
onPrint: function () {
|
||
|
if (this.options.showLayouts) {
|
||
|
if (!this._actionsVisible) {
|
||
|
this._showActionsToolbar();
|
||
|
} else {
|
||
|
this._hideActionsToolbar();
|
||
|
}
|
||
|
} else {
|
||
|
this._provider.print();
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
L.control.print = function (options) {
|
||
|
return new L.Control.Print(options);
|
||
|
};
|
||
|
|
||
|
|
||
|
}(this, document));
|