Skip to content

Instantly share code, notes, and snippets.

@max-mapper
Last active September 30, 2022 22:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save max-mapper/51ec11ea3228d8ecb8b70e228e49d6cb to your computer and use it in GitHub Desktop.
Save max-mapper/51ec11ea3228d8ecb8b70e228e49d6cb to your computer and use it in GitHub Desktop.
la county impervious surface assessor parcel map

install

npm i tessera tilelive-imageserver http-server -g

run

tessera --require=tilelive-imageserver "imageserver:///?source=https://enviroatlas.epa.gov/arcgis/rest/services/Supplemental/Landcover_AllCommunities/ImageServer&maxzoom=18"
http-server

open localhost:8081

<html>
<head>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui"
/>
<link
rel="stylesheet"
href="https://unpkg.com/leaflet@1.8.0/dist/leaflet.css"
crossorigin=""
/>
<script
src="https://unpkg.com/leaflet@1.8.0/dist/leaflet.js"
crossorigin=""
></script>
<script src="http://localhost:8080/zepto/zepto.min.js"></script>
<script src="http://localhost:8080/leaflet-hash/leaflet-hash.js"></script>
<link
href="https://api.tiles.mapbox.com/mapbox-gl-js/v1.5.0/mapbox-gl.css"
rel="stylesheet"
/>
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.5.0/mapbox-gl.js"></script>
<script src="https://unpkg.com/mapbox-gl-leaflet/leaflet-mapbox-gl.js"></script>
<script src="https://unpkg.com/@turf/turf@6/turf.min.js"></script>
<!-- Load Esri Leaflet from CDN -->
<script src="https://unpkg.com/esri-leaflet@^3.0.8/dist/esri-leaflet.js"></script>
<link rel="stylesheet" href="http://localhost:8080/css/l.geosearch.css" />
<style type="text/css">
body,
#map {
height: 100%;
margin: 0;
padding: 0;
background-image: url(images/transparent.png);
}
</style>
</head>
<body>
<div id="map"></div>
<script>
var leaflet = L.map("map", {
scrollWheelZoom: false,
attributionControl: false,
keyboardPanOffset: 256,
maxZoom: 22,
});
if (!location.hash) leaflet.setView([34.0775, -118.2096], 13);
new L.Hash(leaflet);
var mapbox = L.mapboxGL({
accessToken:
"pk.eyJ1Ijoib21lcjA5IiwiYSI6ImNreWJkcjdmczBlYmMydm9mazYwMnBxMm8ifQ.yC2TC8C5hsIFb13-HgP_Pw",
container: "map", // container ID
style: {
version: 8,
sources: {
"raster-tiles": {
type: "raster",
tiles: ["http://localhost:8080/{z}/{x}/{y}.png"],
tileSize: 256,
},
},
layers: [
{
id: "simple-tiles",
type: "raster",
source: "raster-tiles",
minzoom: 0,
maxzoom: 22,
},
],
},
preserveDrawingBuffer: true,
}).addTo(leaflet);
var map = mapbox._glMap;
window.zoningLayer = L.esri
.featureLayer({
url: "https://public.gis.lacounty.gov/public/rest/services/LACounty_Cache/LACounty_Parcel/MapServer/0",
})
.addTo(leaflet);
zoningLayer.bindPopup(
function (el) {
var f = el.feature;
updateArea({ features: [f] });
Object.keys(f.properties).forEach((key) => {
if (!f.properties[key] || f.properties[key] === " ") {
delete f.properties[key];
}
});
return (
"<pre>" +
JSON.stringify(f.properties, null, " ").replace(/[\{\}"]/g, "") +
"</pre>"
);
},
{ maxHeight: "200" }
);
function getPixels(ctx) {
return ctx.readPixels ? getPixels3d(ctx) : getPixels2d(ctx);
}
function getPixels3d(gl) {
var canvas = gl.canvas;
var height = canvas.height;
var width = canvas.width;
var buffer = new Uint8Array(width * height * 4);
gl.readPixels(
0,
0,
canvas.width,
canvas.height,
gl.RGBA,
gl.UNSIGNED_BYTE,
buffer
);
return buffer;
}
function getPixels2d(ctx) {
var canvas = ctx.canvas;
var height = canvas.height;
var width = canvas.width;
return ctx.getImageData(0, 0, width, height).data;
}
function webglToCanvas2d(webgl, canvas2D) {
var outCanvas = canvas2D
? canvas2D.canvas || canvas2D
: document.createElement("canvas");
var outContext = outCanvas.getContext("2d", { antialias: false });
var outImageData;
webgl =
webgl instanceof WebGLRenderingContext
? webgl
: webgl.getContext("webgl", { antialias: false }) ||
webgl.getContext("experimental-webgl", { antialias: false });
outCanvas.width = webgl.canvas.width;
outCanvas.height = webgl.canvas.height;
outImageData = outContext.getImageData(
0,
0,
outCanvas.width,
outCanvas.height
);
outImageData.data.set(new Uint8ClampedArray(getPixels3d(webgl).buffer));
outContext.putImageData(outImageData, 0, 0);
outContext.translate(0, outCanvas.height);
outContext.scale(1, -1);
outContext.drawImage(outCanvas, 0, 0);
outContext.setTransform(1, 0, 0, 1, 0, 0);
return outCanvas;
}
function downloadCanvasAsImage(canvas, fileName) {
console.log(doStats(canvas));
// var link = document.createElement("a");
// link.download = fileName;
// link.href = canvas.toDataURL();
// link.click();
}
var points = [];
var savedPolygon;
function saveClipped() {
var mapCanvas = mapbox._glMap.getCanvas();
var ctx = mapCanvas.getContext("webgl", { antialias: false });
var canvas2d = webglToCanvas2d(ctx);
var ctx2d = canvas2d.getContext("2d", { antialias: false });
var clippedCanvas = document.createElement("canvas");
clippedCanvas.width = mapCanvas.clientWidth;
clippedCanvas.height = mapCanvas.clientHeight;
var clippedCtx = clippedCanvas.getContext("2d", { antialias: false });
var factX = mapCanvas.clientWidth / mapCanvas.width;
var factY = mapCanvas.clientHeight / mapCanvas.height;
var minX = points[0].x;
var maxX = points[0].x;
var minY = points[0].y;
var maxY = points[0].y;
for (var i = 1; i < points.length; i++) {
if (points[i].x < minX) minX = points[i].x;
else if (points[i].x > maxX) {
maxX = points[i].x;
}
if (points[i].y < minY) minY = points[i].y;
else if (points[i].y > maxY) {
maxY = points[i].y;
}
}
clippedCtx.scale(1 / factX, 1 / factY);
clippedCtx.translate(-minX, -minY);
clippedCtx.beginPath();
clippedCtx.moveTo(points[0].x, points[0].y);
for (var i = 1; i < points.length; i++) {
clippedCtx.lineTo(points[i].x, points[i].y);
}
clippedCtx.closePath();
clippedCtx.lineWidth = 1;
clippedCtx.stroke();
clippedCtx.clip();
clippedCtx.scale(factX, factY);
clippedCtx.drawImage(canvas2d, 0, 0);
var finalCanvas = document.createElement("canvas");
var finalWidth = (maxX - minX) / factX;
var finalHeight = (maxY - minY) / factY;
finalCanvas.width = finalWidth;
finalCanvas.height = finalHeight;
var finalCtx = finalCanvas.getContext("2d", { antialias: false });
finalCtx.drawImage(
clippedCanvas,
0,
0,
finalWidth,
finalHeight,
0,
0,
finalWidth,
finalHeight
);
downloadCanvasAsImage(finalCanvas, "clipped-image.png");
}
function updateArea(e) {
points = [];
if (e.features[0].geometry.type == "Polygon") {
savedPolygon = e.features[0];
var polygonId = e.features[0].id;
var coords = savedPolygon.geometry.coordinates[0];
coords.forEach(function (coord) {
points.push(mapbox._glMap.project(coord));
});
setTimeout(saveClipped, 100);
}
}
function doStats(canv) {
var ctx = canv.getContext("2d", { antialias: false });
var imagedata = ctx.getImageData(0, 0, canv.width, canv.height);
var data = imagedata.data;
var counts = {};
var total = 0;
var colors = {
"210,205,192,255": "grey",
"255,0,0,255": "red",
"137,205,102,255": "lightgreen",
"38,115,0,255": "darkgreen",
"205,170,102,255": "tan",
};
for (let i = 0; i < data.length; i += 4) {
var rgba = [data[i], data[i + 1], data[i + 2], data[i + 3]];
var str = rgba.join(",");
// console.log(rgba, str, counts[str]);
if (!counts[str]) counts[str] = 1;
else counts[str]++;
if (colors[str]) total++;
}
var results = [];
Object.keys(colors).forEach((c) => {
var color = colors[c];
var count = counts[c] || 0;
results.push({
color,
count,
percent: (count / total) * 100,
});
});
return results;
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment