Public
Edited
Apr 28, 2024
Insert cell
Insert cell
container = html `<div style="height:450px;"></div>`
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
defaultProps = {
return {
// Center of each circle, in [longitude, latitude, (z)]
getPosition: {type: 'accessor', value: x => x.position},
// Radius of each circle, in meters
getRadius: {type: 'accessor', value: 1},
// Color of each circle, in [R, G, B, (A)]
getColor: {type: 'accessor', value: [0, 0, 0, 255]},
// Amount to soften the edges
smoothRadius: {type: 'number', min: 0, value: 0.5},
}
}
Insert cell
layer0 = {
const {Layer} = deck;
// Our custom layer class
class ScatterplotLayer extends Layer {
initializeState() {
// TODO
}
updateState() {
// TODO
}
}
ScatterplotLayer.layerName = 'ScatterplotLayer';
ScatterplotLayer.defaultProps = defaultProps;

return new ScatterplotLayer({
id: `scatterplot-${Date.now()}`,
data,
getPosition: d => d.position,
getRadius: d => d.size,
getColor: d => d.color
});
}
Insert cell
Insert cell
layer0.props.smoothRadius
Insert cell
Insert cell
// vertexShader = `
// attribute vec3 positions;
// attribute vec3 instancePositions;
// attribute vec3 instancePositions64Low;
// attribute float instanceRadius;
// attribute vec4 instanceColors;

// varying vec4 vColor;
// varying vec2 vPosition;

// void main(void) {
// vec3 offsetCommon = positions * project_size(instanceRadius);
// vec3 positionCommon = project_position(instancePositions, instancePositions64Low);
// gl_Position = project_common_position_to_clipspace(vec4(positionCommon + offsetCommon, 1.0));

// vPosition = positions.xy;
// vColor = instanceColors;
// }`


vertexShader = `
#version 300 es

in vec3 positions;
in vec3 instancePositions;
in vec3 instancePositions64Low;
in float instanceRadius;
in vec4 instanceColors;

out vec4 vColor;
out vec2 vPosition;

void main(void) {
vec3 offsetCommon = positions * project_size(instanceRadius);
vec3 positionCommon = project_position(instancePositions, instancePositions64Low);
gl_Position = project_common_position_to_clipspace(vec4(positionCommon + offsetCommon, 1.0));

vPosition = positions.xy;
vColor = instanceColors;
}


`
Insert cell
// fragmentShader = `
// precision highp float;

// uniform float smoothRadius;

// varying vec4 vColor;
// varying vec2 vPosition;

// void main(void) {
// float distToCenter = length(vPosition);

// if (distToCenter > 1.0) {
// discard;
// }

// float alpha = smoothstep(1.0, 1.0 - smoothRadius, distToCenter);
// gl_FragColor = vec4(vColor.rgb, vColor.a * alpha);
// }`;

fragmentShader = `

#version 300 es
precision highp float;

in vec4 vColor;
in vec2 vPosition;
out vec4 fragColor;

uniform float smoothRadius;

void main(void) {
float distToCenter = length(vPosition);

if (distToCenter > 1.0) {
discard;
}

float alpha = smoothstep(1.0, 1.0 - smoothRadius, distToCenter);
fragColor = vec4(vColor.rgb, vColor.a * alpha);
}


`
Insert cell
Insert cell
// getModel = {
// const {Model, Geometry} = luma;
// return gl => {
// // Four corners of the quad
// const positions = new Float32Array([-1, -1, -1, 1, 1, 1, 1, -1]);
// const geometry = new Geometry({
// drawMode: gl.TRIANGLE_FAN,
// vertexCount: 4,
// attributes: {
// positions: {size: 2, value: positions}
// }
// });
// return new Model(gl, {vs: vertexShader, fs: fragmentShader, geometry, isInstanced: true});
// }
// }

// getModel = {
// const {Model, Geometry} = luma;
// return gl => {
// const positions = new Float32Array([-1, -1, 0, 1, 1, 0, 1, -1, 0]);
// const geometry = new Geometry({
// drawMode: gl.TRIANGLE_FAN,
// vertexCount: 4,
// attributes: {
// positions: {size: 3, value: positions}
// }
// });

// return new Model(gl, {
// vs: vertexShader,
// fs: fragmentShader,
// geometry,
// isInstanced: true
// });
// }
// }


getModel = {
const {Model, Geometry} = luma;

return gl => {
const positions = new Float32Array([-1, -1, 0, 1, 1, 0, 1, -1, 0]);
const geometry = new Geometry({
drawMode: gl.TRIANGLE_FAN,
vertexCount: 4,
attributes: {
positions: {size: 2, value: positions}
}
});

const model = new Model(gl, {
vs: vertexShader,
fs: fragmentShader,
geometry,
isInstanced: true
});

model.on('error', (error) => console.error('Model error:', error));

return model;
}
}

Insert cell
Insert cell
layer2 = {
const {Layer} = deck;
class ScatterplotLayer extends Layer {
// initializeState() {
// const {gl} = this.context;

// console.log('FLOAT', gl.FLOAT); // Should log 5126
// console.log('UNSIGNED_BYTE', gl.UNSIGNED_BYTE); // Should log 5121

// console.log('WebGL Version:', gl.getParameter(gl.VERSION));
// console.log('WebGL Renderer:', gl.getParameter(gl.RENDERER));

// // Register attributes
// this.getAttributeManager().addInstanced({
// instancePositions: {
// size: 3,
// type: gl.FLOAT, // Changed from gl.DOUBLE to gl.FLOAT
// accessor: 'getPosition'
// },
// instanceRadius: {
// size: 1,
// accessor: 'getRadius',
// defaultValue: 1
// },
// instanceColors: {
// size: 4,
// normalized: true,
// type: gl.UNSIGNED_BYTE,
// accessor: 'getColor',
// defaultValue: [0, 0, 0, 255]
// }
// });
// // Save the model in layer state
// this.setState({
// model: getModel(gl)
// });
// }

initializeState() {
const {gl} = this.context;
this.getAttributeManager().addInstanced({
instancePositions: {
size: 3,
type: gl.FLOAT,
accessor: () => [0, 0, 0], // Hardcoded value for testing
defaultValue: [0, 0, 0]
},
instanceRadius: {
size: 1,
accessor: () => 1, // Hardcoded value for testing
defaultValue: 1
},
instanceColors: {
size: 4,
type: gl.UNSIGNED_BYTE,
normalized: true,
accessor: () => [255, 0, 0, 255], // Hardcoded value for testing
defaultValue: [0, 0, 0, 255]
}
});
const model = getModel(gl);
if (model) {
this.setState({model});
} else {
console.error('Model failed to initialize');
}
}
// updateState() {
// // Retrieve the model from layer state
// this.state.model.setUniforms({
// smoothRadius: this.props.smoothRadius
// });
// }

updateState({props, oldProps, changeFlags}) {
if (changeFlags.dataChanged) {
console.log('Data changed, updating attributes');
this.getAttributeManager().invalidateAll();
}
if (this.state.model) {
try {
this.state.model.setUniforms({smoothRadius: this.props.smoothRadius});
} catch (error) {
console.error('Error updating model uniforms:', error);
}
} else {
console.error('Model not initialized');
}
}
}
ScatterplotLayer.layerName = 'ScatterplotLayer';
ScatterplotLayer.defaultProps = defaultProps;

const layer = new ScatterplotLayer({
id: `scatterplot-${Date.now()}`,
data,
getPosition: d => d.position,
getRadius: d => d.size,
getColor: d => d.color
});
deckgl.setProps({layers: [layer]});
return layer;
}
Insert cell
Insert cell
layer2.getAttributeManager().getAttributes();
Insert cell
Insert cell
deck = require.alias({
// optional dependencies
h3: {}
})('deck.gl@latest/dist.min.js')

// deck = require.alias({
// // optional dependencies
// h3: {}
// })('deck.gl@8.9.1/dist.min.js')
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