Skip to content

Commit 2c81ee9

Browse files
donmccurdyDon McCurdy
andauthored
[website] Migrate 'plot' example to deck.gl v9 (#8289)
- update to deck.gl v9 API - use TypeScript for example layers - small changes to allow stricter types --------- Co-authored-by: Don McCurdy <donmccurdy@cartodb.com>
1 parent dcb297a commit 2c81ee9

File tree

8 files changed

+291
-157
lines changed

8 files changed

+291
-157
lines changed

examples/website/plot/app.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ export default function App({resolution = 200, showAxis = true, equation = EQUAT
2828
equation &&
2929
resolution &&
3030
new PlotLayer({
31-
getPosition: (u, v) => {
31+
getPosition: ([u, v]) => {
3232
const x = (u - 1 / 2) * Math.PI * 2;
3333
const y = (v - 1 / 2) * Math.PI * 2;
3434
return [x, y, equation(x, y)];
3535
},
36-
getColor: (x, y, z) => [40, z * 128 + 128, 160],
36+
getColor: ([x, y, z]) => [40, z * 128 + 128, 160],
3737
getXScale: getScale,
3838
getYScale: getScale,
3939
getZScale: getScale,

examples/website/plot/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
},
1111
"dependencies": {
1212
"d3-scale": "^2.0.0",
13-
"deck.gl": "^8.8.0",
13+
"deck.gl": "^9.0.0-alpha.3",
1414
"react": "^18.0.0",
1515
"react-dom": "^18.0.0"
1616
},

examples/website/plot/plot-layer/axes-layer.js renamed to examples/website/plot/plot-layer/axes-layer.ts

Lines changed: 125 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,69 @@
1-
import {Layer} from '@deck.gl/core';
2-
import GL from '@luma.gl/constants';
3-
import {Model, Geometry} from '@luma.gl/core';
1+
import {Color, DefaultProps, Layer, LayerDataSource, LayerProps} from '@deck.gl/core';
2+
import {Model, Geometry} from '@luma.gl/engine';
3+
import {Texture} from '@luma.gl/core';
4+
import {ScaleLinear} from 'd3-scale';
45

56
import {textMatrixToTexture} from './utils';
67

78
import fragmentShader from './axes-fragment.glsl';
89
import gridVertex from './grid-vertex.glsl';
910
import labelVertex from './label-vertex.glsl';
1011
import labelFragment from './label-fragment.glsl';
12+
import {Axis, Tick, TickFormat, Vec2, Vec3} from './types';
1113

1214
/* Constants */
1315
const DEFAULT_FONT_SIZE = 48;
1416
const DEFAULT_TICK_COUNT = 6;
15-
const DEFAULT_TICK_FORMAT = x => x.toFixed(2);
17+
const DEFAULT_TICK_FORMAT = (x: number) => x.toFixed(2);
18+
const DEFAULT_COLOR: Color = [0, 0, 0, 255];
19+
20+
interface LabelTexture {
21+
labelHeight: number;
22+
labelWidths: number[];
23+
labelTextureDim: Vec2;
24+
labelTexture: Texture;
25+
}
1626

17-
const defaultProps = {
27+
const defaultProps: DefaultProps<AxesLayerProps> = {
1828
data: [],
1929
fontSize: 12,
20-
xScale: null,
21-
yScale: null,
22-
zScale: null,
30+
xScale: undefined,
31+
yScale: undefined,
32+
zScale: undefined,
2333
xTicks: DEFAULT_TICK_COUNT,
2434
yTicks: DEFAULT_TICK_COUNT,
2535
zTicks: DEFAULT_TICK_COUNT,
26-
xTickFormat: DEFAULT_TICK_FORMAT,
27-
yTickFormat: DEFAULT_TICK_FORMAT,
28-
zTickFormat: DEFAULT_TICK_FORMAT,
36+
xTickFormat: DEFAULT_TICK_FORMAT as TickFormat,
37+
yTickFormat: DEFAULT_TICK_FORMAT as TickFormat,
38+
zTickFormat: DEFAULT_TICK_FORMAT as TickFormat,
2939
padding: 0,
30-
color: [0, 0, 0, 255],
40+
color: DEFAULT_COLOR,
3141
xTitle: 'x',
3242
yTitle: 'y',
3343
zTitle: 'z'
3444
};
3545

36-
/* Utils */
37-
function flatten(arrayOfArrays) {
38-
const flatArray = arrayOfArrays.reduce((acc, arr) => acc.concat(arr), []);
39-
if (Array.isArray(flatArray[0])) {
40-
return flatten(flatArray);
41-
}
42-
return flatArray;
43-
}
44-
45-
function getTicks(props) {
46-
const {axis} = props;
47-
let ticks = props[`${axis}Ticks`];
48-
const scale = props[`${axis}Scale`];
49-
const tickFormat = props[`${axis}TickFormat`];
50-
51-
if (!Array.isArray(ticks)) {
52-
ticks = scale.ticks(ticks);
53-
}
54-
55-
const titleTick = {
56-
value: props[`${axis}Title`],
57-
position: (scale.range()[0] + scale.range()[1]) / 2,
58-
text: props[`${axis}Title`]
59-
};
60-
61-
return [
62-
...ticks.map(t => ({
63-
value: t,
64-
position: scale(t),
65-
text: tickFormat(t, axis)
66-
})),
67-
titleTick
68-
];
69-
}
46+
/** All props supported by AxesLayer. */
47+
export type AxesLayerProps<DataT = unknown> = _AxesLayerProps<DataT> & LayerProps;
48+
49+
type _AxesLayerProps<DataT> = {
50+
data: LayerDataSource<DataT>;
51+
fontSize: number;
52+
xScale: ScaleLinear<number, number>;
53+
yScale: ScaleLinear<number, number>;
54+
zScale: ScaleLinear<number, number>;
55+
xTicks: number;
56+
yTicks: number;
57+
zTicks: number;
58+
xTickFormat: TickFormat<DataT>;
59+
yTickFormat: TickFormat<DataT>;
60+
zTickFormat: TickFormat<DataT>;
61+
padding: 0;
62+
color: Color;
63+
xTitle: string;
64+
yTitle: string;
65+
zTitle: string;
66+
};
7067

7168
/*
7269
* @classdesc
@@ -93,30 +90,38 @@ function getTicks(props) {
9390
* @param {Number} [props.fontSize] - size of the labels
9491
* @param {Array} [props.color] - color of the gridlines, in [r,g,b,a]
9592
*/
96-
export default class AxesLayer extends Layer {
93+
export default class AxesLayer<DataT = any, ExtraPropsT extends {} = {}> extends Layer<
94+
ExtraPropsT & Required<_AxesLayerProps<DataT>>
95+
> {
96+
static layerName = 'AxesLayer';
97+
static defaultProps = defaultProps;
98+
99+
// @ts-ignore
100+
state!: Layer['state'] & {
101+
models: [Model, Model];
102+
modelsByName: {grids: Model; labels: Model};
103+
numInstances: number;
104+
ticks: [Tick[], Tick[], Tick[]];
105+
gridDims: Vec3;
106+
gridCenter: Vec3;
107+
labelTexture: LabelTexture | null;
108+
};
109+
97110
initializeState() {
98111
const {gl} = this.context;
99-
const attributeManager = this.getAttributeManager();
112+
const attributeManager = this.getAttributeManager()!;
100113

101114
attributeManager.addInstanced({
102115
instancePositions: {size: 2, update: this.calculateInstancePositions, noAlloc: true},
103116
instanceNormals: {size: 3, update: this.calculateInstanceNormals, noAlloc: true},
104117
instanceIsTitle: {size: 1, update: this.calculateInstanceIsTitle, noAlloc: true}
105118
});
106119

107-
this.setState(
108-
Object.assign(
109-
{
110-
numInstances: 0,
111-
labels: null
112-
},
113-
this._getModels(gl)
114-
)
115-
);
120+
this.setState(Object.assign({numInstances: 0}, this._getModels(gl)));
116121
}
117122

118123
updateState({oldProps, props, changeFlags}) {
119-
const attributeManager = this.getAttributeManager();
124+
const attributeManager = this.getAttributeManager()!;
120125

121126
if (
122127
oldProps.xScale !== props.xScale ||
@@ -157,7 +162,8 @@ export default class AxesLayer extends Layer {
157162
}
158163

159164
draw({uniforms}) {
160-
const {gridDims, gridCenter, modelsByName, labelTexture, numInstances} = this.state;
165+
const {gridDims, gridCenter, modelsByName, numInstances} = this.state;
166+
const {labelTexture, ...labelTextureUniforms} = this.state.labelTexture!;
161167
const {fontSize, color, padding} = this.props;
162168

163169
if (labelTexture) {
@@ -172,10 +178,14 @@ export default class AxesLayer extends Layer {
172178
modelsByName.grids.setInstanceCount(numInstances);
173179
modelsByName.labels.setInstanceCount(numInstances);
174180

175-
modelsByName.grids.setUniforms(Object.assign({}, uniforms, baseUniforms)).draw();
176-
modelsByName.labels
177-
.setUniforms(Object.assign({}, uniforms, baseUniforms, labelTexture))
178-
.draw();
181+
modelsByName.grids.setUniforms(Object.assign({}, uniforms, baseUniforms));
182+
modelsByName.labels.setBindings({labelTexture});
183+
modelsByName.labels.setUniforms(
184+
Object.assign({}, uniforms, baseUniforms, labelTextureUniforms)
185+
);
186+
187+
modelsByName.grids.draw(this.context.renderPass);
188+
modelsByName.labels.draw(this.context.renderPass);
179189
}
180190
}
181191

@@ -222,29 +232,29 @@ export default class AxesLayer extends Layer {
222232
0, -1, 0, 0, -1, 0
223233
];
224234

225-
const grids = new Model(gl, {
235+
const grids = new Model(gl.device, {
226236
id: `${this.props.id}-grids`,
227237
vs: gridVertex,
228238
fs: fragmentShader,
239+
bufferLayout: this.getAttributeManager()!.getBufferLayouts(),
229240
geometry: new Geometry({
230241
topology: 'line-list',
231242
attributes: {
232-
positions: new Float32Array(gridPositions),
233-
normals: new Float32Array(gridNormals)
243+
positions: {value: new Float32Array(gridPositions), size: 3},
244+
normals: {value: new Float32Array(gridNormals), size: 3}
234245
},
235246
vertexCount: gridPositions.length / 3
236-
}),
237-
isInstanced: true
247+
})
238248
});
239249

240250
/* labels
241251
* one label is placed at each end of every grid line
242252
* show/hide is toggled by the vertex shader
243253
*/
244-
let labelTexCoords = [];
245-
let labelPositions = [];
246-
let labelNormals = [];
247-
let labelIndices = [];
254+
let labelTexCoords: number[] = [];
255+
let labelPositions: number[] = [];
256+
let labelNormals: number[] = [];
257+
let labelIndices: number[] = [];
248258
for (let i = 0; i < 8; i++) {
249259
/*
250260
* each label is rendered as a rectangle
@@ -271,20 +281,20 @@ export default class AxesLayer extends Layer {
271281
}
272282
}
273283

274-
const labels = new Model(gl, {
284+
const labels = new Model(gl.device, {
275285
id: `${this.props.id}-labels`,
276286
vs: labelVertex,
277287
fs: labelFragment,
288+
bufferLayout: this.getAttributeManager()!.getBufferLayouts(),
278289
geometry: new Geometry({
279290
topology: 'triangle-list',
280291
attributes: {
281292
indices: new Uint16Array(labelIndices),
282-
positions: new Float32Array(labelPositions),
283-
texCoords: {size: 2, value: new Float32Array(labelTexCoords)},
284-
normals: new Float32Array(labelNormals)
293+
positions: {value: new Float32Array(labelPositions), size: 3},
294+
texCoords: {value: new Float32Array(labelTexCoords), size: 2},
295+
normals: {value: new Float32Array(labelNormals), size: 3}
285296
}
286-
}),
287-
isInstanced: true
297+
})
288298
});
289299

290300
return {
@@ -329,9 +339,9 @@ export default class AxesLayer extends Layer {
329339
attribute.value = new Float32Array(flatten(isTitle));
330340
}
331341

332-
renderLabelTexture(ticks) {
333-
if (this.state.labels) {
334-
this.state.labels.labelTexture.delete();
342+
renderLabelTexture(ticks): LabelTexture | null {
343+
if (this.state.labelTexture) {
344+
this.state.labelTexture.labelTexture.destroy();
335345
}
336346

337347
// attach a 2d texture of all the label texts
@@ -351,5 +361,37 @@ export default class AxesLayer extends Layer {
351361
}
352362
}
353363

354-
AxesLayer.layerName = 'AxesLayer';
355-
AxesLayer.defaultProps = defaultProps;
364+
/* Utils */
365+
function flatten(arrayOfArrays) {
366+
const flatArray = arrayOfArrays.reduce((acc, arr) => acc.concat(arr), []);
367+
if (Array.isArray(flatArray[0])) {
368+
return flatten(flatArray);
369+
}
370+
return flatArray;
371+
}
372+
373+
function getTicks(props: AxesLayerProps<number> & {axis: Axis}): Tick[] {
374+
const {axis} = props;
375+
let ticks = props[`${axis}Ticks`] as number | number[];
376+
const scale = props[`${axis}Scale`];
377+
const tickFormat = props[`${axis}TickFormat`];
378+
379+
if (!Array.isArray(ticks)) {
380+
ticks = scale.ticks(ticks) as number[];
381+
}
382+
383+
const titleTick = {
384+
value: props[`${axis}Title`],
385+
position: (scale.range()[0] + scale.range()[1]) / 2,
386+
text: props[`${axis}Title`]
387+
};
388+
389+
return [
390+
...ticks.map(t => ({
391+
value: String(t),
392+
position: scale(t),
393+
text: tickFormat(t, axis)
394+
})),
395+
titleTick
396+
];
397+
}

0 commit comments

Comments
 (0)