Skip to content

Instantly share code, notes, and snippets.

@tmcw
Created August 14, 2014 18:01
Show Gist options
  • Save tmcw/49d7e51f4012e2e86961 to your computer and use it in GitHub Desktop.
Save tmcw/49d7e51f4012e2e86961 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>Leaflet Image</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.tiles.mapbox.com/mapbox.js/v2.0.1/mapbox.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox.js/v2.0.1/mapbox.css' rel='stylesheet' />
<style>
body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width:100%; }
</style>
</head>
<body>
<style>
.ui-button {
position:absolute;
top:10px;
right:10px;
z-index:1000;
}
#map {
width:50%;
}
#snapshot {
position:absolute;
top:0;bottom:0;right:0;
width:50%;
}
</style>
<button id='snap' class='ui-button'>Take a snapshot</button>
<div id='snapshot'></div>
<div id='map'></div>
<script src='https://api.tiles.mapbox.com/mapbox.js/plugins/leaflet-heat/v0.1.0/leaflet-heat.js'></script>
<script src='leaflet-image.js'></script>
<script>
L.mapbox.accessToken = 'pk.eyJ1IjoidG1jdyIsImEiOiJIZmRUQjRBIn0.lRARalfaGHnPdRcc-7QZYQ';
var snapshot = document.getElementById('snapshot');
var map = L.mapbox.map('map', 'examples.map-i875kd35')
.setView([38.88995, -77.00906], 15);
document.getElementById('snap').addEventListener('click', function() {
leafletImage(map, doImage);
});
function doImage(err, canvas) {
var img = document.createElement('img');
var dimensions = map.getSize();
img.width = dimensions.x;
img.height = dimensions.y;
img.src = canvas.toDataURL();
snapshot.innerHTML = '';
snapshot.appendChild(img);
}
var heat = L.heatLayer([], {maxZoom: 18}).addTo(map);
var draw = true;
// add points on mouse move (except when interacting with the map)
map.on({
movestart: function () { draw = false; },
moveend: function () { draw = true; },
mousemove: function (e) {
if (draw) {
heat.addLatLng(e.latlng);
}
}
})
</script>
</body>
</html>
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.leafletImage=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
var queue = _dereq_('./queue');
// leaflet-image
module.exports = function leafletImage(map, callback) {
var dimensions = map.getSize(),
layerQueue = new queue(1);
var canvas = document.createElement('canvas');
canvas.width = dimensions.x;
canvas.height = dimensions.y;
var ctx = canvas.getContext('2d');
// layers are drawn in the same order as they are composed in the DOM:
// tiles, paths, and then markers
map.eachLayer(drawTileLayer);
if (map._pathRoot) layerQueue.defer(handlePathRoot, map._pathRoot);
map.eachLayer(drawMarkerLayer);
layerQueue.awaitAll(layersDone);
function drawTileLayer(l) {
if (l instanceof L.TileLayer) layerQueue.defer(handleTileLayer, l);
else if (l._heat) layerQueue.defer(handlePathRoot, l._canvas);
}
function drawMarkerLayer(l) {
if (l instanceof L.Marker && l.options.icon instanceof L.Icon) {
layerQueue.defer(handleMarkerLayer, l);
}
}
function done() {
callback(null, canvas);
}
function layersDone(err, layers) {
if (err) throw err;
layers.forEach(function(layer) {
if (layer && layer.canvas) {
ctx.drawImage(layer.canvas, 0, 0);
}
});
done();
}
function handleTileLayer(layer, callback) {
var canvas = document.createElement('canvas');
canvas.width = dimensions.x;
canvas.height = dimensions.y;
var ctx = canvas.getContext('2d'),
bounds = map.getPixelBounds(),
origin = map.getPixelOrigin(),
zoom = map.getZoom(),
tileSize = layer.options.tileSize;
if (zoom > layer.options.maxZoom ||
zoom < layer.options.minZoom ||
// mapbox.tileLayer
(layer.options.format && !layer.options.tiles)) {
return callback();
}
var offset = new L.Point(
((origin.x / tileSize) - Math.floor(origin.x / tileSize)) * tileSize,
((origin.y / tileSize) - Math.floor(origin.y / tileSize)) * tileSize
);
var tileBounds = L.bounds(
bounds.min.divideBy(tileSize)._floor(),
bounds.max.divideBy(tileSize)._floor()),
tiles = [],
center = tileBounds.getCenter(),
j, i, point,
tileQueue = new queue(1);
for (j = tileBounds.min.y; j <= tileBounds.max.y; j++) {
for (i = tileBounds.min.x; i <= tileBounds.max.x; i++) {
tiles.push(new L.Point(i, j));
}
}
tiles.forEach(function(tilePoint) {
var originalTilePoint = tilePoint.clone();
layer._adjustTilePoint(tilePoint);
var tilePos = layer._getTilePos(originalTilePoint)
.subtract(bounds.min)
.add(origin);
if (tilePoint.y >= 0) {
var url = addCacheString(layer.getTileUrl(tilePoint));
tileQueue.defer(loadTile, url, tilePos, tileSize);
}
});
tileQueue.awaitAll(tileQueueFinish);
function loadTile(url, tilePos, tileSize, callback) {
var im = new Image();
im.crossOrigin = '';
im.onload = function() {
callback(null, {
img: this,
pos: tilePos,
size: tileSize
});
};
im.src = url;
}
function tileQueueFinish(err, data) {
data.forEach(drawTile);
callback(null, { canvas: canvas });
}
function drawTile(d) {
ctx.drawImage(d.img, Math.floor(d.pos.x), Math.floor(d.pos.y),
d.size, d.size);
}
}
function handlePathRoot(root, callback) {
var bounds = map.getPixelBounds(),
origin = map.getPixelOrigin(),
canvas = document.createElement('canvas');
canvas.width = dimensions.x;
canvas.height = dimensions.y;
var ctx = canvas.getContext('2d');
var pos = L.DomUtil.getPosition(root).subtract(bounds.min).add(origin);
ctx.drawImage(root, pos.x, pos.y);
callback(null, {
canvas: canvas
});
}
function handleMarkerLayer(marker, callback) {
var canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d'),
pixelBounds = map.getPixelBounds(),
minPoint = new L.Point(pixelBounds.min.x, pixelBounds.min.y),
pixelPoint = map.project(marker.getLatLng()),
url = addCacheString(marker._icon.src),
im = new Image(),
options = marker.options.icon.options,
size = options.iconSize,
pos = pixelPoint.subtract(minPoint),
anchor = L.point(options.iconAnchor || size && size.divideBy(2, true)),
x = pos.x - size[0] + anchor.x,
y = pos.y - anchor.y;
canvas.width = dimensions.x;
canvas.height = dimensions.y;
im.crossOrigin = '';
im.onload = function() {
ctx.drawImage(this, x, y, size[0], size[1]);
callback(null, {
canvas: canvas
});
};
im.src = url;
}
function addCacheString(url) {
return url + ((url.match(/\?/)) ? '&' : '?') + 'cache=' + (+new Date());
}
};
},{"./queue":2}],2:[function(_dereq_,module,exports){
(function() {
if (typeof module === "undefined") self.queue = queue;
else module.exports = queue;
queue.version = "1.0.4";
var slice = [].slice;
function queue(parallelism) {
var q,
tasks = [],
started = 0, // number of tasks that have been started (and perhaps finished)
active = 0, // number of tasks currently being executed (started but not finished)
remaining = 0, // number of tasks not yet finished
popping, // inside a synchronous task callback?
error = null,
await = noop,
all;
if (!parallelism) parallelism = Infinity;
function pop() {
while (popping = started < tasks.length && active < parallelism) {
var i = started++,
t = tasks[i],
a = slice.call(t, 1);
a.push(callback(i));
++active;
t[0].apply(null, a);
}
}
function callback(i) {
return function(e, r) {
--active;
if (error != null) return;
if (e != null) {
error = e; // ignore new tasks and squelch active callbacks
started = remaining = NaN; // stop queued tasks from starting
notify();
} else {
tasks[i] = r;
if (--remaining) popping || pop();
else notify();
}
};
}
function notify() {
if (error != null) await(error);
else if (all) await(error, tasks);
else await.apply(null, [error].concat(tasks));
}
return q = {
defer: function() {
if (!error) {
tasks.push(arguments);
++remaining;
pop();
}
return q;
},
await: function(f) {
await = f;
all = false;
if (!remaining) notify();
return q;
},
awaitAll: function(f) {
await = f;
all = true;
if (!remaining) notify();
return q;
}
};
}
function noop() {}
})();
},{}]},{},[1])
(1)
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment