Published
Edited
Mar 18, 2020
1 fork
Insert cell
md`# Private Kit`
Insert cell
default_data = ({ "timelineObjects": [] })
Insert cell
mutable data = default_data
Insert cell
md`## Choose the input data here`
Insert cell
viewof data_in = html`<input type=file accept="*/*">`
Insert cell
data_text = Files.text(data_in)
Insert cell
{ mutable data = JSON.parse(data_text) }
Insert cell
data
Insert cell
Insert cell
function extractTimeS(timeStrMs) {
if (timeStrMs.length != 13)
throw `Unexpected string ${timeStrMs}`
return parseInt(timeStrMs.substr(0, timeStrMs.length - 3), 10);
}
Insert cell
extractTimeS("1583085476383") == 1583085476
Insert cell
path = {
var failures = []
var p = []
var len = data["timelineObjects"].length;
for (var i = 0; i < len; i++) {
let item = data["timelineObjects"][i];
if (item['activitySegment']) {
let o = item['activitySegment'];
p.push({
y: o["startLocation"]["latitudeE7"],
x: o["startLocation"]["longitudeE7"],
t: extractTimeS(o["duration"]["startTimestampMs"])
});
p.push({
y: o["endLocation"]["latitudeE7"],
x: o["endLocation"]["longitudeE7"],
t: extractTimeS(o["duration"]["endTimestampMs"])
});
} else if (item['placeVisit']) {
let o = item['placeVisit'];
p.push({
y: o["centerLatE7"],
x: o["centerLngE7"],
t: extractTimeS(o["duration"]["startTimestampMs"]),
meta: o["location"],
});
p.push({
y: o["centerLatE7"],
x: o["centerLngE7"],
t: extractTimeS(o["duration"]["endTimestampMs"]),
meta: o["location"],
});
} else {
failures.push(item)
}
}
return p;
}
Insert cell
md`# Rudimentary deletion support`
Insert cell
Insert cell
md`## Choose the parameters to blur the data with (distance, time) here`
Insert cell
Insert cell
Insert cell
blur_radius_m
Insert cell
Insert cell
Insert cell
blur_time_s
Insert cell
function offsetLatE7(distance_m) {
return distance_m * (1e7/111111)
}
Insert cell
function offsetLngE7(distance_m, latE7) {
return distance_m * (1e7/111111) * Math.cos((latE7/1e7) * Math.PI/180)
}
Insert cell
function offsetPoint(pt) {
let offset_angle = Math.random() * 2 * Math.PI;
let offset_y = blur_radius_m * Math.sin(offset_angle);
let offset_x = blur_radius_m * Math.cos(offset_angle);
let offset_time_s = Math.random() * blur_time_s;
return {
y: Math.round(pt.y + offsetLatE7(offset_y)),
x: Math.round(pt.x + offsetLngE7(offset_x, pt.y)),
t: Math.round(pt.t + offset_time_s)
}
}
Insert cell
offsetPoint({y: 423962436,
x: -710998953,
t: 1583084539})
Insert cell
blurred_path = {
let len = path.length;
let p = [];
if (len > 0) {
p.push(offsetPoint(path[0]));
}
for (var i = 1; i < len - 1; i+=2) {
p.push(offsetPoint(path[i]));
if (path[i+1].x == path[i].x && path[i+1].y == path[i].y &&
path[i+1].t == path[i].t) {
// Avoid offsetting the same location by two random numbers
// which will reduce the blur.
p.push(p[i]);
} else {
p.push(offsetPoint(path[i + 1]));
}
}
if (len > 1) {
p[len - 1] = offsetPoint(path[len - 1]);
}
return p
}
Insert cell
md`# Create a 3d index`
Insert cell
rb3d = require('rbush-3d@0.0.4/dist/rbush3d.min.js')
Insert cell
rtree = {
let tree = new rb3d.RBush3D();
let items = [];
let len = blurred_path.length;
for (var i = 0; i < len; i+=2) {
let a = blurred_path[i];
let b = blurred_path[i + 1];
items.push({
data: i,
minX: Math.min(a.x, b.x),
minY: Math.min(a.y, b.y),
minZ: Math.min(a.t, b.t),
maxX: Math.max(a.x, b.x ),
maxY: Math.max(a.y, b.y),
maxZ: Math.max(a.t, b.t),
});
}
tree.load(items)
return tree;
}
Insert cell
{
if (path.length > 0) {
return rtree.collides({
minX: Math.min(path[0].x, path[1].x),
minY: Math.min(path[0].y, path[1].y),
minZ: Math.min(path[0].t, path[1].t),
maxX: Math.max(path[0].x, path[1].x),
maxY: Math.max(path[0].y, path[1].y),
maxZ: Math.max(path[0].t, path[1].t)
})
}
}
Insert cell
{
if (path.length > 0) {
return rtree.collides({
minX: Math.min(path[0].x, path[1].x),
minY: Math.min(path[0].y, path[1].y),
minZ: (new Date().getTime()),
maxX: Math.max(path[0].x, path[1].x),
maxY: Math.max(path[0].y, path[1].y),
maxZ: (new Date().getTime() + 100)
})
}
}

Insert cell
Insert cell
import { pathsIntersect, overlapTime, flatEarth } from "@kunalb/intersection"
Insert cell
blurred_path
Insert cell
viewof test_radius_m = html`<input type=range>`
Insert cell
function testSegment(segment) {
let potential_intersections = rtree.search({
minX: Math.min(segment[0].x, segment[1].x),
minY: Math.min(segment[0].y, segment[1].y),
minZ: Math.min(segment[0].t, segment[1].t),
maxX: Math.max(segment[0].x, segment[1].x),
maxY: Math.max(segment[0].y, segment[1].y),
maxZ: Math.max(segment[0].t, segment[1].t)
});
for (var i in potential_intersections) {
let potential_segment = [
blurred_path[potential_intersections[i].data],
blurred_path[potential_intersections[i].data + 1]
];
let flattened = flatEarth(segment, potential_segment);
let overlapped = overlapTime(flattened[0], flattened[1]);

console.log(overlapped);
if (overlapped.length > 0 && pathsIntersect(overlapped[0], overlapped[1], test_radius_m)) {
return true;
}
}
return false;
}
Insert cell
path.length && testSegment([path[0], path[1]])
Insert cell
function testPath(path) {
}
Insert cell
md`# Visualization`
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