floating labels
This commit is contained in:
parent
4a671e8019
commit
890c86e654
4 changed files with 62 additions and 21 deletions
16
index.html
16
index.html
|
@ -11,7 +11,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
font: 16/1.5 sans-serif normal;
|
font: 16px monospace;
|
||||||
color-scheme: light dark;
|
color-scheme: light dark;
|
||||||
color: #EEE;
|
color: #EEE;
|
||||||
background-color: #222;
|
background-color: #222;
|
||||||
|
@ -30,10 +30,24 @@
|
||||||
#info > button.highlighted {
|
#info > button.highlighted {
|
||||||
border-color: yellow;
|
border-color: yellow;
|
||||||
}
|
}
|
||||||
|
label {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
margin-top: -.5em;
|
||||||
|
margin-left: .5em;
|
||||||
|
font-weight: bold;
|
||||||
|
color: white;
|
||||||
|
pointer-events: none;
|
||||||
|
transform: translate(0, 0);
|
||||||
|
background: #0008;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="info">Click a star to get options.</div>
|
<div id="info">Click a star to get options.</div>
|
||||||
|
<div id="labels"></div>
|
||||||
<script type="module" src="/src/main.ts"></script>
|
<script type="module" src="/src/main.ts"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
13
src/main.ts
13
src/main.ts
|
@ -1,4 +1,3 @@
|
||||||
import { IncomingMessage } from 'http'
|
|
||||||
import {
|
import {
|
||||||
WebGLRenderer,
|
WebGLRenderer,
|
||||||
Scene,
|
Scene,
|
||||||
|
@ -64,7 +63,7 @@ function init() {
|
||||||
let closest: Intersection<Object3D<Event>> | null = null
|
let closest: Intersection<Object3D<Event>> | null = null
|
||||||
|
|
||||||
for (let i of intersections) {
|
for (let i of intersections) {
|
||||||
if (i.distanceToRay === undefined) continue
|
if (i.distanceToRay === undefined) continue // ignore Lines
|
||||||
if (closest === null || i.distanceToRay < (closest.distanceToRay ?? 0)) {
|
if (closest === null || i.distanceToRay < (closest.distanceToRay ?? 0)) {
|
||||||
closest = i
|
closest = i
|
||||||
}
|
}
|
||||||
|
@ -86,8 +85,16 @@ function init() {
|
||||||
raycaster.intersectObject(stars, true, intersections)
|
raycaster.intersectObject(stars, true, intersections)
|
||||||
|
|
||||||
renderer.render(scene, camera)
|
renderer.render(scene, camera)
|
||||||
|
|
||||||
|
// update label positions in HTML space
|
||||||
|
// Attention: This has to happen after the render call, to avoid flickering
|
||||||
|
for (let star of stars.children) {
|
||||||
|
;(star as Star).setLabelPos(camera, w, h)
|
||||||
|
// set label z-index to distance to make them overlap intuitively
|
||||||
|
}
|
||||||
})
|
})
|
||||||
document.body.appendChild(renderer.domElement)
|
|
||||||
|
document.body.prepend(renderer.domElement)
|
||||||
}
|
}
|
||||||
|
|
||||||
init()
|
init()
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import { BufferGeometry, Group, Line, LineBasicMaterial, Shape, Vector3 } from 'three'
|
import { BufferGeometry, Group, Line, LineBasicMaterial, Shape, Vector3 } from 'three'
|
||||||
|
|
||||||
export function planeGeometry(radius: number, n = 5) {
|
export function planeGeometry(radius: number, n = 5) {
|
||||||
const material = new LineBasicMaterial({
|
const material = new LineBasicMaterial({ color: 0x205020 })
|
||||||
color: 0x303030,
|
|
||||||
})
|
|
||||||
const plane = new Group()
|
const plane = new Group()
|
||||||
|
|
||||||
const xLine = new BufferGeometry().setFromPoints([
|
const xLine = new BufferGeometry().setFromPoints([
|
||||||
|
|
50
src/stars.ts
50
src/stars.ts
|
@ -8,6 +8,7 @@ import {
|
||||||
LineBasicMaterial,
|
LineBasicMaterial,
|
||||||
Vector3,
|
Vector3,
|
||||||
Spherical,
|
Spherical,
|
||||||
|
Camera,
|
||||||
} from 'three'
|
} from 'three'
|
||||||
|
|
||||||
import data from './testdata.json'
|
import data from './testdata.json'
|
||||||
|
@ -25,9 +26,7 @@ export class Star extends Group {
|
||||||
public isStar = true
|
public isStar = true
|
||||||
public starData: StarData
|
public starData: StarData
|
||||||
|
|
||||||
private tangentialCoords = new Vector3()
|
private coords = new Vector3()
|
||||||
private cartesianCoords = new Vector3()
|
|
||||||
private sphericalCoords = new Spherical()
|
|
||||||
|
|
||||||
private isHighlighted = false
|
private isHighlighted = false
|
||||||
private normalPointSize = 2
|
private normalPointSize = 2
|
||||||
|
@ -40,30 +39,40 @@ export class Star extends Group {
|
||||||
private whiteColor = new Float32BufferAttribute([255, 255, 255], 3)
|
private whiteColor = new Float32BufferAttribute([255, 255, 255], 3)
|
||||||
private yellowColor = new Float32BufferAttribute([255, 255, 0], 3)
|
private yellowColor = new Float32BufferAttribute([255, 255, 0], 3)
|
||||||
|
|
||||||
private poleLine = new Line(new BufferGeometry(), this.lineMaterial)
|
private labelEl = document.createElement('label')
|
||||||
|
|
||||||
|
private point: Points<BufferGeometry, PointsMaterial>
|
||||||
|
|
||||||
constructor(starData: StarData) {
|
constructor(starData: StarData) {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
const { radius, phi, theta } = starData
|
|
||||||
this.starData = starData
|
this.starData = starData
|
||||||
this.sphericalCoords.set(radius, phi, theta)
|
|
||||||
this.cartesianCoords.setFromSpherical(this.sphericalCoords)
|
|
||||||
|
|
||||||
const { x, z } = this.cartesianCoords
|
const { radius, phi, theta } = starData
|
||||||
this.tangentialCoords.set(x, 0, z)
|
const sphericalCoords = new Spherical(radius, phi, theta)
|
||||||
|
this.coords.setFromSpherical(sphericalCoords)
|
||||||
|
|
||||||
this.poleLine.geometry.setFromPoints([this.cartesianCoords, this.tangentialCoords])
|
const { x, z } = this.coords
|
||||||
|
const tangentialCoords = new Vector3(x, 0, z)
|
||||||
|
|
||||||
this.add(this.poleLine)
|
// distance indicator / pole
|
||||||
|
const poleLine = new Line(new BufferGeometry(), this.lineMaterial)
|
||||||
|
poleLine.geometry.setFromPoints([this.coords, tangentialCoords])
|
||||||
|
this.add(poleLine)
|
||||||
|
|
||||||
const coords = [this.cartesianCoords.x, this.cartesianCoords.y, this.cartesianCoords.z]
|
// the actual "star"
|
||||||
|
const coords = [this.coords.x, this.coords.y, this.coords.z]
|
||||||
this.pointGeometry.setAttribute('position', new Float32BufferAttribute(coords, 3))
|
this.pointGeometry.setAttribute('position', new Float32BufferAttribute(coords, 3))
|
||||||
this.pointGeometry.setAttribute('color', this.whiteColor)
|
this.pointGeometry.setAttribute('color', this.whiteColor)
|
||||||
this.pointGeometry.computeBoundingSphere()
|
this.pointGeometry.computeBoundingSphere()
|
||||||
|
|
||||||
const point = new Points(this.pointGeometry, this.pointMaterial)
|
this.point = new Points(this.pointGeometry, this.pointMaterial)
|
||||||
this.add(point)
|
this.add(this.point)
|
||||||
|
|
||||||
|
// label
|
||||||
|
const container = document.getElementById('labels')!
|
||||||
|
this.labelEl.innerText = starData.name
|
||||||
|
container.appendChild(this.labelEl)
|
||||||
}
|
}
|
||||||
|
|
||||||
private setHighlight(isHighlight = true) {
|
private setHighlight(isHighlight = true) {
|
||||||
|
@ -87,6 +96,19 @@ export class Star extends Group {
|
||||||
this.isHighlighted = !this.isHighlighted
|
this.isHighlighted = !this.isHighlighted
|
||||||
this.setHighlight(this.isHighlighted)
|
this.setHighlight(this.isHighlighted)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setLabelPos(camera: Camera, width: number, height: number) {
|
||||||
|
const dpr = window.devicePixelRatio
|
||||||
|
const pos = this.coords.clone()
|
||||||
|
pos.project(camera)
|
||||||
|
|
||||||
|
pos.x = Math.round((0.5 + pos.x / 2) * (width / dpr))
|
||||||
|
pos.y = Math.round((0.5 - pos.y / 2) * (height / dpr))
|
||||||
|
|
||||||
|
this.labelEl.style.transform = `translate(${pos.x}px, ${pos.y}px)`
|
||||||
|
const zIndex = `${10000000 - Math.round(pos.z * 10000000)}`
|
||||||
|
this.labelEl.style.zIndex = zIndex
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function renderStars(maxRadius: number) {
|
export function renderStars(maxRadius: number) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue