Published
Edited
Feb 3, 2021
1 fork
8 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
styleDoc2 = {
var styleDoc2 = JSON.parse(JSON.stringify(styleDoc));
styleDoc2.sources["states"] = {
type: "geojson",
tiles: tileIndexStates,
minzoom: 0,
maxzoom: 14,
tileSize: 512,
vector_layers: [{ id: "states", minzoom: 0, maxzoom: 14 }]
};
styleDoc2.layers[styleDoc.layers.length] = [
{
id: "states",
type: "circle",
source: "states",
"source-layer": "states",
layout: { visibility: "visible" },
paint: {
"circle-radius": 2,
"circle-color": "#FF0000",
"circle-opacity": 1
}
}
][0];
return styleDoc2;
}
Insert cell
Insert cell
function initGeoJsonLoader(source) {
let layerId = source.vector_layers[0].id;

function request({ z, x, y, callback }) {
var data = [
{ [layerId]: { type: "FeatureCollection", compressed: [{}] } }
][0]; //this is the structure the addPaths is expecting
//console.log("z/x/y: " + z + "/" + x + "/" + y);
var tile = source.tiles.getTile(z, x, y); //request tile
var replacedTile = [];

if (
tile &&
tile !== "null" &&
tile !== "undefined" &&
tile.features.length > 0
) {
for (let i = 0; i < tile.features.length; i++) {
replacedTile[i] = rep(tile.features[i]);
}
data[layerId].compressed = replacedTile;
data[layerId] = addPaths(data[layerId]);
}

function addPaths(data2) {
data2.compressed.forEach(feature => {
feature.path = geomToPath(feature.geometry);
delete feature.geometry;
});
//console.log(JSON.stringify(data2));
return data2;
}

const errMsg =
"ERROR in GeojsonLoader for tile z,x,y = " + [z, x, y].join(",");
if (
tile &&
tile !== "null" &&
tile !== "undefined" &&
tile.features.length > 0
) {
callback(null, data);
} else {
callback(errMsg);
}

function abort() {
//img.src = "";
}
return { abort };
}
return { request };
}
Insert cell
function rep(value) {
if (value.geometry) {
var type;
var rawType = value.type;
var geometry = value.geometry;

if (rawType === 1) {
type = 'MultiPoint';
if (geometry.length == 1) {
type = 'Point';
geometry = geometry[0];
//geometry = [geometry];
}
} else if (rawType === 2) {
type = 'MultiLineString';
if (geometry.length == 1) {
type = 'LineString';
geometry = geometry[0];
}
} else if (rawType === 3) {
type = 'Polygon';
if (geometry.length > 1) {
type = 'MultiPolygon';
geometry = [geometry];
}
}

return {
type: 'Feature',
geometry: {
type: type,
coordinates: geometry
},
properties: value.tags
};
} else {
return value;
}
}
Insert cell
function replacer(value) {
//http://www.scgis.net/api/ol/v4.1.1/examples/geojson-vt.html
if (value.geometry) {
var type;
var rawType = value.type;
var geometry = value.geometry;

if (rawType === 1) {
type = geometry.length === 1 ? 'Point' : 'MultiPoint';
} else if (rawType === 2) {
type = geometry.length === 1 ? 'LineString' : 'MultiLineString';
console.log("line");
} else if (rawType === 3) {
type = geometry.length === 1 ? 'Polygon' : 'MultiPolygon';
}

if (rawType === 1) {
return {
geometry: {
type: type,
coordinates: geometry.length == 1 ? geometry[0] : [geometry]
},
properties: value.tags
};
} else {
return {
geometry: {
type: type,
coordinates: geometry.length == 1 ? geometry : [geometry]
},
properties: value.tags
};
}
} else {
return value;
}
}
Insert cell
function geomToPath(geometry) {
// Converts a GeoJSON Feature geometry to a Path2D object

function pointPath(path, point) {
// Draws a Point geometry, which is an array of two coordinates
//console.log("Inside the pointPath function");
path.moveTo(point[0], point[1]);
path.lineTo(point[0], point[1]);
}

function linePath(path, points) {
// Draws a LineString geometry, which is an array of Points.
var p = points[0],
i = 0,
n = points.length;
console.log("linePath points length: " + n);
path.moveTo(p[0], p[1]);
console.log(p[0] + ", " + p[1]);
while (++i < n) (p = points[i]), path.lineTo(p[0], p[1]);
}

function polygonPath(path, lines) {
// Draws a Polygon geometry, which is an array of LineStrings
//console.log("Inside the polygonPath function");
var i = -1,
n = lines.length;
console.log("PolygonPath lines length: " + n);
while (++i < n) linePath(path, lines[i]);
}

const pathFuncs = {
Point: pointPath,
LineString: linePath,
Polygon: polygonPath
};

var type = geometry.type;
var isMulti = type.substring(0, 5) === "Multi";
if (isMulti) type = type.substring(5);

const pathFunc = pathFuncs[type];

const path = new Path2D();

const coords = geometry.coordinates;

if (isMulti) {
// While loops faster than forEach: https://jsperf.com/loops/32
var i = -1,
n = coords.length;
while (++i < n) pathFunc(path, coords[i]);
} else {
pathFunc(path, coords);
}

return path;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
parsedStyle = tileStencil.loadStyle(styleDoc2)
Insert cell
Insert cell
function initSources(style) {
const queue = chunkedQueue.init();
const { sources, layers } = style;
const getters = {};
const workerMonitors = [];
const listenerDiv = DOM.element("div");

Object.entries(sources).forEach(([key, source]) => {
var loader;
if (source.type === "vector") {
loader = initVectorLoader(key, source);
}
if (source.type === "geojson") {
console.log("Check how often this happens");
loader = initGeoJsonLoader(source);
}
if (source.type === "raster") {
loader = initRasterLoader(source);
}

let tileFactory = buildFactory(loader, listenerDiv);
getters[key] = initSource({ source, tileFactory });
});

function initVectorLoader(key, source) {
let subset = layers.filter(
l => l.source === key && l.type !== "fill-extrusion"
);
let loader = tileMixer.initTileMixer({ source, layers: subset, queue });
workerMonitors.push(loader.workerTasks);
return loader;
}

function getTilesets(viewpt, transfm) {
const tilesets = {};
Object.entries(getters).forEach(([key, getter]) => {
tilesets[key] = getter.getTiles(viewpt, transfm);
});
queue.sortTasks();
return tilesets;
}

return {
getTilesets,
workerTasks: () =>
workerMonitors.reduce((sum, counter) => sum + counter(), 0),
queuedTasks: () => queue.countTasks()
};
}
Insert cell
Insert cell
Insert cell
function initRasterLoader(source) {
const getURL = initUrlFunc(source.tiles);

function request({ z, x, y, callback }) {
const href = getURL(z, x, y);
const errMsg = "ERROR in loadImage for href " + href;

const img = new Image();
img.onerror = () => callback(errMsg);
img.onload = () => {
return img.complete && img.naturalWidth !== 0
? callback(null, img)
: callback(errMsg);
};
img.crossOrigin = "anonymous";
img.src = href;

function abort() {
img.src = "";
}

return { abort };
}

return { request };
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
mutable transform = d3.zoomIdentity
.translate(projection([0, 0])[0], projection([0, 0])[1])
.scale(projection.scale() * 2 * Math.PI)
Insert cell
projection = d3
.geoMercator()
.center([-73.886, 40.745])
.scale(Math.pow(2, 18) / (2 * Math.PI))
.translate([width / 2, reactiveHeight / 2])
Insert cell
Insert cell
Insert cell
Insert cell
//outcropLayer = [{"id":"outcropFeatures", "type":"circle", "source":"outcropFeatures", "source-layer":"outcropFeatures", "layout":{"visibility":"visible"},"paint":{"circle-radius":5, "circle-color":"#FF0000"}}][0]
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
geojsonvt = require('geojson-vt')
Insert cell
d3tileAlternate = {
// Alternate version of d3-tile, that adds minZoom and maxZoom setters
const response = await fetch(
"https://raw.githubusercontent.com/GlobeletJS/d3-tile/master/dist/d3-tile.min.js"
);
const blob = await response.blob();
return require(URL.createObjectURL(blob)).catch(() => window.tileMaxZoom);
}
Insert cell
import { getTileMetric } from "@jjhembd/map-tile-priorities"
Insert cell
d3 = require("d3@5", "d3-geo@1", "d3-tile@1")
Insert cell
tileRack = import("tile-rack@0.2.2")
Insert cell
tilePainter = import("tile-painter@0.3.4")
Insert cell
chunkedQueue = import("chunked-queue@0.1.2")
Insert cell
tileMixer = import("tile-mixer@0.0.8")
Insert cell
tileStencil = import('tile-stencil@0.2.1')
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more