Skip to content

Instantly share code, notes, and snippets.

@bmeredyk
Last active June 1, 2020 01:34
Show Gist options
  • Save bmeredyk/ed3ead7cbc313a448f9f5fa064b7f121 to your computer and use it in GitHub Desktop.
Save bmeredyk/ed3ead7cbc313a448f9f5fa064b7f121 to your computer and use it in GitHub Desktop.
Modified BitFocus Companion tablet.html to fit on iPad better
<!--
This modified version of Companion'stablet.html is designed so that the
layout of buttons remains consistent. In otherwords they won't wrap
throughing off the layout you specified when designing your deck.
Semi-Scaling Buttons:
-----------------------
The buttons will change their size a bit depending on your device's
resolution. It'll change between 72, 90px (iPad in landscape) and 100px
(higher res. tablets & desktops) buttons.
Note that for lower resolution mobile devices you will likely need to
hold it in landscape in order to see all of the buttons!
Previous/Next Page buttons
---------------------------
This version also includes Previous/Next buttons at the top of each
page to allow you to move through your pages without having to scroll.
(Any Page up/down button on the deck itself do not work!) If you've opted
to use the pages= querystring parameter to limit the pages the links will
take this into account (they don't just blindly add 1 to the current page#)
Optional Deck_Size (# buttons)
-------------------------------
Finally, an extra querystring parameter "deck_size" was added. This will
allow you to simulate the original 15 button steam deck (?deck_size=15)
or even the 6 button version (?deck_size=6) which could be useful to anyone
wanting to utilize their phone instead of a tablet. (Note that the buttons
will not enlarge themselves - they'll be set at 72px even if technically
they could be larger, I just don't feel like writing that many @media
queries)
-->
<!-- /*
* This file is part of the Companion project
* Copyright (c) 2018 Bitfocus AS
* Authors: William Viker <william@bitfocus.io>, Håkon Nessjøen <haakon@bitfocus.io>
*
* This program is free software.
* You should have received a copy of the MIT licence as well as the Bitfocus
* Individual Contributor License Agreement for companion along with
* this program.
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial activities involving the Companion software without
* disclosing the source code of your own applications.
*
*/ -->
<html>
<head>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0 , maximum-scale=1.0, user-scalable=0"
/>
<link rel="manifest" href="/manifest.json" />
<!-- PWA support -->
<meta name="theme-color" content="#000000" />
<!-- ios support -->
<link
rel="apple-touch-icon"
sizes="72x72"
href="/img/brand/icons-72-square.png"
/>
<link
rel="apple-touch-icon"
sizes="96x96"
href="/img/brand/icons-96-square.png"
/>
<link
rel="apple-touch-icon"
sizes="128x128"
href="/img/brand/icons-128-square.png"
/>
<link
rel="apple-touch-icon"
sizes="512x512"
href="/img/brand/icons-512-square.png"
/>
<style>
body {
margin: 0;
padding: 0;
background-color: black;
font-size: 2em;
font-family: helvetica;
}
h1 {
font-size: 30px;
padding-left: 30px;
padding-top: 30px;
}
.page-title {
color: rgb(255, 198, 0);
clear: both;
margin-top: 20px;
padding-bottom: 10px;
margin-bottom: 0px;
}
.page {
padding: 20px;
}
/* .page-bank-content {
float:left;
}
.page-bank-content canvas {
width: 72px;
margin: 10px;
height: 72px;
box-shadow: 0px 0px 25px #333;
border: 1px solid rgba(255,255,255,0.15);
} */
.page-bank-content {
/* float:left; */
flex-grow: 1;
}
@media screen and (max-width: 767px) {
/* ..This is basic media query for respective device.In to this media query CSS code cover the both view landscape and portrait view. */
}
@media screen and (min-width: 320px) and (max-width: 767px) and (orientation: landscape) {
/* ..This orientation media query. In to this orientation media query you can specify more about CSS code for landscape view. */
}
@media screen and (max-width: 1024px) {
/* This is basic media query for respective device.In to this media query CSS code cover the both view landscape and portrait view. */
.page-bank-content canvas {
width: 72px;
margin: 15px;
height: 72px;
box-shadow: 0px 0px 25px #333;
border: 1px solid rgba(255, 255, 255, 0.15);
}
}
@media screen and (min-width: 768px) and (max-width: 1024px) and (orientation: landscape) {
/* ..This orientation media query. In to this orientation media query you can specify more about CSS code for landscape view. */
.page-bank-content canvas {
width: 90px;
margin: 15px;
height: 90px;
box-shadow: 0px 0px 25px #333;
border: 1px solid rgba(255, 255, 255, 0.15);
}
}
@media screen and (min-width: 1024px) and (orientation: landscape) {
/* ..This orientation media query. In to this orientation media query you can specify more about CSS code for landscape view. */
.page-bank-content canvas {
width: 100px;
margin: 15px;
height: 100px;
box-shadow: 0px 0px 25px #333;
border: 1px solid rgba(255, 255, 255, 0.15);
}
}
.page-bank-content canvas {
/* width: 72px; */
margin: 15px;
/* height: 72px; */
box-shadow: 0px 0px 25px #333;
border: 1px solid rgba(255, 255, 255, 0.15);
}
.disable-dbl-tap-zoom {
touch-action: manipulation;
}
* {
touch-action: manipulation;
}
* {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
-o-user-select: none;
touch-action: pan-y;
touch-action: manipulation;
}
canvas {
image-rendering: optimizeSpeed; /* Older versions of FF */
image-rendering: -moz-crisp-edges; /* FF 6.0+ */
image-rendering: -webkit-optimize-contrast; /* Safari */
image-rendering: -o-crisp-edges; /* OS X & Windows Opera (12.02+) */
image-rendering: pixelated; /* Awesome future-browsers */
-ms-interpolation-mode: nearest-neighbor; /* IE */
}
.grid-container {
display: grid;
}
.grid-container-8 {
grid-template-columns: repeat(8, minmax(80px, 1fr));
}
.grid-container-3 {
align-items: flex-end;
grid-template-columns: repeat(3, 1fr);
}
a:link,
a:visited {
/*background-color: rgb(255,198,0);*/
color: rgb(255, 198, 0);
padding: 14px 25px;
text-align: center;
text-decoration: none;
display: inline-block;
box-shadow: 0px 0px 25px #333;
border: 1px solid rgba(255, 255, 255, 0.15);
}
a:hover,
a:active {
box-shadow: 0px 0px 25px #333;
border: 2px solid rgba(255, 255, 255, 0.15);
}
</style>
<title>Companion Tablet Surface</title>
</head>
<body class="disable-dbl-tap-zoom">
<script src="js/jquery/jquery.min.js"></script>
<script src="socket.io/socket.io.js"></script>
<script src="js/viewport.js"></script>
<script src="js/preview.js"></script>
<div id="pages"></div>
<script type="text/javascript">
document.addEventListener("gesturestart", function (e) {
e.preventDefault();
});
var socket = io("");
var config = {};
var cache = {};
var been_connected = false;
var pages = [];
var pageinfo = {};
function int2hex(number) {
var r = ("0" + ((number >> 16) & 0xff).toString("16")).substr(-2);
var g = ("0" + ((number >> 8) & 0xff).toString("16")).substr(-2);
var b = ("0" + (number & 0xff).toString("16")).substr(-2);
return "#" + r + g + b;
}
function parseQuery(queryString) {
var query = {};
var pairs = (queryString[0] === "?"
? queryString.substr(1)
: queryString
).split("&");
for (var i = 0; i < pairs.length; i++) {
var pair = pairs[i].split("=");
query[decodeURIComponent(pair[0])] = decodeURIComponent(
pair[1] || ""
);
}
return query;
}
function hex2int(hex) {
return parseInt(hex.substr(1), 16);
}
var query = parseQuery(window.location.search);
// Does querystring specify to only show certain pages?
if (query.pages !== undefined) {
var mypages = query.pages.split(/,+/).map(function (el) {
return parseInt(el);
});
if (mypages.length) {
pages = mypages;
}
}
function getDeckSettings() {
var query = parseQuery(window.location.search);
var deckSettings = {
//default 32 buttons
keeperButtons: Array.from({ length: 32 }, (v, k) => k + 1),
rowStartingButtons: [1, 9, 17, 25],
};
if (query.deck_size !== undefined) {
if (query.deck_size == 15) {
//only 15 buttons of original stream deck
deckSettings.keeperButtons = [
1,
2,
3,
4,
5,
9,
10,
11,
12,
13,
17,
18,
19,
20,
21,
];
deckSettings.rowStartingButtons = [1, 9, 17];
} else if (query.deck_size == 6) {
//only 6 buttons
deckSettings.keeperButtons = [1, 2, 3, 9, 10, 11];
deckSettings.rowStartingButtons = [1, 9];
}
}
return deckSettings;
}
var deckSettings = getDeckSettings();
// console.log('keeperButtons='+deckSettings.keeperButtons);
// console.log('rowStartingButtons='+deckSettings.rowStartingButtons);
function hasPage(thispage) {
thispage = parseInt(thispage);
if (pages.length == 0 || pages.indexOf(thispage) !== -1) {
return true;
}
return false;
}
if (pages.length == 0) {
for (var page = 1; page <= 99; page++) {
pages.push(page);
}
}
var $bs = $("#pages");
pages.forEach(function (page) {
var pageIndex = pages.indexOf(page);
// console.log('Page '+pageIndex+' of '+pages.length)
if (pageIndex == 0) {
//first page, no prev button necessary
var $page = $(
"<div class='page'><div class=' grid grid-container grid-container-3'><div><h1 class='page-title' id='page_title_" +
page +
"'>Page " +
page +
"</h1></div><div>&nbsp;</div><div><a href='#page_" +
pages[pageIndex + 1] +
"'>Next ></a></div></div>"
);
} else if (pageIndex + 1 == pages.length) {
//last page, no next button necessary
var $page = $(
"<div class='page'><div class=' grid grid-container grid-container-3'><div><h1 class='page-title' id='page_title_" +
page +
"'>Page " +
page +
"</h1></div><div><a href='#page_" +
pages[pageIndex - 1] +
"'>< Previous</a></div><div>&nbsp;</div></div>"
);
} else {
var $page = $(
"<div class='page'><div class=' grid grid-container grid-container-3'><div><h1 class='page-title' id='page_title_" +
page +
"'>Page " +
page +
"</h1></div><div><a href='#page_" +
pages[pageIndex - 1] +
"'>< Previous</a></div><div><a href='#page_" +
pages[pageIndex + 1] +
"'>Next ></a></div></div>"
);
}
var rowStartingButtons = [1, 9, 17, 25];
for (var bank = 1; bank <= 32; bank++) {
if (deckSettings.keeperButtons.includes(bank)) {
// console.log('Bank '+bank)
if (deckSettings.rowStartingButtons.includes(bank)) {
if (bank > 1) {
$page.append($buttonRow);
}
// console.log('row break');
var $buttonRow = $(
"<div width='100%' id='row_" +
page +
"_" +
bank +
"' class='grid grid-container grid-container-8'></div>"
);
}
var $pageBank = $(
"<div class=' page-bank-content' id='bank_" +
page +
"_" +
bank +
"'><canvas class='canvases' width=72 height=72 id='c" +
page +
"_" +
bank +
"'></canvas></div>"
);
$buttonRow.append($pageBank);
}
}
// console.log('End of page')
$page.append($buttonRow); //finish final div
$page.attr("pageid", page);
$page.attr("id", "page_" + page);
$bs.append($page);
});
socket.on("set_page", function (page, value) {
pageinfo[page] = value;
// var $h1 = $bs.find('.page[pageid="' + page + '"] > h1');
var $h1 = $bs.find("#page_title_" + page);
if ($h1.length) {
if (value.name != "PAGE") {
$h1.html(value.name);
} else {
$h1.html("Page " + page);
}
}
});
socket.on("pages", function (_pageinfo) {
pageinfo = _pageinfo;
for (var page in pageinfo) {
// var $h1 = $bs.find('.page[pageid="' + page + '"] > h1');
var $h1 = $bs.find("#page_title_" + page);
if ($h1.length) {
if (pageinfo[page].name != "PAGE") {
$h1.html(pageinfo[page].name);
} else {
$h1.html("Page " + page);
}
}
}
});
var lastdown;
var touchdevice = false;
window.addEventListener(
"touchstart",
function onFirstTouch() {
touchdevice = true;
$("body").on("touchstart", ".canvases", function () {
lastdown = $(this).parent().attr("id").split(/_/);
if (lastdown[0] === "bank") {
socket.emit("hot_press", lastdown[1], lastdown[2], true);
}
});
$("body").on("touchend", ".canvases", function () {
if (lastdown !== undefined && lastdown[0] === "bank") {
socket.emit("hot_press", lastdown[1], lastdown[2], false);
}
});
window.removeEventListener("touchstart", onFirstTouch, false);
},
false
);
$("body").on("mousedown", ".canvases", function () {
if (!touchdevice) {
lastdown = $(this).parent().attr("id").split(/_/);
if (lastdown[0] === "bank") {
socket.emit("hot_press", lastdown[1], lastdown[2], true);
}
}
});
$("body").on("mouseup", ".canvases", function () {
if (!touchdevice) {
if (lastdown !== undefined && lastdown[0] === "bank") {
socket.emit("hot_press", lastdown[1], lastdown[2], false);
}
}
});
function drawBank(page, bank, data) {
if (!hasPage(page)) {
console.log("Not showing page " + page);
return;
}
var deckSettings = getDeckSettings();
if (deckSettings.keeperButtons.includes(parseInt(bank))) {
// console.log('#c' + page + '_' + bank);
var canvas = $("#c" + page + "_" + bank).get(0);
if (canvas) {
var ctx = canvas.getContext("2d");
ctx.webkitImageSmoothingEnabled = false;
var imageData = dataToButtonImage(data.buffer);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.putImageData(imageData, 0, 0);
ctx.drawImage(canvas, 0, 0, canvas.width, canvas.height);
}
}
}
$(window).on("scroll", scroll);
// Lazy load pages
function scroll() {
// Not ready
if (cache[pages[0]] === undefined) {
return;
}
$(".page")
.isInViewport({ tolerance: window.innerHeight / 2 })
.each(function () {
var page = $(this).attr("pageid");
if (cache[page][1] !== undefined || cache[page].wait == true) {
return;
}
var cachedata = {};
for (var _bank = 1; _bank <= 12; ++_bank) {
if (cache[page][_bank] !== undefined) {
cachedata[_bank] = cache[page][_bank].updated;
}
}
socket.emit("web_buttons_page", page, cachedata);
cache[page].wait = true;
});
}
socket.on("connect", function () {
if (been_connected === true) {
window.location.reload(true);
}
been_connected = true;
socket.on("buttons_page_data", function (page, data) {
if (!hasPage(page)) {
return;
}
cache[page].wait = false;
for (var key in data) {
cache[page][key] = data[key];
drawBank(page, key, data[key]);
}
});
socket.on("buttons_bank_data", function (page, data) {
if (!hasPage(page)) {
return;
}
for (key in data) {
drawBank(page, key, data[key]);
}
});
socket.emit("web_buttons");
for (var i = 1; i < 100; ++i) {
cache[i] = {};
}
// Request first page
socket.emit("web_buttons_page", pages[0], {});
// Check what is visible
scroll();
});
</script>
</body>
</html>
<!-- /*
* This file is part of the Companion project
* Copyright (c) 2018 Bitfocus AS
* Authors: William Viker <william@bitfocus.io>, Håkon Nessjøen <haakon@bitfocus.io>
*
* This program is free software.
* You should have received a copy of the MIT licence as well as the Bitfocus
* Individual Contributor License Agreement for companion along with
* this program.
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial activities involving the Companion software without
* disclosing the source code of your own applications.
*
*/ -->
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0 , maximum-scale=1.0, user-scalable=0">
<link rel="manifest" href="/manifest.json">
<!-- PWA support -->
<meta name="theme-color" content="#000000"/>
<!-- ios support -->
<link rel="apple-touch-icon" sizes="72x72" href="/img/brand/icons-72-square.png">
<link rel="apple-touch-icon" sizes="96x96" href="/img/brand/icons-96-square.png">
<link rel="apple-touch-icon" sizes="128x128" href="/img/brand/icons-128-square.png">
<link rel="apple-touch-icon" sizes="512x512" href="/img/brand/icons-512-square.png">
<style>
body {
margin: 0;
padding: 0;
background-color: black;
font-size: 2em;
font-family: helvetica;
}
h1 {
font-size: 30px;
padding-left: 30px;
padding-top: 30px;
}
.page-title {
color: rgb(255,198,0);
clear:both;
margin-top: 20px;
padding-bottom: 10px;
margin-bottom: 0px;
}
.page {
padding: 20px;
}
.page-bank-content {
float:left;
}
.page-bank-content canvas {
width: 72px;
margin: 15px;
height: 72px;
box-shadow: 0px 0px 50px #333;
border: 1px solid rgba(255,255,255,0.15);
}
.disable-dbl-tap-zoom {
touch-action: manipulation;
}
*{
touch-action: manipulation;
}
* {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select:none;
user-select:none;
-o-user-select:none;
touch-action: pan-y;
touch-action: manipulation;
}
canvas {
image-rendering: optimizeSpeed; /* Older versions of FF */
image-rendering: -moz-crisp-edges; /* FF 6.0+ */
image-rendering: -webkit-optimize-contrast; /* Safari */
image-rendering: -o-crisp-edges; /* OS X & Windows Opera (12.02+) */
image-rendering: pixelated; /* Awesome future-browsers */
-ms-interpolation-mode: nearest-neighbor; /* IE */
}
/* Addition to help form rows of buttons, borrowed form main Companion Admin button management screen */
.row {
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
margin-right: -15px;
margin-left: -15px;
}
</style>
<title>Companion Tablet Surface</title>
</head>
<body class="disable-dbl-tap-zoom">
<script src="js/jquery/jquery.min.js"></script>
<script src="socket.io/socket.io.js"></script>
<script src="js/viewport.js"></script>
<script src="js/preview.js"></script>
<div id="pages"></div>
<script type="text/javascript">
document.addEventListener('gesturestart', function (e) {
e.preventDefault();
});
var socket = io();
var config = {};
var cache = {};
var been_connected = false;
var pages = [];
var pageinfo = {};
function int2hex(number) {
var r = ('0' + ((number >> 16) & 0xff).toString('16')).substr(-2);
var g = ('0' + ((number >> 8) & 0xff).toString('16')).substr(-2);
var b = ('0' + (number & 0xff).toString('16')).substr(-2);
return '#' + r + g + b;
}
function parseQuery(queryString) {
var query = {};
var pairs = (queryString[0] === '?' ? queryString.substr(1) : queryString).split('&');
for (var i = 0; i < pairs.length; i++) {
var pair = pairs[i].split('=');
query[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || '');
}
return query;
}
function hex2int(hex) {
return parseInt(hex.substr(1), 16);
}
var query = parseQuery(window.location.search);
if (query.pages !== undefined) {
var mypages = query.pages.split(/,+/).map(function (el) {return parseInt(el);});
if (mypages.length) {
pages = mypages;
}
}
function hasPage(thispage) {
thispage = parseInt(thispage);
if (pages.length == 0 || pages.indexOf(thispage) !== -1) {
return true;
}
return false;
}
if (pages.length == 0) {
for (var page = 1; page <= 99; page++) {
pages.push(page);
}
}
var $bs = $("#pages");
//Begin modifications
pages.forEach(function (page) {
var $page = $("<div class='page'><h1 class='page-title'>Page "+page+"</h1></div>");
var firstBankButtons = [1,9,17,25];
for (var bank = 1; bank <= 32; bank++) {
//console.log('Bank '+bank)
if(firstBankButtons.includes(bank)){
if(bank > 1){
$page.append($buttonRow);
}
//console.log('row break');
var $buttonRow = $("<div width='100%' id='row_"+page+"_"+bank+"' class='row'></div>");
}
var $pageBank = $("<div class='page-bank-content' id='bank_"+page+"_"+bank+"'><canvas class='canvases' width=72 height=72 id='c"+page+"_"+bank+"'></canvas></div>");
$buttonRow.append($pageBank);
}
//console.log('End of page')
$page.append($buttonRow)//finish final div
$page.attr('pageid', page);
$bs.append($page);
});
//End modifications
socket.on('set_page', function (page, value) {
pageinfo[page] = value;
var $h1 = $bs.find('.page[pageid="' + page + '"] > h1');
if ($h1.length) {
if (value.name != 'PAGE') {
$h1.html(value.name);
} else {
$h1.html('Page ' + page);
}
}
});
socket.on('pages', function (_pageinfo) {
pageinfo = _pageinfo;
for (var page in pageinfo) {
var $h1 = $bs.find('.page[pageid="' + page + '"] > h1');
if ($h1.length) {
if (pageinfo[page].name != 'PAGE') {
$h1.html(pageinfo[page].name);
} else {
$h1.html('Page ' + page);
}
}
}
});
var lastdown;
var touchdevice = false;
window.addEventListener('touchstart', function onFirstTouch() {
touchdevice = true;
$("body").on('touchstart', '.canvases', function() {
lastdown = $(this).parent().attr('id').split(/_/);
if (lastdown[0] === 'bank') {
socket.emit('hot_press', lastdown[1], lastdown[2], true);
}
});
$("body").on('touchend', '.canvases', function() {
if (lastdown !== undefined && lastdown[0] === 'bank') {
socket.emit('hot_press', lastdown[1], lastdown[2], false);
}
});
window.removeEventListener('touchstart', onFirstTouch, false);
}, false);
$("body").on('mousedown', '.canvases', function() {
if (!touchdevice) {
lastdown = $(this).parent().attr('id').split(/_/);
if (lastdown[0] === 'bank') {
socket.emit('hot_press', lastdown[1], lastdown[2], true);
}
}
});
$("body").on('mouseup', '.canvases', function() {
if (!touchdevice) {
if (lastdown !== undefined && lastdown[0] === 'bank') {
socket.emit('hot_press', lastdown[1], lastdown[2], false);
}
}
});
function drawBank(page, bank, data) {
if (!hasPage(page)) {
return;
}
var canvas = $('#c' + page + '_' + bank).get(0);
var ctx = canvas.getContext('2d');
ctx.webkitImageSmoothingEnabled = false;
var imageData = dataToButtonImage(data.buffer);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.putImageData(imageData, 0, 0);
ctx.drawImage(canvas, 0, 0, canvas.width, canvas.height);
}
$(window).on('scroll', scroll);
// Lazy load pages
function scroll() {
// Not ready
if (cache[pages[0]] === undefined) {
return;
}
$('.page').isInViewport({ tolerance: window.innerHeight/2 }).each(function () {
var page = $(this).attr('pageid');
if (cache[page][1] !== undefined || cache[page].wait == true) {
return;
}
var cachedata = {};
for (var _bank = 1; _bank <= 12; ++_bank) {
if (cache[page][_bank] !== undefined) {
cachedata[_bank] = cache[page][_bank].updated;
}
}
socket.emit('web_buttons_page', page, cachedata);
cache[page].wait = true;
});
}
socket.on('connect', function () {
if (been_connected === true) {
window.location.reload(true);
}
been_connected = true;
socket.on('buttons_page_data', function(page, data) {
if (!hasPage(page)) {
return;
}
cache[page].wait = false;
for (var key in data) {
cache[page][key] = data[key];
drawBank(page, key, data[key]);
}
});
socket.on('buttons_bank_data', function(page, data) {
if (!hasPage(page)) {
return;
}
for (key in data) {
drawBank(page, key, data[key]);
}
});
socket.emit('web_buttons');
for (var i = 1; i < 100; ++i) {
cache[i] = {};
}
// Request first page
socket.emit('web_buttons_page', pages[0], {});
// Check what is visible
scroll();
});
</script>
</body>
</html>
<!--Modified version of BitFocus Companion's tablet.html that will only show 15 buttons like the original Stream Deck.
It uses buttons 1-5, 9-13 & 17-21 (the same ones outlined in grey on the Button Layout tab of Companions Admin UI.
-->
<!-- /*
* This file is part of the Companion project
* Copyright (c) 2018 Bitfocus AS
* Authors: William Viker <william@bitfocus.io>, Håkon Nessjøen <haakon@bitfocus.io>
*
* This program is free software.
* You should have received a copy of the MIT licence as well as the Bitfocus
* Individual Contributor License Agreement for companion along with
* this program.
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial activities involving the Companion software without
* disclosing the source code of your own applications.
*
*/ -->
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0 , maximum-scale=1.0, user-scalable=0">
<link rel="manifest" href="/manifest.json">
<!-- PWA support -->
<meta name="theme-color" content="#000000"/>
<!-- ios support -->
<link rel="apple-touch-icon" sizes="72x72" href="/img/brand/icons-72-square.png">
<link rel="apple-touch-icon" sizes="96x96" href="/img/brand/icons-96-square.png">
<link rel="apple-touch-icon" sizes="128x128" href="/img/brand/icons-128-square.png">
<link rel="apple-touch-icon" sizes="512x512" href="/img/brand/icons-512-square.png">
<style>
body {
margin: 0;
padding: 0;
background-color: black;
font-size: 2em;
font-family: helvetica;
}
h1 {
font-size: 30px;
padding-left: 30px;
padding-top: 30px;
}
.page-title {
color: rgb(255,198,0);
clear:both;
margin-top: 20px;
padding-bottom: 10px;
margin-bottom: 0px;
}
.page {
padding: 20px;
}
.page-bank-content {
float:left;
}
.page-bank-content canvas {
width: 72px;
margin: 15px;
height: 72px;
box-shadow: 0px 0px 50px #333;
border: 1px solid rgba(255,255,255,0.15);
}
.disable-dbl-tap-zoom {
touch-action: manipulation;
}
*{
touch-action: manipulation;
}
* {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select:none;
user-select:none;
-o-user-select:none;
touch-action: pan-y;
touch-action: manipulation;
}
canvas {
image-rendering: optimizeSpeed; /* Older versions of FF */
image-rendering: -moz-crisp-edges; /* FF 6.0+ */
image-rendering: -webkit-optimize-contrast; /* Safari */
image-rendering: -o-crisp-edges; /* OS X & Windows Opera (12.02+) */
image-rendering: pixelated; /* Awesome future-browsers */
-ms-interpolation-mode: nearest-neighbor; /* IE */
}
/* Addition to help form rows of buttons, borrowed form main Companion Admin button management screen */
.row {
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
margin-right: -15px;
margin-left: -15px;
}
</style>
<title>Companion Tablet Surface</title>
</head>
<body class="disable-dbl-tap-zoom">
<script src="js/jquery/jquery.min.js"></script>
<script src="socket.io/socket.io.js"></script>
<script src="js/viewport.js"></script>
<script src="js/preview.js"></script>
<div id="pages"></div>
<script type="text/javascript">
document.addEventListener('gesturestart', function (e) {
e.preventDefault();
});
var socket = io();
var config = {};
var cache = {};
var been_connected = false;
var pages = [];
var pageinfo = {};
function int2hex(number) {
var r = ('0' + ((number >> 16) & 0xff).toString('16')).substr(-2);
var g = ('0' + ((number >> 8) & 0xff).toString('16')).substr(-2);
var b = ('0' + (number & 0xff).toString('16')).substr(-2);
return '#' + r + g + b;
}
function parseQuery(queryString) {
var query = {};
var pairs = (queryString[0] === '?' ? queryString.substr(1) : queryString).split('&');
for (var i = 0; i < pairs.length; i++) {
var pair = pairs[i].split('=');
query[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || '');
}
return query;
}
function hex2int(hex) {
return parseInt(hex.substr(1), 16);
}
var query = parseQuery(window.location.search);
if (query.pages !== undefined) {
var mypages = query.pages.split(/,+/).map(function (el) {return parseInt(el);});
if (mypages.length) {
pages = mypages;
}
}
function hasPage(thispage) {
thispage = parseInt(thispage);
if (pages.length == 0 || pages.indexOf(thispage) !== -1) {
return true;
}
return false;
}
if (pages.length == 0) {
for (var page = 1; page <= 99; page++) {
pages.push(page);
}
}
var $bs = $("#pages");
//Begin modifications
pages.forEach(function (page) {
var $page = $("<div class='page'><h1 class='page-title'>Page "+page+"</h1></div>");
var firstBankButtons = [1,9,17,25];
var skipButtons = [6,7,8,14,15,16,22,23,24,25,26,27,28,29,30,31,32]
for (var bank = 1; bank <= 32; bank++) {
if(!skipButtons.includes(bank)){
console.log('Bank '+bank)
if(firstBankButtons.includes(bank)){
if(bank > 1){
$page.append($buttonRow);
}
console.log('row break');
var $buttonRow = $("<div width='100%' id='row_"+page+"_"+bank+"' class='row'></div>");
}
var $pageBank = $("<div class='page-bank-content' id='bank_"+page+"_"+bank+"'><canvas class='canvases' width=72 height=72 id='c"+page+"_"+bank+"'></canvas></div>");
$buttonRow.append($pageBank);
}
}
console.log('End of page')
$page.append($buttonRow)//finish final div
$page.attr('pageid', page);
$bs.append($page);
});
//End modifications
socket.on('set_page', function (page, value) {
pageinfo[page] = value;
var $h1 = $bs.find('.page[pageid="' + page + '"] > h1');
if ($h1.length) {
if (value.name != 'PAGE') {
$h1.html(value.name);
} else {
$h1.html('Page ' + page);
}
}
});
socket.on('pages', function (_pageinfo) {
pageinfo = _pageinfo;
for (var page in pageinfo) {
var $h1 = $bs.find('.page[pageid="' + page + '"] > h1');
if ($h1.length) {
if (pageinfo[page].name != 'PAGE') {
$h1.html(pageinfo[page].name);
} else {
$h1.html('Page ' + page);
}
}
}
});
var lastdown;
var touchdevice = false;
window.addEventListener('touchstart', function onFirstTouch() {
touchdevice = true;
$("body").on('touchstart', '.canvases', function() {
lastdown = $(this).parent().attr('id').split(/_/);
if (lastdown[0] === 'bank') {
socket.emit('hot_press', lastdown[1], lastdown[2], true);
}
});
$("body").on('touchend', '.canvases', function() {
if (lastdown !== undefined && lastdown[0] === 'bank') {
socket.emit('hot_press', lastdown[1], lastdown[2], false);
}
});
window.removeEventListener('touchstart', onFirstTouch, false);
}, false);
$("body").on('mousedown', '.canvases', function() {
if (!touchdevice) {
lastdown = $(this).parent().attr('id').split(/_/);
if (lastdown[0] === 'bank') {
socket.emit('hot_press', lastdown[1], lastdown[2], true);
}
}
});
$("body").on('mouseup', '.canvases', function() {
if (!touchdevice) {
if (lastdown !== undefined && lastdown[0] === 'bank') {
socket.emit('hot_press', lastdown[1], lastdown[2], false);
}
}
});
function drawBank(page, bank, data) {
if (!hasPage(page)) {
return;
}
//buttons to skip when only doing 15 button of original SD
var skipButtons = [6,7,8,14,15,16,22,23,24,25,26,27,28,29,30,31,32];
if(!skipButtons.includes(bank)){
console.log('#c' + page + '_' + bank);
var canvas = $('#c' + page + '_' + bank).get(0);
if(canvas){
var ctx = canvas.getContext('2d');
ctx.webkitImageSmoothingEnabled = false;
var imageData = dataToButtonImage(data.buffer);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.putImageData(imageData, 0, 0);
ctx.drawImage(canvas, 0, 0, canvas.width, canvas.height);
}
}
}
$(window).on('scroll', scroll);
// Lazy load pages
function scroll() {
// Not ready
if (cache[pages[0]] === undefined) {
return;
}
$('.page').isInViewport({ tolerance: window.innerHeight/2 }).each(function () {
var page = $(this).attr('pageid');
if (cache[page][1] !== undefined || cache[page].wait == true) {
return;
}
var cachedata = {};
for (var _bank = 1; _bank <= 12; ++_bank) {
if (cache[page][_bank] !== undefined) {
cachedata[_bank] = cache[page][_bank].updated;
}
}
socket.emit('web_buttons_page', page, cachedata);
cache[page].wait = true;
});
}
socket.on('connect', function () {
if (been_connected === true) {
window.location.reload(true);
}
been_connected = true;
socket.on('buttons_page_data', function(page, data) {
if (!hasPage(page)) {
return;
}
cache[page].wait = false;
for (var key in data) {
cache[page][key] = data[key];
drawBank(page, key, data[key]);
}
});
socket.on('buttons_bank_data', function(page, data) {
if (!hasPage(page)) {
return;
}
for (key in data) {
drawBank(page, key, data[key]);
}
});
socket.emit('web_buttons');
for (var i = 1; i < 100; ++i) {
cache[i] = {};
}
// Request first page
socket.emit('web_buttons_page', pages[0], {});
// Check what is visible
scroll();
});
</script>
</body>
</html
@bmeredyk
Copy link
Author

bmeredyk commented Jun 1, 2020

Just use ipad.html, the others are earlier versions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment