Public
Edited
May 17
Insert cell
Insert cell
//if you want to use a different file use the file upload thing and change this to file.json()
boundsfile = sprucepine03
Insert cell
sprucepine03 = FileAttachment("sprucepine03.geojson").json()
Insert cell
boundingBox = turf.bbox(boundsfile)
Insert cell
viewof file = Inputs.file({ label: "Upload geoJSON" })
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
levels = 50
Insert cell
Insert cell
alltiles = turf.dissolve(
turf.featureCollection(
tiles
.map((t) => tilebelt.tileToGeoJSON([t.x, t.y, t.z]))
.map((m) => {
return { type: "Feature", geometry: m };
})
)
)
Insert cell
Insert cell
Insert cell
tiles.translate
Insert cell
(xyz_tiles.scale = 256)
Insert cell
(xyz_tiles.translate = alt_projection.translate())
Insert cell
alt_projection = d3
.geoMercator()
.center(turf.center(boundsfile).geometry.coordinates)
//.translate([0, 0])
//.scale(Math.pow(2, 21) / (2 * Math.PI))
.fitExtent(
[
[0, 0],
[width, height]
],
turf.rewind(boundsfile, { reverse: true })
)
//.fitSize([width, height], turf.rewind(boundsfile, { reverse: true }))
Insert cell
altsize = Math.ceil(Math.sqrt(xyz_tiles.length) * 256)
Insert cell
Insert cell
Insert cell
Insert cell
tileSize = 256
Insert cell
tileDim = 256
Insert cell
gridSize = tileSize + 1
Insert cell
height = 1200
Insert cell
width = 1200
Insert cell
heightExtent = rgbextent
Insert cell
palestine_full_no_golan = FileAttachment("palestine_full_no_golan.geojson").json()
Insert cell
sealevel = -0.6999999999989086
Insert cell
revisedExtent = d3.extent(ele.flat())
Insert cell
rgbextent = d3.extent(rgbarr.map((r) => r.h))
Insert cell
lowest_pixel = rgbarr.sort((a, b) => a.h - b.h)[0]
Insert cell
shuffle = tiles.sort(() => 0.5 - Math.random()).slice(1, tiles.length * 0.2)
Insert cell
Insert cell
Insert cell
getDemData = function ({ x, y, z }) {
const url = `https://api.mapbox.com/v4/mapbox.terrain-rgb/${z}/${x}/${y}.pngraw?access_token=${mapbox}`;

return new Promise((resolve, reject) => {
const image = new Image();
image.crossOrigin = "anonymous";
image.onerror = reject;
image.src = url;

image.onload = () => {
const canvas = DOM.canvas(tileSize, tileSize);
const ctx = canvas.getContext("2d");

ctx.drawImage(
image,
0,
0,
image.width,
image.height,
0,
0,
tileDim,
tileDim
);
const rawData = ctx.getImageData(0, 0, image.width, image.height).data;
resolve(rawData);
};
});
}
Insert cell
(tiles[0].x + tiles.translate[0]) * tiles.scale
Insert cell
ele = getElevationData(turf.bbox(boundsfile), height, width)
Insert cell
size = Math.sqrt(rgbarr.length)
Insert cell
heightExtent[1] - heightExtent[0]
Insert cell
Insert cell
isolines = {
return heightThresholds.map((lower) => {
return {
lines: MarchingSquares.isoBands(ele, lower, heightExtent[1] + 1, {
noFrame: false,
linearRing: true
}),
threshold: lower
};
});
// .filter((d) => {
// return d.lines.length > 0;
// });
}
Insert cell
northbend = FileAttachment("northbend.geojson").json()
Insert cell
xScale = d3.scaleLinear().domain([0, size]).range([-10, 10])
Insert cell
yScale = d3.scaleLinear().domain([0, size]).range([-10, 10])
Insert cell
zScale = d3.scaleLinear().domain(heightExtent).range([0, terrainExaggeration])
Insert cell
edges = Object.assign({
top: ele[0],
bottom: ele[ele.length - 1],
left: ele.map((r) => r[0]),
right: ele.map((r) => r[ele.length - 1])
})
Insert cell
parameters = Object.assign({ ...worldParameters, ...perspectiveParameters })
Insert cell
Insert cell
scene = {
let scene = [];
let scale = 0.075;

//const allRings = []
isolines.forEach((lvl, i) => {
//lvl.lines.forEach((isoline) => {
//const lvl = isolines[levelIndex]
lvl.lines.forEach((isoline) => {
let entity = simplify(
isoline.map((d) => {
return { x: d[0], y: d[1] };
}),
lineSimplification
).map((c) => {
let copy = [xScale(c.x), yScale(c.y), zScale(lvl.threshold), 1];

return copy;
});

entity.closed = true;
entity.fillColor = "white";
entity.fillOpacity = 0.1;
entity.strokeWidth = 0.5;
entity.groupname = `group${lvl.threshold}`;

scene.push(entity);
});
});

// scene.push(label);

// const east = [[14, 0, terrainExaggeration / 2, 1]];
// east.text = "E";
// east.textAnchor = "middle";

// const west = [[-14, 0, terrainExaggeration / 2, 1]];
// west.text = "W";
// west.textAnchor = "middle";

// const south = [[0, 14, terrainExaggeration / 2, 1]];
// south.text = "S";
// south.textAnchor = "middle";

// const north = [[0, -14, terrainExaggeration / 2, 1]];
// north.text = "N";
// north.textAnchor = "middle";

// scene.push(north);
// scene.push(south);
// scene.push(east);
// scene.push(west);

return scene;
}
Insert cell
processedScene = {
var t0 = performance.now();
const result = processScene(scene, parameters);
var t1 = performance.now();

console.log(`processor: ${t1 - t0}`);

return result;
}
Insert cell
processedscene_layer = d3
.nest()
.key((d) => d.groupname)
.entries(processedScene)
.map((m) => {
m.values.flat();
return m;
})
Insert cell
anaglyphRenderer = (processedScene) => {
var t0 = performance.now();

const leftLayer = [];
const rightLayer = [];

const behindProjectionPlane = (item) => {
return item.map((points) => {
points.map((d) => d[0][2]).find((d) => d <= 0) === undefined &&
points.map((d) => d[1][2]).find((d) => d <= 0) === undefined;
});

return true;
};

let allLeftPath = "";
let allRightPath = "";

const svgStuff = processedscene_layer.map((m) => {
leftLayer.push(
svg`<g id=${m.key}>${m.values
.filter(behindProjectionPlane)
.map((item) => {
const leftPath =
"M " +
item.map((p) => `${p[0][0]} ${p[0][1]}`).join(" L ") +
(item.closed ? " Z" : "");
const rightPath =
"M " +
item.map((p) => `${p[1][0]} ${p[1][1]}`).join(" L ") +
(item.closed ? " Z" : "");

// allLeftPath += ' ' + leftPath
// allRightPath += ' ' + rightPath

return svg`<path d="${leftPath}" fill="${
item.fillColor ? item.fillColor : "none"
}" fill-opacity = ${item.fillOpacity} stroke="black" stroke-width="${
item.strokeWidth ? item.strokeWidth : 1
}"/>`;
})}</g>`
);
});

// if (allLeftPath !== '') {
// leftLayer.push(svg`<path d="${allLeftPath}" fill="white" stroke="${colors.left}" stroke-width="1" style="mix-blend-mode: multiply;" />`)
// }

// if (allRightPath !== '') {
// rightLayer.push(svg`<path d="${allRightPath}" fill="white" stroke="${colors.right}" stroke-width="1" style="mix-blend-mode: multiply;" />`)
// }

var t1 = performance.now();

console.log(`renderer: ${t1 - t0}`);

return svg`<g>
<g transform="translate(${width / 2},${
width / 2
})" style="mix-blend-mode: multiply;">
${rightLayer}
</g>
<g transform="translate(${width / 2},${
width/ 2
})" style="mix-blend-mode: multiply;">
${leftLayer}
</g>
</g>`;
}
Insert cell
import {
renderer,
processScene
} with { height } from "@tonyhschu/anaglyph-pipeline-in-gpujs"
Insert cell
import { rasterize } from "@mbostock/saving-svg"
Insert cell
canvas = async (t) => {
let img = new Image();
img.crossOrigin = "anonymous";
img.src = url(t);
await new Promise((resolve) => img.addEventListener("load", resolve));
let ctx = DOM.canvas(img.width, img.height).getContext("2d");
ctx.drawImage(img, 0, 0);
return ctx.canvas;
}
Insert cell
url = (t) =>
`https://api.mapbox.com/v4/mapbox.terrain-rgb/${t.z}/${t.x}/${t.y}.png?access_token=${mapbox}`
Insert cell
Insert cell
import { drawGrid } from "@mourner/martin-real-time-rtin-terrain-mesh"
Insert cell
d3 = require("d3-geo@1", "d3-selection@1", "d3-fetch@1", "d3-tile@0.0", "d3-scale@2.1.2", "d3-collection@latest", "d3-array@3", "d3", "d3-color")
Insert cell
path = d3.geoPath(projection)
Insert cell
turf = require("@turf/turf@latest")
Insert cell
xyz = require("https://bundle.run/xyz-affair@0.9.1")
Insert cell
tilebelt = import("https://cdn.skypack.dev/@mapbox/tilebelt@1.0.2?min")
Insert cell
mapbox = "pk.eyJ1IjoibGlmZXdpbm5pbmciLCJhIjoiY2t6bXA2dWZlMmtzbTJ2bjJ0ZTdwYnoyNyJ9.cF_Xt3B9htHIUD0lAKXaRg"
Insert cell
MarchingSquares = import(
"https://unpkg.com/marchingsquares@1.3.3/dist/marchingsquares-esm.js?module"
)
Insert cell
simplify = require("simplify-js")
Insert cell
import { view } from "@tomlarkworthy/view"
Insert cell
import { convertToHeight } from "@dvreed77/tiled-elevation-data"
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