Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,15 @@ Available event data:
Available command data:
| Key | Default value | Description |
|------------------------------------|---------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
| type | - (required) | Type of the command (view_command, settings_command) |
| type | - (required) | Type of the command (clear_map_command, view_command, settings_command) |
| command_delay | - | Delay the execution of this command in ms (similar to draw_delay). Can be useful to precisely control commands |
| view_lat | - (required - view_command only) | Latitude of the new view position |
| view_lon | - (required - view_command only) | Longitude of the new view position |
| view_zoom | - | Zoom level of the new view position (-10, 10). Zoom level is not changed if undefined |
| view_speed | 1 | Relative view movement speed. Can be set to < 1 (but > 0) for slower view movement, or > 1 for faster movement |
| settings | - (required - settings_command only) | JSON object containing keys for settings that need to be changed. All keys are the same as in URL parameters and all are expected to be strings |
| clear_types | [] | Event types to clear from the map. Use empty array to clear all types |
| clear_events | true | Determines if the event counter should be updated after removing events from the map |

## Configuration

Expand Down
7 changes: 7 additions & 0 deletions examples/data/all-types.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,12 @@
"downloaded_object_scale": 2,
"hover_text": "Click here to open wikipedia",
"link_url": "https://wikipedia.org"
},
{
"type": "clear_map_command",
"clear_types": [
"bar"
],
"clear_events": true
}
]
6 changes: 6 additions & 0 deletions src/data/analysismode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export class AnalysisModeData implements PointData {
total_lifetime: number;
startTime: number;
counter?: number;
pointName: string;

public get fade_duration(): number {
return 0;
Expand All @@ -23,6 +24,7 @@ export class AnalysisModeData implements PointData {
this.counter = data.counter;
this.total_lifetime = lifetime;
this.startTime = Date.now();
this.pointName = data.eventName();
}

visible(): boolean {
Expand Down Expand Up @@ -63,4 +65,8 @@ export class AnalysisModeData implements PointData {
timeLeft(): number {
return this.total_lifetime;
}

eventName(): string {
return this.pointName;
}
}
8 changes: 8 additions & 0 deletions src/data/arc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,10 @@ export class ArcData
clone(): ArcData {
return new ArcData(this.cloneData());
}

eventName(): string {
return "arc";
}
}

/**
Expand Down Expand Up @@ -189,4 +193,8 @@ export class ArcLabel
clone(): ArcLabel {
return new ArcLabel(this.defaultHeight, this.startTime, this.cloneData());
}

eventName(): string {
return "arc";
}
}
4 changes: 4 additions & 0 deletions src/data/bar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ export class BarData
return new BarData(this.cloneData());
}

eventName(): string {
return "bar";
}

faceCamera(): boolean {
// Yhe bar should never face towards the camera, because that makes it appear as just a hexagon.
return false;
Expand Down
4 changes: 4 additions & 0 deletions src/data/circle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,8 @@ export class CircleData
clone(): CircleData {
return new CircleData(this.cloneData());
}

eventName(): string {
return "circle";
}
}
6 changes: 5 additions & 1 deletion src/data/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export abstract class CommonData<T>
/**
* Time when this point was added. It can be in the future too, which will make it appear later.
*/
protected startTime: number;
startTime: number;

/**
* Current lifetime of the point
Expand Down Expand Up @@ -227,4 +227,8 @@ export abstract class CommonData<T>
variableScale(): boolean {
return false;
}

eventName(): string {
throw new Error("Method not implemented.");
}
}
4 changes: 4 additions & 0 deletions src/data/downloaded.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,8 @@ export class DownloadedData
labelScale(): number {
return this.scale();
}

eventName(): string {
return "download";
}
}
4 changes: 4 additions & 0 deletions src/data/explosion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,4 +306,8 @@ export class ExplosionData
// This ensures that label generally stays the same size throughout the explosion inflation
return 1 / this.scale();
}

eventName(): string {
return "explosion";
}
}
5 changes: 5 additions & 0 deletions src/data/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ export interface PointData {
* Useful for optimization - to sort objects by lifetime for easier removal.
*/
timeLeft(): number;

/**
* Returns the name of the event that this {@link PointData} represents.
*/
eventName(): string;
}

/**
Expand Down
4 changes: 4 additions & 0 deletions src/data/pointer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,8 @@ export class PointerData
// Ensures the label scales with the pointer
return this.scale();
}

eventName(): string {
return "pointer";
}
}
12 changes: 11 additions & 1 deletion src/globe/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as THREE from "three";
import ThreeGlobe from "three-globe";
import { Settings, SettingsChangedEvent } from "../settings";
import { AppState } from "../service/state";
import { AppState, ClearMapEvent } from "../service/state";
import { GlobeLayerRegistry } from "./layer";
import { RotationLayer } from "./layers/rotation";
import { CoreMapLayer } from "./layers/coremap";
Expand Down Expand Up @@ -127,6 +127,16 @@ export function setupGlobe(
registry.takeNewPoint(p);
});

// TODO: What happens if we have both new points queue and clear events?
state.clearEventsQueue
.splice(0, state.clearEventsQueue.length)
.forEach((e: ClearMapEvent) => {
const counters = registry.handleClearEvent(e);
if (e.clearEvents) {
state.newEventsQueue.push(...counters);
}
});

registry.updateData(globe, settings);
}, 200);

Expand Down
18 changes: 17 additions & 1 deletion src/globe/layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as THREE from "three";
import ThreeGlobe from "three-globe";
import { Settings } from "../settings";
import { PointData } from "../data";
import { AppState } from "../service/state";
import { AppState, ClearMapEvent, CountEvent } from "../service/state";

/**
* Marker interface for any of the globe layers
Expand Down Expand Up @@ -102,6 +102,14 @@ export interface GlobeLayerNewDataHook extends GlobeLayer {
* @param point the point to take in and optionally store
*/
takeNewPoint(point: PointData): void;

/**
* Passes a clear event that has been received into this layer. The event is shared so it should be read-only!
* This should return negative count events that should match the removed items.
*
* @param event the event describing how to clear map
*/
handleClearEvent(event: ClearMapEvent): CountEvent[];
}

/**
Expand Down Expand Up @@ -257,6 +265,14 @@ export class GlobeLayerRegistry
}
}

handleClearEvent(e: ClearMapEvent): CountEvent[] {
const events = [];
for (const hook of this.newDataHooks) {
events.push(...hook.handleClearEvent(e));
}
return events;
}

updateData(globe: ThreeGlobe, settings: Settings): void {
for (const hook of this.dataUpdateHooks) {
hook.updateData(globe, settings);
Expand Down
24 changes: 24 additions & 0 deletions src/globe/layers/analysismode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
GlobeLayerSettingsHook,
} from "../layer";
import { AnalysisModeData } from "../../data/analysismode";
import { ClearMapEvent, CountEvent } from "../../service/state";

/**
* Globe layer that provides analysis mode implementation
Expand Down Expand Up @@ -128,6 +129,29 @@ export class AnalysisModeLayer
return point.counter_include ?? true;
}

handleClearEvent(event: ClearMapEvent): CountEvent[] {
// Clear all events
if (event.types.length == 0) {
this.data.length = 0;
return [];
}

// Only clear events matching this filter
let i = 0;
let newLength = 0;

while (i < this.data.length) {
const val = this.data[i];
if (!event.types.includes(val.eventName())) {
this.data[newLength++] = val;
}
i++;
}

this.data.length = newLength;
return [];
}

takeNewPoint(point: PointData): void {
this.data.push(new AnalysisModeData(point, this.analysisModeDecay * 1000));
}
Expand Down
16 changes: 16 additions & 0 deletions src/globe/layers/arcs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
GlobeLayerNewDataHook,
GlobeLayerPreUpdateHook,
} from "../layer";
import { ClearMapEvent, CountEvent } from "../../service/state";

/**
* Globe layer that draws {@link ArcData} objects
Expand Down Expand Up @@ -169,6 +170,21 @@ export class ArcsLayer
binarySearchReplace(this.arcsData, point as ArcData, compare_arcs);
binarySearchReplace(this.arcLabels, (point as ArcData).produceLabel());
}
handleClearEvent(event: ClearMapEvent): CountEvent[] {
const events = [];
if (event.types.length == 0 || event.types.includes("arc")) {
if (event.clearEvents) {
for (const arc of this.arcsData) {
events.push({
startTime: arc.startTime,
count: -(arc.counter ?? 1),
});
}
}
this.arcsData.length = 0;
}
return events;
}
updateData(globe: ThreeGlobe, settings: Settings): void {
if (settings.enableArcs) {
globe.arcsData(this.arcsData);
Expand Down
1 change: 1 addition & 0 deletions src/globe/layers/bars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ export class BarsLayer
*/
export class BarsObjectProvider extends CommonObjectProvider<BarData> {
readonly layerName: string = "BarsProvider";
readonly objectType: string = "bar";

shouldTakePoint(point: PointData): boolean {
return point instanceof BarData;
Expand Down
1 change: 1 addition & 0 deletions src/globe/layers/circles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ export class CirclesLayer
*/
export class CirclesObjectProvider extends CommonObjectProvider<CircleData> {
readonly layerName: string = "CirclesProvider";
readonly objectType: string = "circle";

layerEnabled(settings: Settings): boolean {
return settings.enableCircles;
Expand Down
1 change: 1 addition & 0 deletions src/globe/layers/downloaded_objects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export class DownloadedObjectsLayer
*/
export class DownloadedObjectsProvider extends CommonObjectProvider<DownloadedData> {
readonly layerName: string = "DownloadedObjectsProvider";
readonly objectType: string = "downloaded";
private imageLoader: THREE.ImageBitmapLoader =
new THREE.ImageBitmapLoader().setOptions({ imageOrientation: "flipY" });

Expand Down
17 changes: 17 additions & 0 deletions src/globe/layers/explosiondata/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
PointData,
updateDataForFrame,
} from "../../../data";
import { ClearMapEvent, CountEvent } from "../../../service/state";

/**
* Globe layer that handles {@link ExplosionData} objects and makes it easier for multiple layers to access them.
Expand Down Expand Up @@ -51,6 +52,22 @@ export class ExplosionDataLayerGroup
return point instanceof ExplosionData;
}

handleClearEvent(event: ClearMapEvent): CountEvent[] {
const events = [];
if (event.types.length == 0 || event.types.includes("explosion")) {
if (event.clearEvents) {
for (const explosion of this.data) {
events.push({
startTime: explosion.startTime,
count: -(explosion.counter ?? 1),
});
}
}
this.data.length = 0;
}
return events;
}

takeNewPoint(point: PointData): void {
// Since explosions are generally randomized and short lived, it makes no sense to replace them if same lat/lon is found
// Instead, sort by time left, for quicker filtering
Expand Down
1 change: 1 addition & 0 deletions src/globe/layers/pointers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ export class PointersLayer
*/
export class PointersObjectProvider extends CommonObjectProvider<PointerData> {
readonly layerName: string = "PointersProvider";
readonly objectType: string = "pointer";

layerEnabled(settings: Settings): boolean {
return settings.enablePointers;
Expand Down
19 changes: 19 additions & 0 deletions src/globe/layers/utils/baseprovider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
GlobeLayerPreUpdateHook,
} from "../../layer";
import { CustomObjectProvider } from "../customobject";
import { ClearMapEvent, CountEvent } from "../../../service/state";

export default abstract class CommonObjectProvider<T extends PointData>
implements
Expand All @@ -21,6 +22,7 @@ export default abstract class CommonObjectProvider<T extends PointData>
CustomObjectProvider
{
abstract readonly layerName: string;
abstract readonly objectType: string;

private data: T[] = [];

Expand All @@ -33,6 +35,23 @@ export default abstract class CommonObjectProvider<T extends PointData>
takeNewPoint(point: PointData): void {
binarySearchReplace(this.data, point);
}
handleClearEvent(event: ClearMapEvent): CountEvent[] {
const events = [];
if (event.types.length == 0 || event.types.includes(this.objectType)) {
if (event.clearEvents) {
for (const data of this.data) {
events.push({
// Most events should have startTime - if they don't, startTime of 0 will probably work fine
// eslint-disable-next-line @typescript-eslint/no-explicit-any
startTime: (data as any).startTime ?? 0,
count: -(data.counter ?? 1),
});
}
}
this.data.length = 0;
}
return events;
}
preUpdate(): void {
mapAndFilter(this.data);
}
Expand Down
Loading