Initial commit

This commit is contained in:
l_samenv
2020-12-04 09:05:06 +01:00
parent 172042e731
commit 9e1d3b4e07
54 changed files with 47695 additions and 0 deletions

56
client/SEAWebClient.html Normal file
View File

@ -0,0 +1,56 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico">
<link rel="icon" type="image/png" href="/favicon192.png" sizes=192x192>
<meta name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style"
content="black-translucent" />
<title>SEAWebClient</title>
<!-- CSS-Files -->
<link rel="stylesheet" href="externalFiles/alertify.css">
<link rel="stylesheet" href="externalFiles/swiper.min.css">
<link rel="stylesheet" href="cssFiles/SEAWebClientSwiper.css">
<link rel="stylesheet" href="cssFiles/SEAWebClientGroup.css">
<link rel="stylesheet" href="cssFiles/SEAWebClientConsole.css">
<link rel="stylesheet" href="cssFiles/SEAWebClientGraphics.css">
<link rel="stylesheet" href="cssFiles/SEAWebClientMain.css">
<!-- JS-Files -->
<script src="externalFiles/alertify.js"></script>
<script src="externalFiles/eventsource.js"></script>
<script src="externalFiles/d3.min.js"></script>
<script src="externalFiles/swiper.min.js"></script>
<script src="externalFiles/Chart.bundle.min.js"></script>
<script src="externalFiles/hammer.js"></script>
<script src="externalFiles/chartjs-zoom.js"></script>
<script src="jsFiles/SEAWebClientResponsivity.js"></script>
<script src="jsFiles/SEAWebClientSwiper.js"></script>
<script src="jsFiles/SEAWebClientGroup.js"></script>
<script src="jsFiles/SEAWebClientConsole.js"></script>
<script src="jsFiles/SEAWebClientGraph.js"></script>
<script src="jsFiles/SEAWebClientCommunication.js"></script>
<script src="jsFiles/SEAWebClientMain.js"></script>
</head>
<body onresize="sizeChange()">
<div class="loading-div">
<span class="loading-span"><br><br>connecting ...</span>
</div>
<div id="main-panel-frame" onclick="toggleHeader()">
<div id="main-panel">
<span id="home-button">
<svg class="interactive" id="home-icon" fill="#000000" height="16" viewBox="0 0 16 16" width="16">
<path d="M8 1 L15 8 13.6 9.4 12.9 8.7 12.9 15 10.9 15 10.9 6.7 8 3.8 5.1 6.7 5.1 15 3.1 15 3.1 8.7 2.4 9.4 1 8 8 1z"/>
<path d="M0 0h16v16H0z" fill="none"/>
</svg>
</span>
<span id="header"></span>
</div>
</div>
<div id="center"></div>
</body>
</html>

View File

@ -0,0 +1,89 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style"
content="black-translucent" />
<title>SEAWebClient_SelectInstrument</title>
<!-- CSS-Files -->
<link rel="stylesheet" href="cssFiles/SEAWebClientStart.css">
<!-- javascript-Files -->
<script src="jsFiles/SEAWebClientStart.js"></script>
</head>
<body>
<div class="start-panel">
<span class="start-text-wrapper">select instrument</span>
</div>
<div class="start-content">
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8850/SEAWebClient.html")>DMC</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8851/SEAWebClient.html")>HRPT</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8852/SEAWebClient.html")>ZEBRA</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8853/SEAWebClient.html")>POLDI</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8854/SEAWebClient.html")>FOCUS</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8855/SEAWebClient.html")>TASP</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8856/SEAWebClient.html")>RITA2</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8857/SEAWebClient.html")>EIGER</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8858/SEAWebClient.html")>SANS 1</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8859/SEAWebClient.html")>SANS 2</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8860/SEAWebClient.html")>AMOR</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8861/SEAWebClient.html")>BOA</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8849/SEAWebClient.html")>PREP0</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8801/SEAWebClient.html")>PREP1</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8802/SEAWebClient.html")>PREP2</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8803/SEAWebClient.html")>PREP3</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8804/SEAWebClient.html")>PREP4</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8805/SEAWebClient.html")>PREP5</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8806/SEAWebClient.html")>PREP6</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8807/SEAWebClient.html")>PREP7</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8808/SEAWebClient.html")>PREP8</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8809/SEAWebClient.html")>PREP9</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8810/SEAWebClient.html")>LAB0</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8811/SEAWebClient.html")>LAB1</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8812/SEAWebClient.html")>LAB2</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8813/SEAWebClient.html")>LAB3</div>
<div class="start-row-links start-link" tabindex = 0 onclick = followLink("http://samenv.psi.ch:8814/SEAWebClient.html")>LAB4</div>
<div class="start-settings">
<div class = start-settings-label>
<span>settings</span>
<span class = "start-settings-show-hide" onclick = toggleSettings()>show</span>
</div>
<div class="start-settings-checkboxes">
<div class="start-row start-row-checkboxes"> <span class="start-left">show graphics?
</span> <span class="start-right"> <input id="check0" name = "sg"
class="start-checkbox" type="checkbox"></input> <label for="check0"
class="start-label"></label>
</span> </div>
<div class="start-row start-row-checkboxes"> <span class="start-left">show console?
</span> <span class="start-right"> <input id="check1" name = "sc"
class="start-checkbox" type="checkbox" checked></input> <label for="check1"
class="start-label"></label>
</span> </div>
<div class="start-row start-row-checkboxes"> <span class="start-left">show overview?
</span> <span class="start-right"> <input id="check2" name = "so"
class="start-checkbox" type="checkbox" checked></input> <label for="check2"
class="start-label"></label>
</span> </div>
<div class="start-row start-row-checkboxes"> <span class="start-left">show main?
</span> <span class="start-right"> <input id="check3" name = "sm"
class="start-checkbox" type="checkbox" checked></input> <label for="check3"
class="start-label"></label>
</span> </div>
<div class="start-row start-row-checkboxes"> <span class="start-left">debug communication?
</span> <span class="start-right"> <input id="check4" name = "dc"
class="start-checkbox" type="checkbox"></input> <label for="check4"
class="start-label"></label>
</span> </div>
<div class="start-row start-row-checkboxes"> <span class="start-left">debug graphics?
</span> <span class="start-right"> <input id="check5" name = "dg"
class="start-checkbox" type="checkbox"></input> <label for="check5"
class="start-label"></label>
</span> </div>
</div>
</div>
</div>
</body>
</html>

150
client/console.html Normal file
View File

@ -0,0 +1,150 @@
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<style>
.footer {
background: #ccc;
padding:5px;
overflow: auto;
height:30px;
position: fixed;
top: 0;
width: 100%;
}
</style>
</head>
<body>
<div id="console" class=code>
<br>
<br>
</div>
<div class=footer>
<form id="command_form" method="GET">
<input type=input id=commandline size=80>
</form>
</div>
<script type="text/javascript">
function getJSON(url, successHandler, errorHandler) {
var xhr = typeof XMLHttpRequest != 'undefined'
? new XMLHttpRequest()
: new ActiveXObject('Microsoft.XMLHTTP');
console.log("fired JSON request", url)
xhr.open('get', url, true);
xhr.onreadystatechange = function() {
console.log(xhr)
var status;
var data;
// https://xhr.spec.whatwg.org/#dom-xmlhttprequest-readystate
if (xhr.readyState == 4) { // `DONE`
status = xhr.status;
if (status == 200) {
data = JSON.parse(xhr.responseText);
successHandler && successHandler(data);
} else {
errorHandler && errorHandler(status);
}
}
};
xhr.send();
};
var historyElement = document.getElementById("console")
// copy query
var evtSrc = new EventSource("http://localhost:5000/update");
function htmlEscape(str) {
return str
.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
}
var our_id=""
var oldtop = -1
evtSrc.onmessage = function(e) {
var message = JSON.parse(e.data)
console.log(message)
if (message.type == "id") {
our_id = message.id
var test = "xxx"
getJSON(
"http://localhost:5000/console?id="+our_id,
function(message) { console.log('msg', message, test); },
function(status) { console.log('stat', status); }
);
} else if (message.type == 'command' || message.type == 'reply') {
pre = ""
post = ""
if (message.type == 'command') {
pre += "<font color='blue'><br>"
post += "</font>"
}
if (message.origin == 'self') {
pre += "<b>"
post = "</b>" + post
}
historyElement.innerHTML += pre + htmlEscape(message.line) + post + "<br>\n"
}
/*
var doc = document.documentElement
var top = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0)
var h = window.innerHeight || window.clientHeight
var d = document.body.scrollHeight
*/
window.scrollTo(0,document.body.scrollHeight)
/*
var top = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0)
var h = window.innerHeight
var d = document.body.scrollHeight
console.log(oldtop + oldh, top + h)
*/
};
evtSrc.onerror = function(e) {
historyElement.innerHTML += "connection lost"
evtSrc.close()
};
function do_command() {
celm = document.getElementById("commandline")
cmd = encodeURI(celm.value);
celm.value = ""
oldtop = -1
if (our_id != "") {
cmd += "&id=" + our_id
}
console.log("http://localhost:5000/sendcommand?command="+cmd)
getJSON(
"http://localhost:5000/sendcommand?command="+cmd,
function(message) { console.log('message', message); },
function(status) { console.log('status', status); }
);
}
function handle_submit(evt) {
evt.preventDefault()
do_command()
}
command_form = document.getElementById("command_form")
if (command_form.addEventListener) {
command_form.addEventListener("submit", handle_submit, true);
} else {
command_form.attachEvent('onsubmit', handle_submit);
}
window.onbeforeunload = closingCode;
function closingCode(){
console.log("CLOSE")
evtSrc.close()
return null;
}
</script>
</body>
</html>

View File

@ -0,0 +1,38 @@
@CHARSET "UTF-8";
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
/* CONSOLE */
.commandline-wrapper {
position: absolute;
z-index: 1;
width: 100%;
padding: 26px 0px 0px 0px;
background-color: darkgray;
}
.commandline {
font-family: monospace;
font-size: 12px;
width: 100%;
text-align: left;
padding-left: 8px;
padding-top: 6px;
padding-bottom: 6px;
border: none;
border-top: solid 8px dimgray;
border-bottom: solid 5px dimgray;
background-color: lightgray;
color: black;
}
.history {
position: absolute;
font-family: monospace;
font-size: 12px;
padding: 80px 8px 50px 8px;
width: 100%;
height: 100%;
overflow-y: auto;
background-color: white;
color: black;
}

View File

@ -0,0 +1,198 @@
.swiper-pagination{
pointer-events: none;
}
.panel.graphics{
display: flex;
justify-content: flex-end;
}
.panel.graphics span{
margin: 0 1em;
display: flex;
user-select: none;
-webkit-user-select: none;
}
.panel.graphics div{
margin-left: 1em;
cursor: pointer;
}
/*********************/
.graphs-container{
height: 100%;
width: 100%;
display: flex;
flex-flow: column;
margin-top: 30px;
}
.graph{
height: 20%;
width: 100%;
}
.graph-0 {
height: 40%;
}
.selection{
display: flex;
flex-direction: column;
overflow-x: hidden;
height: 100%;
/*align-items: center;*/
width: 100%;
}
.selection .select{
margin: 0.2em;
padding: 0.3em;
cursor: pointer;
display: flex;
border-bottom: 1px dashed black;
}
.selection .select:last-of-type{
border-bottom: none;
}
.selection .select:hover{
background-color: #eaeaea;
}
.selection .select .title{
font-weight: 900;
}
.selection .params{
display: flex;
}
.selection .param{
white-space: nowrap;
margin: 0 0.4em;
}
.chart-container{
position: relative;
width: 100%;
height: 100%;
}
.legend{
display: flex;
flex-direction: column;
flex-wrap: wrap;
position: absolute;
background-color: rgb(255,255,255,0.8);
color: #000000;
padding: 0.3em;
/*transition: left 0.5s, top 0.5s;*/
top: 0px;
left: 0px;
user-select: none;
-webkit-user-select: none;
cursor: grab;
border: 1px solid black;
}
.legend:active{
cursor: grabbing;
}
body.black .legend{
background-color: rgb(0,0,0,0.8);
border: none;
color: white;
}
.legend .controls{
}
.legend .control{
cursor: pointer;
display: inline-block;
}
.legend .vcontrol{
clear: both;
float: left;
border-bottom: 1px solid black;
padding-bottom: 0.1em;
padding-top: 0.1em;
}
.legend .subcontrol{
cursor: pointer;
display: inline-block;
padding-bottom: 0.1em;
padding-top: 0.1em;
color: #777777;
}
.legend .subcontrol:hover{
color: #000000;
}
.legend .subspacer{
display: inline-block;
width: 0.2em;
}
.legend .vcontrol:hover{
color: #777777;
}
.legend .control:last-of-type{
border-bottom: none;
padding-bottom: 0.3em;
}
.legendel{
cursor: pointer;
display: flex;
position: relative;
}
.legendel:hover{
color: #777777;
}
.legendel .color{
width: 2em;
height: 0.1em;
margin-top: 0.45em;
margin-right: 1em;
}
.legendel .value{
margin-left: 1em;
}
.legendel.hidden .value{
display: none;
}
/*.legendel.hidden:before{
content: '';
width: 100%;
height: 0.05em;
top: 50%;
margin-top: -0.025em;
background-color: #FFF;
position: absolute;
}*/
.legendel.hidden{
opacity: 0.5;
}
.legendel.hidden .color{
opacity: 0;
}

View File

@ -0,0 +1,178 @@
/* GROUP */
@CHARSET "UTF-8";
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
/* CONTENT */
.content {
padding: 60px 20px 20px 20px;
display: block;
width: 100%;
height: 100%;
overflow-y: auto;
}
.content-console {
display: block;
width: 100%;
height: 100%;
overflow-y: hidden;
}
.link {
transition: 0.4s;
cursor: pointer;
color: steelblue;
text-decoration: underline;
}
.link:focus {
color: orangered;
outline: none;
}
.row {
padding: 4px 0px 4px 0px;
width: 100%;
min-height: 24px;
display: block;
border-bottom: dotted darkgray 2px;
overflow: hidden;
transition: 0.2s;
position: relative;
}
.clickable:hover {
background-color: lightgray;
}
.link-static {
padding-left: 4px;
background-color: #303030;
color: white;
border-bottom: none;
}
.info-box {
margin: 4px 0px 4px 0px;
padding: 4px;
border-radius: 4px;
background-color: darkslategray;
color: white;
display: none;
width: 100%;
cursor: pointer;
}
.col-left {
min-height: 24px;
line-height: 24px;
float: left;
}
.event-toggle-info {
color: darkslategray;
cursor: pointer;
}
.col-right {
float: right;
}
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
/* TEXT */
.input-text {
height: 24px;
font-family: monospace;
background-color: lightgray;
border: solid 2px dimgray;
color: black;
text-align: right;
}
::-ms-clear { /* remove the x in the input box on IE */
width : 0;
height: 0;
}
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
/* CHECKBOX */
.parameter-checkbox {
opacity: 0;
float: left;
}
.parameter-checkbox + .parameter-label {
position: relative;
cursor: pointer;
float: left;
}
.parameter-checkbox:focus+.parameter-label {
opacity: 0.8;
}
.parameter-checkbox+.parameter-label::before {
content: ' ';
position: absolute;
left: -24px;
top: -2px;
width: 20px;
height: 20px;
display: block;
background: lightgray;
border: 2px solid dimgray;
}
.parameter-checkbox+.parameter-label::after {
content: ' ';
position: absolute;
left: -19px;
top: 3px;
width: 14px;
height: 14px;
display: block;
z-index: 1;
background-color: dimgray;
-ms-transition: all .2s ease;
-webkit-transition: all .2s ease;
transition: all .3s ease;
-ms-transform: scale(0);
-webkit-transform: scale(0);
transform: scale(0);
opacity: 0;
}
.parameter-checkbox:checked+.parameter-label::after {
-ms-transform: scale(1);
-webkit-transform: scale(1);
transform: scale(1);
opacity: 1;
}
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
/* RADIO */
option {
height: 24px;
background-color: dimgray;
color: white;
}
.select-params {
height: 24px;
border: none;
background-color: dimgray;
color: white;
width: auto;
min-width: 120px;
}
.select-params:focus {
opacity: 0.85;
}
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
/* PUSH-BUTTON */
.push-button {
border: 2px solid dimgray;
border-radius: 4px;
}

View File

@ -0,0 +1,128 @@
@CHARSET "UTF-8";
* {
box-sizing: border-box; /* include margin into width and height calculation */
}
meta, body {
font-family: sans-serif;
font-size: 16px;
/* the following is about the ability to select text */
/*-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;*/
width: 100%;
height: 100%;
padding: 0;
margin: 0;
overflow: hidden;
}
.loading-div {
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
background: #303030;
z-index: 100;
text-align: center;
opacity: 0.6;
}
.loading-span {
height: 100vh;
line-height: 36px;
color: white;
font-size: 32px;
}
/* class for links and buttons */
.interactive {
cursor: pointer;
}
.interactive:hover {
background-color: lightgray;
fill: gray;
color: gray;
}
.interactive:active {
fill: orangered;
color: orangered;
}
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
/* HEADER (was main title bar) */
#main-panel-frame {
height: 30px;
z-index: 50;
top: 4px;
left: 4px;
position: fixed;
border: solid 2px #303030;
background-color: dimgray;
border-bottom-right-radius: 12px;
padding: 1px 9px 1px 9px;
}
#main-panel {
display: inline;
cursor: pointer;
/* position: fixed; */
width: auto;
height: 30px;
vertical-align: top;
line-height: 24px;
}
#header {
display: inline;
font-size: 16px;
color: white;
/* display: inline; */
cursor: pointer;
/* position: fixed; */
width: auto;
transition: 0.6s;
padding: 0px 0px 0px 6px;
}
#home-button {
display: inline;
cursor: pointer;
height: 16px;
}
#home-icon {
display: inline;
transition: 0.4s;
cursor: pointer;
/*float: right;*/
fill: white;
height: 24px;
vertical-align: top;
}
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
/* CENTER */
#center {
height: 100%;
width: 100%;
display: block;
}
.grid-element {
width: 100vw;
height: 100vh;
display: none;
overflow: hidden;
border: solid 4px dimgray;
}

View File

@ -0,0 +1,190 @@
@CHARSET "UTF-8";
* {
box-sizing: border-box;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
meta, body {
font-family: sans-serif;
font-size: 16px;
width: 100vw;
height: 100vh;
padding: 0;
margin: 0;
overflow: hidden;
}
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
/* PANEL */
.start-panel {
position: fixed;
top: 0px;
left: 0px;
z-index: 1;
color: white;
background: #303030;
width: 100%;
height: 30px;
line-height: 30px;
padding-left: 30px;
text-align: center;
}
.start-text-wrapper {
height: 30px;
}
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
/* CONTENT */
.start-content {
padding: 60px 40px 30px 40px;
width: 100%;
height: 100%;
overflow: auto;
}
.start-row-links {
padding: 4px 0px 4px 0px;
width: 100%;
min-height: 24px;
display: block;
border-bottom: dotted darkgray 2px;
position: relative;
}
/* %%%%%%%%%% links %%%%%%%%%%*/
.start-link {
transition: 0.4s;
cursor: pointer;
color: steelblue;
text-decoration: underline;
}
.start-link:focus {
color: orangered;
outline: none;
}
.start-link:hover {
color: gray;
}
.start-link:active {
color: orangered;
}
/* %%%%%%%%%% settings %%%%%%%%%%*/
.start-settings {
color: white;
background: #303030;
margin-top: 30px;
padding: 10px 20px 10px 20px;
border-radius: 6px;
}
.start-settings-label {
border-bottom: solid darkgray 2px;
}
.start-settings-show-hide {
float: right;
color: lightgray;
cursor: pointer;
}
.start-settings-show-hide:focus {
color: orangered;
outline: none;
}
.start-settings-show-hide:hover {
color: gray;
}
.start-settings-show-hide:active {
color: orangered;
}
.start-settings-checkboxes {
display: none;
}
.start-row-checkboxes {
border-bottom: dotted darkgray 2px;
height: 28px;
padding-left: 4px;
padding-right: 2px;
}
.start-left {
min-height: 24px;
line-height: 24px;
float: left;
}
.start-right {
min-height: 24px;
line-height: 24px;
float: right;
}
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
/* CHECKBOX */
.start-checkbox {
opacity: 0;
float: left;
}
.start-checkbox + .start-label {
position: relative;
cursor: pointer;
float: left;
}
.start-checkbox:focus+.start-label {
opacity: 0.8;
}
.start-checkbox+.start-label::before {
content: ' ';
position: absolute;
left: -24px;
top: 2px;
width: 20px;
height: 20px;
display: block;
background: lightgray;
border: 2px solid dimgray;
}
.start-checkbox+.start-label::after {
content: ' ';
position: absolute;
left: -19px;
top: 7px;
width: 14px;
height: 14px;
display: block;
z-index: 1;
background-color: dimgray;
-ms-transition: all .2s ease;
-webkit-transition: all .2s ease;
transition: all .3s ease;
-ms-transform: scale(0);
-webkit-transform: scale(0);
transform: scale(0);
opacity: 0;
}
.start-checkbox:checked+.start-label::after {
-ms-transform: scale(1);
-webkit-transform: scale(1);
transform: scale(1);
opacity: 1;
}

View File

@ -0,0 +1,41 @@
@CHARSET "UTF-8";
.swiper-container-main {
width: 100%;
height: 100%;
overflow: hidden;
}
.swiper-slide-main {
background-color: white;
overflow: hidden;
width: 100%;
height: 100%;
padding-bottom: 30px;
}
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
/* PANEL */
.panel {
text-align: center;
background-color: #303030;
color: white;
padding: 6px 6px 6px 6px;
position: absolute;
z-index: 20;
width: 100%;
height: 30px;
}
.slide-close-icon {
transition: 0.4s;
cursor: pointer;
float: right;
padding-right: 6px;
height: 100%;
fill: white;
}
.toggle-updates-graphics {
float: right;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,884 @@
/**
* alertifyjs 1.8.0 http://alertifyjs.com
* AlertifyJS is a javascript framework for developing pretty browser dialogs and notifications.
* Copyright 2016 Mohammad Younes <Mohammad@alertifyjs.com> (http://alertifyjs.com)
* Licensed under GPL 3 <https://opensource.org/licenses/gpl-3.0>*/
.alertify .ajs-dimmer {
position: fixed;
z-index: 1981;
top: 0;
right: 0;
bottom: 0;
left: 0;
padding: 0;
margin: 0;
background-color: #252525;
opacity: .5;
}
.alertify .ajs-modal {
position: fixed;
top: 0;
right: 0;
left: 0;
bottom: 0;
padding: 0;
overflow-y: auto;
z-index: 1981;
}
.alertify .ajs-dialog {
position: relative;
margin: 5% auto;
min-height: 110px;
max-width: 500px;
padding: 24px 24px 0 24px;
outline: 0;
background-color: #fff;
}
.alertify .ajs-dialog.ajs-capture:before {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: block;
z-index: 1;
}
.alertify .ajs-reset {
position: absolute !important;
display: inline !important;
width: 0 !important;
height: 0 !important;
opacity: 0 !important;
}
.alertify .ajs-commands {
position: absolute;
right: 4px;
margin: -14px 24px 0 0;
z-index: 2;
}
.alertify .ajs-commands button {
display: none;
width: 10px;
height: 10px;
margin-left: 10px;
padding: 10px;
border: 0;
background-color: transparent;
background-repeat: no-repeat;
background-position: center;
cursor: pointer;
}
.alertify .ajs-commands button.ajs-close {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABZ0RVh0Q3JlYXRpb24gVGltZQAwNy8xMy8xNOrZqugAAAAcdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzbovLKMAAAAh0lEQVQYlY2QsQ0EIQwEB9cBAR1CJUaI/gigDnwR6NBL/7/xWLNrZ2b8EwGotVpr7eOitWa1VjugiNB7R1UPrKrWe0dEAHBbXUqxMQbeewDmnHjvyTm7C3zDwAUd9c63YQdUVdu6EAJzzquz7HXvTiklt+H9DQFYaxFjvDqllFyMkbXWvfpXHjJrWFgdBq/hAAAAAElFTkSuQmCC);
}
.alertify .ajs-commands button.ajs-maximize {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABZ0RVh0Q3JlYXRpb24gVGltZQAwNy8xMy8xNOrZqugAAAAcdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzbovLKMAAAAOUlEQVQYlWP8//8/AzGAhYGBgaG4uBiv6t7eXkYmooxjYGAgWiELsvHYFMCcRX2rSXcjoSBiJDbAAeD+EGu+8BZcAAAAAElFTkSuQmCC);
}
.alertify .ajs-header {
margin: -24px;
margin-bottom: 0;
padding: 16px 24px;
background-color: #fff;
}
.alertify .ajs-body {
min-height: 56px;
}
.alertify .ajs-body .ajs-content {
padding: 16px 24px 16px 16px;
}
.alertify .ajs-footer {
padding: 4px;
margin-left: -24px;
margin-right: -24px;
min-height: 43px;
background-color: #fff;
}
.alertify .ajs-footer .ajs-buttons.ajs-primary {
text-align: right;
}
.alertify .ajs-footer .ajs-buttons.ajs-primary .ajs-button {
margin: 4px;
}
.alertify .ajs-footer .ajs-buttons.ajs-auxiliary {
float: left;
clear: none;
text-align: left;
}
.alertify .ajs-footer .ajs-buttons.ajs-auxiliary .ajs-button {
margin: 4px;
}
.alertify .ajs-footer .ajs-buttons .ajs-button {
min-width: 88px;
min-height: 35px;
}
.alertify .ajs-handle {
position: absolute;
display: none;
width: 10px;
height: 10px;
right: 0;
bottom: 0;
z-index: 1;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABZ0RVh0Q3JlYXRpb24gVGltZQAwNy8xMS8xNEDQYmMAAAAcdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzbovLKMAAAAQ0lEQVQYlaXNMQoAIAxD0dT7H657l0KX3iJuUlBUNOsPPCGJm7VDp6ryeMxMuDsAQH7owW3pyn3RS26iKxERMLN3ugOaAkaL3sWVigAAAABJRU5ErkJggg==);
-webkit-transform: scaleX(1) /*rtl:scaleX(-1)*/;
transform: scaleX(1) /*rtl:scaleX(-1)*/;
cursor: se-resize;
}
.alertify.ajs-no-overflow .ajs-body .ajs-content {
overflow: hidden !important;
}
.alertify.ajs-no-padding.ajs-maximized .ajs-body .ajs-content {
left: 0;
right: 0;
padding: 0;
}
.alertify.ajs-no-padding:not(.ajs-maximized) .ajs-body {
margin-left: -24px;
margin-right: -24px;
}
.alertify.ajs-no-padding:not(.ajs-maximized) .ajs-body .ajs-content {
padding: 0;
}
.alertify.ajs-no-padding.ajs-resizable .ajs-body .ajs-content {
left: 0;
right: 0;
}
.alertify.ajs-maximizable .ajs-commands button.ajs-maximize,
.alertify.ajs-maximizable .ajs-commands button.ajs-restore {
display: inline-block;
}
.alertify.ajs-closable .ajs-commands button.ajs-close {
display: inline-block;
}
.alertify.ajs-maximized .ajs-dialog {
width: 100% !important;
height: 100% !important;
max-width: none !important;
margin: 0 auto !important;
top: 0 !important;
left: 0 !important;
}
.alertify.ajs-maximized.ajs-modeless .ajs-modal {
position: fixed !important;
min-height: 100% !important;
max-height: none !important;
margin: 0 !important;
}
.alertify.ajs-maximized .ajs-commands button.ajs-maximize {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABZ0RVh0Q3JlYXRpb24gVGltZQAwNy8xMy8xNOrZqugAAAAcdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzbovLKMAAAASklEQVQYlZWQ0QkAMQhDtXRincOZX78KVtrDCwgqJNEoIB3MPLj7lRUROlpyVXGzby6zWuY+kz6tj5sBMTMAyVV3/595RbOh3cAXsww1raeiOcoAAAAASUVORK5CYII=);
}
.alertify.ajs-resizable .ajs-dialog,
.alertify.ajs-maximized .ajs-dialog {
padding: 0;
}
.alertify.ajs-resizable .ajs-commands,
.alertify.ajs-maximized .ajs-commands {
margin: 14px 24px 0 0;
}
.alertify.ajs-resizable .ajs-header,
.alertify.ajs-maximized .ajs-header {
position: absolute;
top: 0;
left: 0;
right: 0;
margin: 0;
padding: 16px 24px;
}
.alertify.ajs-resizable .ajs-body,
.alertify.ajs-maximized .ajs-body {
min-height: 224px;
display: inline-block;
}
.alertify.ajs-resizable .ajs-body .ajs-content,
.alertify.ajs-maximized .ajs-body .ajs-content {
position: absolute;
top: 50px;
right: 24px;
bottom: 50px;
left: 24px;
overflow: auto;
}
.alertify.ajs-resizable .ajs-footer,
.alertify.ajs-maximized .ajs-footer {
position: absolute;
left: 0;
right: 0;
bottom: 0;
margin: 0;
}
.alertify.ajs-resizable:not(.ajs-maximized) .ajs-dialog {
min-width: 548px;
}
.alertify.ajs-resizable:not(.ajs-maximized) .ajs-handle {
display: block;
}
.alertify.ajs-movable:not(.ajs-maximized) .ajs-header {
cursor: move;
}
.alertify.ajs-modeless .ajs-dimmer,
.alertify.ajs-modeless .ajs-reset {
display: none;
}
.alertify.ajs-modeless .ajs-modal {
overflow: visible;
max-width: none;
max-height: 0;
}
.alertify.ajs-modeless.ajs-pinnable .ajs-commands button.ajs-pin {
display: inline-block;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABZ0RVh0Q3JlYXRpb24gVGltZQAwNy8xMy8xNOrZqugAAAAcdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzbovLKMAAAAQklEQVQYlcWPMQ4AIAwCqU9u38GbcbHRWN1MvKQDhQFMEpKImGJA0gCgnYw0V0rwxseg5erT4oSkQVI5d9f+e9+xA0NbLpWfitPXAAAAAElFTkSuQmCC);
}
.alertify.ajs-modeless.ajs-unpinned .ajs-modal {
position: absolute;
}
.alertify.ajs-modeless.ajs-unpinned .ajs-commands button.ajs-pin {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABZ0RVh0Q3JlYXRpb24gVGltZQAwNy8xMy8xNOrZqugAAAAcdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzbovLKMAAAAO0lEQVQYlWP8//8/AzGAiShV6AqLi4txGs+CLoBLMYbC3t5eRmyaWfBZhwwYkX2NTxPRvibKjRhW4wMAhxkYGbLu3pEAAAAASUVORK5CYII=);
}
.alertify.ajs-modeless:not(.ajs-unpinned) .ajs-body {
max-height: 500px;
overflow: auto;
}
.alertify.ajs-basic .ajs-header {
opacity: 0;
}
.alertify.ajs-basic .ajs-footer {
visibility: hidden;
}
.alertify.ajs-frameless .ajs-header {
position: absolute;
top: 0;
left: 0;
right: 0;
min-height: 60px;
margin: 0;
padding: 0;
opacity: 0;
z-index: 1;
}
.alertify.ajs-frameless .ajs-footer {
display: none;
}
.alertify.ajs-frameless .ajs-body .ajs-content {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.alertify.ajs-frameless:not(.ajs-resizable) .ajs-dialog {
padding-top: 0;
}
.alertify.ajs-frameless:not(.ajs-resizable) .ajs-dialog .ajs-commands {
margin-top: 0;
}
.ajs-no-overflow {
overflow: hidden !important;
outline: none;
}
.ajs-no-overflow.ajs-fixed {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow-y: scroll!important;
}
.ajs-no-selection,
.ajs-no-selection * {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
@media screen and (max-width: 568px) {
.alertify .ajs-dialog {
min-width: 150px;
}
.alertify:not(.ajs-maximized) .ajs-modal {
padding: 0 5%;
}
.alertify:not(.ajs-maximized).ajs-resizable .ajs-dialog {
min-width: initial;
min-width: auto /*IE fallback*/;
}
}
@-moz-document url-prefix() {
.alertify button:focus {
outline: 1px dotted #3593D2;
}
}
.alertify .ajs-dimmer,
.alertify .ajs-modal {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
transition-property: opacity, visibility;
transition-timing-function: linear;
transition-duration: 250ms;
}
.alertify.ajs-hidden .ajs-dimmer,
.alertify.ajs-hidden .ajs-modal {
visibility: hidden;
opacity: 0;
}
.alertify.ajs-in:not(.ajs-hidden) .ajs-dialog {
-webkit-animation-duration: 500ms;
animation-duration: 500ms;
}
.alertify.ajs-out.ajs-hidden .ajs-dialog {
-webkit-animation-duration: 250ms;
animation-duration: 250ms;
}
.alertify .ajs-dialog.ajs-shake {
-webkit-animation-name: ajs-shake;
animation-name: ajs-shake;
-webkit-animation-duration: .1s;
animation-duration: .1s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
@-webkit-keyframes ajs-shake {
0%,
100% {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
10%,
30%,
50%,
70%,
90% {
-webkit-transform: translate3d(-10px, 0, 0);
transform: translate3d(-10px, 0, 0);
}
20%,
40%,
60%,
80% {
-webkit-transform: translate3d(10px, 0, 0);
transform: translate3d(10px, 0, 0);
}
}
@keyframes ajs-shake {
0%,
100% {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
10%,
30%,
50%,
70%,
90% {
-webkit-transform: translate3d(-10px, 0, 0);
transform: translate3d(-10px, 0, 0);
}
20%,
40%,
60%,
80% {
-webkit-transform: translate3d(10px, 0, 0);
transform: translate3d(10px, 0, 0);
}
}
.alertify.ajs-slide.ajs-in:not(.ajs-hidden) .ajs-dialog {
-webkit-animation-name: ajs-slideIn;
animation-name: ajs-slideIn;
-webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275);
animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
.alertify.ajs-slide.ajs-out.ajs-hidden .ajs-dialog {
-webkit-animation-name: ajs-slideOut;
animation-name: ajs-slideOut;
-webkit-animation-timing-function: cubic-bezier(0.6, -0.28, 0.735, 0.045);
animation-timing-function: cubic-bezier(0.6, -0.28, 0.735, 0.045);
}
.alertify.ajs-zoom.ajs-in:not(.ajs-hidden) .ajs-dialog {
-webkit-animation-name: ajs-zoomIn;
animation-name: ajs-zoomIn;
}
.alertify.ajs-zoom.ajs-out.ajs-hidden .ajs-dialog {
-webkit-animation-name: ajs-zoomOut;
animation-name: ajs-zoomOut;
}
.alertify.ajs-fade.ajs-in:not(.ajs-hidden) .ajs-dialog {
-webkit-animation-name: ajs-fadeIn;
animation-name: ajs-fadeIn;
}
.alertify.ajs-fade.ajs-out.ajs-hidden .ajs-dialog {
-webkit-animation-name: ajs-fadeOut;
animation-name: ajs-fadeOut;
}
.alertify.ajs-pulse.ajs-in:not(.ajs-hidden) .ajs-dialog {
-webkit-animation-name: ajs-pulseIn;
animation-name: ajs-pulseIn;
}
.alertify.ajs-pulse.ajs-out.ajs-hidden .ajs-dialog {
-webkit-animation-name: ajs-pulseOut;
animation-name: ajs-pulseOut;
}
.alertify.ajs-flipx.ajs-in:not(.ajs-hidden) .ajs-dialog {
-webkit-animation-name: ajs-flipInX;
animation-name: ajs-flipInX;
}
.alertify.ajs-flipx.ajs-out.ajs-hidden .ajs-dialog {
-webkit-animation-name: ajs-flipOutX;
animation-name: ajs-flipOutX;
}
.alertify.ajs-flipy.ajs-in:not(.ajs-hidden) .ajs-dialog {
-webkit-animation-name: ajs-flipInY;
animation-name: ajs-flipInY;
}
.alertify.ajs-flipy.ajs-out.ajs-hidden .ajs-dialog {
-webkit-animation-name: ajs-flipOutY;
animation-name: ajs-flipOutY;
}
@-webkit-keyframes ajs-pulseIn {
0%,
20%,
40%,
60%,
80%,
100% {
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
0% {
opacity: 0;
-webkit-transform: scale3d(0.3, 0.3, 0.3);
transform: scale3d(0.3, 0.3, 0.3);
}
20% {
-webkit-transform: scale3d(1.1, 1.1, 1.1);
transform: scale3d(1.1, 1.1, 1.1);
}
40% {
-webkit-transform: scale3d(0.9, 0.9, 0.9);
transform: scale3d(0.9, 0.9, 0.9);
}
60% {
opacity: 1;
-webkit-transform: scale3d(1.03, 1.03, 1.03);
transform: scale3d(1.03, 1.03, 1.03);
}
80% {
-webkit-transform: scale3d(0.97, 0.97, 0.97);
transform: scale3d(0.97, 0.97, 0.97);
}
100% {
opacity: 1;
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
}
@keyframes ajs-pulseIn {
0%,
20%,
40%,
60%,
80%,
100% {
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
0% {
opacity: 0;
-webkit-transform: scale3d(0.3, 0.3, 0.3);
transform: scale3d(0.3, 0.3, 0.3);
}
20% {
-webkit-transform: scale3d(1.1, 1.1, 1.1);
transform: scale3d(1.1, 1.1, 1.1);
}
40% {
-webkit-transform: scale3d(0.9, 0.9, 0.9);
transform: scale3d(0.9, 0.9, 0.9);
}
60% {
opacity: 1;
-webkit-transform: scale3d(1.03, 1.03, 1.03);
transform: scale3d(1.03, 1.03, 1.03);
}
80% {
-webkit-transform: scale3d(0.97, 0.97, 0.97);
transform: scale3d(0.97, 0.97, 0.97);
}
100% {
opacity: 1;
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
}
@-webkit-keyframes ajs-pulseOut {
20% {
-webkit-transform: scale3d(0.9, 0.9, 0.9);
transform: scale3d(0.9, 0.9, 0.9);
}
50%,
55% {
opacity: 1;
-webkit-transform: scale3d(1.1, 1.1, 1.1);
transform: scale3d(1.1, 1.1, 1.1);
}
100% {
opacity: 0;
-webkit-transform: scale3d(0.3, 0.3, 0.3);
transform: scale3d(0.3, 0.3, 0.3);
}
}
@keyframes ajs-pulseOut {
20% {
-webkit-transform: scale3d(0.9, 0.9, 0.9);
transform: scale3d(0.9, 0.9, 0.9);
}
50%,
55% {
opacity: 1;
-webkit-transform: scale3d(1.1, 1.1, 1.1);
transform: scale3d(1.1, 1.1, 1.1);
}
100% {
opacity: 0;
-webkit-transform: scale3d(0.3, 0.3, 0.3);
transform: scale3d(0.3, 0.3, 0.3);
}
}
@-webkit-keyframes ajs-zoomIn {
0% {
opacity: 0;
-webkit-transform: scale3d(0.25, 0.25, 0.25);
transform: scale3d(0.25, 0.25, 0.25);
}
100% {
opacity: 1;
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
}
@keyframes ajs-zoomIn {
0% {
opacity: 0;
-webkit-transform: scale3d(0.25, 0.25, 0.25);
transform: scale3d(0.25, 0.25, 0.25);
}
100% {
opacity: 1;
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
}
@-webkit-keyframes ajs-zoomOut {
0% {
opacity: 1;
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
100% {
opacity: 0;
-webkit-transform: scale3d(0.25, 0.25, 0.25);
transform: scale3d(0.25, 0.25, 0.25);
}
}
@keyframes ajs-zoomOut {
0% {
opacity: 1;
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
100% {
opacity: 0;
-webkit-transform: scale3d(0.25, 0.25, 0.25);
transform: scale3d(0.25, 0.25, 0.25);
}
}
@-webkit-keyframes ajs-fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes ajs-fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@-webkit-keyframes ajs-fadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes ajs-fadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@-webkit-keyframes ajs-flipInX {
0% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
transition-timing-function: ease-in;
opacity: 0;
}
40% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
transition-timing-function: ease-in;
}
60% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
opacity: 1;
}
80% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
}
100% {
-webkit-transform: perspective(400px);
transform: perspective(400px);
}
}
@keyframes ajs-flipInX {
0% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
transition-timing-function: ease-in;
opacity: 0;
}
40% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
transition-timing-function: ease-in;
}
60% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
opacity: 1;
}
80% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
}
100% {
-webkit-transform: perspective(400px);
transform: perspective(400px);
}
}
@-webkit-keyframes ajs-flipOutX {
0% {
-webkit-transform: perspective(400px);
transform: perspective(400px);
}
30% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
opacity: 1;
}
100% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
opacity: 0;
}
}
@keyframes ajs-flipOutX {
0% {
-webkit-transform: perspective(400px);
transform: perspective(400px);
}
30% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
opacity: 1;
}
100% {
-webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
opacity: 0;
}
}
@-webkit-keyframes ajs-flipInY {
0% {
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
transition-timing-function: ease-in;
opacity: 0;
}
40% {
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
transition-timing-function: ease-in;
}
60% {
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
opacity: 1;
}
80% {
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
}
100% {
-webkit-transform: perspective(400px);
transform: perspective(400px);
}
}
@keyframes ajs-flipInY {
0% {
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
transition-timing-function: ease-in;
opacity: 0;
}
40% {
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
transition-timing-function: ease-in;
}
60% {
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
opacity: 1;
}
80% {
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
}
100% {
-webkit-transform: perspective(400px);
transform: perspective(400px);
}
}
@-webkit-keyframes ajs-flipOutY {
0% {
-webkit-transform: perspective(400px);
transform: perspective(400px);
}
30% {
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
opacity: 1;
}
100% {
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
opacity: 0;
}
}
@keyframes ajs-flipOutY {
0% {
-webkit-transform: perspective(400px);
transform: perspective(400px);
}
30% {
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
opacity: 1;
}
100% {
-webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
opacity: 0;
}
}
@-webkit-keyframes ajs-slideIn {
0% {
margin-top: -100%;
}
100% {
margin-top: 5%;
}
}
@keyframes ajs-slideIn {
0% {
margin-top: -100%;
}
100% {
margin-top: 5%;
}
}
@-webkit-keyframes ajs-slideOut {
0% {
margin-top: 5%;
}
100% {
margin-top: -100%;
}
}
@keyframes ajs-slideOut {
0% {
margin-top: 5%;
}
100% {
margin-top: -100%;
}
}
.alertify-notifier {
position: fixed;
width: 0;
overflow: visible;
z-index: 1982;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
.alertify-notifier .ajs-message {
position: relative;
width: 260px;
max-height: 0;
padding: 0;
opacity: 0;
margin: 0;
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
transition-duration: 250ms;
transition-timing-function: linear;
}
.alertify-notifier .ajs-message.ajs-visible {
transition-duration: 500ms;
transition-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275);
opacity: 1;
max-height: 100%;
padding: 15px;
margin-top: 10px;
}
.alertify-notifier .ajs-message.ajs-success {
background: rgba(91, 189, 114, 0.95);
}
.alertify-notifier .ajs-message.ajs-error {
background: rgba(217, 92, 92, 0.95);
}
.alertify-notifier .ajs-message.ajs-warning {
background: rgba(252, 248, 215, 0.95);
}
.alertify-notifier.ajs-top {
top: 10px;
}
.alertify-notifier.ajs-bottom {
bottom: 10px;
}
.alertify-notifier.ajs-right {
right: 10px;
}
.alertify-notifier.ajs-right .ajs-message {
right: -320px;
}
.alertify-notifier.ajs-right .ajs-message.ajs-visible {
right: 290px;
}
.alertify-notifier.ajs-left {
left: 10px;
}
.alertify-notifier.ajs-left .ajs-message {
left: -300px;
}
.alertify-notifier.ajs-left .ajs-message.ajs-visible {
left: 0;
}

File diff suppressed because it is too large Load Diff

1650
client/externalFiles/alertify.min.css vendored Normal file

File diff suppressed because it is too large Load Diff

3
client/externalFiles/alertify.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,678 @@
//'use strict';
import {Chart} from 'chart.js';
import Hammer from 'hammerjs';
var helpers = Chart.helpers;
// Take the zoom namespace of Chart
var zoomNS = Chart.Zoom = Chart.Zoom || {};
// Where we store functions to handle different scale types
var zoomFunctions = zoomNS.zoomFunctions = zoomNS.zoomFunctions || {};
var panFunctions = zoomNS.panFunctions = zoomNS.panFunctions || {};
function resolveOptions(chart, options) {
var deprecatedOptions = {};
if (typeof chart.options.pan !== 'undefined') {
deprecatedOptions.pan = chart.options.pan;
}
if (typeof chart.options.zoom !== 'undefined') {
deprecatedOptions.zoom = chart.options.zoom;
}
var props = chart.$zoom;
options = props._options = helpers.merge({}, [options, deprecatedOptions]);
// Install listeners. Do this dynamically based on options so that we can turn zoom on and off
// We also want to make sure listeners aren't always on. E.g. if you're scrolling down a page
// and the mouse goes over a chart you don't want it intercepted unless the plugin is enabled
var node = props._node;
var zoomEnabled = options.zoom && options.zoom.enabled;
var dragEnabled = options.zoom.drag;
if (zoomEnabled && !dragEnabled) {
node.addEventListener('wheel', props._wheelHandler);
} else {
node.removeEventListener('wheel', props._wheelHandler);
}
if (zoomEnabled && dragEnabled) {
node.addEventListener('mousedown', props._mouseDownHandler);
node.ownerDocument.addEventListener('mouseup', props._mouseUpHandler);
} else {
node.removeEventListener('mousedown', props._mouseDownHandler);
node.removeEventListener('mousemove', props._mouseMoveHandler);
node.ownerDocument.removeEventListener('mouseup', props._mouseUpHandler);
}
}
function storeOriginalOptions(chart) {
var originalOptions = chart.$zoom._originalOptions;
helpers.each(chart.scales, function(scale) {
if (!originalOptions[scale.id]) {
originalOptions[scale.id] = helpers.clone(scale.options);
}
});
helpers.each(originalOptions, function(opt, key) {
if (!chart.scales[key]) {
delete originalOptions[key];
}
});
}
/**
* @param {string} mode can be 'x', 'y' or 'xy'
* @param {string} dir can be 'x' or 'y'
* @param {Chart} chart instance of the chart in question
*/
function directionEnabled(mode, dir, chart) {
if (mode === undefined) {
return true;
} else if (typeof mode === 'string') {
return mode.indexOf(dir) !== -1;
} else if (typeof mode === 'function') {
return mode({chart: chart}).indexOf(dir) !== -1;
}
return false;
}
function rangeMaxLimiter(zoomPanOptions, newMax) {
if (zoomPanOptions.scaleAxes && zoomPanOptions.rangeMax &&
!helpers.isNullOrUndef(zoomPanOptions.rangeMax[zoomPanOptions.scaleAxes])) {
var rangeMax = zoomPanOptions.rangeMax[zoomPanOptions.scaleAxes];
if (newMax > rangeMax) {
newMax = rangeMax;
}
}
return newMax;
}
function rangeMinLimiter(zoomPanOptions, newMin) {
if (zoomPanOptions.scaleAxes && zoomPanOptions.rangeMin &&
!helpers.isNullOrUndef(zoomPanOptions.rangeMin[zoomPanOptions.scaleAxes])) {
var rangeMin = zoomPanOptions.rangeMin[zoomPanOptions.scaleAxes];
if (newMin < rangeMin) {
newMin = rangeMin;
}
}
return newMin;
}
function zoomCategoryScale(scale, zoom, center, zoomOptions) {
var labels = scale.chart.data.labels;
var minIndex = scale.min;
var lastLabelIndex = labels.length - 1;
var maxIndex = scale.max;
var sensitivity = zoomOptions.sensitivity;
var chartCenter = scale.isHorizontal() ? scale.left + (scale.width / 2) : scale.top + (scale.height / 2);
var centerPointer = scale.isHorizontal() ? center.x : center.y;
zoomNS.zoomCumulativeDelta = zoom > 1 ? zoomNS.zoomCumulativeDelta + 1 : zoomNS.zoomCumulativeDelta - 1;
if (Math.abs(zoomNS.zoomCumulativeDelta) > sensitivity) {
if (zoomNS.zoomCumulativeDelta < 0) {
if (centerPointer >= chartCenter) {
if (minIndex <= 0) {
maxIndex = Math.min(lastLabelIndex, maxIndex + 1);
} else {
minIndex = Math.max(0, minIndex - 1);
}
} else if (centerPointer < chartCenter) {
if (maxIndex >= lastLabelIndex) {
minIndex = Math.max(0, minIndex - 1);
} else {
maxIndex = Math.min(lastLabelIndex, maxIndex + 1);
}
}
zoomNS.zoomCumulativeDelta = 0;
} else if (zoomNS.zoomCumulativeDelta > 0) {
if (centerPointer >= chartCenter) {
minIndex = minIndex < maxIndex ? minIndex = Math.min(maxIndex, minIndex + 1) : minIndex;
} else if (centerPointer < chartCenter) {
maxIndex = maxIndex > minIndex ? maxIndex = Math.max(minIndex, maxIndex - 1) : maxIndex;
}
zoomNS.zoomCumulativeDelta = 0;
}
scale.options.min = rangeMinLimiter(zoomOptions, labels[minIndex]);
scale.options.max = rangeMaxLimiter(zoomOptions, labels[maxIndex]);
}
}
function zoomNumericalScale(scale, zoom, center, zoomOptions) {
var range = scale.max - scale.min;
var newDiff = range * (zoom - 1);
var centerPoint = scale.isHorizontal() ? center.x : center.y;
var minPercent = (scale.getValueForPixel(centerPoint) - scale.min) / range;
var maxPercent = 1 - minPercent;
var minDelta = newDiff * minPercent;
var maxDelta = newDiff * maxPercent;
console.log("SCOPT", scale.options)
scale.options.min = rangeMinLimiter(zoomOptions, scale.min + minDelta);
scale.options.max = rangeMaxLimiter(zoomOptions, scale.max - maxDelta);
}
function zoomScale(scale, zoom, center, zoomOptions) {
var fn = zoomFunctions[scale.type];
if (fn) {
fn(scale, zoom, center, zoomOptions);
}
}
/**
* @param chart The chart instance
* @param {number} percentZoomX The zoom percentage in the x direction
* @param {number} percentZoomY The zoom percentage in the y direction
* @param {{x: number, y: number}} focalPoint The x and y coordinates of zoom focal point. The point which doesn't change while zooming. E.g. the location of the mouse cursor when "drag: false"
* @param {string} whichAxes `xy`, 'x', or 'y'
* @param {number} animationDuration Duration of the animation of the redraw in milliseconds
*/
function doZoom(chart, percentZoomX, percentZoomY, focalPoint, whichAxes, animationDuration) {
var ca = chart.chartArea;
if (!focalPoint) {
focalPoint = {
x: (ca.left + ca.right) / 2,
y: (ca.top + ca.bottom) / 2,
};
}
var zoomOptions = chart.$zoom._options.zoom;
if (zoomOptions.enabled) {
storeOriginalOptions(chart);
// Do the zoom here
var zoomMode = typeof zoomOptions.mode === 'function' ? zoomOptions.mode({chart: chart}) : zoomOptions.mode;
// Which axe should be modified when figers were used.
var _whichAxes;
if (zoomMode === 'xy' && whichAxes !== undefined) {
// based on fingers positions
_whichAxes = whichAxes;
} else {
// no effect
_whichAxes = 'xy';
}
helpers.each(chart.scales, function(scale) {
if (scale.isHorizontal() && directionEnabled(zoomMode, 'x', chart) && directionEnabled(_whichAxes, 'x', chart)) {
zoomOptions.scaleAxes = 'x';
zoomScale(scale, percentZoomX, focalPoint, zoomOptions);
} else if (!scale.isHorizontal() && directionEnabled(zoomMode, 'y', chart) && directionEnabled(_whichAxes, 'y', chart)) {
// Do Y zoom
zoomOptions.scaleAxes = 'y';
zoomScale(scale, percentZoomY, focalPoint, zoomOptions);
}
});
if (animationDuration) {
// needs to create specific animation mode
if (!chart.options.animation.zoom) {
chart.options.animation.zoom = {
duration: animationDuration,
easing: 'easeOutQuad',
};
}
chart.update('zoom');
} else {
chart.update('none');
}
if (typeof zoomOptions.onZoom === 'function') {
zoomOptions.onZoom({chart: chart});
}
}
}
function panCategoryScale(scale, delta, panOptions) {
var labels = scale.chart.data.labels;
var lastLabelIndex = labels.length - 1;
var offsetAmt = Math.max(scale.ticks.length, 1);
var panSpeed = panOptions.speed;
var minIndex = scale.min;
var step = Math.round(scale.width / (offsetAmt * panSpeed));
var maxIndex;
zoomNS.panCumulativeDelta += delta;
minIndex = zoomNS.panCumulativeDelta > step ? Math.max(0, minIndex - 1) : zoomNS.panCumulativeDelta < -step ? Math.min(lastLabelIndex - offsetAmt + 1, minIndex + 1) : minIndex;
zoomNS.panCumulativeDelta = minIndex !== scale.min ? 0 : zoomNS.panCumulativeDelta;
maxIndex = Math.min(lastLabelIndex, minIndex + offsetAmt - 1);
scale.options.min = rangeMinLimiter(panOptions, labels[minIndex]);
scale.options.max = rangeMaxLimiter(panOptions, labels[maxIndex]);
}
function panNumericalScale(scale, delta, panOptions) {
var scaleOpts = scale.options;
var prevStart = scale.min;
var prevEnd = scale.max;
var newMin = scale.getValueForPixel(scale.getPixelForValue(prevStart) - delta);
var newMax = scale.getValueForPixel(scale.getPixelForValue(prevEnd) - delta);
var rangeMin = newMin;
var rangeMax = newMax;
var diff;
if (panOptions.scaleAxes && panOptions.rangeMin &&
!helpers.isNullOrUndef(panOptions.rangeMin[panOptions.scaleAxes])) {
rangeMin = panOptions.rangeMin[panOptions.scaleAxes];
}
if (panOptions.scaleAxes && panOptions.rangeMax &&
!helpers.isNullOrUndef(panOptions.rangeMax[panOptions.scaleAxes])) {
rangeMax = panOptions.rangeMax[panOptions.scaleAxes];
}
console.log("SCOPT pan", scaleOpts);
if (newMin >= rangeMin && newMax <= rangeMax) {
scaleOpts.min = newMin;
scaleOpts.max = newMax;
} else if (newMin < rangeMin) {
diff = prevStart - rangeMin;
scaleOpts.min = rangeMin;
scaleOpts.max = prevEnd - diff;
} else if (newMax > rangeMax) {
diff = rangeMax - prevEnd;
scaleOpts.max = rangeMax;
scaleOpts.min = prevStart + diff;
}
}
function panScale(scale, delta, panOptions) {
var fn = panFunctions[scale.type];
if (fn) {
fn(scale, delta, panOptions);
}
}
function doPan(chartInstance, deltaX, deltaY) {
storeOriginalOptions(chartInstance);
var panOptions = chartInstance.$zoom._options.pan;
if (panOptions.enabled) {
var panMode = typeof panOptions.mode === 'function' ? panOptions.mode({chart: chartInstance}) : panOptions.mode;
helpers.each(chartInstance.scales, function(scale) {
if (scale.isHorizontal() && directionEnabled(panMode, 'x', chartInstance) && deltaX !== 0) {
panOptions.scaleAxes = 'x';
panScale(scale, deltaX, panOptions);
} else if (!scale.isHorizontal() && directionEnabled(panMode, 'y', chartInstance) && deltaY !== 0) {
panOptions.scaleAxes = 'y';
panScale(scale, deltaY, panOptions);
}
});
chartInstance.update('none');
if (typeof panOptions.onPan === 'function') {
panOptions.onPan({chart: chartInstance});
}
}
}
function getXAxis(chartInstance) {
var scales = chartInstance.scales;
var scaleIds = Object.keys(scales);
for (var i = 0; i < scaleIds.length; i++) {
var scale = scales[scaleIds[i]];
if (scale.isHorizontal()) {
return scale;
}
}
}
function getYAxis(chartInstance) {
var scales = chartInstance.scales;
var scaleIds = Object.keys(scales);
for (var i = 0; i < scaleIds.length; i++) {
var scale = scales[scaleIds[i]];
if (!scale.isHorizontal()) {
return scale;
}
}
}
// Store these for later
zoomNS.zoomFunctions.category = zoomCategoryScale;
zoomNS.zoomFunctions.time = zoomNumericalScale;
zoomNS.zoomFunctions.linear = zoomNumericalScale;
zoomNS.zoomFunctions.logarithmic = zoomNumericalScale;
zoomNS.panFunctions.category = panCategoryScale;
zoomNS.panFunctions.time = panNumericalScale;
zoomNS.panFunctions.linear = panNumericalScale;
zoomNS.panFunctions.logarithmic = panNumericalScale;
// Globals for category pan and zoom
zoomNS.panCumulativeDelta = 0;
zoomNS.zoomCumulativeDelta = 0;
// Chartjs Zoom Plugin
var zoomPlugin = {
id: 'zoom',
defaults: {
pan: {
enabled: false,
mode: 'xy',
speed: 20,
threshold: 10
},
zoom: {
enabled: false,
mode: 'xy',
sensitivity: 3,
speed: 0.1
}
},
afterInit: function(chartInstance) {
chartInstance.resetZoom = function() {
storeOriginalOptions(chartInstance);
var originalOptions = chartInstance.$zoom._originalOptions;
helpers.each(chartInstance.scales, function(scale) {
var options = scale.options;
if (originalOptions[scale.id]) {
options.min = originalOptions[scale.id].min;
options.max = originalOptions[scale.id].max;
} else {
delete options.min;
delete options.max;
}
});
chartInstance.update();
};
},
beforeUpdate: function(chart, args, options) {
resolveOptions(chart, options);
},
beforeInit: function(chartInstance, pluginOptions) {
chartInstance.$zoom = {
_originalOptions: {}
};
var node = chartInstance.$zoom._node = chartInstance.ctx.canvas;
resolveOptions(chartInstance, pluginOptions);
var options = chartInstance.$zoom._options;
var panThreshold = options.pan && options.pan.threshold;
chartInstance.$zoom._mouseDownHandler = function(event) {
node.addEventListener('mousemove', chartInstance.$zoom._mouseMoveHandler);
chartInstance.$zoom._dragZoomStart = event;
};
chartInstance.$zoom._mouseMoveHandler = function(event) {
if (chartInstance.$zoom._dragZoomStart) {
chartInstance.$zoom._dragZoomEnd = event;
chartInstance.update('none');
}
};
chartInstance.$zoom._mouseUpHandler = function(event) {
if (!chartInstance.$zoom._dragZoomStart) {
return;
}
node.removeEventListener('mousemove', chartInstance.$zoom._mouseMoveHandler);
var beginPoint = chartInstance.$zoom._dragZoomStart;
var offsetX = beginPoint.target.getBoundingClientRect().left;
var startX = Math.min(beginPoint.clientX, event.clientX) - offsetX;
var endX = Math.max(beginPoint.clientX, event.clientX) - offsetX;
var offsetY = beginPoint.target.getBoundingClientRect().top;
var startY = Math.min(beginPoint.clientY, event.clientY) - offsetY;
var endY = Math.max(beginPoint.clientY, event.clientY) - offsetY;
var dragDistanceX = endX - startX;
var dragDistanceY = endY - startY;
// Remove drag start and end before chart update to stop drawing selected area
chartInstance.$zoom._dragZoomStart = null;
chartInstance.$zoom._dragZoomEnd = null;
var zoomThreshold = (options.zoom && options.zoom.threshold) || 0;
if (dragDistanceX <= zoomThreshold && dragDistanceY <= zoomThreshold) {
return;
}
var chartArea = chartInstance.chartArea;
var zoomOptions = chartInstance.$zoom._options.zoom;
var chartDistanceX = chartArea.right - chartArea.left;
var xEnabled = directionEnabled(zoomOptions.mode, 'x', chartInstance);
var zoomX = xEnabled && dragDistanceX ? 1 + ((chartDistanceX - dragDistanceX) / chartDistanceX) : 1;
var chartDistanceY = chartArea.bottom - chartArea.top;
var yEnabled = directionEnabled(zoomOptions.mode, 'y', chartInstance);
var zoomY = yEnabled && dragDistanceY ? 1 + ((chartDistanceY - dragDistanceY) / chartDistanceY) : 1;
doZoom(chartInstance, zoomX, zoomY, {
x: (startX - chartArea.left) / (1 - dragDistanceX / chartDistanceX) + chartArea.left,
y: (startY - chartArea.top) / (1 - dragDistanceY / chartDistanceY) + chartArea.top
}, undefined, zoomOptions.drag.animationDuration);
if (typeof zoomOptions.onZoomComplete === 'function') {
zoomOptions.onZoomComplete({chart: chartInstance});
}
};
var _scrollTimeout = null;
chartInstance.$zoom._wheelHandler = function(event) {
// Prevent the event from triggering the default behavior (eg. Content scrolling).
if (event.cancelable) {
event.preventDefault();
}
// Firefox always fires the wheel event twice:
// First without the delta and right after that once with the delta properties.
if (typeof event.deltaY === 'undefined') {
return;
}
var rect = event.target.getBoundingClientRect();
var offsetX = event.clientX - rect.left;
var offsetY = event.clientY - rect.top;
var center = {
x: offsetX,
y: offsetY
};
var zoomOptions = chartInstance.$zoom._options.zoom;
var speedPercent = zoomOptions.speed;
if (event.deltaY >= 0) {
speedPercent = -speedPercent;
}
doZoom(chartInstance, 1 + speedPercent, 1 + speedPercent, center);
clearTimeout(_scrollTimeout);
_scrollTimeout = setTimeout(function() {
if (typeof zoomOptions.onZoomComplete === 'function') {
zoomOptions.onZoomComplete({chart: chartInstance});
}
}, 250);
};
if (Hammer) {
var mc = new Hammer.Manager(node);
mc.add(new Hammer.Pinch());
mc.add(new Hammer.Pan({
threshold: panThreshold
}));
// Hammer reports the total scaling. We need the incremental amount
var currentPinchScaling;
var handlePinch = function(e) {
var diff = 1 / (currentPinchScaling) * e.scale;
var rect = e.target.getBoundingClientRect();
var offsetX = e.center.x - rect.left;
var offsetY = e.center.y - rect.top;
var center = {
x: offsetX,
y: offsetY
};
// fingers position difference
var x = Math.abs(e.pointers[0].clientX - e.pointers[1].clientX);
var y = Math.abs(e.pointers[0].clientY - e.pointers[1].clientY);
// diagonal fingers will change both (xy) axes
var p = x / y;
var xy;
if (p > 0.3 && p < 1.7) {
xy = 'xy';
} else if (x > y) {
xy = 'x'; // x axis
} else {
xy = 'y'; // y axis
}
doZoom(chartInstance, diff, diff, center, xy);
var zoomOptions = chartInstance.$zoom._options.zoom;
if (typeof zoomOptions.onZoomComplete === 'function') {
zoomOptions.onZoomComplete({chart: chartInstance});
}
// Keep track of overall scale
currentPinchScaling = e.scale;
};
mc.on('pinchstart', function() {
currentPinchScaling = 1; // reset tracker
});
mc.on('pinch', handlePinch);
mc.on('pinchend', function(e) {
handlePinch(e);
currentPinchScaling = null; // reset
zoomNS.zoomCumulativeDelta = 0;
});
var currentDeltaX = null;
var currentDeltaY = null;
var panning = false;
var handlePan = function(e) {
if (currentDeltaX !== null && currentDeltaY !== null) {
panning = true;
var deltaX = e.deltaX - currentDeltaX;
var deltaY = e.deltaY - currentDeltaY;
currentDeltaX = e.deltaX;
currentDeltaY = e.deltaY;
doPan(chartInstance, deltaX, deltaY);
}
};
mc.on('panstart', function(e) {
currentDeltaX = 0;
currentDeltaY = 0;
handlePan(e);
});
mc.on('panmove', handlePan);
mc.on('panend', function() {
currentDeltaX = null;
currentDeltaY = null;
zoomNS.panCumulativeDelta = 0;
setTimeout(function() {
panning = false;
}, 500);
var panOptions = chartInstance.$zoom._options.pan;
if (typeof panOptions.onPanComplete === 'function') {
panOptions.onPanComplete({chart: chartInstance});
}
});
chartInstance.$zoom._ghostClickHandler = function(e) {
if (panning && e.cancelable) {
e.stopImmediatePropagation();
e.preventDefault();
}
};
node.addEventListener('click', chartInstance.$zoom._ghostClickHandler);
chartInstance._mc = mc;
}
},
beforeDatasetsDraw: function(chartInstance) {
var ctx = chartInstance.ctx;
if (chartInstance.$zoom._dragZoomEnd) {
var xAxis = getXAxis(chartInstance);
var yAxis = getYAxis(chartInstance);
var beginPoint = chartInstance.$zoom._dragZoomStart;
var endPoint = chartInstance.$zoom._dragZoomEnd;
var startX = xAxis.left;
var endX = xAxis.right;
var startY = yAxis.top;
var endY = yAxis.bottom;
if (directionEnabled(chartInstance.$zoom._options.zoom.mode, 'x', chartInstance)) {
var offsetX = beginPoint.target.getBoundingClientRect().left;
startX = Math.min(beginPoint.clientX, endPoint.clientX) - offsetX;
endX = Math.max(beginPoint.clientX, endPoint.clientX) - offsetX;
}
if (directionEnabled(chartInstance.$zoom._options.zoom.mode, 'y', chartInstance)) {
var offsetY = beginPoint.target.getBoundingClientRect().top;
startY = Math.min(beginPoint.clientY, endPoint.clientY) - offsetY;
endY = Math.max(beginPoint.clientY, endPoint.clientY) - offsetY;
}
var rectWidth = endX - startX;
var rectHeight = endY - startY;
var dragOptions = chartInstance.$zoom._options.zoom.drag;
ctx.save();
ctx.beginPath();
ctx.fillStyle = dragOptions.backgroundColor || 'rgba(225,225,225,0.3)';
ctx.fillRect(startX, startY, rectWidth, rectHeight);
if (dragOptions.borderWidth > 0) {
ctx.lineWidth = dragOptions.borderWidth;
ctx.strokeStyle = dragOptions.borderColor || 'rgba(225,225,225)';
ctx.strokeRect(startX, startY, rectWidth, rectHeight);
}
ctx.restore();
}
},
destroy: function(chartInstance) {
if (!chartInstance.$zoom) {
return;
}
var props = chartInstance.$zoom;
var node = props._node;
node.removeEventListener('mousedown', props._mouseDownHandler);
node.removeEventListener('mousemove', props._mouseMoveHandler);
node.ownerDocument.removeEventListener('mouseup', props._mouseUpHandler);
node.removeEventListener('wheel', props._wheelHandler);
node.removeEventListener('click', props._ghostClickHandler);
delete chartInstance.$zoom;
var mc = chartInstance._mc;
if (mc) {
mc.remove('pinchstart');
mc.remove('pinch');
mc.remove('pinchend');
mc.remove('panstart');
mc.remove('pan');
mc.remove('panend');
mc.destroy();
}
}
};
Chart.register(zoomPlugin);
export default zoomPlugin;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

8
client/externalFiles/d3.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,541 @@
/** @license
* eventsource.js
* Available under MIT License (MIT)
* https://github.com/Yaffle/EventSource/
*/
/*jslint indent: 2, vars: true, plusplus: true */
/*global setTimeout, clearTimeout */
(function (global) {
"use strict";
var setTimeout = global.setTimeout;
var clearTimeout = global.clearTimeout;
function Map() {
this.data = {};
}
Map.prototype.get = function (key) {
return this.data[key + "~"];
};
Map.prototype.set = function (key, value) {
this.data[key + "~"] = value;
};
Map.prototype["delete"] = function (key) {
delete this.data[key + "~"];
};
function EventTarget() {
this.listeners = new Map();
}
function throwError(e) {
setTimeout(function () {
throw e;
}, 0);
}
EventTarget.prototype.dispatchEvent = function (event) {
event.target = this;
var type = event.type.toString();
var listeners = this.listeners;
var typeListeners = listeners.get(type);
if (typeListeners == undefined) {
return;
}
var length = typeListeners.length;
var i = -1;
var listener = undefined;
while (++i < length) {
listener = typeListeners[i];
try {
listener.call(this, event);
} catch (e) {
throwError(e);
}
}
};
EventTarget.prototype.addEventListener = function (type, callback) {
type = type.toString();
var listeners = this.listeners;
var typeListeners = listeners.get(type);
if (typeListeners == undefined) {
typeListeners = [];
listeners.set(type, typeListeners);
}
var i = typeListeners.length;
while (--i >= 0) {
if (typeListeners[i] === callback) {
return;
}
}
typeListeners.push(callback);
};
EventTarget.prototype.removeEventListener = function (type, callback) {
type = type.toString();
var listeners = this.listeners;
var typeListeners = listeners.get(type);
if (typeListeners == undefined) {
return;
}
var length = typeListeners.length;
var filtered = [];
var i = -1;
while (++i < length) {
if (typeListeners[i] !== callback) {
filtered.push(typeListeners[i]);
}
}
if (filtered.length === 0) {
listeners["delete"](type);
} else {
listeners.set(type, filtered);
}
};
function Event(type) {
this.type = type;
this.target = undefined;
}
function MessageEvent(type, options) {
Event.call(this, type);
this.data = options.data;
this.lastEventId = options.lastEventId;
}
MessageEvent.prototype = Event.prototype;
var XHR = global.XMLHttpRequest;
var XDR = global.XDomainRequest;
var isCORSSupported = XHR != undefined && (new XHR()).withCredentials != undefined;
var Transport = isCORSSupported || (XHR != undefined && XDR == undefined) ? XHR : XDR;
var WAITING = -1;
var CONNECTING = 0;
var OPEN = 1;
var CLOSED = 2;
var AFTER_CR = 3;
var FIELD_START = 4;
var FIELD = 5;
var VALUE_START = 6;
var VALUE = 7;
var contentTypeRegExp = /^text\/event\-stream;?(\s*charset\=utf\-8)?$/i;
var MINIMUM_DURATION = 1000;
var MAXIMUM_DURATION = 18000000;
function getDuration(value, def) {
var n = value;
if (n !== n) {
n = def;
}
return (n < MINIMUM_DURATION ? MINIMUM_DURATION : (n > MAXIMUM_DURATION ? MAXIMUM_DURATION : n));
}
function fire(that, f, event) {
try {
if (typeof f === "function") {
f.call(that, event);
}
} catch (e) {
throwError(e);
}
}
function EventSource(url, options) {
url = url.toString();
var withCredentials = isCORSSupported && options != undefined && Boolean(options.withCredentials);
var initialRetry = getDuration(1000, 0);
var heartbeatTimeout = getDuration(45000, 0);
var lastEventId = "";
var that = this;
var retry = initialRetry;
var wasActivity = false;
var CurrentTransport = options != undefined && options.Transport != undefined ? options.Transport : Transport;
var xhr = new CurrentTransport();
var timeout = 0;
var timeout0 = 0;
var charOffset = 0;
var currentState = WAITING;
var dataBuffer = [];
var lastEventIdBuffer = "";
var eventTypeBuffer = "";
var onTimeout = undefined;
var state = FIELD_START;
var field = "";
var value = "";
function close() {
currentState = CLOSED;
if (xhr != undefined) {
xhr.abort();
xhr = undefined;
}
if (timeout !== 0) {
clearTimeout(timeout);
timeout = 0;
}
if (timeout0 !== 0) {
clearTimeout(timeout0);
timeout0 = 0;
}
that.readyState = CLOSED;
}
function onEvent(type) {
var responseText = "";
if (currentState === OPEN || currentState === CONNECTING) {
try {
responseText = xhr.responseText;
} catch (error) {
// IE 8 - 9 with XMLHttpRequest
}
}
var event = undefined;
var isWrongStatusCodeOrContentType = false;
if (currentState === CONNECTING) {
var status = 0;
var statusText = "";
var contentType = undefined;
if (!("contentType" in xhr)) {
try {
status = xhr.status;
statusText = xhr.statusText;
contentType = xhr.getResponseHeader("Content-Type");
} catch (error) {
// https://bugs.webkit.org/show_bug.cgi?id=29121
status = 0;
statusText = "";
contentType = undefined;
// FF < 14, WebKit
// https://bugs.webkit.org/show_bug.cgi?id=29658
// https://bugs.webkit.org/show_bug.cgi?id=77854
}
} else if (type !== "" && type !== "error") {
status = 200;
statusText = "OK";
contentType = xhr.contentType;
}
if (contentType == undefined) {
contentType = "";
}
if (status === 0 && statusText === "" && type === "load" && responseText !== "") {
status = 200;
statusText = "OK";
if (contentType === "") { // Opera 12
var tmp = (/^data\:([^,]*?)(?:;base64)?,[\S]*$/).exec(url);
if (tmp != undefined) {
contentType = tmp[1];
}
}
}
if (status === 200 && contentTypeRegExp.test(contentType)) {
currentState = OPEN;
wasActivity = true;
retry = initialRetry;
that.readyState = OPEN;
event = new Event("open");
that.dispatchEvent(event);
fire(that, that.onopen, event);
if (currentState === CLOSED) {
return;
}
} else {
// Opera 12
if (status !== 0 && (status !== 200 || contentType !== "")) {
var message = "";
if (status !== 200) {
message = "EventSource's response has a status " + status + " " + statusText.replace(/\s+/g, " ") + " that is not 200. Aborting the connection.";
} else {
message = "EventSource's response has a Content-Type specifying an unsupported type: " + contentType.replace(/\s+/g, " ") + ". Aborting the connection.";
}
setTimeout(function () {
throw new Error(message);
}, 0);
isWrongStatusCodeOrContentType = true;
}
}
}
if (currentState === OPEN) {
if (responseText.length > charOffset) {
wasActivity = true;
}
var i = charOffset - 1;
var length = responseText.length;
var c = "\n";
while (++i < length) {
c = responseText.charAt(i);
if (state === AFTER_CR && c === "\n") {
state = FIELD_START;
} else {
if (state === AFTER_CR) {
state = FIELD_START;
}
if (c === "\r" || c === "\n") {
if (field === "data") {
dataBuffer.push(value);
} else if (field === "id") {
lastEventIdBuffer = value;
} else if (field === "event") {
eventTypeBuffer = value;
} else if (field === "retry") {
initialRetry = getDuration(Number(value), initialRetry);
retry = initialRetry;
} else if (field === "heartbeatTimeout") {
heartbeatTimeout = getDuration(Number(value), heartbeatTimeout);
if (timeout !== 0) {
clearTimeout(timeout);
timeout = setTimeout(onTimeout, heartbeatTimeout);
}
}
value = "";
field = "";
if (state === FIELD_START) {
if (dataBuffer.length !== 0) {
lastEventId = lastEventIdBuffer;
if (eventTypeBuffer === "") {
eventTypeBuffer = "message";
}
event = new MessageEvent(eventTypeBuffer, {
data: dataBuffer.join("\n"),
lastEventId: lastEventIdBuffer
});
that.dispatchEvent(event);
if (eventTypeBuffer === "message") {
fire(that, that.onmessage, event);
}
if (currentState === CLOSED) {
return;
}
}
dataBuffer.length = 0;
eventTypeBuffer = "";
}
state = c === "\r" ? AFTER_CR : FIELD_START;
} else {
if (state === FIELD_START) {
state = FIELD;
}
if (state === FIELD) {
if (c === ":") {
state = VALUE_START;
} else {
field += c;
}
} else if (state === VALUE_START) {
if (c !== " ") {
value += c;
}
state = VALUE;
} else if (state === VALUE) {
value += c;
}
}
}
}
charOffset = length;
}
if ((currentState === OPEN || currentState === CONNECTING) &&
(type === "load" || type === "error" || isWrongStatusCodeOrContentType || (charOffset > 1024 * 1024) || (timeout === 0 && !wasActivity))) {
if (isWrongStatusCodeOrContentType) {
close();
} else {
if (type === "" && timeout === 0 && !wasActivity) {
setTimeout(function () {
throw new Error("No activity within " + heartbeatTimeout + " milliseconds. Reconnecting.");
}, 0);
}
currentState = WAITING;
xhr.abort();
if (timeout !== 0) {
clearTimeout(timeout);
timeout = 0;
}
if (retry > initialRetry * 16) {
retry = initialRetry * 16;
}
if (retry > MAXIMUM_DURATION) {
retry = MAXIMUM_DURATION;
}
timeout = setTimeout(onTimeout, retry);
retry = retry * 2 + 1;
that.readyState = CONNECTING;
}
event = new Event("error");
that.dispatchEvent(event);
fire(that, that.onerror, event);
} else {
if (timeout === 0) {
wasActivity = false;
timeout = setTimeout(onTimeout, heartbeatTimeout);
}
}
}
function onProgress() {
onEvent("progress");
}
function onLoad() {
onEvent("load");
}
function onError() {
onEvent("error");
}
function onReadyStateChange() {
if (xhr.readyState === 4) {
if (xhr.status === 0) {
onEvent("error");
} else {
onEvent("load");
}
} else {
onEvent("progress");
}
}
if (("readyState" in xhr) && global.opera != undefined) {
// workaround for Opera issue with "progress" events
timeout0 = setTimeout(function f() {
if (xhr.readyState === 3) {
onEvent("progress");
}
timeout0 = setTimeout(f, 500);
}, 0);
}
onTimeout = function () {
timeout = 0;
if (currentState !== WAITING) {
onEvent("");
return;
}
// loading indicator in Safari, Chrome < 14
// loading indicator in Firefox
// https://bugzilla.mozilla.org/show_bug.cgi?id=736723
if ((!("ontimeout" in xhr) || ("sendAsBinary" in xhr) || ("mozAnon" in xhr)) && global.document != undefined && global.document.readyState != undefined && global.document.readyState !== "complete") {
timeout = setTimeout(onTimeout, 4);
return;
}
// XDomainRequest#abort removes onprogress, onerror, onload
xhr.onload = onLoad;
xhr.onerror = onError;
if ("onabort" in xhr) {
// improper fix to match Firefox behaviour, but it is better than just ignore abort
// see https://bugzilla.mozilla.org/show_bug.cgi?id=768596
// https://bugzilla.mozilla.org/show_bug.cgi?id=880200
// https://code.google.com/p/chromium/issues/detail?id=153570
xhr.onabort = onError;
}
if ("onprogress" in xhr) {
xhr.onprogress = onProgress;
}
// IE 8-9 (XMLHTTPRequest)
// Firefox 3.5 - 3.6 - ? < 9.0
// onprogress is not fired sometimes or delayed
// see also #64
if ("onreadystatechange" in xhr) {
xhr.onreadystatechange = onReadyStateChange;
}
wasActivity = false;
timeout = setTimeout(onTimeout, heartbeatTimeout);
charOffset = 0;
currentState = CONNECTING;
dataBuffer.length = 0;
eventTypeBuffer = "";
lastEventIdBuffer = lastEventId;
value = "";
field = "";
state = FIELD_START;
var s = url.slice(0, 5);
if (s !== "data:" && s !== "blob:") {
s = url + ((url.indexOf("?", 0) === -1 ? "?" : "&") + "lastEventId=" + encodeURIComponent(lastEventId) + "&r=" + (Math.random() + 1).toString().slice(2));
} else {
s = url;
}
xhr.open("GET", s, true);
if ("withCredentials" in xhr) {
// withCredentials should be set after "open" for Safari and Chrome (< 19 ?)
xhr.withCredentials = withCredentials;
}
if ("responseType" in xhr) {
xhr.responseType = "text";
}
if ("setRequestHeader" in xhr) {
// Request header field Cache-Control is not allowed by Access-Control-Allow-Headers.
// "Cache-control: no-cache" are not honored in Chrome and Firefox
// https://bugzilla.mozilla.org/show_bug.cgi?id=428916
//xhr.setRequestHeader("Cache-Control", "no-cache");
xhr.setRequestHeader("Accept", "text/event-stream");
// Request header field Last-Event-ID is not allowed by Access-Control-Allow-Headers.
//xhr.setRequestHeader("Last-Event-ID", lastEventId);
}
xhr.send(undefined);
};
EventTarget.call(this);
this.close = close;
this.url = url;
this.readyState = CONNECTING;
this.withCredentials = withCredentials;
this.onopen = undefined;
this.onmessage = undefined;
this.onerror = undefined;
onTimeout();
}
function F() {
this.CONNECTING = CONNECTING;
this.OPEN = OPEN;
this.CLOSED = CLOSED;
}
F.prototype = EventTarget.prototype;
EventSource.prototype = new F();
F.call(EventSource);
if (isCORSSupported) {
EventSource.prototype.withCredentials = undefined;
}
var isEventSourceSupported = function () {
// Opera 12 fails this test, but this is fine.
return global.EventSource != undefined && ("withCredentials" in global.EventSource.prototype);
};
if (Transport != undefined && (global.EventSource == undefined || (isCORSSupported && !isEventSourceSupported()))) {
// Why replace a native EventSource ?
// https://bugzilla.mozilla.org/show_bug.cgi?id=444328
// https://bugzilla.mozilla.org/show_bug.cgi?id=831392
// https://code.google.com/p/chromium/issues/detail?id=260144
// https://code.google.com/p/chromium/issues/detail?id=225654
// ...
global.NativeEventSource = global.EventSource;
global.EventSource = EventSource;
}
}(typeof window !== 'undefined' ? window : this));

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

15
client/externalFiles/oldswiper.min.css vendored Normal file

File diff suppressed because one or more lines are too long

18
client/externalFiles/oldswiper.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,576 @@
/**
* Swiper 3.4.0
* Most modern mobile touch slider and framework with hardware accelerated transitions
*
* http://www.idangero.us/swiper/
*
* Copyright 2016, Vladimir Kharlampidi
* The iDangero.us
* http://www.idangero.us/
*
* Licensed under MIT
*
* Released on: October 16, 2016
*/
.swiper-container {
margin-left: auto;
margin-right: auto;
position: relative;
overflow: hidden;
/* Fix of Webkit flickering */
z-index: 1;
}
.swiper-container-no-flexbox .swiper-slide {
float: left;
}
.swiper-container-vertical > .swiper-wrapper {
-webkit-box-orient: vertical;
-moz-box-orient: vertical;
-ms-flex-direction: column;
-webkit-flex-direction: column;
flex-direction: column;
}
.swiper-wrapper {
position: relative;
width: 100%;
height: 100%;
z-index: 1;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-transition-property: -webkit-transform;
-moz-transition-property: -moz-transform;
-o-transition-property: -o-transform;
-ms-transition-property: -ms-transform;
transition-property: transform;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
}
.swiper-container-android .swiper-slide,
.swiper-wrapper {
-webkit-transform: translate3d(0px, 0, 0);
-moz-transform: translate3d(0px, 0, 0);
-o-transform: translate(0px, 0px);
-ms-transform: translate3d(0px, 0, 0);
transform: translate3d(0px, 0, 0);
}
.swiper-container-multirow > .swiper-wrapper {
-webkit-box-lines: multiple;
-moz-box-lines: multiple;
-ms-flex-wrap: wrap;
-webkit-flex-wrap: wrap;
flex-wrap: wrap;
}
.swiper-container-free-mode > .swiper-wrapper {
-webkit-transition-timing-function: ease-out;
-moz-transition-timing-function: ease-out;
-ms-transition-timing-function: ease-out;
-o-transition-timing-function: ease-out;
transition-timing-function: ease-out;
margin: 0 auto;
}
.swiper-slide {
-webkit-flex-shrink: 0;
-ms-flex: 0 0 auto;
flex-shrink: 0;
width: 100%;
height: 100%;
position: relative;
}
/* Auto Height */
.swiper-container-autoheight,
.swiper-container-autoheight .swiper-slide {
height: auto;
}
.swiper-container-autoheight .swiper-wrapper {
-webkit-box-align: start;
-ms-flex-align: start;
-webkit-align-items: flex-start;
align-items: flex-start;
-webkit-transition-property: -webkit-transform, height;
-moz-transition-property: -moz-transform;
-o-transition-property: -o-transform;
-ms-transition-property: -ms-transform;
transition-property: transform, height;
}
/* a11y */
.swiper-container .swiper-notification {
position: absolute;
left: 0;
top: 0;
pointer-events: none;
opacity: 0;
z-index: -1000;
}
/* IE10 Windows Phone 8 Fixes */
.swiper-wp8-horizontal {
-ms-touch-action: pan-y;
touch-action: pan-y;
}
.swiper-wp8-vertical {
-ms-touch-action: pan-x;
touch-action: pan-x;
}
/* Arrows */
.swiper-button-prev,
.swiper-button-next {
position: absolute;
top: 70%;
width: 30px;
height: 30px;
margin-top: -10px;
z-index: 10;
cursor: pointer;
-moz-background-size: 27px 44px;
-webkit-background-size: 27px 44px;
background-size: 27px 44px;
background-position: center;
background-repeat: no-repeat;
opacity: 0.6;
}
.swiper-button-prev.swiper-button-disabled,
.swiper-button-next.swiper-button-disabled {
opacity: 0.2;
cursor: auto;
pointer-events: none;
}
.swiper-button-prev,
.swiper-container-rtl .swiper-button-next {
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M0%2C22L22%2C0l2.1%2C2.1L4.2%2C22l19.9%2C19.9L22%2C44L0%2C22L0%2C22L0%2C22z'%20fill%3D'%23007aff'%2F%3E%3C%2Fsvg%3E");
left: 10px;
right: auto;
}
.swiper-button-prev.swiper-button-black,
.swiper-container-rtl .swiper-button-next.swiper-button-black {
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M0%2C22L22%2C0l2.1%2C2.1L4.2%2C22l19.9%2C19.9L22%2C44L0%2C22L0%2C22L0%2C22z'%20fill%3D'%23000000'%2F%3E%3C%2Fsvg%3E");
}
.swiper-button-prev.swiper-button-white,
.swiper-container-rtl .swiper-button-next.swiper-button-white {
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M0%2C22L22%2C0l2.1%2C2.1L4.2%2C22l19.9%2C19.9L22%2C44L0%2C22L0%2C22L0%2C22z'%20fill%3D'%23ffffff'%2F%3E%3C%2Fsvg%3E");
}
.swiper-button-next,
.swiper-container-rtl .swiper-button-prev {
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M27%2C22L27%2C22L5%2C44l-2.1-2.1L22.8%2C22L2.9%2C2.1L5%2C0L27%2C22L27%2C22z'%20fill%3D'%23007aff'%2F%3E%3C%2Fsvg%3E");
right: 10px;
left: auto;
}
.swiper-button-next.swiper-button-black,
.swiper-container-rtl .swiper-button-prev.swiper-button-black {
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M27%2C22L27%2C22L5%2C44l-2.1-2.1L22.8%2C22L2.9%2C2.1L5%2C0L27%2C22L27%2C22z'%20fill%3D'%23000000'%2F%3E%3C%2Fsvg%3E");
}
.swiper-button-next.swiper-button-white,
.swiper-container-rtl .swiper-button-prev.swiper-button-white {
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2027%2044'%3E%3Cpath%20d%3D'M27%2C22L27%2C22L5%2C44l-2.1-2.1L22.8%2C22L2.9%2C2.1L5%2C0L27%2C22L27%2C22z'%20fill%3D'%23ffffff'%2F%3E%3C%2Fsvg%3E");
}
/* Pagination Styles */
.swiper-pagination {
position: absolute;
text-align: center;
-webkit-transition: 300ms;
-moz-transition: 300ms;
-o-transition: 300ms;
transition: 300ms;
-webkit-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
z-index: 10;
}
.swiper-pagination.swiper-pagination-hidden {
opacity: 0;
}
/* Common Styles */
.swiper-pagination-fraction,
.swiper-pagination-custom,
.swiper-container-horizontal > .swiper-pagination-bullets {
bottom: 10px;
left: 0;
width: 100%;
}
/* Bullets */
.swiper-pagination-bullet {
width: 8px;
height: 8px;
display: inline-block;
border-radius: 100%;
background: #000;
opacity: 0.2;
}
button.swiper-pagination-bullet {
border: none;
margin: 0;
padding: 0;
box-shadow: none;
-moz-appearance: none;
-ms-appearance: none;
-webkit-appearance: none;
appearance: none;
}
.swiper-pagination-clickable .swiper-pagination-bullet {
cursor: pointer;
}
.swiper-pagination-white .swiper-pagination-bullet {
background: #fff;
}
.swiper-pagination-bullet-active {
opacity: 1;
background: #007aff;
}
.swiper-pagination-white .swiper-pagination-bullet-active {
background: #fff;
}
.swiper-pagination-black .swiper-pagination-bullet-active {
background: #000;
}
.swiper-container-vertical > .swiper-pagination-bullets {
right: 10px;
top: 50%;
-webkit-transform: translate3d(0px, -50%, 0);
-moz-transform: translate3d(0px, -50%, 0);
-o-transform: translate(0px, -50%);
-ms-transform: translate3d(0px, -50%, 0);
transform: translate3d(0px, -50%, 0);
}
.swiper-container-vertical > .swiper-pagination-bullets .swiper-pagination-bullet {
margin: 5px 0;
display: block;
}
.swiper-container-horizontal > .swiper-pagination-bullets .swiper-pagination-bullet {
margin: 0 5px;
}
/* Progress */
.swiper-pagination-progress {
background: rgba(0, 0, 0, 0.25);
position: absolute;
}
.swiper-pagination-progress .swiper-pagination-progressbar {
background: #007aff;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
-webkit-transform: scale(0);
-ms-transform: scale(0);
-o-transform: scale(0);
transform: scale(0);
-webkit-transform-origin: left top;
-moz-transform-origin: left top;
-ms-transform-origin: left top;
-o-transform-origin: left top;
transform-origin: left top;
}
.swiper-container-rtl .swiper-pagination-progress .swiper-pagination-progressbar {
-webkit-transform-origin: right top;
-moz-transform-origin: right top;
-ms-transform-origin: right top;
-o-transform-origin: right top;
transform-origin: right top;
}
.swiper-container-horizontal > .swiper-pagination-progress {
width: 100%;
height: 4px;
left: 0;
top: 0;
}
.swiper-container-vertical > .swiper-pagination-progress {
width: 4px;
height: 100%;
left: 0;
top: 0;
}
.swiper-pagination-progress.swiper-pagination-white {
background: rgba(255, 255, 255, 0.5);
}
.swiper-pagination-progress.swiper-pagination-white .swiper-pagination-progressbar {
background: #fff;
}
.swiper-pagination-progress.swiper-pagination-black .swiper-pagination-progressbar {
background: #000;
}
/* 3D Container */
.swiper-container-3d {
-webkit-perspective: 1200px;
-moz-perspective: 1200px;
-o-perspective: 1200px;
perspective: 1200px;
}
.swiper-container-3d .swiper-wrapper,
.swiper-container-3d .swiper-slide,
.swiper-container-3d .swiper-slide-shadow-left,
.swiper-container-3d .swiper-slide-shadow-right,
.swiper-container-3d .swiper-slide-shadow-top,
.swiper-container-3d .swiper-slide-shadow-bottom,
.swiper-container-3d .swiper-cube-shadow {
-webkit-transform-style: preserve-3d;
-moz-transform-style: preserve-3d;
-ms-transform-style: preserve-3d;
transform-style: preserve-3d;
}
.swiper-container-3d .swiper-slide-shadow-left,
.swiper-container-3d .swiper-slide-shadow-right,
.swiper-container-3d .swiper-slide-shadow-top,
.swiper-container-3d .swiper-slide-shadow-bottom {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 10;
}
.swiper-container-3d .swiper-slide-shadow-left {
background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0)));
/* Safari 4+, Chrome */
background-image: -webkit-linear-gradient(right, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
/* Chrome 10+, Safari 5.1+, iOS 5+ */
background-image: -moz-linear-gradient(right, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
/* Firefox 3.6-15 */
background-image: -o-linear-gradient(right, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
/* Opera 11.10-12.00 */
background-image: linear-gradient(to left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
/* Firefox 16+, IE10, Opera 12.50+ */
}
.swiper-container-3d .swiper-slide-shadow-right {
background-image: -webkit-gradient(linear, right top, left top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0)));
/* Safari 4+, Chrome */
background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
/* Chrome 10+, Safari 5.1+, iOS 5+ */
background-image: -moz-linear-gradient(left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
/* Firefox 3.6-15 */
background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
/* Opera 11.10-12.00 */
background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
/* Firefox 16+, IE10, Opera 12.50+ */
}
.swiper-container-3d .swiper-slide-shadow-top {
background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0)));
/* Safari 4+, Chrome */
background-image: -webkit-linear-gradient(bottom, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
/* Chrome 10+, Safari 5.1+, iOS 5+ */
background-image: -moz-linear-gradient(bottom, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
/* Firefox 3.6-15 */
background-image: -o-linear-gradient(bottom, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
/* Opera 11.10-12.00 */
background-image: linear-gradient(to top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
/* Firefox 16+, IE10, Opera 12.50+ */
}
.swiper-container-3d .swiper-slide-shadow-bottom {
background-image: -webkit-gradient(linear, left bottom, left top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0)));
/* Safari 4+, Chrome */
background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
/* Chrome 10+, Safari 5.1+, iOS 5+ */
background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
/* Firefox 3.6-15 */
background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
/* Opera 11.10-12.00 */
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
/* Firefox 16+, IE10, Opera 12.50+ */
}
/* Coverflow */
.swiper-container-coverflow .swiper-wrapper,
.swiper-container-flip .swiper-wrapper {
/* Windows 8 IE 10 fix */
-ms-perspective: 1200px;
}
/* Cube + Flip */
.swiper-container-cube,
.swiper-container-flip {
overflow: visible;
}
.swiper-container-cube .swiper-slide,
.swiper-container-flip .swiper-slide {
pointer-events: none;
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-ms-backface-visibility: hidden;
backface-visibility: hidden;
z-index: 1;
}
.swiper-container-cube .swiper-slide .swiper-slide,
.swiper-container-flip .swiper-slide .swiper-slide {
pointer-events: none;
}
.swiper-container-cube .swiper-slide-active,
.swiper-container-flip .swiper-slide-active,
.swiper-container-cube .swiper-slide-active .swiper-slide-active,
.swiper-container-flip .swiper-slide-active .swiper-slide-active {
pointer-events: auto;
}
.swiper-container-cube .swiper-slide-shadow-top,
.swiper-container-flip .swiper-slide-shadow-top,
.swiper-container-cube .swiper-slide-shadow-bottom,
.swiper-container-flip .swiper-slide-shadow-bottom,
.swiper-container-cube .swiper-slide-shadow-left,
.swiper-container-flip .swiper-slide-shadow-left,
.swiper-container-cube .swiper-slide-shadow-right,
.swiper-container-flip .swiper-slide-shadow-right {
z-index: 0;
-webkit-backface-visibility: hidden;
-moz-backface-visibility: hidden;
-ms-backface-visibility: hidden;
backface-visibility: hidden;
}
/* Cube */
.swiper-container-cube .swiper-slide {
visibility: hidden;
-webkit-transform-origin: 0 0;
-moz-transform-origin: 0 0;
-ms-transform-origin: 0 0;
transform-origin: 0 0;
width: 100%;
height: 100%;
}
.swiper-container-cube.swiper-container-rtl .swiper-slide {
-webkit-transform-origin: 100% 0;
-moz-transform-origin: 100% 0;
-ms-transform-origin: 100% 0;
transform-origin: 100% 0;
}
.swiper-container-cube .swiper-slide-active,
.swiper-container-cube .swiper-slide-next,
.swiper-container-cube .swiper-slide-prev,
.swiper-container-cube .swiper-slide-next + .swiper-slide {
pointer-events: auto;
visibility: visible;
}
.swiper-container-cube .swiper-cube-shadow {
position: absolute;
left: 0;
bottom: 0px;
width: 100%;
height: 100%;
background: #000;
opacity: 0.6;
-webkit-filter: blur(50px);
filter: blur(50px);
z-index: 0;
}
/* Fade */
.swiper-container-fade.swiper-container-free-mode .swiper-slide {
-webkit-transition-timing-function: ease-out;
-moz-transition-timing-function: ease-out;
-ms-transition-timing-function: ease-out;
-o-transition-timing-function: ease-out;
transition-timing-function: ease-out;
}
.swiper-container-fade .swiper-slide {
pointer-events: none;
-webkit-transition-property: opacity;
-moz-transition-property: opacity;
-o-transition-property: opacity;
transition-property: opacity;
}
.swiper-container-fade .swiper-slide .swiper-slide {
pointer-events: none;
}
.swiper-container-fade .swiper-slide-active,
.swiper-container-fade .swiper-slide-active .swiper-slide-active {
pointer-events: auto;
}
.swiper-zoom-container {
width: 100%;
height: 100%;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-box-pack: center;
-moz-box-pack: center;
-ms-flex-pack: center;
-webkit-justify-content: center;
justify-content: center;
-webkit-box-align: center;
-moz-box-align: center;
-ms-flex-align: center;
-webkit-align-items: center;
align-items: center;
text-align: center;
}
.swiper-zoom-container > img,
.swiper-zoom-container > svg,
.swiper-zoom-container > canvas {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
/* Scrollbar */
.swiper-scrollbar {
border-radius: 10px;
position: relative;
-ms-touch-action: none;
background: rgba(0, 0, 0, 0.1);
}
.swiper-container-horizontal > .swiper-scrollbar {
position: absolute;
left: 1%;
bottom: 3px;
z-index: 50;
height: 5px;
width: 98%;
}
.swiper-container-vertical > .swiper-scrollbar {
position: absolute;
right: 3px;
top: 1%;
z-index: 50;
width: 5px;
height: 98%;
}
.swiper-scrollbar-drag {
height: 100%;
width: 100%;
position: relative;
background: rgba(0, 0, 0, 0.5);
border-radius: 10px;
left: 0;
top: 0;
}
.swiper-scrollbar-cursor-drag {
cursor: move;
}
/* Preloader */
.swiper-lazy-preloader {
width: 42px;
height: 42px;
position: absolute;
left: 50%;
top: 50%;
margin-left: -21px;
margin-top: -21px;
z-index: 10;
-webkit-transform-origin: 50%;
-moz-transform-origin: 50%;
transform-origin: 50%;
-webkit-animation: swiper-preloader-spin 1s steps(12, end) infinite;
-moz-animation: swiper-preloader-spin 1s steps(12, end) infinite;
animation: swiper-preloader-spin 1s steps(12, end) infinite;
}
.swiper-lazy-preloader:after {
display: block;
content: "";
width: 100%;
height: 100%;
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20viewBox%3D'0%200%20120%20120'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20xmlns%3Axlink%3D'http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink'%3E%3Cdefs%3E%3Cline%20id%3D'l'%20x1%3D'60'%20x2%3D'60'%20y1%3D'7'%20y2%3D'27'%20stroke%3D'%236c6c6c'%20stroke-width%3D'11'%20stroke-linecap%3D'round'%2F%3E%3C%2Fdefs%3E%3Cg%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(30%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(60%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(90%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(120%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(150%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.37'%20transform%3D'rotate(180%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.46'%20transform%3D'rotate(210%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.56'%20transform%3D'rotate(240%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.66'%20transform%3D'rotate(270%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.75'%20transform%3D'rotate(300%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.85'%20transform%3D'rotate(330%2060%2C60)'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
background-position: 50%;
-webkit-background-size: 100%;
background-size: 100%;
background-repeat: no-repeat;
}
.swiper-lazy-preloader-white:after {
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg%20viewBox%3D'0%200%20120%20120'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20xmlns%3Axlink%3D'http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink'%3E%3Cdefs%3E%3Cline%20id%3D'l'%20x1%3D'60'%20x2%3D'60'%20y1%3D'7'%20y2%3D'27'%20stroke%3D'%23fff'%20stroke-width%3D'11'%20stroke-linecap%3D'round'%2F%3E%3C%2Fdefs%3E%3Cg%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(30%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(60%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(90%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(120%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.27'%20transform%3D'rotate(150%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.37'%20transform%3D'rotate(180%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.46'%20transform%3D'rotate(210%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.56'%20transform%3D'rotate(240%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.66'%20transform%3D'rotate(270%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.75'%20transform%3D'rotate(300%2060%2C60)'%2F%3E%3Cuse%20xlink%3Ahref%3D'%23l'%20opacity%3D'.85'%20transform%3D'rotate(330%2060%2C60)'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
}
@-webkit-keyframes swiper-preloader-spin {
100% {
-webkit-transform: rotate(360deg);
}
}
@keyframes swiper-preloader-spin {
100% {
transform: rotate(360deg);
}
}

File diff suppressed because it is too large Load Diff

12
client/externalFiles/swiper.min.css vendored Normal file

File diff suppressed because one or more lines are too long

13
client/externalFiles/swiper.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

BIN
client/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

BIN
client/favicon192.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

149
client/group.html Normal file
View File

@ -0,0 +1,149 @@
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body style='width:400px;'>
<div id="event"></div>
<script type="text/javascript">
var blockElement = document.getElementById("event");
// copy query
query = window.location.search;
if (query == "") {
query = "?path=main";
}
var evtSrc = new EventSource("http://localhost:5000/update");
function getJSON(url, successHandler, errorHandler) {
var xhr = typeof XMLHttpRequest != 'undefined'
? new XMLHttpRequest()
: new ActiveXObject('Microsoft.XMLHTTP');
console.log("fired JSON request", url)
xhr.open('get', url, true);
xhr.onreadystatechange = function() {
var status;
var data;
// https://xhr.spec.whatwg.org/#dom-xmlhttprequest-readystate
if (xhr.readyState == 4) { // `DONE`
status = xhr.status;
if (status == 200) {
data = JSON.parse(xhr.responseText);
successHandler && successHandler(data);
} else {
errorHandler && errorHandler(status);
}
}
};
xhr.send();
};
function htmlEscape(str) {
return str
.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
}
function draw(message) {
var blk = "<h3>" + message.title + "</h3><table>\n"
for (var i=0; i < message.components.length; i++) {
var component = message.components[i]
var name = component.name
var type = component.type
if ("title" in component) {
var title = component.title
} else {
var title = name
}
if (type == "group") {
blk += "<tr><td>link</td><td><a href='?path=" + encodeURI(message.path + "," + name) + "'>"+ title + "</a></td></tr>\n"
} else if (type == "rdonly") {
blk += "<tr><td >" + title + "</td><td id='"+ name +"' __ctype__=rdonly></td></tr>\n"
} else if (type == "input") {
blk += "<tr><td>" + title + "</td><td><input type=input id='"+ name +"' __ctype__=input></td></tr>\n"
} else if (type == "checkbox") {
blk += "<tr><td>" + title + "</td><td><input type=checkbox id='"+ name +"' __ctype__=checkbox></td></tr>\n"
} else if (type == "radio") {
blk += "<tr><td>" + title + "</td><td id='" + name + "' __ctype__=radio>\n"
for (var j = 0; j < component.buttons.length; j++) {
button = component.buttons[j]
var rbname = name + ":" + button.value
if (j != 0) blk+= "<br>"
blk += "<input type=radio name='" + name + "' id='"+rbname+"' value='" + button.value + "'>" + button.title + "\n"
}
blk += "</td></tr>\n"
}
}
blk += "</table>\n"
blockElement.innerHTML = blk
}
function updateblock(id) {
getJSON("http://localhost:5000/updateblock"+query+"&id="+id,
function(message) { console.log(message); },
function(status) { console.log('stat', status); }
);
}
evtSrc.onmessage = function(e) {
var message = JSON.parse(e.data)
if (message.type == "id") {
var id = message.id
getJSON("http://localhost:5000/getblock"+query+"&id="+id,
function(message) { draw(message); updateblock(id); },
function(status) { console.log('stat', status); }
);
} else if (message.type == "draw") {
draw(message);
} else if (message.type == "update") {
for (var i=0; i < message.updates.length; i++) {
var component = message.updates[i]
var name = component.name
var value = component.value
var elm = document.getElementById(name)
if (!elm) continue
var type = elm.getAttribute("__ctype__")
if (type == "rdonly") {
elm.innerHTML = htmlEscape(value)
} else if (type == "input") {
elm.value = value
} else if (type == "checkbox") {
elm.checked = (value != 0) && (value != "0")
} else if (type == "radio") {
var elm = document.getElementById(name + ":" + value)
if (elm) {
elm.checked = true // this will uncheck all radio buttons with the same name
} else { // no element with this value: we have to go through all radio buttons
var elms = document.getElementsByName(name)
for (var j; j < elms.length; j++) {
if (elms[j].checked) {
elms[j].checked = false
break // we have found the victim, we can leave
}
}
}
}
}
} else if (message.type == "close") {
evtSrc.close()
}
};
evtSrc.onerror = function(e) {
blockElement.innerHTML = "connection lost"
evtSrc.close()
};
window.onbeforeunload = closingCode;
function closingCode(){
console.log("CLOSE")
evtSrc.close()
return null;
}
</script>
</body>
</html>

View File

@ -0,0 +1,385 @@
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// % COMMUNICATION
var timeoutID; // We need this ID to reset the timer every 30 seconds
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Server Sent Event
function buildUpdateConnection() {
// Establishes server-sent-event-connection, which is used for all sorts of
// updates and exists as long as the client is running.
// Executed at programstart (see also SEAWebClientMain.js).
var path = "http://" + hostPort + "/update";
if (debugCommunication) {
console.log("%cto server (SSE): " + path,
"color:white;background:lightblue");
}
try {
var src = new EventSource(path);
} catch (e) {
console.log(e)
alertify.prompt(
"NETWORK ERROR",
"Failed to establish connection to data-server at the given address!"
+ "Try to enter HOST and PORT of the data-server manually!",
hostPort, function(evt, value) {
hostPort = value;
buildUpdateConnection();
}, function() {
})
}
src.onmessage = function(e) {
var message = JSON.parse(e.data);
if (message) {
handleUpdateMessage(src, message);
}
};
src.onerror = function(e) {
console.log(e);
console.log('EVTSRC error')
alertify
.prompt(
"NETWORK ERROR",
"Failed to establish connection to data-server at the given address!"
+ "Try to enter HOST and PORT of the data-server manually!",
hostPort, function(evt, value) {
hostPort = value;
buildUpdateConnection();
}, function() {
})
src.close();
};
}
function handleUpdateMessage(src, message) {
// Handles incoming SSE-messages depending on type of message.
if (debugCommunication > 1) {
console.log("%cfrom server (SSE): " + message.type,
"color:white;background:lightgray", message);
}
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// <---------------------------------------------------------------------------------BUG!!!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
resetTimer(src);
switch (message.type) {
// id-message: Confirms establishment of SSE-connection and determines
// specific ID of the client
case "id":
for (var i = 0; i < swiper.length; i++) {
swiper[i].removeAllSlides();
}
clientID = message.id;
if ("device" in message) {
if (message.device == "_inst_select") {
clientTitle = "select instrument";
console.log('IDselect')
pushInitCommand("getblock?path=_inst_select&", "instrument selection");
menuMode = true;
sizeChange();
} else {
clientTitle = message.instrument + " " + message.device;
console.log('loadBlocks')
loadFirstBlocks();
}
document.title = "SEA "+clientTitle;
} else {
document.title = "SEA "+clientTitle + " " + message.title;
}
var header = document.getElementById("header");
header.setAttribute("style", "width: auto;");
header.innerHTML = clientTitle;
console.log('ID', initCommands);
nextInitCommand();
break;
// console-update-message: Confirms a command.
case "command":
var histories = document.getElementsByClassName("history");
for (var i = 0; i < histories.length; i++) {
var line = document.createElement('div');
line.innerHTML = htmlEscape(message.line);
line.style.color = "cornflowerblue";
if (message.origin == "self") {
line.style.fontWeight = "bold";
}
histories[i].appendChild(document.createElement('br'));
histories[i].appendChild(line);
histories[i].scrollTop = histories[i].scrollHeight;
}
var cmd = htmlEscape(message.line);
if (commandHistory.indexOf(cmd) === -1) {
commandHistory.unshift(cmd);
}
break;
// console-update-message: Confirms execution of command.
case "reply":
var histories = document.getElementsByClassName("history");
for (var i = 0; i < histories.length; i++) {
var line = document.createElement('div');
line.innerHTML = htmlEscape(message.line);
line.style.color = "black";
if (message.origin == "self") {
line.style.fontWeight = "bold";
} else if (message.origin == "async") {
line.style.color = "green";
if (!showAsync) continue;
}
histories[i].appendChild(line);
histories[i].scrollTop = histories[i].scrollHeight;
}
break;
// graph-message: Evokes redraw of graphics.
case "graph":
console.log("graph");
createCharts2(message.graph);
break;
// redraw.message: Communicates changes requiring reset of a whole group
case "redraw": // SHOULD BE TESTED
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// SPECIAL CASE: is message.title = "main possible? It should evoke
// redraw of client
// special meaning: s < 0: replace slides in all swiper instances
reqJSON(-1, "http://" + hostPort + "/getblock?path=" + message.path
+ "&id=" + clientID, successHandler, errorHandler);
break;
// graph-update-message:
case "graph-update":
//if (getUpdatesGraphics) {
//timeServer = message.time;
console.log("graph-update");
updateCharts2(message.graph);
//}
break;
// update-message: Communicates change of values.
case "update":
if (debugCommunication > 1) {
console.log(message);
}
updateValues(message, src);
break;
}
}
function htmlEscape(str) {
if (!str) return "";
return str.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/'/g,
'&#39;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
function resetTimer(src) {
// Executed every time a heartbeat-message is obtained.
// If no heartbeat-messages are obtained for a certain amount of time,
// an error-message is thrown.
clearTimeout(timeoutID);
timeoutID = setTimeout(function(src) {
console.log("timeout");
alertify.error("connection lost");
if (src) {
src.close();
}
}, 60000);
}
function updateValues(message, src) {
// Handles changes of parameter-values
for (var i = 0; i < message.updates.length; i++) {
var component = message.updates[i];
var value = component.value;
var matches = document.getElementsByName(component.name);
for (var j = 0; j < matches.length; j++) {
var type = matches[j].getAttribute("__ctype__");
if (type == "rdonly") {
var text = htmlEscape(value);
if (text) {
matches[j].innerHTML = text;
}
} else if (type == "input") {
var row = matches[j].parentNode.parentNode.parentNode;
row.style.backgroundColor = "white";
var oldValue = matches[j].getAttribute("oldValue")
|| matches[j].value;
if (value != matches[j].value && value != oldValue) {
if (matches[j] == document.activeElement
|| oldValue != matches[j].value) {
row.style.backgroundColor = "orange";
} else {
matches[j].value = value;
}
}
matches[j].setAttribute("actualValue", value);
resizeTextfield(matches[j]);
} else if (type == "checkbox") {
var row = matches[j].parentNode.parentNode;
row.style.backgroundColor = "white";
matches[j].checked = value == 1 && value == "1";
} else if (type == "enum") {
matches[j].style.display = "block";
var row = matches[j].parentNode.parentNode;
row.style.backgroundColor = "white";
matches[j].value = value;
}
}
}
}
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// XMLHttpRequest
function reqJSON(s, url, successHandler, errorHandler) {
var xhr = typeof XMLHttpRequest != 'undefined' ? new XMLHttpRequest()
: new ActiveXObject('Microsoft.XMLHTTP');
if (debugCommunication) {
console.log("%cto server (reqJSON): " + url,
"color:white;background:lightgreen");
}
xhr.open('get', url, true);
xhr.onreadystatechange = function() {
// console.log(xhr)
var status;
var data;
// https://xhr.spec.whatwg.org/#dom-xmlhttprequest-readystate
if (xhr.readyState == 4) { // `DONE`
status = xhr.status;
if (status == 200) {
data = JSON.parse(xhr.responseText);
successHandler && successHandler(s, data);
} else {
errorHandler && errorHandler(status);
}
}
};
xhr.send();
}
function successHandler(s, message) {
// Handles incoming XMLHttp-messages depending on type of message.
// s: slide number or -1 for replacing slide in all slider instances
if (debugCommunication) {
console.log("%cfrom server (reqJSON): " + message.type,
"color:white;background:dimgray", message);
}
switch (message.type) {
// Response to a "getblock"-server-request.
case "draw":
if (debugCommunication) {
console.log(message);
}
if (message.path == "main") {
// Happens only initially or at device change.
for (var sLocal = 0; sLocal < MAXBLOCK; sLocal++) {
insertSlide(sLocal, message.title, "main", createContent(
sLocal, message));
}
} else {
if (s < 0) { // redraw: check for slides in all swiper instances
for (var isw = 0; isw < MAXBLOCK; isw ++) {
var slide = findSlide(isw, message.path);
if (slide) {
console.log("redraw", isw);
replaceSlideContent(slide, message.title,
createContent(isw, message));
}
}
} else {
insertSlide(s, message.title, message.path, createContent(s,
message));
}
}
nextInitCommand();
// Request for updates.
if (getUpdates) {
reqJSON(s, "http://" + hostPort + "/updateblock?path="
+ message.path + "&id=" + clientID, successHandler,
errorHandler);
}
break;
// Response to a "update-block"-server-request.
case "accept-block":
break;
// Response to a "console"-server-request.
case "accept-console":
// draw console, only on the first and the last swiper
insertSlide(0, "console", "console",
createContentConsole(sLocal));
insertSlide(3, "console", "console",
createContentConsole(sLocal));
nextInitCommand();
// send empty command in order to trigger getting history
reqJSON(0, "http://" + hostPort + "/sendcommand?command=&id=" + clientID, successHandler,
errorHandler);
break;
// Response to a "gettime"-server-request.
case "time":
timeRange = message.time;
/*createGraphics();
// By default mostleft swiper-instance shows graphics.
swiper[0].slideTo(0);
// Update time-selection. (see also SEAWebClientGraphics.js)
var select = document.getElementsByClassName("select-time")[0];
begin = timeRange[0] - timeRange[1];
select.value = begin;
// Server-request for variable-list.*/
reqJSON(0, "http://" + hostPort + "/getvars?time=" + timeRange + "&id="
+ clientID, successHandler, errorHandler);
break;
// Response to a "getvars"-server-request.
case "var_list":
//blocks = message.blocks;
/*var varlist = [];
for (var i = 0; i < blocks.length; i++) {
for (var j = 0; j < blocks[i].curves.length; j++) {
varlist.push(blocks[i].curves[j].name);
}
}
// Update graphics
if (varlist.length > 0) {
reqJSON(0, "http://" + hostPort + "/graph?time=" + timeRange
+ "&variables=" + varlist + "&id=" + clientID,
successHandler, errorHandler);
} else {
nextInitCommand();
}*/
graphs.receivedVars(message.blocks);
nextInitCommand();
break;
// Response to a "graph"-server-request.
case "graph-draw":
// obsolete?
if (debugCommunication) {
console.log("graph-draw", message);
}
createCharts2(message.graph);
nextInitCommand();
// Request for updates.
reqJSON(s, "http://" + hostPort + "/updategraph?id=" + clientID,
successHandler, errorHandler);
break;
// Response to a "updategraph"-server-request.
case "accept-graph":
break;
case "error":
console.log("%cError-Message received!", "color:white;background:red");
console.log(message);
break;
default:
break;
}
}
function errorHandler(status) {
if (debugCommunication) {
console.log("error", status);
}
}

View File

@ -0,0 +1,67 @@
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// % CONSOLE
var commandHistory = []; // Stores commands executed by console.
var histIndex = -1; // Selected element of 'commandHistory'. (-1 = "")
function createContentConsole(s) {
// Creates input-textfield and texarea showing console-history.
var commandline = document.createElement('input');
commandline.setAttribute("type", "text");
commandline.setAttribute("class", "row commandline");
commandline.onkeydown = function (e) {
//console.log(histIndex);
if (e.which === 38 || e.key == "ArrowUp") {
if (histIndex + 1 < commandHistory.length) {
histIndex++;
this.value = commandHistory[histIndex];
}
var input = this;
window.setTimeout(
function () {
input.setSelectionRange(input.value.length,
input.value.length);
}, 0, input);
}
if (e.which === 40 || e.key == "ArrowDown") {
if (histIndex >= 0) {
histIndex--;
if (histIndex > -1) {
this.value = commandHistory[histIndex];
} else {
this.value = "";
}
}
}
};
commandline.setAttribute("autocomplete", "on");
var wrapper = document.createElement('form');
wrapper.setAttribute("class", "commandline-wrapper");
wrapper.onsubmit = function (e) {
e.preventDefault();
histIndex = -1;
// Request for command.
reqJSON(s, "http://" + hostPort + "/sendcommand?command="
+ commandline.value + "&id=" + clientID, successHandler,
errorHandler);
commandline.value = "";
};
wrapper.setAttribute("method", 'GET');
wrapper.appendChild(commandline);
var history = document.createElement('div');
history.setAttribute("class", "history");
var content = document.createElement('div');
content.setAttribute("class", "content-console");
content.appendChild(wrapper);
content.appendChild(history);
return content;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,31 @@
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// % GRAPHICS
/*
var swiperGraphics = []; // This array contains graphics-swiper-Instances.
var begin = -10; // Time to look back (in seconds).
var timeServer; // Every time a graph-update-mesage is received the
// server-timestamp is stored.
var timeRange; // Range of time to regard (unix-time in seconds).
var blocks; // array of graphic-blocks sorted by units. (as from var_list, but values added)
var MARGIN_TOP = 10;
var MARGIN_RIGHT = 10;
var MARGIN_BOTTOM = 20;
var MARGIN_LEFT = 60;
var width;
var height;
var margin;
var scaleX;
zoomSelection = false;
function createCharts(graph) {
createCharts2(graph);
return
}
function updateCharts(graph){
updateCharts2(graph)
}

View File

@ -0,0 +1,565 @@
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// % GROUP
var writePermissionTimeout; // Sets writePermission to 'false, restarts by
// user-interaction.
var prompt = false // True while a prompt is opened.
function getGroup(s, name) {
var found = false;
if (name == "") {
swiper[s].slideTo(defaultSlidePos(s));
return;
}
for (var i = 0; i < swiper[s].slides.length; i++) {
var slideType = swiper[s].slides[i].getAttribute("slide-type");
if (slideType == name) {
found = true;
swiper[s].slideTo(i);
}
}
if (!found && name != "console" && name != "graphics") {
// Server-request for group.
reqJSON(s, "http://" + hostPort + "/getblock?path=" + name
+ "&id=" + clientID, successHandler, errorHandler);
}
}
function sendCommand(s, command) {
reqJSON(s, "http://" + hostPort + "/sendcommand?command=" + command
+ "&id=" + clientID, successHandler, errorHandler);
}
function createContent(s, message) {
// Depending on the message received from the server the content of the
// group
// is created dynamically. Handles draw-message.
var content = document.createElement('div');
content.setAttribute("class", "content");
// Process components of the message
for (var i = 0; i < message.components.length; i++) {
var component = message.components[i];
var name = component.name;
var type = component.type;
var title = name;
if ("title" in component)
title = component.title;
var info = component.info;
switch (type) {
case "group":
content.appendChild(createLink(s, name, title));
break;
case "rdonly":
if ("link" in component) {
content.appendChild(createReadOnlyInstrLink(s, name, title,
component.link, info));
} else {
content.appendChild(createReadOnly(s, name, title, info));
}
break;
case "rdlink":
content.appendChild(createReadOnlyGroupLink(s, name, title, info));
break;
case "input":
content.appendChild(createInput(s, name, title,
info));
break;
case "checkbox":
content.appendChild(createCheckbox(s, name, title,
info));
break;
case "enum":
content.appendChild(createSelection(s, name, title,
component.enum_names, info));
break;
case "pushbutton":
console.log(component);
console.log(component.info);
content.appendChild(createPushButton(s, name, title,
info));
break;
default:
break;
}
}
return content;
}
function gotoGroups(slideNames) {
slideNames = slideNames.split("%20");
var l = Math.min(MAXBLOCK,slideNames.length);
document.title = "SEA "+ clientTitle + " " + slideNames.join(" ");
for (var s=0; s<l; s++) {
getGroup(s, slideNames[s]);
}
}
function createLink(s, name, title) {
// Creates row-element containing link.
var row = document.createElement('row');
row.setAttribute("id", name);
row.setAttribute("name", title);
row.setAttribute("class", "interactive row link");
row.setAttribute("tabindex", 0);
row.onclick = function () {
var slideNames = getSlideNames();
slideNames[s] = name;
document.title = "SEA "+ clientTitle + " " + slideNames.join(" ");
history.pushState({func: "gotoGroups", funarg: slideNames.join("%20")}, document.title, "#" + slideNames.join("%20"));
getGroup(s, name);
}
if (title === "console" || title === "device config") {
row.setAttribute("class", "interactive row link link-static");
row.innerHTML = "console";
}
row.innerHTML = title;
return row;
}
function createReadOnly(s, name, title, info) {
// Creates row-element containing read-only-item.
var left = createTitle(title, info);
var right = document.createElement('span');
right.setAttribute("class", "col-right");
right.setAttribute("name", name);
right.setAttribute("__ctype__", "rdonly");
return appendToContent(info, left, right);
}
function createReadOnlyGroupLink(s, name, title, info) {
// Creates row-element containing link AND read-only-item.
// for secop
var left = createTitle(title, info);
left.setAttribute("id", name);
left.setAttribute("name", title);
left.setAttribute("class", "interactive link");
left.onclick = function () {
getGroup(s, title);
}
var right = document.createElement('span');
right.setAttribute("class", "col-right");
right.setAttribute("name", name);
right.setAttribute("__ctype__", "rdonly");
return appendToContent(info, left, right);
}
function createReadOnlyInstrLink(s, name, title, link, info) {
// Creates row-element containing link AND read-only-item.
// var left = createTitle(title, info);
var left = document.createElement('a');
left.setAttribute("class", "col-left");
left.innerHTML = title;
left.setAttribute("id", name);
left.setAttribute("name", title);
left.setAttribute("class", "interactive link");
var right = document.createElement('span');
right.setAttribute("class", "col-right");
right.setAttribute("name", name);
right.setAttribute("__ctype__", "rdonly");
row = appendToContent(info, left, right);
row.onclick = function () {
this.style.backgroundColor = "orangered";
left.click();
}
if (link.charAt(0) == ':') {
left.href = "http://" + location.hostname + link + "/";
} else {
left.href = link;
}
row.setAttribute("class", "row clickable");
return row;
}
function createPushButton(s, name, title, info) {
// Creates row-element containing a push button
var left = createTitle(title, info);
console.log(info);
left.setAttribute("id", name);
left.setAttribute("name", title);
var right = document.createElement('span');
right.setAttribute("class", "col-right clickable push-button");
right.setAttribute("name", name);
right.setAttribute("__ctype__", "rdonly");
row = appendToContent(info, left, right);
right.onclick = function () {
if (writePermission) {
var row = left.parentNode;
right.style.backgroundColor = "orangered";
// Request for command
sendCommand(s, name);
} else {
prompt = true;
alertify.confirm("", "You are connected with <b>" + clientTitle
+ "</b>. <br>"
+ "Are you sure you want to modify things here?",
function () {
// User decided to proceed.
writePermission = true;
writePermissionTimeout = setTimeout(function () {
writePermission = false;
}, 3600000);
var row = left.parentNode;
row.style.backgroundColor = "orangered";
// Request for command
sendCommand(s, name);
prompt = false;
}, function () {
// User decided to cancel
prompt = false;
});
}
}
row.setAttribute("class", "row");
return row;
}
function createInput(s, name, title, info) {
// Creates row-element containing input-item.
if (info) {
var infoBox = createInfo(title, info);
}
var left = createTitle(title, info);
var input = document.createElement('input');
input.setAttribute("type", "text");
input.setAttribute("class", "input-text");
input.setAttribute("name", name);
input.setAttribute("__ctype__", "input");
input.style.width = "100px";
input.onkeydown = function (e) {
if (e.which === 27 || e.key == "Escape") {
// User decided to cancel
input.value = input.getAttribute("oldValue");
resizeTextfield(input);
var row = left.parentNode;
row.style.backgroundColor = "white";
}
}
input.onfocus = function () {
input.setAttribute("oldValue", input.value);
if (isTouchDevice())
setTimeout(function () {
posTextfield(s, left);
}, 1);
}
input.onblur = function () {
if (prompt) {
return false;
}
var row = left.parentNode;
var value = input.value;
var oldValue = input.getAttribute("oldValue") || value;
if (!input.hasAttribute("actualValue")) {
input.setAttribute("actualValue", oldValue);
}
var actualValue = input.getAttribute("actualValue");
if (value === actualValue || value === oldValue) {
input.value = actualValue;
// nothing to do.
row.style.backgroundColor = "white";
return false;
}
// User changed value and moved focus to other object.
alertify.confirm("", "You changed a field without pressing the return key.<br>"
+ "Hint: press ESC for leaving a field unchanged.<b>"
+ "You are connected with <b>" + clientTitle + "</b>.<br>"
+ "Are you sure you want to change the value of<br><b>"
+ name + "</b> from <b>" + actualValue
+ "</b> to <b>" + value + "</b>?", function () {
// User decided to proceed.
writePermission = true;
writePermissionTimeout = setTimeout(function () {
writePermission = false;
}, 3600000);
row.style.backgroundColor = "orangered";
// Request for command
sendCommand(s, name + " " + value);
resizeTextfield(input);
prompt = false;
}, function () {
// User decided to cancel
input.value = input.getAttribute("actualValue");
resizeTextfield(input);
row.style.backgroundColor = "white";
prompt = false;
});
}
var form = document.createElement('form');
form.onsubmit = function (e) {
e.preventDefault();
// remove following check: sometimes we want to send a command even with an unchanged value
//if (input.value === input.getAttribute("oldValue")) {
// // nothing to do.
// return false;
//}
if (writePermission) {
var row = left.parentNode;
row.style.backgroundColor = "orangered";
// Request for command
sendCommand(s, name + " " + input.value);
} else {
var value = input.value
prompt = true;
alertify.confirm("", "You are connected with <b>" + clientTitle
+ "</b>. <br>"
+ "Are you sure you want to modify things here?",
function () {
// User decided to proceed.
writePermission = true;
writePermissionTimeout = setTimeout(function () {
writePermission = false;
}, 3600000);
var row = left.parentNode;
row.style.backgroundColor = "orangered";
// Request for command
sendCommand(s, name + " " + value);
resizeTextfield(input);
prompt = false;
}, function () {
// User decided to cancel
input.value = input.getAttribute("oldValue");
resizeTextfield(input);
prompt = false;
});
}
};
form.appendChild(input);
var right = document.createElement('span');
right.setAttribute("class", "col-right");
right.appendChild(form);
return appendToContent(info, left, right);
}
function posTextfield(s, left) {
var content = swiper[s].slides[swiper[s].activeIndex].childNodes[1];
var row = left.parentNode;
content.scrollTop = row.offsetTop - 30;
}
function resizeTextfield(input) {
if (input.value.length > input.size * 12 / 20) {
var str0 = window.getComputedStyle(input).fontSize;
var str1 = str0.substring(0, str0.length - 2);
if (input.value.length < 43) {
input.style.width = input.value.length * str1 * 12 / 20 + "px";
}
} else {
input.style.width = "100px";
}
}
function createCheckbox(s, name, title, info) {
// Creates row-element containing checkbox-item
var left = createTitle(title, info);
var input = document.createElement('input');
input.setAttribute("type", "checkbox");
input.setAttribute("name", name);
input.setAttribute("__ctype__", "checkbox");
input.setAttribute("class", "parameter-checkbox");
input.onkeyup = function (e) {
if (e.keyCode === 32) {
handleCheckbox();
}
}
var label = document.createElement('label');
label.setAttribute("for", input);
label.setAttribute("class", "parameter-label");
label.onclick = function () {
handleCheckbox();
}
function handleCheckbox() {
if (writePermission) {
var row = left.parentNode;
row.style.backgroundColor = "orangered";
if (input.checked) {
var value = "0";
input.checked = false;
} else {
var value = "1";
input.checked = true;
}
// Request for command
sendCommand(s, name + " " + value);
} else {
alertify.confirm("", "You are connected with <b>" + clientTitle
+ "</b>. <br>"
+ "Are you sure you want to modify things here?",
function () {
// User decided to proceed.
writePermission = true;
writePermissionTimeout = setTimeout(function () {
writePermission = false;
}, 3600000);
var row = left.parentNode;
row.style.backgroundColor = "orangered";
if (input.checked) {
var value = "0";
input.checked = false;
} else {
var value = "1";
input.checked = true;
}
// Request for command
sendCommand(s, name + " " + value);
}, function () {
// User decided to cancel
});
}
};
var right = document.createElement('span');
right.setAttribute("class", "col-right");
right.appendChild(input);
right.appendChild(label);
return appendToContent(info, left, right);
}
function createSelection(s, name, title, buttons, info) {
// Creates row-element containing dropdown-selection.
var left = createTitle(title, info);
var select = document.createElement('select');
select.setAttribute("name", name);
select.setAttribute("__ctype__", "enum");
select.setAttribute("class", "select-params");
select.onfocus = function () {
select.setAttribute("oldIndex", select.selectedIndex);
}
select.oninput = function () {
if (writePermission && title != "device config") {
var row = left.parentNode;
row.style.backgroundColor = "orangered";
// Request for command
sendCommand(s, name + " " + this.value);
} else {
alertify.confirm("", "You are connected with <b>" + clientTitle
+ "</b>. <br>"
+ "Are you sure you want to modify things here?",
function () {
// User decided to proceed.
writePermission = true;
writePermissionTimeout = setTimeout(function () {
writePermission = false;
}, 3600000);
var row = left.parentNode;
row.style.backgroundColor = "orangered";
// Request for command
sendCommand(s, name + " " + select.value);
}, function () {
// User decided to cancel
select.value = select.options[select
.getAttribute("oldIndex")].value;
});
}
};
for (var i = 0; i < buttons.length; i++) {
var option = document.createElement('option');
option.setAttribute("type", "enum");
option.setAttribute("class", "option-params");
option.setAttribute("value", buttons[i].value);
option.appendChild(document.createTextNode(buttons[i].title));
select.add(option);
}
select.style.display = "none";
var right = document.createElement('span');
right.setAttribute("class", "col-right");
right.appendChild(select);
return appendToContent(info, left, right);
}
function createTitle(title, info) {
// Creates left side of row-tag containing title. Title may hold additional
// information, which is shown, when title-tag is clicked.
var left = document.createElement('span');
if (info) {
left.setAttribute("class", "col-left event-toggle-info");
left.onclick = function () {
var infoBox = left.parentNode.childNodes[0];
if (infoBox.style.display == "none") {
infoBox.style.display = "block";
} else {
infoBox.style.display = "none";
}
}
left.innerHTML = title + "<sup><b>(i)</b></sup>";
} else {
left.setAttribute("class", "col-left");
left.innerHTML = title;
}
return left;
}
function createInfo(info) {
// Creates info-box, which isn't visible by default but can be displayed.
var infoBox = document.createElement('div');
infoBox.setAttribute("class", "info-box");
infoBox.onclick = function () {
infoBox.style.display = "none";
}
infoBox.innerHTML = info;
return infoBox;
}
function appendToContent(info, left, right) {
// Cretees row-tag containing infoBox (not visible by default), left side
// (span)
// and right side (span).
var row = document.createElement('div');
row.setAttribute("class", "row");
if (info) {
row.appendChild(createInfo(info));
}
for (var i = 1; i < arguments.length; i++)
if (arguments[i]) {
row.appendChild(arguments[i]);
}
return row;
}

View File

@ -0,0 +1,198 @@
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// % INIT
var MAXBLOCK = 4; // max number of blocks
var elements = []; // grid elements
var swiper = []; // This array contains main-swiper-Instances.
var hostPort = ""; // Address and port of static html-file.
var clientID = ""; // ID given by server when SSE-connection is established.
var clientTitle = ""; // Contains name of instrument and device.
var getUpdates = true;
var getUpdatesGraphics = true;
var initCommands = [];
var loadingShown = true;
var writePermission = false;
var menuMode = false;
var panelOn = true;
var firstState = 0;
function Settings() {
// get key/value pairs from search part of the URL and fill into query
var qstr = location.search;
console.log(qstr);
if (qstr) {
var a = (qstr[0] === '?' ? qstr.substr(1) : qstr).split('&');
for (var i = 0; i < a.length; i++) {
var b = a[i].split('=');
key = decodeURIComponent(b[0]);
value = decodeURIComponent(b.slice(1).join("=").replace(/\+/g, '%20'));
this[key] = value;
}
}
this.treat = function (variable, shortcut, convert, defaultValue) {
// the third argument should be:
// None or omitted for a string
// to_bool for converting to boolean
// Number for converting to a number
if (shortcut in this) {
value = this[shortcut];
if (convert) {
value = convert(value);
}
} else {
value = defaultValue;
}
//console.log(variable, value);
window[variable] = value;
return this;
}
this.add_init = function (shortcut, command, defaultValue) {
if (shortcut in this) {
value = to_bool(this[shortcut]);
console.log(shortcut, value);
} else {
value = defaultValue;
console.log(shortcut, value);
}
if (value) {
initCommands.push(command);
}
return this;
}
}
function to_bool(string) {
// everything else than false, 0 or an empty string is considered as true
return !/^(false|FALSE|False|0|)$/.test(string);
}
// example: localhost:5000/SEAWebClient.html?hp=ldmzolliker:5000&dc=1
// hostPort given and debugCommunication switched on
new Settings()
.treat("debugCommunication", "dc", 0, 0) // 1: debug synchronous comm. 2: debug syn and asyn comm
.treat("debugGraphics", "dg", to_bool, false)
.treat("hostPort", "hp", 0, location.hostname + ":" + location.port)
.treat("showMain", "sm", to_bool, true)
.treat("showConsole", "sc", to_bool, true)
.treat("showOverview", "so", to_bool, true)
.treat("showGraphics", "sg", to_bool, true)
.treat("showAsync", "sa", to_bool, false)
function loadFirstBlocks() {
if (showMain) pushInitCommand("getblock?path=main&", "main")
if (showConsole) pushInitCommand("console?", "console")
if (nColumns == 1) { // probably mobile phone}
if (showGraphics) pushInitCommand("gettime?time=-1800,0&", "graphics")
if (showOverview) pushInitCommand("getblock?path=_overview&", "overview")
} else {
if (showOverview) pushInitCommand("getblock?path=_overview&", "overview")
if (showGraphics) pushInitCommand("gettime?time=-1800,0&", "graphics")
// last is shown first
}
}
function nextInitCommand() {
// do the next init request
if (initCommands.length > 0) {
next = initCommands.shift();
cmd = next[0]
text = next[1]
var loadingSpan = document.getElementsByClassName("loading-span")[0];
loadingSpan.innerHTML = loadingSpan.innerHTML + "<br>loading " + htmlEscape(text) + " ...";
reqJSON(0, "http://" + hostPort + "/" + cmd + "id=" + clientID, successHandler, errorHandler);
} else if (loadingShown) {
var loadingScreen = document.getElementsByClassName("loading-div")[0];
loadingScreen.style.display = "none";
loadingShown = false;
if (location.hash) { // there was a #hash part
var slideNames = location.hash.substr(1);
gotoGroups(slideNames);
}
console.log("loading finished");
}
}
function pushInitCommand(cmd, text) {
initCommands.push([cmd, text]);
}
window.onload = function() {
// Executed when loading of page is completed.
// Create grid-elements. (see also at
// 'SEAWebClientResponsivity.js')
elements = createGrid();
// Number of shown columns 'm' and rows 'n' is determined depending on
// available viewport-size.
determineViewportSize();
// Determine size of grid-elements depending on number of columns 'm' and
// rows 'n'
adjustGrid();
// Create swiper-instances.
for (var s = 0; s < MAXBLOCK; s++) {
swiper[s] = insertSwiper(s);
}
var homeButton = document.getElementById("home-icon");
homeButton.onclick = function () {
window.location = "http://" + location.hostname + ":8800/";
};
buildUpdateConnection();
if (location.hash) {
console.log("hash in url", location.hash);
initSlides = location.hash.substring(1);
} else {
initSlides = "";
}
// Initialisation will be continued, when SSE-connection is established
// and id-message is obtained.
// (see also at SEAWebClientCommunication.js)
addEventListener("popstate", function (e) {
if (e.state) {
if (loadingShown) {
if (initSlides != e.state.funarg) {
console.log("hash mismatch", initSlides, e.state.funarg);
initSlides = e.state.funarg;
}
} else {
console.log("popstate", e.state.func, e.state.funarg);
window[e.state.func](e.state.funarg);
}
} else {
document.title = "SEA "+ clientTitle;
for (var s=0; s<MAXBLOCK; s++) {
swiper[s].slideTo(defaultSlidePos(s));
}
}
})
};
function toggleHeader() {
// Show and hide box showing name of the current device ('see also
// SEAWebClient.html')
var main_panel = document.getElementById("main-panel");
panelOn = !panelOn;
if (panelOn) {
header.innerHTML = clientTitle
/* header.setAttribute("style", "width: auto;"); */
main_panel.setAttribute("style", "display: block;");
} else {
/* header.setAttribute("style", "width: 30px;"); */
main_panel.setAttribute("style", "display: none;");
}
return true;
}

View File

@ -0,0 +1,151 @@
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// % RESPONSIVITY
var nColumns = 1; // Viewport is subdivided in nColumns columns.
var nRows = 1; // Viewport is subdivided in nRows rows.
var gridCountGraphics = 2; // Number of displayed graphics-swipers.
var MINWIDTH = 400; // Minimal width of block.
var MINHEIGHT = 700; // Minimal height of block.
function createGrid() {
// Creates grid-elements. By default only the first one is shown
// and
// takes the whole viewport.
var elements = [];
for (var i = 0; i < 4; i++) {
var element = document.createElement('div');
element.setAttribute("class", "grid-element");
document.getElementById("center").appendChild(element);
elements.push(element);
}
return elements;
}
function determineViewportSize() {
// Number of columns 'nColumns' and rows 'nRows' is determined depending on available
// viewport-size.
var width = window.innerWidth || document.documentElement.clientWidth
|| document.body.clientWidth;
var height = window.innerHeight || document.documentElement.clientHeight
|| document.body.clientHeight;
nColumns = 1;
if (width > MINWIDTH * 1.8) {
nColumns = 2;
}
if (width > MINWIDTH * 2.5) {
nColumns = 3;
}
if (width > MINWIDTH * 3.5) {
nColumns = 4;
}
nRows = 1;
if (height > MINHEIGHT) {
nRows = 2;
}
if (menuMode) {
nRows = 1;
nColumns = 1;
}
}
function sizeChange() {
determineViewportSize();
adjustGrid();
}
function adjustGrid() {
// Determines size of grid-elements depending on number of columns 'nColumns' and
// rows 'nRows'
var width = window.innerWidth || document.documentElement.clientWidth
|| document.body.clientWidth;
var height = window.innerHeight || document.documentElement.clientHeight
|| document.body.clientHeight;
switch (nColumns) {
case 1:
if (menuMode) {
leftWidth = Math.min(100, MINWIDTH / width * 100);
style(0,leftWidth + "vw","100vh");
style(1); // hide
style(2); // hide
style(3); // hide
} else {
style(0,"100vw","100vh");
style(1); // hide
style(2); // hide
style(3); // hide
}
break;
case 2:
rightWidth = Math.min(50, MINWIDTH / width * 100);
leftWidth = 100 - rightWidth;
if (nRows == 1) {
style(0,leftWidth + "vw","100vh");
style(1,rightWidth + "vw","100vh");
style(2); // hide
style(3); // hide
} else {
style(0,leftWidth + "vw","100vh");
style(1,rightWidth + "vw","50vh");
style(2); // hide
style(3,rightWidth + "vw","50vh");
}
break;
case 3:
rightWidth = MINWIDTH / width * 100;
leftWidth = 100 - rightWidth;
if (nRows == 1) {
style(0,leftWidth + "vw","100vh");
style(1,rightWidth + "vw","100vh");
style(2); // hide
style(3); // hide
} else {
style(0,leftWidth + "vw","100vh");
style(1,rightWidth + "vw","50vh");
style(2); // hide
style(3,rightWidth + "vw","50vh");
}
break;
case 4:
rightWidth = MINWIDTH / width * 100;
leftWidth = 100 - 2 * rightWidth;
if (nRows == 1) {
style(0,leftWidth + "vw","100vh");
style(1,rightWidth + "vw","100vh");
style(2); // hide
style(3,rightWidth + "vw","100vh");
} else {
style(0,leftWidth + "vw","100vh");
style(1,rightWidth + "vw","50vh");
style(2,rightWidth + "vw","50vh");
style(3,(2 * rightWidth) + "vw","50vh");
}
break;
default:
break;
}
}
function style(s, width, height) {
if (width) {
elements[s].style.display = "inline-block";
elements[s].style.width = width;
} else {
elements[s].style.display = "none";
}
if (height) {
elements[s].style.height = height;
}
elements[s].style.float = "left";
}
function isTouchDevice() {
return !!('ontouchstart' in window)
|| !!('msmaxtouchpoints' in window.navigator);
};

View File

@ -0,0 +1,42 @@
var showSettings = false;
function toggleSettings() {
// Shows and hides settings.
console.log("toggle settings");
if (showSettings) {
document.getElementsByClassName("start-settings-checkboxes")[0].style.display = "none";
document.getElementsByClassName("start-settings-show-hide")[0].innerHTML = "show";
showSettings = false;
} else {
document.getElementsByClassName("start-settings-checkboxes")[0].style.display = "inline";
document.getElementsByClassName("start-settings-show-hide")[0].innerHTML = "hide";
showSettings = true;
}
}
function followLink(destination) {
// Build query string and load new page.
var checkboxes = document.getElementsByClassName("start-checkbox");
var query = "";
// Loop through settings-checkboxes.
for (var i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].checked != checkboxes[i].defaultChecked) {
if (query === "") {
query = "?";
} else {
query += "&";
}
query += checkboxes[i].name + "=";
if (checkboxes[i].checked) {
query += "1";
} else {
query += "0";
}
}
}
destination += query;
console.log(destination);
window.location = destination;
}

View File

@ -0,0 +1,174 @@
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// % SWIPER
function insertSwiper(s) {
// Create an empty swiper-instance and append the swiper-container to
// 'grid-element' s.
var container = document.createElement('div');
container.setAttribute("class", "swiper-container swiper-container-main");
elements[s].appendChild(container);
var swiperwrapper = document.createElement('div');
swiperwrapper.setAttribute("class", "swiper-wrapper swiper-wrapper-main");
swiperwrapper.setAttribute("s", s);
container.appendChild(swiperwrapper);
var paginationWrapper = document.createElement('div');
paginationWrapper.setAttribute("class", "swiper-pagination");
container.appendChild(paginationWrapper);
var buttonPrev = document.createElement("div");
buttonPrev.setAttribute("class", "swiper-button-prev swiper-button-black");
var buttonNext = document.createElement("div");
buttonNext.setAttribute("class", "swiper-button-next swiper-button-black");
var swiper = new Swiper(container, {
direction : 'horizontal',
pagination: {
el: paginationWrapper,
clickable: true
},
spaceBetween : 0,
navigation:{
prevEl: buttonPrev,
nextEl: buttonNext
}
});
//console.log(swiper);
if (!isTouchDevice()) {
// Add swiper-button.
swiper.params.noSwipingClass = "swiper-slide-main";
container.appendChild(buttonPrev);
container.appendChild(buttonNext);
}
return swiper;
}
function findSlide(s, type) {
var i;
for (i = 0; i < swiper[s].slides.length; i++) {
if (swiper[s].slides[i].getAttribute("slide-type") === type) {
return swiper[s].slides[i];
}
}
return null;
}
function replaceSlideContent(slide, title, content) {
titlewrapper = slide.childNodes[0].childNodes[0];
titlewrapper.innerHTML = title;
slide.replaceChild(content, slide.childNodes[1])
}
function insertSlide(s, title, type, content) {
// Inserts new group to instance s of Swiper.
var slide = findSlide(s, type);
if (slide) { // slide already exists
replaceSlideContent(slide, title, content);
return
}
var panel = document.createElement('div');
panel.setAttribute("class", "panel");
titlewrapper = document.createElement('span');
titlewrapper.innerHTML = title;
panel.appendChild(titlewrapper);
if (type == "_overview" || type == "main") {
//panel.appendChild(createHomeButton(s));
} else if (type != "graphics" && type != "_inst_select" && type != "console") {
panel.appendChild(createCloseButton(s));
}
/*if (type === "graphics") {
panel.appendChild(createUpdateButton(s));
}*/
slide = document.createElement('div');
slide.setAttribute("class", "swiper-slide swiper-slide-main");
// Store type so it can be found easiely later.
slide.setAttribute("slide-type", type);
slide.appendChild(panel);
slide.appendChild(content);
// Graphics-slide is put at mostleft position.
if (type == "graphics" || type == "_overview") {
// Remove old graphics-slide.
/* see above
if(swiper[0].slides[0].getAttribute("slide-type") === "graphics"){
swiper[0].removeSlide(0);
}
*/
swiper[s].prependSlide(slide);
swiper[s].slideTo(0);
} else if (type == "console") {
swiper[s].appendSlide(slide);
if (s === 3) {
// Slide mostright swiper-instance to last position (console)
swiper[3].slideNext();
}
} else {
swiper[s].appendSlide(slide);
if (swiper[s].slides.length > 1) {
var consoleslide = swiper[s].slides[swiper[s].slides.length - 2];
if (consoleslide.getAttribute["slide-type"] == "console") {
// shift Console-slide to mostright position.
swiper[s].removeSlide(swiper[s].slides.length - 2);
swiper[s].appendSlide(consoleslide);
// Slide to position of new slide
swiper[s].slideTo(swiper[s].slides.length - 2);
} else {
swiper[s].slideTo(swiper[s].slides.length - 1);
}
}
}
}
function createCloseButton(s) {
// Creates 'span'-element containing close-button.
var wrapper = document.createElement('span');
wrapper.onclick = function () {
swiper[s].removeSlide(swiper[s].activeIndex);
swiper[s].slidePrev();
};
var closeButton = '<svg class="interactive icon slide-close-icon" fill="#000000" height="24" viewBox="0 0 24 24" width="24"><path d="M19 6.41L17.6 5 12 10.6 6.4 5 5 6.4 10.6 12 5 17.6 6.4 19 12 13.4 17.6 19 19 17.6 13.4 12z"/><path d="M0 0h24v24H0z" fill="none"/></svg>';
wrapper.innerHTML = closeButton;
return wrapper;
}
function createUpdateButton(s){
// Creates 'span'-element containing update-button (Should be removed later!)
var button = document.createElement('span');
button.setAttribute("class","interactive toggle-updates-graphics")
button.onclick = function () {
getUpdatesGraphics = ! getUpdatesGraphics;
button.innerHTML = "updates = "+getUpdatesGraphics;
};
button.innerHTML = "updates: "+getUpdatesGraphics;
return button;
}
function defaultSlidePos(s) {
return s < 3 ? 0 : swiper[s].slides.length-1;
}
function getSlideNames() {
var names = []
for (var s=0; s<MAXBLOCK; s++) {
var sw = swiper[s];
var name = "";
if (sw.activeIndex != defaultSlidePos(s)) {
name = sw.slides[sw.activeIndex].getAttribute("slide-type");
}
names.push();
}
for (var s=MAXBLOCK-1; s>=0; s--) {
if (names[s] != "") break;
names.pop();
}
return names;
}

68
client/main.html Normal file
View File

@ -0,0 +1,68 @@
<html>
<body>
<a href="http://localhost:5000/console.html" target=console>console</a>
<a href="http://localhost:5000/group.html?path=/nv" target=group>group</a>
<button onclick="action.value='getblock?path=/nv&id=*';">?getblock</button>
<button onclick="action.value='updateblock?path=/nv&id=*';">?updateblock</button>
<button onclick="action.value='console?id=*';">?console</button>
<button onclick="action.value='gettime?time=-1800,0&id=*';">?gettime</button>
<button onclick="action.value='getvars?time=-1800,0&id=*';">?getvars</button>
<button onclick="action.value='graph?time=-1800,0&variables=tt.tm,lev&id=*';">?graph</button><br>
<input type=text value="console?id=*" size=120 id=action>
<button onclick='act();'>Send</button>
<div id=result>
</div><p>
<textarea rows=50 cols=132 id=t>
</textarea>
<script type="text/javascript">
var myid = 0
var result = document.getElementById("result")
var action = document.getElementById("action")
function getJSON(url, successHandler, errorHandler) {
var xhr = typeof XMLHttpRequest != 'undefined'
? new XMLHttpRequest()
: new ActiveXObject('Microsoft.XMLHTTP');
console.log("fired JSON request", url)
xhr.open('get', url, true);
xhr.onreadystatechange = function() {
var status;
var data;
// https://xhr.spec.whatwg.org/#dom-xmlhttprequest-readystate
if (xhr.readyState == 4) { // `DONE`
status = xhr.status;
if (status == 200) {
data = JSON.parse(xhr.responseText);
successHandler && successHandler(data);
} else {
errorHandler && errorHandler(status);
}
}
};
xhr.send();
};
function insert(link) {
action.value = link
}
function act() {
getJSON("http://localhost:5000/" + action.value.split("*").join(myid),
function(message) { result.innerHTML = JSON.stringify(message); },
function(status) { console.log(status); }
)
}
var evtSrc = new EventSource("http://localhost:5000/update");
evtSrc.onmessage = function(e) {
var message = JSON.parse(e.data);
if (message.type == "id") {
myid = message.id
}
t.value = t.value + e.data + "\n";
}
</script>
</body>
</html>

70
client/plotex.html Normal file
View File

@ -0,0 +1,70 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="externalFiles/mjs_plot_0_3_n.js"></script>
</head>
<!body>
<body onresize="draw_graphs()" onload="draw_graphs()">
<canvas id="democanvas" width="600" height="400"></canvas>
<script>
//make a graph object
time = [0,1,2,3,4,5];
pot = [2,4,3,4,null,1];
still = [9,8,7,6,5,4];
var pressure_graph = mjs_plot.new_graph("pressure_graph","democanvas");
//give it data
pressure_graph.set_data([[time,pot],[time,still]]);
pressure_graph.set_captions(['pot','still']);
//set up some graphics styling (optional)
pressure_graph.default_graphics_style.title = "Pressures";
pressure_graph.default_graphics_style.x_axis_title = "Hours";
pressure_graph.default_graphics_style.y_axis_title = "pressure mbar";
pressure_graph.default_graphics_style.color_bg = '#fff';
//plot the graph
pressure_graph.reset();
pressure_graph.mjs_plot();
tim = 5;
saved_time = 5;
live = true;
function addPoint() {
pot.push(pot[tim]+0.1);
still.push(still[tim]+0.1);
tim += 1;
time.push(tim);
if (pressure_graph.busy()) {
return;
}
if (live) {
if (saved_time > pressure_graph.graphics_style.x_auto_max) {
live = false;
console.log("live", live);
return;
}
if (tim > pressure_graph.graphics_style.x_auto_max) {
pressure_graph.graphics_style.x_scale_auto_max = false;
pressure_graph.graphics_style.x_manual_max = tim;
}
} else if (tim < pressure_graph.graphics_style.x_auto_max) {
live = true;
console.log("live", live);
}
saved_time = tim;
pressure_graph.set_data([[time,pot],[time,still]]);
pressure_graph.mjs_plot();
}
setInterval(addPoint, 1000);
function draw_graphs(){
pressure_graph.canvas.width = window.innerWidth - 20;
pressure_graph.canvas.height = window.innerHeight - 20;
//tell the graph to plot
pressure_graph.mjs_plot();
}
</script>
</body>
</html>

61
client/select.html Normal file
View File

@ -0,0 +1,61 @@
<html>
<body>
<table>
<tr><td>
<a href='http://samenv.psi.ch:8850/'>DMC</a>
</td><td>
<a href='http://samenv.psi.ch:8851/'>HRPT</a>
</td><td>
<a href='http://samenv.psi.ch:8852/'>ZEBRA</a>
</td><td>
<a href='http://samenv.psi.ch:8853/'>POLDI</a>
</td></tr><tr><td>
<a href='http://samenv.psi.ch:8854/'>FOCUS</a>
</td><td>
<a href='http://samenv.psi.ch:8855/'>TASP</a>
</td><td>
<a href='http://samenv.psi.ch:8856/'>RITA2</a>
</td><td>
<a href='http://samenv.psi.ch:8857/'>EIGER</a>
</td></tr><tr><td>
<a href='http://samenv.psi.ch:8854/'>SANS 1</a>
</td><td>
<a href='http://samenv.psi.ch:8855/'>SANS 2</a>
</td><td>
<a href='http://samenv.psi.ch:8856/'>AMOR</a>
</td><td>
<a href='http://samenv.psi.ch:8857/'>BOA</a>
</td></tr><tr><td>
<a href='http://samenv.psi.ch:8801/'>PREP1</a>
</td><td>
<a href='http://samenv.psi.ch:8802/'>PREP2</a>
</td><td>
<a href='http://samenv.psi.ch:8803/'>PREP3</a>
</td><td>
<a href='http://samenv.psi.ch:8804/'>PREP4</a>
</td></tr><tr><td>
<a href='http://samenv.psi.ch:8805/'>PREP5</a>
</td><td>
<a href='http://samenv.psi.ch:8806/'>PREP6</a>
</td><td>
<a href='http://samenv.psi.ch:8807/'>PREP7</a>
</td><td>
<a href='http://samenv.psi.ch:8808/'>PREP8</a>
</td></tr><tr><td>
<a href='http://samenv.psi.ch:8809/'>PREP9</a>
</td><td>
<a href='http://samenv.psi.ch:8800/'>PREP0</a>
</td></tr><tr><td>
<a href='http://samenv.psi.ch:8810/'>LAB0</a>
</td><td>
<a href='http://samenv.psi.ch:8811/'>LAB1</a>
</td><td>
<a href='http://samenv.psi.ch:8812/'>LAB2</a>
</td><td>
<a href='http://samenv.psi.ch:8813/'>LAB3</a>
</td></tr><tr><td>
<a href='http://samenv.psi.ch:8814/'>LAB4</a>
</td></tr>
</table>
</body>
</html>

84
client/touchtest.html Normal file
View File

@ -0,0 +1,84 @@
<html>
<head>
<meta name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style"
content="black-translucent" />
</head>
<body>
<canvas id=inp width='300' height='500' style="border:1px solid #000000;"></canvas>
<div id=out style="width: 300px;"></div>
<script>
var canvas=document.getElementById("inp");
var rect = canvas.getBoundingClientRect();
console.log(rect);
// Setup canvas and expose context via ctx variable
ctx=canvas.getContext("2d");
function strt(touch) {
return {i:touch.identifier,x:touch.pageX,y:touch.pageY}
}
function stre(event) {
if (event.touches) {
t = {};
for (var i=0; i<event.touches.length;i++) {
id=event.touches[i].identifier.toString();
t[id] = strt(event.touches[i]);
}
tc = [];
for (var i=0; i<event.changedTouches.length;i++) {
id=event.touches[i].identifier.toString();
t[id]['changed'] = 1;
}
for (var i=0; i<event.targetTouches.length;i++) {
id=event.touches[i].identifier.toString();
t[id]['target'] = 1;
}
}
return {type:event.type,x:event.pageX,y:event.pageY,t:t};
}
var styles=["rgba(0, 0, 200, 1)", "rgba(0, 255, 0, 1)", "rgba(255, 0, 0, 1)"]
canvas.addEventListener('touchstart', function(event) {
for (var i = 0; i < event.touches.length; i++) {
var touch = event.touches[i];
ctx.beginPath();
ctx.arc(touch.pageX-rect.left, touch.pageY-rect.top, 5, 0, 2*Math.PI, true);
ctx.lineWidth = 2.0;
ctx.strokeStyle = styles[i];
ctx.stroke();
}
}, false);
canvas.addEventListener('touchmove', function(event) {
document.getElementById("out").innerHTML = JSON.stringify(stre(event));
event.preventDefault();
for (var i = 0; i < event.touches.length; i++) {
var touch = event.touches[i];
ctx.beginPath();
ctx.arc(touch.pageX-rect.left, touch.pageY-rect.top, 1, 0, 2*Math.PI, true);
ctx.lineWidth = 2.0;
ctx.strokeStyle = styles[i];
ctx.stroke();
}
}, false);
canvas.addEventListener('touchend', function(event) {
for (var i = 0; i < event.changedTouches.length; i++) {
var touch = event.changedTouches[i];
ctx.beginPath();
ctx.arc(touch.pageX-rect.left, touch.pageY-rect.top, 50, 0, 2*Math.PI, true);
ctx.lineWidth = 2.0;
ctx.strokeStyle = styles[i];
ctx.stroke();
}
}, false);
canvas.addEventListener('click', function(event) {
console.log(event);
ctx.beginPath();
ctx.arc(event.clientX-rect.left, event.clientY - rect.top, 2, 0, 2*Math.PI, true);
ctx.lineWidth = 2.0;
ctx.strokeStyle = "rgba(0, 0, 200, 0.8)";
ctx.stroke();
}, false);
</script>
</body></html>

BIN
doc/Screen Shot sea.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

1
doc/blocks.tsv Normal file
View File

@ -0,0 +1 @@
1 2 3 4
Can't render this file because it contains an unexpected character in line 1 and column 36.

35
doc/graphics_todo.txt Normal file
View File

@ -0,0 +1,35 @@
Grafik:
- Einbindung in slider
ok, aber Responsivity fehlt noch
- updates funktionieren manchmal nicht (könnte auch am Server liegen)
- marker linie nicht genau synchronisiert
- Zoom-Rechteck funktioniert teilweise
- Zoom selbst muss noch implementiert werden
- Im Moment wird die Zeitachse erst gezeichnet, wenn der erste Update kommt
dies muss noch überdacht werden.
Zeitachse muss an zwei stellen im Code erzeugt werden (in Funktion auslagern).
- die Variable begin bedeutet aktuell:
a) die erste Zeitspanne (zurück)
b) der freie Platz (Zukunft)
dies muss in 2 Variablen aufgeteilt werden
(b eher als absolute Zeit)
- MAXBLOCKGRAPHICS (sowie auch MAXBLOCK) wieder einführen
höhen müssen noch berechnet werden (aktuell fix im css)
- im Moment sind Grafikslider auf (MAXBLOCKGRAPHICS = 1) gesetzt,
sollte aber mit mehreren funktionieren.
- y-domain: statt min/max quantile(?) verwenden
- D3: müssen kurven neu gezeichnet werden, oder kann man auch ansetzen?

41
doc/message_chain.txt Normal file
View File

@ -0,0 +1,41 @@
U id : if showMain : CHAIN getblock/main (accept-block, draw, redraw)
R draw: if main: if showConsole: CHAIN console (accept-console)
else: update slides in all swiper instances
R accept-console: if showGraphics: CHAIN gettime (time)
elif showOverviews: CHAIN getblock FINI
else FINI
R time: CHAIN getvars (var_list)
R var_list: CHAIN graph (graph-draw)
R graph-draw: FINI CHAIN updategraph
R accept-graph: pass
U redraw: CHAIN getblock (accept-block)
U update: updateValues
U graph: createCharts
U graph-update: updateCharts
U command: add to history / add to console
U reply: add to console
R accept-block: pass
R error: ERROR
1. getblock/main
2. console
3. gettime
console "/console?"
graph "/gettime?time=-10,0&"
overview "/getblock?path=_overview&"

201
doc/protocol.txt Normal file
View File

@ -0,0 +1,201 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
***** ServerSentEvents *****
The only constantly open connection:
/updates
response: <id-message> <update-message> <redraw-message> <console-update-message> <graph-update-message>
the id-message is got immediately, later a mix of all other types of messages may be received
*********************************************************************************************************************************
<id-message> = {
"type": "id",
"id":<id>,
"title": <title>
}
<update-message> = {
"type": "update",
"updates": [{"name": <name0>, "value": <value0>}, ...]
}
<redraw-message> = {
"type": "redraw",
"path": <path>
}
<console-update-message> = {
"type": "command" | "reply",
"origin": "self" | "other",
"lines": <line>
}
<graph-update-message> = {
"type": "graph-update",
"reduced": true/false,
"time": <server-time>,
"graph": {
"<name1>": [[<time>,<value>],[<time>,<value>]...
"<name2>": [[<time>,<value>],[<time>,<value>]...
...
}
}
<graph-redraw-message> = {
"type": "graph-redraw"
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
***** XMLHttp *****
All other connections are to be closed (getJSON):
*********************************************************************************************************************************
/getblock?path=<path>&id=<id>
response: <draw-message>
<draw-message> = {
"type": "draw",
"path": <path>,
"components": [<component0>, <component1>, ...]
}
*********************************************************************************************************************************
<component> = <input> | <rdonly> | <checkbox> | <radio-group>
<input> = {
"type": "input",
"name": <variable name>,
"title": <title>
<optional-attributes>
}
<rdonly> = {
"type": "rdonly",
"name": <variable name>,
"title": <title>
<optional-attributes>
}
<checkbox> = {
"type": "checkbox",
"name": <variable name>,
"title": <title>
<optional-attributes>
}
<radio-group> = {
"type": "radio",
"name": <variable name>,
"title": <title>,
"buttons": [{"value": <value0>, "title": <title0>} , ...],
<optional-attributes>
}
<optional-attributes> =
["info": <tool-tip-text> ,]
*********************************************************************************************************************************
/updateblock?path=<path>&id=<id>
response: <accept-block-message> (and from now on, update-messages (incl. initial updates) are sent)
<accept-block-message> = {
"type": "accept-block",
}
*********************************************************************************************************************************
/sendcommand?command=<command>&id=<id>
response: <accept-command-message>
<accept-command-message> = {
"type": "accept-command",
}
*********************************************************************************************************************************
/gettime?time=<start>,<end>&id=<id>
response: <time-message>
<time-message> = {
"type":"time",
"time": [<start>, <end>]
}
*********************************************************************************************************************************
/getvars?time=<time>&id=<id>
response: <varlist-message>
<varlist-message> = {
"type":"var_list",
"blocks": [
{
"tag":"K_2",
"unit": "K",
"curves": [
{
"name":<name1>,
"label":<label1>,
"color":<color1>
},
{
"name":<name2>,
...
} ...
]
},
{
"tag":"mbar",
"unit": "mbar",
"curves": ...
},
...
]
}
*********************************************************************************************************************************
/updategraph?id=<id>
response: <accept-graph-message>
<accept-graph-message> = = {
"type": "accept-graph"
}
*********************************************************************************************************************************
/graph?time=<start>,<end>&variables=<variable list>&id=<id>
response: <graph-draw-message>
<graph-draw-message> = = {
"type": "graph-draw",
"reduced": true/false,
"graph": {
"<name1>": [[<time>,<value>],[<time>,<value>]...
"<name2>": [[<time>,<value>],[<time>,<value>]...
...
}
*********************************************************************************************************************************
/console?id=<id>
response: <accept-console-message> (and from now on, console-updates-messages (incl. history) are sent)
<accept-console-message> = {
"type": "accept-console",
}

17
doc/urls for graphics.txt Normal file
View File

@ -0,0 +1,17 @@
user serverside events for all updates, from the first message
the client id can be retrieved
localhost:8000/update
get the actual data for the chart:
localhost:8000/graph?variables=tt,treg.set.reg&time=-1800,0&id=<client-id>
activate updates for chart:
localhost:8000/graphupdate?id=<client-id>
Start without main and blocks:
localhost:8000/?sg=1&sm=0&sc=0