Public
Edited
Mar 26, 2024
Insert cell
Insert cell
viewof MapView_3 = {
const segments = LineSegments;

await visibility();
const map = new _MapLibre({ height: 800, zoom: 12.55 });
yield map.attach;

const ScaleFunction = (x) => 0.16 / 2 ** (x - 10);

map.map.on("load", () => {
map.map.addSource("LinesData", {
type: "geojson",
data: RenderLines(ScaleFunction(Math.round(12.55 * 100) / 100)),
lineMetrics: true
});
map.map.addLayer({
id: "LinesMap",
type: "line",
source: "LinesData",
paint: {
"line-color": { type: "identity", property: "stroke" },
"line-width": 3
}
});
});

map.map.on("zoom", () => {
map.map
.getSource("LinesData")
.setData(
RenderLines(ScaleFunction(Math.round(map.map.getZoom() * 100) / 100))
);
});

invalidation.then(map.kill);
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
CompareCoords = {
return (c1, c2) => {
return c1[0] == c2[0] && c1[1] == c2[1];
};
}
Insert cell
ClipLine = {
return (line, distanceFromEdges) => {
if (_Imports.Geospatial.turf.length(line) <= distanceFromEdges * 3) {
return line;
} else {
const StartDistance = _Imports.Geospatial.turf.along(
line,
Math.min(
(_Imports.Geospatial.turf.length(line) / 10) * 4,
distanceFromEdges
)
);
const EndDistance = _Imports.Geospatial.turf.along(
line,
Math.max(
(_Imports.Geospatial.turf.length(line) / 10) * 6,
_Imports.Geospatial.turf.length(line) - distanceFromEdges
)
);

const SlicedLine = _Imports.Geospatial.turf.lineSlice(
StartDistance,
EndDistance,
line
);
try {
return _Imports.Geospatial.turf.cleanCoords(
SlicedLine.geometry.coordinates.length > 4 ? SlicedLine : line
);
} catch (e) {
return line;
}
}
};
}
Insert cell
LineSegments = {
const Segments = new Map();

// add arcs as nodes
for (let i = 0; i < LinesAsTopoJson.arcs.length; i++) {
Segments.set(`Segment:${i}`, {
geometry: LinesAsTopoJson.arcs[i],
top: LinesAsTopoJson.arcs[i][0],
bottom: LinesAsTopoJson.arcs[i][LinesAsTopoJson.arcs[i].length - 1],
colors: [
...new Set(
LinesAsTopoJson.objects.lines.geometries.map((line) => {
if (i < 0 ? line.arcs.includes(i * -1 - 1) : line.arcs.includes(i))
return line.properties.stroke || "#000000";
})
)
].filter((e) => e != null)
});
}

return Segments;
}
Insert cell
Insert cell
LineConnections = {
const Connections = [];

const ConnectionsDedupe = [];

for (const line of LinesAsTopoJson.objects.lines.geometries) {
line.arcs.reduce((acc, cur) => {
const fromId = acc < 0 ? acc * -1 - 1 : acc;
const fromPart = acc < 0 ? "top" : "bottom";
const toId = cur < 0 ? cur * -1 - 1 : cur;
const toPart = cur < 0 ? "bottom" : "top";

const DedupeString = [
line.properties.stroke,
fromId,
fromPart,
toId,
toPart
].join(":");

if (!ConnectionsDedupe.includes(DedupeString)) {
Connections.push({
from: [fromId, fromPart],
to: [toId, toPart],
color: line.properties.stroke
});
ConnectionsDedupe.push(DedupeString);
}

return cur;
});
}
return Connections;
}
Insert cell
RenderLines = {
return (spi) => {
const sp = Math.max(0.00005, Math.round(spi * 10000) / 10000);

const renderedColor = new Map();
const CoordsOfInterest = new Map();

function FindPointsInLine(in_geom, line_buffer) {
return in_geom.reduce(
(acc, cur, idx) => {
const last = acc[acc.length - 1],
next = in_geom[idx + 1];
if (next !== undefined) {
const isTheSame = CompareCoords(last, next);
if (isTheSame) {
return acc;
} else {
acc.push(cur);
return acc;
}
} else {
acc.push(cur);
return acc;
}
},
[in_geom[0]]
);
}

for (const [id, segment] of LineSegments.entries()) {
let linewidth = sp,
spacing = linewidth + sp,
maxline = segment.colors.length;

for (const color of segment.colors) {
const lineoffset =
segment.colors.indexOf(color) * spacing -
((maxline - 1) * spacing) / 2;

const line = _Imports.Geospatial.turf.lineString(segment.geometry, {
stroke: color,
id: `${id}:${color}`
});

const ClippedLine = ClipLine(line, Math.max(0.005, sp * 3));

const offsetClippedLine = _Imports.Geospatial.turf.lineOffset(
ClippedLine,
Math.floor(lineoffset * 10000) / 10000
);

const PointsThatFallInLine = false
? FindPointsInLine(offsetClippedLine.geometry.coordinates)
: offsetClippedLine.geometry.coordinates;

CoordsOfInterest.set(`${id}:${color}:top`, PointsThatFallInLine[0]);
CoordsOfInterest.set(
`${id}:${color}:bottom`,
PointsThatFallInLine[PointsThatFallInLine.length - 1]
);

if (renderedColor.has(color)) {
renderedColor.get(color).push(PointsThatFallInLine);
} else {
renderedColor.set(color, [PointsThatFallInLine]);
}
}
}

for (const connection of LineConnections) {
const coords = [
CoordsOfInterest.get(
`Segment:${connection.from[0]}:${connection.color}:${connection.from[1]}`
),
CoordsOfInterest.get(
`Segment:${connection.to[0]}:${connection.color}:${connection.to[1]}`
)
];

if (!coords.includes(undefined)) {
const line = _Imports.Geospatial.turf.lineString(
FindPointsInLine(coords)
);

renderedColor.get(connection.color).push(line.geometry.coordinates);
}
}

const rendered = [];

for (const [color, coords] of renderedColor.entries()) {
rendered.push(
_Imports.Geospatial.turf.multiLineString(coords, {
id: color,
stroke: color
})
);
}

return _Imports.Geospatial.turf.featureCollection(rendered);
};
}
Insert cell
{
const ScaleFunction = (x) => 0.16 / 2 ** (x - 10);
return RenderLines(ScaleFunction(Math.round(15.07 * 100) / 100));
}
Insert cell
{
const ScaleFunction = (x) => 0.16 / 2 ** (x - 10);
return ScaleFunction(21.5);
}
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