Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(docs): Update i3s colorization tutorial #2900

Merged
merged 2 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 0 additions & 118 deletions docs/modules/i3s/recipes/attribute-driven-colorization.md

This file was deleted.

130 changes: 130 additions & 0 deletions docs/modules/i3s/recipes/attribute-driven-colorization.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# Attribute-driven colorization

import Demo from 'examples/website/i3s-colorization-by-attributes/src/app';

<div style={{height: '50vh'}}>
<Demo />
</div>
Please find source code of the example [here](https://github.com/visgl/loaders.gl/tree/master/examples/website/i3s-colorization-by-attributes)

In I3S, a feature represents a real-world object within a node. For example, a building within a 3D object scene layer. Node resources such as geometry buffer and attributes can belong to a feature and can be accessed by an object-ID.

In terms of geometry, every vertex of a mesh is associated with some feature. At the same time, every feature is associated with feature attribute values. For example, there might be `HEIGHT` attribute that stores roof height information about every building.

All that means that it is possible to make some visual effects related to attribute value. It might be text labels, colors, opacity etc.

The complete case of attributes colorization is done in [I3S Explorer](https://i3s.loaders.gl/viewer?tileset=new-york). It is an open source ReactJS application. See source code on [GitHub](https://github.com/visgl/loaders.gl-showcases).

![I3S New York dataset colorized by height roof](i3s-new-york-colorize-by-heightroof.png)

## Find out layer's attributes

It is necessary to pick some attribute to colorize a layer by. So it is necessary to load the layer JSON:

```javascript
import {load} from '@loaders.gl/core';
import {I3SLoader} from '@loaders.gl/i3s';

const i3sLayer = await load(url, I3SBuildingSceneLayerLoader);
```

List and types of attributes might be taken from [`i3sLayer.fields`](https://github.com/Esri/i3s-spec/blob/master/docs/1.9/field.cmn.md) and [`i3sLayer.attributeStorageInfo`](https://github.com/Esri/i3s-spec/blob/master/docs/1.8/attributeStorageInfo.cmn.md) properties.

## Setup colorization scale

Attributes colorization capability applies linear color gradient. To create this gradient attribute values range is required.

To get minimum and maximum attribute values [statistics](https://github.com/Esri/i3s-spec/blob/master/docs/1.9/statisticsInfo.cmn.md) can be used. The [statistics info JSON](https://github.com/Esri/i3s-spec/blob/master/docs/1.9/statsInfo.cmn.md) has min and max values. Usage of those values allows setting true attribute values range not clamping extremum values.

As soon as statistics info is stored in separate resources, it has to be loaded in a separate request. Statistics is just a JSON data and can be loaded the following way:

```ts
import {fetchFile} from '@loaders.gl/core';
import {StatsInfo} from '@loaders.gl/i3s';

const dataResponse = await fetchFile(`${url}/statistics/f_5/0`);
const data = JSON.parse(await dataResponse.text());
const stats: StatsInfo | null = (data?.stats as StatsInfo) || null;
```

## Use @deck.gl-community/layers
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the section should be called DataDrivenTile3DLayer - the fact that it is in the deck.gl-community repo/namespace is more of a detail?

If we reference this layer, does it have documentation in the deck.gl-community website that we can link to?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You right, changed to DataDrivenTile3DLayer.
There is no documentation in the deck.gl-community for the layer.


To colorize an I3S dataset on the fly you have to use `DataDrivenTile3DLayer` from `@deck.gl-community/layers`. First of all you need to add `@deck.gl-community/layers` into the project:

```bash
yarn add @deck.gl-community/layers
```

Then you can use `DataDrivenTile3DLayer`, `colorizeTile` util function as a prop `customizeColors` of the layer and set prop `colorsByAttribute` with required params (attribute name, min/max values, min/max colors, mode):

```ts
import Map from 'react-map-gl';
import maplibregl from 'maplibre-gl';
import DeckGL from "@deck.gl/react";
import {DataDrivenTile3DLayer, colorizeTile} from '@deck.gl-community/layers';
import {I3SLoader} from "@loaders.gl/i3s";

function renderLayers() {
const loadOptions = {i3s: {coordinateSystem: COORDINATE_SYSTEM.LNGLAT_OFFSETS}};
const colorsByAttribute = {
attributeName,
minValue: stats.min,
maxValue: stats.max,
minColor: [146, 146, 252, 255], // #9292FC
maxColor: [44, 44, 175, 255], // #2C2CAF
mode: 'replace'
}
const layers = new DataDrivenTile3DLayer({
data: url,
loader: I3SLoader,
onTilesetLoad: onTilesetLoadHandler,
loadOptions,
colorsByAttribute,
customizeColors: colorizeTile
});

return layers;
}

<DeckGL initialViewState={viewState} layers={renderLayers()} controller>
<Map
reuseMaps
mapLib={maplibregl}
mapStyle={style}
/>
</DeckGL>
```

## Colorization mode

Attributes colorization capability can work in 2 modes: 'replace' and 'multiply'.

`replace` mode. Attribute-based colors replace geometry vertex colors.

`multiply` mode. Attribute-based colors multiply with geometry vertex colors.

Usage example:

```ts
function renderLayers() {
const loadOptions = {i3s: {coordinateSystem: COORDINATE_SYSTEM.LNGLAT_OFFSETS}};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth adding comments explaining why this is necessary.

const colorsByAttribute = {
attributeName,
minValue: stats.min,
maxValue: stats.max,
minColor: [146, 146, 252, 255], // #9292FC
maxColor: [44, 44, 175, 255], // #2C2CAF
mode: 'multiply' // or 'replace'
};
const layers = new DataDrivenTile3DLayer({
data: url,
loader: I3SLoader,
onTilesetLoad: onTilesetLoadHandler,
loadOptions,
colorsByAttribute,
customizeColors: colorizeTile
});

return layers;
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"@loaders.gl/core": "^4.0.0",
"@loaders.gl/i3s": "^4.0.0",
"@luma.gl/core": "^8.5.21",
"mapbox-gl": "npm:empty-npm-package@^1.0.0",
"mapbox-gl": "^3.1.2",
"maplibre-gl": "^3.6.2",
"prop-types": "^15.7.2",
"react": "^18.2.0",
Expand Down
3 changes: 2 additions & 1 deletion examples/website/i3s-colorization-by-attributes/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React, {useEffect, useState} from 'react';
import {createRoot} from 'react-dom/client';

import {Map} from 'react-map-gl';
import Map from 'react-map-gl';
import maplibregl from 'maplibre-gl';
import 'mapbox-gl/dist/mapbox-gl.css';

import DeckGL from '@deck.gl/react';
import {ViewState, FlyToInterpolator} from '@deck.gl/core';
Expand Down
2 changes: 1 addition & 1 deletion website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
"docusaurus-mdx-checker": "^3.0.0",
"docusaurus-node-polyfills": "^1.0.0",
"expr-eval": "^2.0.2",
"mapbox-gl": "npm:empty-npm-package@1.0.0",
"mapbox-gl": "^3.1.2",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are trying to move away from mapbox.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted it back

"maplibre-gl": "^2.4.0",
"marked": "^0.7.0",
"prism-react-renderer": "^2.1.0",
Expand Down
63 changes: 57 additions & 6 deletions website/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3581,7 +3581,7 @@
resolved "https://registry.yarnpkg.com/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz#8a83f9335c7860effa2eeeca254332aa0aeed8f2"
integrity sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==

"@mapbox/tiny-sdf@^2.0.5":
"@mapbox/tiny-sdf@^2.0.5", "@mapbox/tiny-sdf@^2.0.6":
version "2.0.6"
resolved "https://registry.yarnpkg.com/@mapbox/tiny-sdf/-/tiny-sdf-2.0.6.tgz#9a1d33e5018093e88f6a4df2343e886056287282"
integrity sha512-qMqa27TLw+ZQz5Jk+RcwZGH7BQf5G/TrutJhspsca/3SHwmgKQ1iq+d3Jxz5oysPVYTGP6aXxCo5Lk9Er6YBAA==
Expand Down Expand Up @@ -6665,6 +6665,11 @@ character-reference-invalid@^2.0.0:
resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz#85c66b041e43b47210faf401278abf808ac45cb9"
integrity sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==

cheap-ruler@^3.0.1:
version "3.0.2"
resolved "https://registry.yarnpkg.com/cheap-ruler/-/cheap-ruler-3.0.2.tgz#60d2b3a0cb77a420472c8c5bb8f2c320fba4bb87"
integrity sha512-02T332h1/HTN6cDSufLP8x4JzDs2+VC+8qZ/N0kWIVPyc2xUkWwWh3B2fJxR7raXkL4Mq7k554mfuM9ofv/vGg==

cheerio-select@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cheerio-select/-/cheerio-select-2.1.0.tgz#4d8673286b8126ca2a8e42740d5e3c4884ae21b4"
Expand Down Expand Up @@ -8579,6 +8584,11 @@ gray-matter@^4.0.3:
section-matter "^1.0.0"
strip-bom-string "^1.0.0"

grid-index@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/grid-index/-/grid-index-1.1.0.tgz#97f8221edec1026c8377b86446a7c71e79522ea7"
integrity sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==

gzip-size@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462"
Expand Down Expand Up @@ -9577,6 +9587,11 @@ kdbush@^3.0.0:
resolved "https://registry.yarnpkg.com/kdbush/-/kdbush-3.0.0.tgz#f8484794d47004cc2d85ed3a79353dbe0abc2bf0"
integrity sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==

kdbush@^4.0.1, kdbush@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/kdbush/-/kdbush-4.0.2.tgz#2f7b7246328b4657dd122b6c7f025fbc2c868e39"
integrity sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==

keyv@^4.5.3:
version "4.5.4"
resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
Expand Down Expand Up @@ -9812,10 +9827,34 @@ make-error@^1.1.1:
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==

"mapbox-gl@npm:empty-npm-package@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/empty-npm-package/-/empty-npm-package-1.0.0.tgz#fda29eb6de5efa391f73d578697853af55f6793a"
integrity sha512-q4Mq/+XO7UNDdMiPpR/LIBIW1Zl4V0Z6UT9aKGqIAnBCtCb3lvZJM1KbDbdzdC8fKflwflModfjR29Nt0EpcwA==
mapbox-gl@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/mapbox-gl/-/mapbox-gl-3.1.2.tgz#4e49681d5b8464978bc6bc0d8dd6ed0cfbc94ecc"
integrity sha512-+KoLEqZM8GxO/ViPz9tKgGURteKne+Y0pXiVCNsowymiZFH3FiL6dt9oZE95owMg5XqD3Kygz5mfchR1ZgmWlA==
dependencies:
"@mapbox/geojson-rewind" "^0.5.2"
"@mapbox/jsonlint-lines-primitives" "^2.0.2"
"@mapbox/mapbox-gl-supported" "^2.0.1"
"@mapbox/point-geometry" "^0.1.0"
"@mapbox/tiny-sdf" "^2.0.6"
"@mapbox/unitbezier" "^0.0.1"
"@mapbox/vector-tile" "^1.3.1"
"@mapbox/whoots-js" "^3.1.0"
cheap-ruler "^3.0.1"
csscolorparser "~1.0.3"
earcut "^2.2.4"
geojson-vt "^3.2.1"
gl-matrix "^3.4.3"
grid-index "^1.1.0"
kdbush "^4.0.1"
murmurhash-js "^1.0.0"
pbf "^3.2.1"
potpack "^2.0.0"
quickselect "^2.0.0"
rw "^1.3.3"
supercluster "^8.0.0"
tinyqueue "^2.0.3"
vt-pbf "^3.1.3"

maplibre-gl@^2.4.0:
version "2.4.0"
Expand Down Expand Up @@ -11581,6 +11620,11 @@ potpack@^1.0.2:
resolved "https://registry.yarnpkg.com/potpack/-/potpack-1.0.2.tgz#23b99e64eb74f5741ffe7656b5b5c4ddce8dfc14"
integrity sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==

potpack@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/potpack/-/potpack-2.0.0.tgz#61f4dd2dc4b3d5e996e3698c0ec9426d0e169104"
integrity sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==

preact@^10.0.0:
version "10.13.2"
resolved "https://registry.yarnpkg.com/preact/-/preact-10.13.2.tgz#2c40c73d57248b57234c4ae6cd9ab9d8186ebc0a"
Expand Down Expand Up @@ -12333,7 +12377,7 @@ run-parallel@^1.1.9:
dependencies:
queue-microtask "^1.2.2"

rw@1:
rw@1, rw@^1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4"
integrity sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==
Expand Down Expand Up @@ -12932,6 +12976,13 @@ supercluster@^7.1.5:
dependencies:
kdbush "^3.0.0"

supercluster@^8.0.0:
version "8.0.1"
resolved "https://registry.yarnpkg.com/supercluster/-/supercluster-8.0.1.tgz#9946ba123538e9e9ab15de472531f604e7372df5"
integrity sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==
dependencies:
kdbush "^4.0.2"

supports-color@^5.3.0, supports-color@^5.5.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
Expand Down
Loading