3d orientation visualization html/css

This commit is contained in:
Timo Volkmann 2020-11-07 17:58:47 +01:00
parent edb74a66fd
commit 718e4c0f51
3 changed files with 220 additions and 146 deletions

View File

@ -1,26 +1,32 @@
package dispatcher
import "errors"
import (
"errors"
"fmt"
)
type Dispatcher struct {
listeners map[int16]chan string
counter int16
}
func New() Dispatcher {
return Dispatcher{
listeners: map[int16]chan string{},
func New() *Dispatcher {
fmt.Println("new dispatcher")
return &Dispatcher{
listeners: make(map[int16]chan string),
counter: 0,
}
}
func (d *Dispatcher) Publish(message string) {
fmt.Println("publish to listeners", len(d.listeners))
for _, ch := range d.listeners {
ch <- message
}
}
func (d *Dispatcher) Subscribe() (id int16, receiver <-chan string) {
fmt.Println("subscribe")
key := d.counter
d.counter++
rec := make(chan string)
@ -29,6 +35,7 @@ func (d *Dispatcher) Subscribe() (id int16, receiver <-chan string) {
}
func (d *Dispatcher) Unsubscribe(id int16) error {
fmt.Println("unsubscribe")
receiver, ok := d.listeners[id]
if !ok {
return errors.New("no subscription with id")

174
index.html Normal file
View File

@ -0,0 +1,174 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script>
window.addEventListener("load", function(evt) {
var output = document.getElementById("output");
var input = document.getElementById("input");
var ws;
var print = function(message) {
var d = document.createElement("div");
d.textContent = message;
output.appendChild(d);
};
var print2 = function(message) {
var d = document.createElement("p");
d.innerText = message;
oldNode = output.firstChild
output.replaceChild(d, oldNode)
};
document.getElementById("open").onclick = function(evt) {
if (ws && ws.OPEN) {
print("Websocket already open")
return false;
}
ws = new WebSocket("{{.}}");
ws.onopen = function(evt) {
print("OPEN");
}
ws.onclose = function(evt) {
ws = null;
print2("CLOSE");
}
ws.onmessage = function(evt) {
print2("RESPONSE: " + evt.data);
let dat = JSON.parse(evt.data)
console.log(dat.orientation)
document.getElementById("gyroscope").style.transform = `rotateX(${dat.orientation[1]}deg) rotateY(${dat.orientation[0]}deg) rotateZ(${-dat.orientation[2]}deg)`
}
ws.onerror = function(evt) {
print("ERROR: " + evt.data);
}
return false;
};
document.getElementById("send").onclick = function(evt) {
if (!ws) {
return false;
}
print("SEND: " + input.value);
ws.send(input.value);
return false;
};
document.getElementById("close").onclick = function(evt) {
if (!ws) {
return false;
}
ws.close();
return false;
};
});
</script>
<style>
* { box-sizing: border-box; }
body { font-family: sans-serif; }
.scene {
width: 200px;
height: 200px;
border: 1px solid #CCC;
margin: 80px;
perspective: 400px;
}
.cube {
width: 200px;
height: 200px;
position: relative;
transform-style: preserve-3d;
transform: translateZ(-100px);
transition: transform 17ms;
}
.cube.show-front { transform: translateZ(-100px) rotateY( 0deg); }
.cube.show-right { transform: translateZ(-100px) rotateY( -90deg); }
.cube.show-back { transform: translateZ(-100px) rotateY(-180deg); }
.cube.show-left { transform: translateZ(-100px) rotateY( 90deg); }
.cube.show-top { transform: translateZ(-100px) rotateX( -90deg); }
.cube.show-bottom { transform: translateZ(-100px) rotateX( 90deg); }
.cube__face {
position: absolute;
width: 200px;
height: 200px;
border: 2px solid black;
line-height: 200px;
font-size: 40px;
font-weight: bold;
color: white;
text-align: center;
}
.cube__face--front { background: hsla( 0, 100%, 50%, 0.7); }
.cube__face--right { background: hsla( 60, 100%, 50%, 0.7); }
.cube__face--back { background: hsla(120, 100%, 50%, 0.7); }
.cube__face--left { background: hsla(180, 100%, 50%, 0.7); }
.cube__face--top { background: hsla(240, 100%, 50%, 0.7); }
.cube__face--bottom { background: hsla(300, 100%, 50%, 0.7); }
.cube__face--front { transform: rotateY( 0deg) translateZ(100px); }
.cube__face--right { transform: rotateY( 90deg) translateZ(100px); }
.cube__face--back { transform: rotateY(180deg) translateZ(100px); }
.cube__face--left { transform: rotateY(-90deg) translateZ(100px); }
.cube__face--top { transform: rotateX( 90deg) translateZ(100px); }
.cube__face--bottom { transform: rotateX(-90deg) translateZ(100px); }
label { margin-right: 10px; }
</style>
</head>
<body>
<table style="font-size: x-small">
<tr>
<td valign="top" width="50%">
<p>Click "Open" to create a connection to the server,
"Send" to send a message to the server and "Close" to close the connection.
You can change the message and send multiple times.
</p>
<form>
<button id="open">Open</button>
<button id="close">Close</button>
<p style="display: none" >
<input id="input" type="text" value="Hello world!">
<button id="send">Send</button>
</p>
</form>
<div class="scene">
<div id="gyroscope" class="cube">
<div class="cube__face cube__face--front">front</div>
<div class="cube__face cube__face--back">back</div>
<div class="cube__face cube__face--right">right</div>
<div class="cube__face cube__face--left">left</div>
<div class="cube__face cube__face--top">top</div>
<div class="cube__face cube__face--bottom">bottom</div>
</div>
</div>
<p class="radio-group" style="display: none">
<label>
<input type="radio" name="rotate-cube-side" value="front" checked /> front
</label>
<label>
<input type="radio" name="rotate-cube-side" value="right" /> right
</label>
<label>
<input type="radio" name="rotate-cube-side" value="back" /> back
</label>
<label>
<input type="radio" name="rotate-cube-side" value="left" /> left
</label>
<label>
<input type="radio" name="rotate-cube-side" value="top" /> top
</label>
<label>
<input type="radio" name="rotate-cube-side" value="bottom" /> bottom
</label>
</p>
</td>
<td valign="top" width="50%">
<div id="output"></div>
</td>
</tr>
</table>
</body>
</html>

177
server.go
View File

@ -2,6 +2,7 @@ package main
import (
"fmt"
"git.timovolkmann.de/gyrogpsc/dispatcher"
"github.com/gorilla/websocket"
"github.com/tidwall/pretty"
"html/template"
@ -19,26 +20,38 @@ const (
var upgrader = websocket.Upgrader{} // use default options
func echo(channel <-chan string) func(w http.ResponseWriter, r *http.Request) {
func echo(d *dispatcher.Dispatcher) func(w http.ResponseWriter, r *http.Request) {
fmt.Println("echo")
return func(w http.ResponseWriter, r *http.Request) {
fmt.Println("upgrading to ws")
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Print("upgrade:", err)
return
}
defer c.Close()
//defer c.Close()
go func() {
for {
if _, _, err := c.NextReader(); err != nil {
c.Close()
break
}
}
}()
dispatcherId, channel := d.Subscribe()
defer d.Unsubscribe(dispatcherId)
for {
//mt, message, err := c.ReadMessage()
log.Println("")
//if err != nil {
// log.Println("read:", err)
// break
//}
//log.Printf("recv: %s", message)
cmsg := <-channel
err = c.WriteMessage(websocket.TextMessage, []byte(cmsg))
if err != nil {
log.Println("write:", err)
break
}
}
@ -46,23 +59,26 @@ func echo(channel <-chan string) func(w http.ResponseWriter, r *http.Request) {
}
func home(w http.ResponseWriter, r *http.Request) {
homeTemplate.Execute(w, "ws://"+r.Host+"/echo")
//var homeTemplate = template.Must(template.New("").ParseFiles("index.html"))
tpl, err := template.ParseFiles("index.html")
if err != nil {
log.Fatalln(err)
}
err = tpl.Execute(w, "ws://"+r.Host+"/echo")
if err != nil {
log.Fatalln(err)
}
}
func main() {
channel := make(chan string)
switch CONN_TYPE {
case "tcp":
go tcp(channel)
case "udp":
go udp()
}
http.HandleFunc("/echo", echo(channel))
d := dispatcher.New()
go tcp(d)
http.HandleFunc("/echo", echo(d))
http.HandleFunc("/", home)
log.Fatal(http.ListenAndServe(":3011", nil))
}
func tcp(messageChannel chan<- string) {
func tcp(d *dispatcher.Dispatcher) {
fmt.Println("Hello TCP")
listener, err := net.Listen("tcp", CONN_PORT)
if err != nil {
@ -72,7 +88,6 @@ func tcp(messageChannel chan<- string) {
// Close the listener when the application closes.
defer listener.Close()
//messageChannel := make(chan string)
for {
// Listen for an incoming connection.
conn, err := listener.Accept()
@ -81,12 +96,13 @@ func tcp(messageChannel chan<- string) {
os.Exit(1)
}
// Handle connections in a new goroutine.
go handleRequest(conn, messageChannel)
go handleRequest(conn, d)
}
}
// Handles incoming requests.
func handleRequest(conn net.Conn, messageChannel chan<- string) {
func handleRequest(conn net.Conn, d *dispatcher.Dispatcher) {
fmt.Println("handling sensordata via tcp")
defer conn.Close()
// Make a buffer to hold incoming data.
for {
@ -99,134 +115,11 @@ func handleRequest(conn net.Conn, messageChannel chan<- string) {
}
json := buf
json = pretty.Pretty(json)
fmt.Println(string(json))
messageChannel <- string(json)
//fmt.Println(string(json))
d.Publish(string(json))
// Send a response back to person contacting us.
// conn.Write([]byte("You stepped into my honey pot. I'll find you! "))
conn.Write([]byte("success"))
// Close the connection when you're done with it.
}
}
func udp() {
fmt.Println("Hello!")
port := CONN_PORT
protocol := "udp"
//Build the address
udpAddr, err := net.ResolveUDPAddr(protocol, port)
if err != nil {
fmt.Println("Wrong Address")
return
}
//Output
fmt.Println("Reading " + protocol + " from " + udpAddr.String())
//Create the connection
udpConn, err := net.ListenUDP(protocol, udpAddr)
if err != nil {
fmt.Println(err)
}
//Keep calling this function
for {
handlePacket(udpConn)
}
}
func handlePacket(conn *net.UDPConn) {
var buf = make([]byte, 2048)
n, err := conn.Read(buf)
fmt.Println("Buffersize:", n)
if err != nil {
fmt.Println("Error Reading")
return
} else {
fmt.Println(string(buf))
//fmt.Println(hex.EncodeToString(buf[0:n]))
//fmt.Println("Package Done")
}
}
var homeTemplate = template.Must(template.New("").Parse(`
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script>
window.addEventListener("load", function(evt) {
var output = document.getElementById("output");
var input = document.getElementById("input");
var ws;
var print = function(message) {
var d = document.createElement("div");
d.textContent = message;
output.appendChild(d);
};
var print2 = function(message) {
var d = document.createElement("p");
d.innerText = message;
oldNode = output.firstChild
output.replaceChild(d, oldNode)
};
document.getElementById("open").onclick = function(evt) {
if (ws) {
return false;
}
ws = new WebSocket("{{.}}");
ws.onopen = function(evt) {
print("OPEN");
}
ws.onclose = function(evt) {
print("CLOSE");
ws = null;
}
ws.onmessage = function(evt) {
print2("RESPONSE: " + evt.data);
}
ws.onerror = function(evt) {
print("ERROR: " + evt.data);
}
return false;
};
document.getElementById("send").onclick = function(evt) {
if (!ws) {
return false;
}
print("SEND: " + input.value);
ws.send(input.value);
return false;
};
document.getElementById("close").onclick = function(evt) {
if (!ws) {
return false;
}
ws.close();
return false;
};
});
</script>
</head>
<body>
<table>
<tr><td valign="top" width="50%">
<p>Click "Open" to create a connection to the server,
"Send" to send a message to the server and "Close" to close the connection.
You can change the message and send multiple times.
<p>
<form>
<button id="open">Open</button>
<button id="close">Close</button>
<p><input id="input" type="text" value="Hello world!">
<button id="send">Send</button>
</form>
</td><td valign="top" width="50%">
<div id="output"></div>
</td></tr></table>
</body>
</html>
`))