Render positions
No frame syncs, so flickers terribly, and performance is garbage. But it works.
This commit is contained in:
parent
b26a39a461
commit
53487944bc
@ -31,7 +31,11 @@ module.exports = {
|
|||||||
asyncArrow: "always"
|
asyncArrow: "always"
|
||||||
}],
|
}],
|
||||||
"quote-props": ["error", "consistent"],
|
"quote-props": ["error", "consistent"],
|
||||||
"quotes": ["error", "double"]
|
"quotes": ["error", "double"],
|
||||||
|
"sort-imports": ["error", {
|
||||||
|
"ignoreCase": true,
|
||||||
|
"allowSeparatedGroups": true
|
||||||
|
}]
|
||||||
},
|
},
|
||||||
overrides: [
|
overrides: [
|
||||||
{
|
{
|
||||||
|
33
src/components/Canvas.tsx
Normal file
33
src/components/Canvas.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import React from "react"
|
||||||
|
|
||||||
|
import CanvasContext from "./CanvasContext"
|
||||||
|
|
||||||
|
export interface SystemCanvasProps {
|
||||||
|
height: number,
|
||||||
|
width: number,
|
||||||
|
children?: JSX.Element[]
|
||||||
|
}
|
||||||
|
|
||||||
|
function SystemCanvas({ height, width, children }: SystemCanvasProps) {
|
||||||
|
const canvasRef = React.useRef<HTMLCanvasElement>(null)
|
||||||
|
const [context, setContext] = React.useState<CanvasRenderingContext2D>(null)
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const context = canvasRef.current.getContext("2d")
|
||||||
|
context.save()
|
||||||
|
context.fillStyle = "black"
|
||||||
|
context.fillRect(0, 0, width, height)
|
||||||
|
context.restore()
|
||||||
|
setContext(context)
|
||||||
|
})
|
||||||
|
|
||||||
|
return (<div>
|
||||||
|
<CanvasContext.Provider value={ context }>
|
||||||
|
<canvas width={width} height={height} ref={canvasRef} style={{ width, height }} />
|
||||||
|
{children}
|
||||||
|
</CanvasContext.Provider>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SystemCanvas
|
5
src/components/CanvasContext.ts
Normal file
5
src/components/CanvasContext.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import React from "react"
|
||||||
|
|
||||||
|
const CanvasContext = React.createContext<CanvasRenderingContext2D | null>(null)
|
||||||
|
|
||||||
|
export default CanvasContext
|
@ -1,17 +1,19 @@
|
|||||||
import React, { useState, useEffect } from "react"
|
import React, { useEffect, useState } from "react"
|
||||||
|
|
||||||
import { Message, Object } from "@app/types"
|
import { Body, Bounds, Message } from "@app/types"
|
||||||
|
import Canvas from "./Canvas"
|
||||||
import Client from "@app/client"
|
import Client from "@app/client"
|
||||||
import ObjectList from "./ObjectList"
|
import RenderedBody from "./RenderedBody"
|
||||||
|
|
||||||
function Home() {
|
function Home() {
|
||||||
const [objects, setObjects] = useState<Object[]>([])
|
const [bodies, setBodies] = useState<Body[]>([])
|
||||||
const [iteration, setIteration] = useState(0)
|
const [iteration, setIteration] = useState(0)
|
||||||
const [messageCount, setMessageCount] = useState(0)
|
const [messageCount, setMessageCount] = useState(0)
|
||||||
const [client, setClient] = useState<Client|null>(null)
|
const [client, setClient] = useState<Client|null>(null)
|
||||||
|
const [bounds, setBounds] = useState<Bounds>(new Bounds(0, 0, 30, 30))
|
||||||
|
|
||||||
const handleMessage = (msg: Message) => {
|
const handleMessage = (msg: Message) => {
|
||||||
setObjects(msg.objects)
|
setBodies(msg.objects)
|
||||||
setIteration(msg.iteration)
|
setIteration(msg.iteration)
|
||||||
setMessageCount((mc) => mc + 1)
|
setMessageCount((mc) => mc + 1)
|
||||||
}
|
}
|
||||||
@ -31,11 +33,29 @@ function Home() {
|
|||||||
}
|
}
|
||||||
}, [client, messageCount])
|
}, [client, messageCount])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setBounds((bounds) => bodies.reduce(
|
||||||
|
(bounds, obj) => new Bounds(
|
||||||
|
Math.min(obj.x, bounds.minX),
|
||||||
|
Math.min(obj.y, bounds.minY),
|
||||||
|
Math.max(obj.x, bounds.maxX),
|
||||||
|
Math.max(obj.y, bounds.maxY)), bounds))
|
||||||
|
}, [bodies])
|
||||||
|
|
||||||
|
const actualBounds = new Bounds(0, 0, 300, 300)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h1>Hello, World!</h1>
|
<h1>Hello, World!</h1>
|
||||||
<p>Iteration: { iteration }, message count: { messageCount }.</p>
|
<p>Iteration: { iteration }, message count: { messageCount }, nObjects: { bodies.length }.</p>
|
||||||
<ObjectList objects={objects} />
|
<Canvas height={actualBounds.height} width={actualBounds.width}>
|
||||||
|
{bodies.map((body) => <RenderedBody
|
||||||
|
key={body.id}
|
||||||
|
body={body}
|
||||||
|
bounds={bounds}
|
||||||
|
actualBounds={actualBounds}
|
||||||
|
/>)}
|
||||||
|
</Canvas>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
import React from "react"
|
|
||||||
|
|
||||||
import { Object } from "@app/types"
|
|
||||||
|
|
||||||
export interface ObjectListProps {
|
|
||||||
objects: Object[]
|
|
||||||
}
|
|
||||||
|
|
||||||
function ObjectList({ objects }: ObjectListProps) {
|
|
||||||
return (<ul>
|
|
||||||
{objects.map((o) => <li key={o.id}>{o.name} @ ({o.x}, {o.y}, {o.z}) </li>)}
|
|
||||||
</ul>)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ObjectList
|
|
33
src/components/RenderedBody.tsx
Normal file
33
src/components/RenderedBody.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import React from "react"
|
||||||
|
|
||||||
|
import { Body, Bounds } from "types"
|
||||||
|
import CanvasContext from "./CanvasContext"
|
||||||
|
|
||||||
|
export interface RenderedBodyProps {
|
||||||
|
body: Body
|
||||||
|
bounds: Bounds
|
||||||
|
actualBounds: Bounds
|
||||||
|
}
|
||||||
|
|
||||||
|
function RenderedBody({ body, bounds, actualBounds } : RenderedBodyProps): JSX.Element {
|
||||||
|
const context = React.useContext(CanvasContext)
|
||||||
|
if (context === null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const xScale = actualBounds.width / bounds.width
|
||||||
|
const yScale = actualBounds.height / bounds.width
|
||||||
|
|
||||||
|
context.save()
|
||||||
|
context.scale(xScale, yScale)
|
||||||
|
context.translate(-bounds.minX, -bounds.minY)
|
||||||
|
context.fillStyle = "white"
|
||||||
|
context.beginPath()
|
||||||
|
context.ellipse(body.x, body.y, 1 / xScale, 1 / yScale, 0, 0, Math.PI * 2)
|
||||||
|
context.fill()
|
||||||
|
context.restore()
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RenderedBody
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react'
|
import React from "react"
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from "react-dom"
|
||||||
|
|
||||||
import Home from '@app/components/Home'
|
import Home from "@app/components/Home"
|
||||||
|
|
||||||
ReactDOM.render(<Home />, document.getElementById('root'))
|
ReactDOM.render(<Home />, document.getElementById("root"))
|
||||||
|
21
src/types.ts
21
src/types.ts
@ -1,4 +1,4 @@
|
|||||||
export interface Object {
|
export interface Body {
|
||||||
name: string,
|
name: string,
|
||||||
id: number,
|
id: number,
|
||||||
x: number,
|
x: number,
|
||||||
@ -8,5 +8,22 @@ export interface Object {
|
|||||||
|
|
||||||
export interface Message {
|
export interface Message {
|
||||||
iteration: number,
|
iteration: number,
|
||||||
objects: Object[]
|
objects: Body[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Bounds {
|
||||||
|
minX: number
|
||||||
|
minY: number
|
||||||
|
maxX: number
|
||||||
|
maxY: number
|
||||||
|
|
||||||
|
constructor(minX: number, minY: number, maxX: number, maxY: number) {
|
||||||
|
this.minX = minX
|
||||||
|
this.minY = minY
|
||||||
|
this.maxX = maxX
|
||||||
|
this.maxY = maxY
|
||||||
|
}
|
||||||
|
|
||||||
|
get width() { return this.maxX - this.minX }
|
||||||
|
get height() { return this.maxY - this.minY }
|
||||||
}
|
}
|
||||||
|
@ -13,4 +13,4 @@
|
|||||||
"@app/*": ["../src/*"]
|
"@app/*": ["../src/*"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user