Public
Edited
Dec 1, 2023
Fork of DeckGL
Insert cell
Insert cell
container = html `<div style="height:450px;"></div>`
Insert cell
Insert cell
sdfShaders = ({
inject: {
'vs:#decl': `\
attribute vec4 instancePerimeterSegmentXyzw;
out float distanceToEdge;
`,
'vs:#main-end': `\
vec2 perimeterCommonCoord1 = project_position(instancePerimeterSegmentXyzw.xy);
vec2 perimeterCommonCoord2 = project_position(instancePerimeterSegmentXyzw.zw);

if (perimeterCommonCoord1 == perimeterCommonCoord2) {
distanceToEdge = distance(geometry.position.xy, perimeterCommonCoord1.xy);
}
else {
float x0 = geometry.position.x;
float y0 = geometry.position.y;
float x1 = perimeterCommonCoord1.x;
float y1 = perimeterCommonCoord1.y;
float x2 = perimeterCommonCoord2.x;
float y2 = perimeterCommonCoord2.y;
float numerator = (x2-x1)*(y1-y0)-(x1-x0)*(y2-y1);
float denominator = distance(perimeterCommonCoord1, perimeterCommonCoord2);
distanceToEdge = abs(numerator / denominator);
}
`,
'fs:#decl': `
varying float distanceToEdge;
`,
'fs:DECKGL_FILTER_COLOR': `\
// vec2 pixelCoord = gl_FragCoord.xy; // * pixelsPerClip;
// vec2 commonCoord = pixelCoord * commonUnitsPerPixel;
// float commonDistance = commonDistanceToSegment(commonCoord);
// float pixelDistance = commonDistance / commonUnitsPerPixel;

color.a = distanceToEdge / 255.0;
// color.a = commonCoord.x / 255.0;
// gl_FragCoord.x * pixelsPerClip.x;
// color.a = gl_FragCoord.x / 256.0;
`,
},
})
Insert cell
skel
Insert cell
SdfPolygonLayer = {
class SdfPolygonLayer extends deck.SolidPolygonLayer {
static {
SdfPolygonLayer.layerName = 'SdfPolygonLayer';
SdfPolygonLayer.defaultProps = _.cloneDeep(deck.SolidPolygonLayer.defaultProps);
SdfPolygonLayer.defaultProps.getPerimeterSegment = () => [0,0,0,0];
}

initializeState(params) {
super.initializeState(params);
this.getAttributeManager().addInstanced({
instancePerimeterSegmentXyzw: {
size: 4,
accessor: 'getPerimeterSegment'
},
});
}
getShaders(type) {
// use object.assign to make sure we don't overwrite existing fields like `vs`, `modules`...
let shaders = super.getShaders(type);
shaders = Object.assign({}, shaders, sdfShaders);
return shaders;
}
}

return SdfPolygonLayer;
}
Insert cell
deck.SolidPolygonLayer.defaultProps
Insert cell
MaskedGeoJsonLayer = {

const MASK_LAYER_DEFAULT_PROPS = _.cloneDeep(deck.SolidPolygonLayer.defaultProps);
delete MASK_LAYER_DEFAULT_PROPS.getLineColor;
const MASK_LAYER_MAPPING = {
type: deck.SolidPolygonLayer,
props: {
extruded: 'extruded',
filled: 'filled',
wireframe: 'wireframe',
elevationScale: 'elevationScale',
material: 'material',
_full3d: '_full3d',
getElevation: 'getElevation',
}
};

function forwardProps(layer, mapping) {
const {transitions, updateTriggers} = layer.props;
const result = {
updateTriggers: {},
transitions: transitions && {
getPosition: transitions.geometry
}
};
for (const sourceKey in mapping) {
const targetKey = mapping[sourceKey];
let value = layer.props[sourceKey];
if (sourceKey.startsWith('get')) {
// isAccessor
value = layer.getSubLayerAccessor(value);
result.updateTriggers[targetKey] = updateTriggers[sourceKey];
if (transitions) {
result.transitions[targetKey] = transitions[sourceKey];
}
}
result[targetKey] = value;
}
return result;
}
class MaskedGeoJsonLayer extends deck.GeoJsonLayer {
static {
MaskedGeoJsonLayer.layerName = 'MaskedGeoJsonLayer';
MaskedGeoJsonLayer.defaultProps = _.cloneDeep(deck.GeoJsonLayer.defaultProps);;
MaskedGeoJsonLayer.defaultProps._subLayerProps = {
"polygons-stroke": {
extensions: [ new deck.MaskExtension() ],
maskByInstance: false,
maskId: "polygons-mask"
},
"polygons-mask": {
operation: 'mask',
}
}
}
_renderMaskLayer() {
const {extruded, wireframe} = this.props;
const {layerProps} = this.state;
const id = 'polygons-mask';
const PolygonMaskLayer =
this.shouldRenderSubLayer(id, layerProps.polygons?.data) &&
this.getSubLayerClass(id, MASK_LAYER_MAPPING.type);
if (PolygonMaskLayer) {
const forwardedProps = forwardProps(this, MASK_LAYER_MAPPING.props);
return new PolygonMaskLayer(
forwardedProps,
this.getSubLayerProps({
id,
updateTriggers: forwardedProps.updateTriggers
}),
layerProps.polygons
);
}
return null;
}
renderLayers() {
debugger;
const {extruded} = this.props;
const polygonFillLayer = this._renderPolygonLayer();
const lineLayers = this._renderLineLayers();
const pointLayers = this._renderPointLayers();
const maskLayer = (lineLayers || pointLayers) ? this._renderMaskLayer() : null;
/*
const nonFillLayers = [lineLayers, pointLayers].filter(a => a).flat();
nonFillLayers.forEach(l => {
if (l.extensions?.length) {
debugger;
}
else {
const extension = new deck.MaskExtension();
extension.initializeState.call(l, l.context, extension);
l.extensions.push(extension);
l.setChangeFlags({ extensionsChanged: true });
l.maskId = 'polygons-mask';
}
});*/
return [
// If not extruded: flat fill layer is drawn below outlines
!extruded && polygonFillLayer,
maskLayer,
lineLayers,
pointLayers,
// If extruded: draw fill layer last for correct blending behavior
extruded && polygonFillLayer
];
}
}

return MaskedGeoJsonLayer;
}
Insert cell
spl = new deck.SolidPolygonLayer()
Insert cell
class PolygonBorderLayer extends deck.SolidPolygonLayer {
static {
PolygonBorderLayer.layerName = 'PolygonBorderLayer';
PolygonBorderLayer.POSITIONS = {
CENTER: 0,
INSIDE: 1,
OUTSIDE: 2
}
PolygonBorderLayer.defaultProps = _.cloneDeep(deck.PathLayer.defaultProps);
PolygonBorderLayer.defaultProps.getPosition = { type: 'accessor', value: 0, min: 0, max: 2 };
updateTriggers: {
getFillColor: [maleColor, femaleColor]
}
}

}
Insert cell
Insert cell
class FeaturesLayer extends deck.CompositeLayer {
static {
FeaturesLayer.layerName = "FeaturesLayer";
FeaturesLayer.defaultProps = Object.assign({}, deck.GeoJsonLayer.defaultProps, {
stroked: true,
filled: true,
extruded: false,
wrapLongitude: true,
autoHighlight: true,
lineWidthUnits: 'common',
lineJointRounded: true,
lineWidthMinPixels: 1,
lineWidthMaxPixels: 10,
getLineWidth: 1,
getFillColor: f => [128, 128, 128],
getLineColor: f => [255, 0, 0],
getOffset: f => 0.5,
extensions: [new deck.PathStyleExtension({offset: true})],
getFeatureId: f => f.properties.name
});
}
getForwardedProps() {
const forwarded = { updateTriggers: {} };
for (let key of Object.keys(deck.GeoJsonLayer.defaultProps)) {
if (key in this.props) forwarded[key] = this.props[key];
if (key in this.props.updateTriggers) forwarded.updateTriggers[key] = this.props.updateTriggers[key];
}
return forwarded;
}
renderLayers() {
const layers = [];
for (let feature of this.props.data ?? []) {
const id = this.props.getFeatureId(feature);
const layer = new deck.GeoJsonLayer(this.getForwardedProps(), this.getSubLayerProps({ id }), { data: feature });
layers.push(layer);
}
return layers;
}
}
Insert cell
countries = fetch('https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_admin_0_scale_rank.geojson')
.then(resp => resp.json())
.then(geo => d3.geoStitch(geo))
.then(result => {
// Join results
const countries = new Map();
for (const feature of result.features) {
const name = feature.properties.sr_subunit;
if (!countries.has(name)) countries.set(name, []);
countries.get(name).push(feature);
}
const features = Array.from(countries.entries())
.map(([name, features], i) => {
// const color = [55 + i / 200, 55 + i % 200, 128];
return (features.length === 1)
? turf.polygon(features[0].geometry.coordinates, {name})
: turf.multiPolygon(features.map(f => f.geometry.coordinates), {name});
// turf.coordEach(feature, c => c[2] = i);
});
const fc = turf.featureCollection(features);
return d3.geoStitch(fc);
});
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
w8r = {
const Offset = (await import('https://cdn.skypack.dev/polygon-offset@0.3.2?min')).default;
const { intersection, diff, union, xor } = await import('https://cdn.skypack.dev/martinez-polygon-clipping@0.7.3?min');
return { Offset, intersection, diff, union, xor };
}
Insert cell
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