Skip to content

Commit

Permalink
Port scatterplot layer to ocular gatsby website.
Browse files Browse the repository at this point in the history
  • Loading branch information
tgorkin committed Nov 22, 2019
1 parent 7ea906e commit 39f5a27
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 5 deletions.
4 changes: 2 additions & 2 deletions website-gatsby/ocular-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,9 @@ based maps.',
},
{
title: 'ScatterplotLayer',
path: 'examples/scatterplot',
path: 'examples/website/scatterplot',
image: 'images/examples/demo-thumb-scatterplot.jpg',
componentUrl: resolve(__dirname, '../examples/website/scatterplot/app.js')
componentUrl: resolve(__dirname, './src/examples/example-scatterplot-layer.jsx')
},
{
title: 'PointCloudLayer',
Expand Down
2 changes: 1 addition & 1 deletion website-gatsby/src/examples/example-geojson-layer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {loadData} from '../utils/data-utils';
import {readableInteger} from '../utils/format-utils';
import App, {COLOR_SCALE} from '../../../examples/website/geojson/app';

export default class IconDemo extends Component {
export default class GeoJSONDemo extends Component {
constructor(props) {
super(props);
this.state = {
Expand Down
2 changes: 1 addition & 1 deletion website-gatsby/src/examples/example-highway-demo.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {loadData} from '../utils/data-utils';
import {readableInteger} from '../utils/format-utils';
import App, {COLOR_SCALE} from '../../../examples/website/highway/app';

export default class IconDemo extends Component {
export default class HighwayDemo extends Component {
constructor(props) {
super(props);
this.state = {
Expand Down
106 changes: 106 additions & 0 deletions website-gatsby/src/examples/example-scatterplot-layer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import React, {Component} from 'react';
import InfoPanel from '../components/info-panel';
import {MAPBOX_STYLES, DATA_URI, GITHUB_TREE} from '../constants/defaults';
import {loadData} from '../utils/data-utils';
import {readableInteger, rgbToHex, colorToRGBArray} from '../utils/format-utils';
import App from '../../../examples/website/scatterplot/app';

export default class ScatterplotDemo extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
points: 0,
maleColor: [0, 128, 255],
femaleColor: [255, 0, 128],
radius: 10
};

this._handleChange = this._handleChange.bind(this);
}

componentDidMount() {
loadData(
`${DATA_URI}/scatterplot-data.txt`,
'/workers/scatterplot-data-decoder.js',
(response, meta) => {
this.setState({
data: response,
points: meta.points
});
}
);
}

_handleChange(event) {
switch (event.target.name) {
case 'female-color':
this.setState({femaleColor: colorToRGBArray(event.target.value)});
break;
case 'male-color':
this.setState({maleColor: colorToRGBArray(event.target.value)});
break;
case 'radius':
this.setState({radius: parseFloat(event.target.value)});
break;
}
}

render() {
const {data, points, maleColor, femaleColor, radius} = this.state;

return (
<div>
<App
mapStyle={MAPBOX_STYLES.LIGHT}
data={data}
maleColor={maleColor}
femaleColor={femaleColor}
radius={radius}
/>
<InfoPanel sourceLink={`${GITHUB_TREE}/${this.props.path}`}>
<h3>Every Person in New York City</h3>
<p>Each dot represents 10 people. Density per tract from 2015 census data</p>
<p>
Data source: <a href="http://www.census.gov">US Census Bureau</a>
</p>
<div className="stat">
No. of Instances
<b>{readableInteger(points)}</b>
</div>
<hr />
<div className="input">
<label>Female</label>
<input
name="female-color"
type="color"
value={rgbToHex(femaleColor)}
onChange={this._handleChange}
/>
</div>
<div className="input">
<label>Male</label>
<input
name="male-color"
type="color"
value={rgbToHex(maleColor)}
onChange={this._handleChange}
/>
</div>
<div className="input">
<label>Radius</label>
<input
name="radius"
type="range"
step="0.1"
min="1"
max="20"
value={radius}
onChange={this._handleChange}
/>
</div>
</InfoPanel>
</div>
);
}
}
2 changes: 1 addition & 1 deletion website-gatsby/src/examples/example-screengrid-layer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {loadData} from '../utils/data-utils';
import {readableInteger} from '../utils/format-utils';
import App from '../../../examples/website/screen-grid/app';

export default class LineDemo extends Component {
export default class ScreengridDemo extends Component {
constructor(props) {
super(props);
this.state = {
Expand Down
85 changes: 85 additions & 0 deletions website-gatsby/static/workers/scatterplot-data-decoder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
importScripts('./util.js');
const FLUSH_LIMIT = 100000;
const COORDINATE_PRECISION = 7;
let sequence;
let result = [];
let count = 0;

onmessage = function(e) {
const lines = e.data.text.split('\n');

lines.forEach(function(l, i) {
if (!l.length) {
return;
}

if (!sequence) {
sequence = decodeSequence(l);
return;
}

const bbox = decodeBbox(l.slice(0, 20));
const bitmap = decodeBitmap(l.slice(20));

for (var i = 0; i < bitmap.length; i++) {
if (bitmap[i] > 0) {
const point = [
bbox[0] + (bbox[2] - bbox[0]) * sequence[i * 2],
bbox[1] + (bbox[3] - bbox[1]) * sequence[i * 2 + 1],
Number(bitmap[i])
];
result.push(point);
count++;
}
}

if (result.length >= FLUSH_LIMIT) {
flush();
}
});

if (e.data.event === 'load') {
flush();
postMessage({action: 'end'});
}
};

function flush() {
postMessage({
action: 'add',
data: result,
meta: {points: count}
});
result = [];
}

function decodeSequence(str) {
const seq = [];
const tokens = str.split(/([A-Z])/).map(function(v) {
return parseInt(v, 36);
});
for (let i = 0; i < tokens.length - 1; i += 2) {
seq.push(tokens[i] / Math.pow(2, tokens[i + 1] - 10));
}
return seq;
}

function decodeBbox(str) {
const multiplyer = Math.pow(10, COORDINATE_PRECISION);
return decodeNumberArr(str, 90, 32, 5).map(function(x) {
return x / multiplyer - 180;
});
}

function decodeBitmap(str) {
const chunkSize = 4;
let match = '';
for (let i = 0; i < str.length; i++) {
let seg = (str.charCodeAt(i) - 32).toString(3);
while (seg.length < chunkSize) {
seg = `0${ seg}`;
}
match += seg;
}
return match;
}

0 comments on commit 39f5a27

Please sign in to comment.