1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
import * as THREE from 'https://unpkg.com/three@0.126.1/build/three.module.js'
import { OrbitControls } from 'https://unpkg.com/three@0.126.1/examples/jsm/controls/OrbitControls.js'
import { CSS2DRenderer, CSS2DObject } from 'https://unpkg.com/three@0.126.1/examples/jsm/renderers/CSS2DRenderer.js'
let camera, scene, renderer, renderer2d, wreck
const SCALE = 10000
init()
animate()
function Wreck(vec3, km) {
const point = new THREE.Object3D()
point.position.copy(vec3)
const div = document.createElement('div')
div.className = 'wreck'
const w = document.importNode(wreck, true)
div.appendChild(w)
const label = new CSS2DObject(div)
point.add(label)
return point;
}
function loadWreckIcon() {
return fetch("wreck.svg")
.then(response => response.text())
.then(text => {
const parser = new window.DOMParser()
const svg = parser.parseFromString(text, "image/svg+xml")
wreck = svg.documentElement
return wreck
})
}
function processKillmails(killmails) {
let clusters = []
killmails.forEach(km => {
const pos = km.victim.position
km.victim.position = new THREE.Vector3(pos.x, pos.y, pos.z)
const vec3 = km.victim.position
let added = false
for (const cluster of clusters) {
if (cluster[0].victim.position.distanceTo(vec3) < 100 * SCALE) {
cluster.push(km)
added = true
break
}
}
if (!added) {
clusters.push([km])
}
})
let center = new THREE.Vector3()
let positions = clusters[0].map(km => km.victim.position)
positions.forEach(pos => center.add(new THREE.Vector3(pos.x, pos.y, pos.z)))
center.divideScalar(positions.length)
clusters[0].sort((a, b) => a.killmail_time.localeCompare(b.killmail_time))
let elements = []
clusters[0].forEach(km => {
const vec3 = km.victim.position
vec3.sub(center)
vec3.divideScalar(SCALE)
const point = new THREE.Object3D()
point.position.copy(vec3)
const div = document.createElement('div')
div.className = 'wreck'
const w = document.importNode(wreck, true)
div.appendChild(w)
const label = new CSS2DObject(div)
point.add(label)
scene.add(point)
elements.push(div)
})
const timeline = document.getElementById("timeline")
timeline.max = elements.length + 1
timeline.oninput = function () {
elements.slice(0, this.value).forEach(element => element.classList.add("killed"))
elements.slice(this.value, this.max).forEach(element => element.classList.remove("killed"))
}
}
function init() {
camera = new THREE.PerspectiveCamera(80, window.innerWidth / window.innerHeight, 0.1, 100)
camera.position.set(8, 8, 8)
camera.lookAt(0, 0, 0)
scene = new THREE.Scene()
loadWreckIcon()
.then(() => {
const url = new URL(window.location.href)
return fetch(url.searchParams.get("related") + ".json")
})
.then(response => response.json())
.then(killmails => {
const url = km => `https://esi.evetech.net/latest/killmails/${km.id}/${km.hash}/?datasource=tranquility`
const retrieve = km => fetch(url(km)).then(response => response.json())
return Promise.all(killmails.map(retrieve))
})
.then(processKillmails)
const grid = new THREE.GridHelper(30, 30)
scene.add(grid)
renderer = new THREE.WebGLRenderer({antialias: true})
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)
renderer2d = new CSS2DRenderer()
renderer2d.setSize(window.innerWidth, window.innerHeight)
renderer2d.domElement.style.position = 'absolute'
renderer2d.domElement.style.top = '0px'
document.body.appendChild(renderer2d.domElement)
const controls = new OrbitControls(camera, renderer2d.domElement)
controls.minDistance = 2
controls.maxDistance = 24
const loader = new THREE.TextureLoader()
loader.loadAsync("https://i.imgur.com/rDGOLFC.jpg") // TODO: Don't use imgur as CDN.
.then(skybox => {
const rt = new THREE.WebGLCubeRenderTarget(skybox.image.height)
rt.fromEquirectangularTexture(renderer, skybox)
scene.background = rt
});
window.addEventListener('resize', onWindowResize)
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
renderer.setSize(window.innerWidth, window.innerHeight)
renderer2d.setSize(window.innerWidth, window.innerHeight)
}
function animate() {
requestAnimationFrame(animate)
renderer.render(scene, camera)
renderer2d.render(scene, camera)
}
|