Kapitel 18: Das Frontend

Drucken

Das Frontend teilt sich Folgendermaße auf:

Datei Funktion
index.html Wird ausgespielt beim aufruf von http://localhost:8080/
In dieser Datei sind alle HTML Elemente mit Id hinterlegt die dann über JavaScript mit den Daten gefüllt werden.
index.js In dieser Java-Script Datei wird die Websocket Verbindung hergestellt. Alle ankommenden Websocket-Nachrichten werden hier empfangen und einem HTML Element zugeordnet. Alle Nachrichten (Tastendrücke) werden hier auch an die Java-Anwendung zurückgespielt.
inout.js Diese Datei ist registriert Tastendrücke.
one-page-wonder.css Hier sind eigene CSS Eigenschaften hinterlegt, um das Design der Website zu definieren.
Ordner img In diesem Ornder sind schlicht einige Bilder für das Frontend hinterlegt.

Die index.html Datei:

<!DOCTYPE html>
<html lang="de" xmlns:th="http://www.w3.org/1999/xhtml">

<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="" />
<meta name="author" content="" />

<title>DIY - Robot Interface</title>

<!-- Bootstrap Core CSS -->
<link
	href="http://cdn.jsdelivr.net/webjars/bootstrap/3.3.7-1/css/bootstrap.min.css"
	th:href="@{/webjars/bootstrap/3.3.7-1/css/bootstrap.min.css}"
	rel="stylesheet" media="screen" />

<!-- Custom CSS -->
<link href="/../static/css/one-page-wonder.css"
	th:href="@{/css/one-page-wonder.css}" rel="stylesheet" />
</head>

<body>
	<noscript>
		<h2 style="color: #ff0000">Seems your browser doesn't support
			Javascript! Websocket relies on Javascript being enabled. Please
			enable Javascript and reload this page!</h2>
	</noscript>

	<!-- Headline -->
	<div class="container">
		<div class="row">
			<div class="jumbotron">
				<h2>DIY - Over9000 KillingRobot</h2>
				<p>Do it yourself Robot - Alpha Version - Controll Site</p>
				<p>
					Please open console for more details:
					<kbd>ctrl+shift+c</kbd>
				</p>
			</div>

		</div>

	</div>

	<!-- Page Content -->
	<div class="container">
		<div class="row">
			<div class="col-xs-4">

				<!-- Content aside the webcam Image -->
				<div class="col-xs-12">
					<br></br>
					<p>Websocket</p>
					<form class="form-inline">
						<div class="form-group">
							<button id="connect" class="btn btn-default" type="submit">Connect</button>
							<button id="disconnect" class="btn btn-default" type="submit"
								disabled="disabled">Disconnect</button>
							<div id="connected" class="alert alert-danger">Disconnected</div>
						</div>
					</form>
					<div class="form-inline">
						<p>Sensor Values:</p>
						<div class="normal-text">
							Front: Abstand in [cm]
							<kbd id="ultrasonicFront">No data available</kbd>
						</div>
						<div class="normal-text">
							Back: Abstand in [cm]
							<kbd id="ultrasonicBack">No data available</kbd>
						</div>
						<div class="normal-text">
							Lichtsensor
							<kbd id="lightSensor">No data available</kbd>
						</div>
						<div class="normal-text">
							RFID Sensor
							<kbd id="rfidSensor">No data available</kbd>
						</div>

						<div class="normal-text">
							Richtung:
							<kbd id="direction">Direction</kbd>
						</div>


					</div>
				</div>


			</div>
			<div class="col-xs-8">
				<img id="webcam" class="img-responsive" width="640" height="480"
					align="right" vspace="50" src="/../static/img/dummy.png"
					th:src="@{/img/dummy.png}" />
			</div>
		</div>
		<div class="row">
			<div class="col-xs-12">
				<p>Fahren: W,A,S,D, od. in kombination W+D für Kurven</p>
				<p>Roboter Arm: Zahlen 1-6 und + od. - für die Drehrichtung</p>
				<p>Laser: E</p>
			</div>
		</div>
		<div class="row">
			<div class="col-xs-12">
				<div class="col-xs-12">
					<p>GPIO-Settings RaspberryPi:</p>
					<img id="GPIO-Setting" class="img-responsive" align="right"
						vspace="5" src="/../static/img/Raspi-Background.png"
						th:src="@{/img/Raspi-Background.png}" style="opacity: 1.0;" />
				</div>
			</div>
		</div>




		<!-- Footer -->
		<div class="container">
			<div class="form-inline">
				<footer>
					<div class="row">
						<div class="col-lg-12">
							<p>
								All references by: <br></br> DIY Project | Nils Bott, Jan-Niklas
								Sturm, Jens Freiburger
							</p>
						</div>
					</div>
				</footer>
			</div>
		</div>
	</div>


	<!-- jQuery -->
	<script
		src="http://cdn.jsdelivr.net/webjars/jquery/3.1.1/jquery.min.js"
		th:src="@{/webjars/jquery/jquery.min.js}"></script>

	<!-- Bootstrap Core JavaScript -->
	<script
		src="http://cdn.jsdelivr.net/webjars/bootstrap/3.3.7-1/bootstrap.min.js"
		th:src="@{/webjars/bootstrap/js/bootstrap.min.js}"></script>

	<!-- Key Event JavaScript -->
	<script src="/../static/js/inout.js" th:src="@{/js/inout.js}"></script>

	<!-- Websocket JavaScript -->
	<script src="/../static/js/index.js" th:src="@{/js/index.js}"></script>
	<script
		src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.1.4/sockjs.min.js"
		th:src="@{/webjars/sockjs-client/sockjs.min.js}"></script>
	<script
		src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"
		th:src="@{/webjars/stomp-websocket/stomp.min.js}"></script>
</body>

</html>

Die index.js Datei:

var stompClient = null;

var imageCounter = 0;

var images = [
    "../img/8IZCR0wzEIQms.gif",
    "../img/pinguenfight.gif",
    "../img/boingbamm.gif",
    "../img/Now-this-is-a-game-I-could-get-into.gif",
    "../img/fightclub.gif",
    "../img/gihdhphy.gif",
    "../img/giphy.gif",
    "../img/giruffyphy.gif",
    "../img/gisfsfdsfdphy.gif",
    "../img/gisfsfsfphy.gif"
]

var i = 0;

function slideshowPicture(){
    $("#webcam").attr(
        "src",
        images[i%images.length]);
    i++;
}
function checkImageExists(imageUrl, callBack) {
    var imageData = new Image();
    imageData.onload = function() {
        callBack(true);
    };
    imageData.onerror = function() {
        callBack(false);
    };
    imageData.src = imageUrl;
}

function connect() {
    try {
        var socket = new SockJS(window.location.protocol + "//"
            + window.location.hostname + ":" + window.location.port
            + "/diy-robotws");
        stompClient = Stomp.over(socket);
        stompClient.connect({}, connect_callback, error_callback);
    } catch (err) {
        console.log(err);
    }
}

function disconnect() {
    if (stompClient != null) {
        stompClient.disconnect();
    }

    setConnected(false);
}

function sendDirection() {
    stompClient.send("/app/stompMessage", {}, JSON.stringify({
        'content': arguments[0]
    }));
}

function setConnected(connected) {
    $("#connect").prop("disabled", connected);
    $("#disconnect").prop("disabled", !connected);
    if (connected) {
        $("#connected").attr("class", "alert alert-success");
        $("#connected").text("Connected");
    } else {
        $("#connected").attr("class", "alert alert-danger");
        $("#connected").text("Disconnected");
    }
}

var connect_callback = function () {
    stompClient.subscribe('/topic/stompMessage', function (message) {
        msg = JSON.parse(message.body).content;
        var res = msg.split(":");
        if (res[0] == "ultrasonicFront") {
        	$("#ultrasonicFront").text(res[1]);
        }
        if (res[0] == "ultrasonicBack") {
        	$("#ultrasonicBack").text(res[1]);
        }
        if (res[0] == "lightSensor") {
            $("#lightSensor").text(res[1]);
        }
        
        if (res[0] == "direction") {
        	$("#direction").text(res[1]);
        }
        if(res[0] == "rfidSensor") {
        	$("#rfidSensor").text(res[1]);
        }
        console.log(msg)
    });
    setConnected(true);
};

var error_callback = function (error) {
    console.log(error);
    setTimeout(connect, 10000);
    setConnected(false);
}

$(function () {
    // connect to websocket
    connect();
    // set webcam image
    imageFile = window.location.protocol + "//" + window.location.hostname + ":8080/?action=stream"
    checkImageExists(imageFile, function(existsImage) {
        if(existsImage == true) {
            $("#webcam").attr(
                "src",
                window.location.protocol + "//" + window.location.hostname
                + ":8080/?action=stream");
            $("#webcam").attr(
                "style",
                "opacity: 1.0;");
        }
        else {
            setInterval(slideshowPicture, 5000);
        }
    });

    // key events
    $('body').on(
        'keypress',
        function (e) {
            var x = e.which;
            var key = String.fromCharCode(x).toUpperCase();
            console.log("Keypress Type: " + e.type + "\n" +
            		"Keypress Char: "+ e.which + " which is Coded: " + key);
            if (stompClient != null) {
                sendDirection(key + ":pressed");
            }
        });

    $('body').on(
        'keyup',
        function (e) {
        	var x = e.which;
        	
        	console.log ("X is set toooo:" + x)
        	
        	var key = String.fromCharCode(x);
        	if (x == 173) {
        		key = "-"
        	}
        	if (x == 171) {
        		key = "+"
        	}
            console.log("Keypress Type: " + e.type);
            if (stompClient != null) {
                sendDirection(key + ":released");
            }
        });
});

OnePageWonder CSS Datei:

/*
 * Start Bootstrap - One Page Wonder (http://startbootstrap.com/)
 * Copyright 2013-2016 Start Bootstrap
 * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap/blob/gh-pages/LICENSE)
 */

body {
    margin-top: 50px; /* Required padding for .navbar-fixed-top. Remove if using .navbar-static-top. Change if height of navigation changes. */
    /*background-image: url(../img/bg-kill-robot.jpg);*/
    background-image: url(../img/roboFace.gif);
    background-repeat: no-repeat;
    background-attachment: fixed;
    background-size: 100% 100%;
    /* background-size: cover; */
}

.jumbotron {
    background-color: black;
    color: greenyellow;
    font-family: Menlo,Monaco,Consolas,"Courier New",monospace;
    opacity: 0.8;
}

img {
    opacity: 0.8;
    background-color: black;
}

kbd {
    color: greenyellow;
    font-family: Menlo,Monaco,Consolas,"Courier New",monospace;
    background-color: black;
    opacity: 1.0;
}

p {
	background-color: black;
	color: white;
	text-transform: capitalize;
	font-family: Menlo,Monaco,Consolas,"Courier New",monospace;
	font-size: 115%;
	border: 2px solid #222222;
    border-color: greenyellow;
    border-radius: 5px;
    padding-left: 10px;
    padding-right: 10px;
    padding-top: 10px;
    padding-bottom: 10px;
    display: inline-block;
}

.btn {
	opacity: 0.6;
	background-color: #222222;
	border: 2px solid #222222;
	color: white;
	font-family: Menlo,Monaco,Consolas,"Courier New",monospace;
}

.normal-text {
	#opacity: 0.0;
	background-color: #222222;
	border: 2px solid #222222;
	color: white;
	font-family: Menlo,Monaco,Consolas,"Courier New",monospace;
    font-size: 115%;
}

.header-image {
    display: block;
    width: 100%;
    text-align: center;
}

.headline {
    padding: 120px 0;
    color: white;
}

.headline h1 {
    font-size: 100px;
    background: #fff;
    background: rgba(255, 255, 255, 0.9);
}

.headline h2 {
    font-size: 77px;
    background: #fff;
    background: rgba(255, 255, 255, 0.9);
}

h3 {
    color: white;
}

.featurette-divider {
    margin: 80px 0;
}

.featurette {
    overflow: hidden;
}

.featurette-image.pull-left {
    margin-right: 40px;
}

.featurette-image.pull-right {
    margin-left: 40px;
}

.featurette-heading {
    font-size: 50px;
}

footer {
    margin: 50px 0;
}

@media (max-width: 1200px) {
    .headline h1 {
        font-size: 140px;
    }

    .headline h2 {
        font-size: 63px;
    }

    .featurette-divider {
        margin: 50px 0;
    }

    .featurette-image.pull-left {
        margin-right: 20px;
    }

    .featurette-image.pull-right {
        margin-left: 20px;
    }

    .featurette-heading {
        font-size: 35px;
    }
}

@media (max-width: 991px) {
    .headline h1 {
        font-size: 105px;
    }

    .headline h2 {
        font-size: 50px;
    }

    .featurette-divider {
        margin: 40px 0;
    }

    .featurette-image {
        max-width: 50%;
    }

    .featurette-image.pull-left {
        margin-right: 10px;
    }

    .featurette-image.pull-right {
        margin-left: 10px;
    }

    .featurette-heading {
        font-size: 30px;
    }
}

@media (max-width: 768px) {
    .container {
        margin: 0 15px;
    }

    .featurette-divider {
        margin: 40px 0;
    }

    .featurette-heading {
        font-size: 25px;
    }
}

@media (max-width: 668px) {
    .headline h1 {
        font-size: 70px;
    }

    .headline h2 {
        font-size: 32px;
    }

    .featurette-divider {
        margin: 30px 0;
    }
}

@media (max-width: 640px) {
    .headline {
        padding: 75px 0 25px 0;
    }

    .headline h1 {
        font-size: 60px;
    }

    .headline h2 {
        font-size: 30px;
    }
}

@media (max-width: 375px) {
    .featurette-divider {
        margin: 10px 0;
    }

    .featurette-image {
        max-width: 100%;
    }

    .featurette-image.pull-left {
        margin-right: 0;
        margin-bottom: 10px;
    }

    .featurette-image.pull-right {
        margin-bottom: 10px;
        margin-left: 0;
    }
}