Skip to content

Instantly share code, notes, and snippets.

@hijiangtao
Created January 24, 2019 10:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hijiangtao/994ddb910228f47292782ed53cc4e2ba to your computer and use it in GitHub Desktop.
Save hijiangtao/994ddb910228f47292782ed53cc4e2ba to your computer and use it in GitHub Desktop.
Fade out ScattetplotLayer in deck.gl #2555
/*
* @Author: hijiangtao (hijiangtao@gmail.com)
* @Date: 2019-01-11 15:00:17
* @Description: A Layer based on ScatterplotLayer, which enable point fade-out animation on Scatterplot.
* @Color schema: [255,0,0] to [255,140,0]
* @Last Modified time: 2019-01-11 15:00:38
*/
import {ScatterplotLayer, CompositeLayer} from 'deck.gl';
const MAX_RADIUSSCALE = 8; // Default Max Display radiusScale
const OVERFLOW_FLAG = 9999; // Animation End Flag
const quantizeScale = (domain, range, value) => {
const domainRange = domain[1] - domain[0];
if (domainRange <= 0) {
console.warn('quantizeScale: invalid domain, returning range[0]');
return range[0];
}
const step = domainRange / range.length;
const idx = Math.floor((value - domain[0]) / step);
const clampIdx = Math.max(Math.min(idx, range.length - 1), 0);
return range[clampIdx];
}
const getQuantizeScale = (domain, range) => {
return value => quantizeScale(domain, range, value.SPACES);
}
class FadeScatterplotLayer extends CompositeLayer {
initializeState() {
this.state = {
radiusScale: OVERFLOW_FLAG,
data: [],
MAX_RADIUSSCALE,
raf: null,
maxSpaces: 1,
minSpaces: 9999,
};
}
shouldUpdateState({changeFlags}) {
if (changeFlags.propsChanged || changeFlags.dataChanged || changeFlags.stateChanged && this.state.radiusScale !== OVERFLOW_FLAG) {
return true;
}
return false;
}
updateState({props, oldProps, changeFlags}) {
super.updateState({props, oldProps, changeFlags});
const {propsChanged, stateChanged, dataChanged} = changeFlags;
// Stop following operation if update is triggered by internal state update
if (!propsChanged && !dataChanged && stateChanged) return false;
const prevMaxRadiusScale = this.state.MAX_RADIUSSCALE;
const newMaxRadiusScale = props.radiusScale || prevMaxRadiusScale;
if (propsChanged) {
this.setState((prevState) => {
return {
...prevState,
data: props.data || prevState.data,
MAX_RADIUSSCALE: newMaxRadiusScale,
}
})
}
/**
* Animaiton trigger judgement
*/
if (props.data && props.data.length) {
// Get max spaces in datasets
let maxSpaces = 1;
let minSpaces = 9999;
props.data.map((d) => {
if (d.SPACES > maxSpaces) {
maxSpaces = d.SPACES;
}
if (d.SPACES < minSpaces) {
minSpaces = d.SPACES;
}
});
this.setState({maxSpaces, minSpaces});
if (!props.showWaveAnimation) {
this.setState({
radiusScale: props.radiusScale || MAX_RADIUSSCALE
});
return ;
}
let {raf} = this.state;
raf && cancelAnimationFrame(raf);
this.startAnimation();
}
}
/**
* Point Spread Animation Method
*/
startAnimation() {
const { speed } = this.props;
let {radiusScale, MAX_RADIUSSCALE, raf} = this.state;
if (radiusScale === OVERFLOW_FLAG) {
radiusScale = 0;
}
radiusScale += speed;
if (radiusScale >= MAX_RADIUSSCALE) {
radiusScale = OVERFLOW_FLAG;
window.cancelAnimationFrame(raf);
}
this.setState({radiusScale});
if (radiusScale < MAX_RADIUSSCALE) {
const raf = window.requestAnimationFrame(this.startAnimation.bind(this));
this.setState({
raf
});
}
}
renderLayers() {
let {updateTriggers = {}, showWaveAnimation, data, colorRange, ...otherProps} = this.props;
const {radiusScale, maxSpaces, minSpaces, MAX_RADIUSSCALE} = this.state;
if (showWaveAnimation) {
otherProps.radiusScale = radiusScale;
}
let alpha = showWaveAnimation ? 255 * (MAX_RADIUSSCALE - radiusScale) / MAX_RADIUSSCALE : 255;
const visible = radiusScale !== OVERFLOW_FLAG;
if (!visible) alpha = 0;
const newColorRange = colorRange.map(e => {
if (!e.length) {
console.error('Wrong Color Range Format');
return [255,255,255,255];
}
const newColorArray = e.slice(0, 3);
return newColorArray.concat(alpha);
});
const layerProps = {
...otherProps,
data,
getColor: getQuantizeScale([minSpaces, maxSpaces], newColorRange),
updateTriggers: {
...updateTriggers,
getColor: [radiusScale],
},
visible,
};
return [
new ScatterplotLayer(layerProps)
]
}
}
FadeScatterplotLayer.layerName = 'FadeScatterplotLayer';
FadeScatterplotLayer.defaultProps = {
...ScatterplotLayer.defaultProps,
showWaveAnimation: false,
speed: 0.02,
colorRange: {
type: 'accessor',
value: [
[255,140,0],
[255,112,0],
[255,84,0],
[255,56,0],
[255,28,0],
[255,0,0],
],
}
};
export default FadeScatterplotLayer;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment