428 lines
24 KiB
HTML
428 lines
24 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>LED-Server :: KJ-intern</title>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
<!-- Font Awesome -->
|
|
<link rel="stylesheet" href="node_modules/font-awesome/css/font-awesome.min.css">
|
|
<!-- Bootstrap core CSS -->
|
|
<link href="node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
<!-- Material Design Bootstrap -->
|
|
<link href="node_modules/bootstrap-material-design/dist/css/bootstrap-material-design.min.css" rel="stylesheet">
|
|
<link href="node_modules/jquery-wheelcolorpicker/css/wheelcolorpicker.css" rel="stylesheet">
|
|
|
|
<link href="node_modules/jquery-minicolors/jquery.minicolors.css" rel="stylesheet">
|
|
|
|
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
|
<!--[if lt IE 9]>
|
|
<script src="node_modules/html5shiv.min.js/html5shiv.min.js"></script>
|
|
<script src="node_modules/respond.min.js/respond.min.js"></script>
|
|
<![endif]-->
|
|
<style>
|
|
.text-nowrap {
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.dimmScreen
|
|
{
|
|
position:fixed;
|
|
padding:0;
|
|
margin:0;
|
|
|
|
top:0;
|
|
left:0;
|
|
|
|
width: 100%;
|
|
height: 100%;
|
|
background:rgba(0, 0, 0, 0.5);
|
|
}
|
|
</style>
|
|
</head>
|
|
<body ng-app="LED-WebFrontend" ng-controller="LED-ServerCtrl" >
|
|
<div style="height: 100vh">
|
|
<div class="container">
|
|
<!-- Not Connected -->
|
|
<div class="row dimmScreen ng-show justify-content-center" ng-hide="connected">
|
|
<div class=" col-md-6 ">
|
|
<div class="row">
|
|
<div class="col-12 mt-3" >
|
|
<div class="card " >
|
|
<!-- Card content -->
|
|
<div class="card-body justify-content-center">
|
|
<!-- Title -->
|
|
<h4 class="card-title infinite animated headShake text-center"><strong>Verbindung wird hergestellt...</strong></h4>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row ng-hide" ng-show="connected">
|
|
<!--Left Col-->
|
|
<div class="col-md-6 mt-3">
|
|
<div class="row">
|
|
<div class="col-12 mt-3" >
|
|
<div class="card " >
|
|
<!-- Card content -->
|
|
<div class="card-body ">
|
|
<!-- Title -->
|
|
<h4 class="card-title"><strong>Neuen Effekt starten</strong></h4>
|
|
<form id="startNewEffectThread">
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="form-group row">
|
|
<label for="newEffectThread" class="col-sm-3 col-form-label"> Select Effect: </label><br>
|
|
<select ng-change="newEffectThread.params=[]" name="newEffectThread" class="form-control col-sm-7 " id="newEffectThread" ng-model="newEffectThread.effect" ng-options="effect.index as effect.name for effect in effects" ></select>
|
|
</div>
|
|
<div class="newEffectThreadDesc">{{effects[newEffectThread.effect].desc}}</div>
|
|
|
|
</div>
|
|
<div class="col-12" ng-repeat="effectParam in effects[newEffectThread.effect].effectParams">
|
|
|
|
<input ng-if="effectParam.type=='colorpicker'"
|
|
minicolors="colorpickerconfig"
|
|
class="form-control"
|
|
type="text"
|
|
ng-init="
|
|
newEffectThreadParamColorPicker[effectParam.index]=rgbToHex(
|
|
effectParam.options[0][2],
|
|
effectParam.options[1][2],
|
|
effectParam.options[2][2]
|
|
);
|
|
newEffectThread.params[effectParam.index] = {};
|
|
newEffectThread.params[effectParam.index][0] = hexToRgb(newEffectThreadParamColorPicker[effectParam.index]).r;
|
|
newEffectThread.params[effectParam.index][1] = hexToRgb(newEffectThreadParamColorPicker[effectParam.index]).g;
|
|
newEffectThread.params[effectParam.index][2] = hexToRgb(newEffectThreadParamColorPicker[effectParam.index]).b
|
|
"
|
|
ng-change="
|
|
newEffectThread.params[effectParam.index][0] = hexToRgb(newEffectThreadParamColorPicker[effectParam.index]).r;
|
|
newEffectThread.params[effectParam.index][1] = hexToRgb(newEffectThreadParamColorPicker[effectParam.index]).g;
|
|
newEffectThread.params[effectParam.index][2] = hexToRgb(newEffectThreadParamColorPicker[effectParam.index]).b"
|
|
ng-model="newEffectThreadParamColorPicker[effectParam.index]"
|
|
>
|
|
|
|
<mdb-range-input ng-if="effectParam.type=='slider'"
|
|
default="true"
|
|
id="range"
|
|
min="{{effectParam.options[0][0]}}"
|
|
ng-value="effectParam.options[0][2]"
|
|
ng-model="newEffectThread.params[effectParam.index][0]"
|
|
max="{{effectParam.options[0][1]}}">
|
|
</mdb-range-input>
|
|
|
|
{{effectParam}}
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-7 mt-3">
|
|
<div class="row">
|
|
<div class="col" ng-repeat="rgbStrip in rgbStrips">
|
|
<!-- Material unchecked -->
|
|
<div class="form-check" >
|
|
<input type="checkbox" class="form-check-input" id="newEffectThreadRGBStrips{{rgbStrip.index}}" name="newEffectThreadRGBStrips[]" ng-model="newEffectThread.rgbStrips[rgbStrip.index]"/>
|
|
<label class="form-check-label text-nowrap" for="newEffectThreadRGBStrips{{rgbStrip.index}}">{{rgbStrip.name}}</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-5 mt-3">
|
|
<!-- Provides extra visual weight and identifies the primary action in a set of buttons -->
|
|
<a href="#" ng-click="startEffect(newEffectThread.effect,newEffectThread.rgbStrips,newEffectThread.params)" class="btn btn-primary float-right">Anwenden</a>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!--Debug!-->
|
|
<div class="col-12 mt-3" ng-show="false">
|
|
<div class="card " >
|
|
<!-- Card content -->
|
|
<div class="card-body ">
|
|
<pre>{{rgbStrips | json}}{{effects | json}}{{effectThreads | json}}{{newEffectThread | json}}</pre>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!--/Left Col-->
|
|
<!--Right Col-->
|
|
<div class="col-md-6 mt-3">
|
|
<div class="row" >
|
|
<form name="moveRGBStripToEffectThreadForm">
|
|
<div class="col-md-12 mt-3" ng-repeat="effectThread in effectThreads" >
|
|
<div class="card" >
|
|
<!-- Card content -->
|
|
<div class="card-body ">
|
|
|
|
<!-- Title -->
|
|
<h4 class="card-title"><strong>{{ effectThread.name }}</strong></h4>
|
|
<!-- Text -->
|
|
<p class="card-text">{{ effectThread.desc }}</p>
|
|
<div class="row">
|
|
<div class="col-12" ng-repeat="effectParam in effectThread.effectParams">
|
|
<input ng-if="effectParam.type=='colorpicker'"
|
|
minicolors="colorpickerconfig"
|
|
class="form-control"
|
|
type="text"
|
|
ng-init="
|
|
effectThreadParamColorPicker[effectThread.index][effectParam.index]=rgbToHex(
|
|
effectParam.values[0],
|
|
effectParam.values[1],
|
|
effectParam.values[2]
|
|
);
|
|
effectThreadParamColorPicker[effectThread.index].params[effectParam.index] = {};
|
|
effectThreadParamColorPicker[effectThread.index].params[effectParam.index][0] = hexToRgb(effectThreadParamColorPicker[effectThread.index][effectParam.index]).r;
|
|
effectThreadParamColorPicker[effectThread.index].params[effectParam.index][1] = hexToRgb(effectThreadParamColorPicker[effectThread.index][effectParam.index]).g;
|
|
effectThreadParamColorPicker[effectThread.index].params[effectParam.index][2] = hexToRgb(effectThreadParamColorPicker[effectThread.index][effectParam.index]).b
|
|
"
|
|
ng-change="
|
|
effectThreadParamColorPicker[effectThread.index].params[effectParam.index][0] = hexToRgb(effectThreadParamColorPicker[effectThread.index][effectParam.index]).r;
|
|
effectThreadParamColorPicker[effectThread.index].params[effectParam.index][1] = hexToRgb(effectThreadParamColorPicker[effectThread.index][effectParam.index]).g;
|
|
effectThreadParamColorPicker[effectThread.index].params[effectParam.index][2] = hexToRgb(effectThreadParamColorPicker[effectThread.index][effectParam.index]).b;
|
|
effectThreadChangeEffectParam(effectThread.index,effectThreadParamColorPicker[effectThread.index].params)
|
|
"
|
|
|
|
ng-model="effectThreadParamColorPicker[effectThread.index][effectParam.index]"
|
|
>
|
|
{{effectParam.values}}
|
|
|
|
<!--
|
|
<input ng-if="effectParam.type=='colorpicker'"
|
|
minicolors="colorpickerconfig"
|
|
id="color-input"
|
|
class="form-control"
|
|
type="text"
|
|
ng-init="effectThreadParamColorPicker[effectThread.index][effectParam.index]=rgbToHex(effectParam.values[0][2],effectParam.values[1][2],effectParam.values[2][2]);"
|
|
ng-change="effectThreadChangeEffectParam(effectThread.index,{0: {0: hexToRgb(effectThreadParamColorPicker[effectThread.index][effectParam.index]).r,1: hexToRgb(effectThreadParamColorPicker[effectThread.index][effectParam.index]).g, 2: hexToRgb(effectThreadParamColorPicker[effectThread.index][effectParam.index]).b}})"
|
|
ng-model="effectThreadParamColorPicker[effectThread.index][effectParam.index]"
|
|
>-->
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col" ng-repeat="rgbStrip in rgbStrips">
|
|
<!-- Material unchecked -->
|
|
<div class="form-check" >
|
|
<input type="radio" ng-checked="isRGBStripActive(rgbStrip,effectThread.activeRGBStips)" ng-change="moveRGBStripToEffectThread(rgbStrip.index,effectThread.index)" class="form-check-input" id="{{ effectThread.name }}EffectThreadRGBStrip{{rgbStrip.index}}" ng-model="moveRGBStripToEffectThreadModel[rgbStrip.index]" name="{{rgbStrip.index}}" value="{{effect.index}}">
|
|
<label class="form-check-label text-nowrap" for="{{ effectThread.name }}EffectThreadRGBStrip{{rgbStrip.index}}">{{rgbStrip.name}}</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<p class="card-text">{{effectThread.dump}}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<!--/Right Col-->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- SCRIPTS -->
|
|
<!-- JQuery -->
|
|
<script type="text/javascript" src="node_modules/jquery/dist/jquery.min.js"></script>
|
|
<script type="text/javascript" src="node_modules/jquery-wheelcolorpicker/jquery.wheelcolorpicker-3.0.5.min.js"></script>
|
|
<script type="text/javascript" src="node_modules/jquery-minicolors/jquery.minicolors.min.js"></script>
|
|
<!-- Bootstrap tooltips -->
|
|
<script type="text/javascript" src="node_modules/popper.js/dist/umd/popper.min.js"></script>
|
|
<script type="text/javascript" src="node_modules/popper.js/dist/umd/popper-utils.min.js"></script>
|
|
<!-- Bootstrap core JavaScript-->
|
|
<script type="text/javascript" src="node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
|
|
<!-- MDB core JavaScript -->
|
|
<script type="text/javascript" src="node_modules/bootstrap-material-design/dist/js/bootstrap-material-design.min.js"></script>
|
|
<script src="node_modules/angular/angular.min.js"></script>
|
|
<script type="text/javascript" src="node_modules/angular-minicolors/angular-minicolors.js"></script>
|
|
<script src="node_modules/reconnecting-websocket/dist/reconnecting-websocket-iife.min.js"></script>
|
|
<script>
|
|
var app = angular.module('LED-WebFrontend',['minicolors']);
|
|
app.factory('socket', [function() {
|
|
var stack = [];
|
|
var onmessageDefer;
|
|
var host = "localhost"
|
|
if (window.location.hostname != ""){
|
|
host = window.location.hostname
|
|
}
|
|
var socket = {
|
|
ws: new ReconnectingWebSocket("ws://"+host+":8001", null, {debug: false, reconnectInterval: 2000}),
|
|
send: function(data) {
|
|
if (socket.ws.readyState == 1) {
|
|
socket.ws.send(data);
|
|
} else {
|
|
stack.push(data);
|
|
}
|
|
},
|
|
onmessage: function(callback) {
|
|
if (socket.ws.readyState == 1) {
|
|
socket.ws.onmessage = callback;
|
|
} else {
|
|
onmessageDefer = callback;
|
|
}
|
|
}
|
|
};
|
|
socket.ws.onopen = function(event) {
|
|
for (i in stack) {
|
|
socket.ws.send(stack[i]);
|
|
}
|
|
stack = [];
|
|
if (onmessageDefer) {
|
|
socket.ws.onmessage = onmessageDefer;
|
|
onmessageDefer = null;
|
|
}
|
|
};
|
|
return socket;
|
|
}]);
|
|
|
|
app.controller('LED-ServerCtrl', ['$scope', 'socket', function($scope, socket) {
|
|
|
|
$scope.connected = false;
|
|
|
|
$scope.rgbStrips = {};
|
|
$scope.effects = {};
|
|
$scope.effectThreads = {};
|
|
|
|
$scope.newEffectThreadParamColorPicker = {}
|
|
$scope.newEffectThread = {}
|
|
$scope.newEffectThread.params = {};
|
|
$scope.newEffectThread.rgbStrips = {};
|
|
|
|
|
|
$scope.colorpickerconfig = {
|
|
// control: 'saturation',
|
|
control: 'hue',
|
|
// control: 'brightness',
|
|
// control: 'wheel',
|
|
theme: 'bootstrap',
|
|
inline: true,
|
|
position: 'top left'
|
|
};
|
|
|
|
socket.ws.addEventListener('close',function(event) {
|
|
$scope.$apply(function(){
|
|
$scope.connected = false
|
|
});
|
|
});
|
|
socket.ws.addEventListener('open',function(event) {
|
|
$scope.$apply(function(){
|
|
socket.send(
|
|
JSON.stringify({
|
|
'register_client_type': 0
|
|
})
|
|
);
|
|
$scope.connected = true
|
|
});
|
|
});
|
|
|
|
socket.onmessage(function(event) {
|
|
$scope.$apply(function(){
|
|
json = JSON.parse(event.data)
|
|
console.log("Message: ",json)
|
|
//remove strips from startEffect that may not exist anymore
|
|
if(json.hasOwnProperty('rgbStrips')){
|
|
jQuery.each($scope.newEffectThread.rgbStrips,function(key,value){
|
|
if (!(key in json.rgbStrips)){
|
|
delete $scope.newEffectThread.rgbStrips[key];
|
|
}
|
|
});
|
|
|
|
}
|
|
if(json.hasOwnProperty('effects') && json.hasOwnProperty('rgbStrips')){
|
|
//$("#startNewEffectThread")[0].reset();
|
|
//$("#newEffectThread").removeAttr("selected");
|
|
|
|
//$scope.effects = {}
|
|
$scope.effects = json.effects
|
|
//$scope.rgbStrips = {}
|
|
$scope.rgbStrips = json.rgbStrips
|
|
}
|
|
if(json.hasOwnProperty('effectThreads')){
|
|
$scope.effectThreads = {}
|
|
$scope.effectThreads = json.effectThreads
|
|
$scope.moveRGBStripToEffectThreadModel = {}
|
|
|
|
$scope.moveRGBStripToEffectThreadForm.$setUntouched();
|
|
$scope.moveRGBStripToEffectThreadForm.$setPristine();
|
|
}
|
|
});
|
|
});
|
|
|
|
$scope.isRGBStripActive=function(rgbStrip, activeRGBStrips) {
|
|
rval = false;
|
|
jQuery.each(
|
|
activeRGBStrips, function() {
|
|
if(this.index == rgbStrip.index){
|
|
rval = true;
|
|
return false;
|
|
}
|
|
});
|
|
return rval;
|
|
};
|
|
|
|
$scope.moveRGBStripToEffectThread = function(rgbStripIndex,effectThreadIndex){
|
|
socket.send(
|
|
JSON.stringify({
|
|
'moveRGBStripToEffectThread': {
|
|
'rgbStrip': rgbStripIndex,
|
|
'effectThread': effectThreadIndex
|
|
}
|
|
})
|
|
);
|
|
};
|
|
|
|
$scope.effectThreadChangeEffectParam = function(effectThreadIndex,params){
|
|
console.log(params)
|
|
socket.send(
|
|
JSON.stringify({
|
|
'effectThreadChangeEffectParam': {
|
|
'params': Object.entries(params),
|
|
'effectThread': effectThreadIndex
|
|
}
|
|
})
|
|
);
|
|
};
|
|
|
|
$scope.startEffect = function(effectIndex,rgbStrips,params){
|
|
console.log(params)
|
|
socket.send(
|
|
JSON.stringify({
|
|
'startEffect': {
|
|
'rgbStrips': Object.entries(rgbStrips),
|
|
'effect': effectIndex,
|
|
'params': Object.entries(params)
|
|
}
|
|
})
|
|
);
|
|
};
|
|
|
|
$scope.changeEffectThreadParameters = function(effectThreadIndex,paramIndex,values){
|
|
|
|
}
|
|
|
|
//https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
|
|
$scope.hexToRgb = function(hex) {
|
|
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
|
|
var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
|
|
hex = hex.replace(shorthandRegex, function(m, r, g, b) {
|
|
return r + r + g + g + b + b;
|
|
});
|
|
|
|
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
return result ? {
|
|
r: parseInt(result[1], 16),
|
|
g: parseInt(result[2], 16),
|
|
b: parseInt(result[3], 16)
|
|
} : null;
|
|
}
|
|
|
|
$scope.rgbToHex = function rgbToHex(r, g, b) {
|
|
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
|
|
}
|
|
|
|
}]);
|
|
</script>
|
|
</body>
|
|
</html> |