summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--derelict.js153
1 files changed, 94 insertions, 59 deletions
diff --git a/derelict.js b/derelict.js
index e7f1f76..4be97ef 100644
--- a/derelict.js
+++ b/derelict.js
@@ -5,17 +5,35 @@ import { CSS2DRenderer, CSS2DObject } from 'https://unpkg.com/three@0.126.1/exam
const SCALE = 10000
const METERS_IN_AU = 149597871000
const EXPIRY = 1000 * 60 * 10
+const GRID_EXTENT = 100 * SCALE
+
+class Timeline {
+ start
+ finish
+ current = 0
+
+ simple_list = []
+
+ register(wreck) {
+ // TODO: Consider expiration right away
+ if (this.start === undefined || wreck.timestamp < this.start)
+ this.start = wreck.timestamp
+ if (this.finish === undefined || wreck.timestamp > this.finish)
+ this.finish = wreck.timestamp
+ // TODO: Implement more reliable and optimized data structure for timeline.
+ this.simple_list.push(wreck)
+ }
+
+ setTo(time) {} // TODO: Implement
+ moveForward(time) {} // TODO: Implement
+ moveBackward(time) {} // TODO: Implement
+}
-class SkirmishGrid {
+class Grid {
scene = new THREE.Scene()
- helper = new THREE.GridHelper(50, 50, 0x303030, 0x222222)
- camera
- controls
- renderer
- renderer2d
- active = false
-
- constructor({container, renderer, renderer2d}) {
+ wrecks = []
+
+ constructor(wreck, {container, renderer, renderer2d}) {
this.container = container
this.renderer = renderer
this.renderer2d = renderer2d
@@ -24,17 +42,32 @@ class SkirmishGrid {
this.camera = new THREE.PerspectiveCamera(80, aspect, 0.1, 1000)
this.camera.position.set(8, 8, 8)
this.camera.lookAt(0, 0, 0)
+
this.controls = new OrbitControls(this.camera, this.renderer2d.domElement)
this.controls.minDistance = 2
this.controls.maxDistance = 30
this.controls.enableDamping = true
this.controls.dampingFactor = 0.4
- this.add(this.helper)
+ const helper = new THREE.GridHelper(50, 50, 0x303030, 0x222222)
+ this.scene.add(helper)
+
+ this.positionOfReference = wreck.killmail.victim.position
+ this.locationOfReference = wreck.location
+ this.scene.add(wreck.object)
+ this.wrecks.push(wreck)
}
- add(obj) {
- this.scene.add(obj)
+ tryAdding(wreck) {
+ if (wreck.location == this.locationOfReference) {
+ const distance = wreck.killmail.victim.position.distanceTo(this.positionOfReference)
+ if (distance < GRID_EXTENT) {
+ this.scene.add(wreck.object)
+ this.wrecks.push(wreck)
+ return true
+ }
+ }
+ return false
}
draw() {
@@ -63,14 +96,41 @@ class SkirmishGrid {
this.active = false
this.controls.enabled = false
}
+
+ recenter() {
+ const center = averagePosition(this.wrecks.map(wreck => wreck.killmail.victim.position))
+ this.wrecks.forEach(wreck => wreck.object.position.sub(center).divideScalar(SCALE)) // TODO: rescale
+ }
+}
+
+class Battle {
+ timeline = new Timeline()
+ grids = []
+
+ constructor(grid_initializer) {
+ this.grid_initializer = grid_initializer
+ }
+
+ add(wreck) {
+ this.timeline.register(wreck)
+ let added = false
+ for (const grid of this.grids) {
+ added = grid.tryAdding(wreck)
+ if (added) break
+ }
+ if (!added) {
+ const grid = new Grid(wreck, this.grid_initializer)
+ this.grids.push(grid)
+ }
+ }
}
class Wreck {
domElement = document.createElement('div')
- point = new THREE.Object3D()
+ object = new THREE.Object3D()
killmail
- constructor({killmail, grid, battle}) {
+ constructor({killmail, battle}) {
const labelElement = document.createElement('div')
const object2d = new CSS2DObject(this.domElement)
const ownerId = "alliance_id" in killmail.victim ? killmail.victim.alliance_id : killmail.victim.corporation_id
@@ -88,16 +148,12 @@ class Wreck {
this.killmail = killmail
this.timestamp = Date.parse(killmail.killmail_time)
- this.point.position.copy(killmail.victim.position)
- this.point.add(object2d)
+ this.object.position.copy(killmail.victim.position)
+ this.object.add(object2d)
this.domElement.classList.add('wreck', team)
this.domElement.appendChild(labelElement)
this.domElement.onclick = () => window.open(`https://zkillboard.com/kill/${this.killmail.killmail_id}/`)
- this.domElement.oncontextmenu = () => {
- grid.controls.target.copy(this.point.position)
- grid.controls.update()
- }
}
toggleKilled(timestamp) {
@@ -122,64 +178,43 @@ function vec3FromXYZ({x, y, z}) {
return new THREE.Vector3(x, y, z)
}
-function splitKillmails(clusters, killmail) {
- const vec3 = vec3FromXYZ(killmail.victim.position)
- const found = clusters.find(cluster => cluster[0].victim.position.distanceTo(vec3) < 100 * SCALE)
- killmail.victim.position = vec3
- if (found === undefined) {
- clusters.push([killmail])
- }
- else {
- found.push(killmail)
- }
- return clusters
-}
-
function averagePosition(positions) {
const sum = positions.reduce((sum, pos) => sum.add(pos), new THREE.Vector3())
return sum.divideScalar(positions.length)
}
function processBattle({battle, renderer, renderer2d, container, toolbar, skybox}) {
- const clusters = battle.killmails.reduce(splitKillmails, new Array())
+ const battle_obj = new Battle({container, renderer, renderer2d})
+ const wrecks = battle.killmails.map(killmail => new Wreck({killmail, battle}))
+ wrecks.forEach(wreck => wreck.killmail.victim.position = vec3FromXYZ(wreck.killmail.victim.position))
+ wrecks.forEach(wreck => battle_obj.add(wreck))
+ battle_obj.grids.forEach(grid => window.addEventListener('resize', () => grid.onresize()))
+ battle_obj.grids.forEach(grid => grid.recenter())
- let elements = []
- let grids = []
const gridSelection = document.getElementById("grid")
- clusters.forEach(cluster => {
+ battle_obj.grids.forEach(grid => {
const option = document.createElement("option")
const origin = new THREE.Vector3()
- origin.copy(cluster[0].victim.position)
+ origin.copy(grid.wrecks[0].killmail.victim.position)
origin.divideScalar(METERS_IN_AU)
option.text = `${origin.x.toFixed(1)} AU, ${origin.y.toFixed(1)} AU, ${origin.z.toFixed(1)} AU`
- gridSelection.options.add(option)
-
- const center = averagePosition(cluster.map(km => km.victim.position))
- const grid = new SkirmishGrid({container, renderer, renderer2d})
- cluster.forEach(killmail => {
- killmail.victim.position.sub(center).divideScalar(SCALE)
- const wreck = new Wreck({killmail, grid, battle})
- grid.add(wreck.point)
- elements.push(wreck)
- })
- grids.push(grid)
- window.addEventListener('resize', () => grid.onresize())
+ gridSelection.appendChild(option)
})
gridSelection.oninput = () => {
- grids.forEach(g => g.disable())
- grids[gridSelection.selectedIndex].enable()
- grids[gridSelection.selectedIndex].draw()
+ battle_obj.grids.forEach(g => g.disable())
+ battle_obj.grids.at(gridSelection.selectedIndex).enable()
+ battle_obj.grids.at(gridSelection.selectedIndex).draw()
}
gridSelection.oninput()
skybox.then(skybox => {
const rt = new THREE.WebGLCubeRenderTarget(skybox.image.height)
rt.fromEquirectangularTexture(renderer, skybox)
- grids.forEach(g => g.scene.background = rt)
+ battle_obj.grids.forEach(g => g.scene.background = rt)
})
- const start = Date.parse(battle.started_at) - EXPIRY
- const end = Date.parse(battle.ended_at) + EXPIRY
+ const start = battle_obj.timeline.start - EXPIRY
+ const end = battle_obj.timeline.finish + EXPIRY
const bottomBar = document.createElement("div")
const seekbar = document.createElement("div")
@@ -227,7 +262,7 @@ function processBattle({battle, renderer, renderer2d, container, toolbar, skybox
else {
current += 5000
}
- elements.forEach(item => item.toggleKilled(current))
+ battle_obj.timeline.simple_list.forEach(item => item.toggleKilled(current))
const norm = (current - start) / (end - start)
progress.style.width = `${norm * 100}%`
writeTime(current)
@@ -245,12 +280,12 @@ function processBattle({battle, renderer, renderer2d, container, toolbar, skybox
const timestamp = start + (end - start) * lim
if (e.clientX != 0 && current != timestamp) {
current = timestamp
- elements.forEach(item => item.toggleKilled(timestamp))
+ battle_obj.timeline.simple_list.forEach(item => item.toggleKilled(timestamp))
progress.style.width = `${lim * 100}%`
writeTime(current)
}
}
- elements.forEach(item => item.toggleKilled(start))
+ battle_obj.timeline.simple_list.forEach(item => item.toggleKilled(start))
writeTime(current)
seekbar.onclick = seekWithBar