Files
infoscreen3/public/js/edit.js
T

776 lines
20 KiB
JavaScript

var canvas;
var bundleData;
var grid = 1280 / 32;
var _clipboard = null;
var slideName = "untitled";
bundleData = {
background: "",
duration: 10,
styleHeader: {},
styleText: {},
useWebFonts: false
};
$(function () {
canvas = new fabric.Canvas('edit');
canvas.includeDefaultValues = false;
canvas.preserveObjectStacking = true;
canvas.antialias = true;
canvas.on('object:moving', function (options) {
if (Math.round(options.target.left / grid * 4) % 4 === 0) {
options.target.set({
left: Math.round(options.target.left / grid) * grid,
}).setCoords();
}
if (Math.round(options.target.top / grid * 4) % 4 === 0) {
options.target.set({top: Math.round(options.target.top / grid) * grid}).setCoords();
}
});
$('html').keyup(function (e) {
if (e.keyCode === 46) {
obj = canvas.getActiveObject();
if (!obj.isEditing) {
removeSelectedObjects();
}
}
});
$('#order')
.dropdown({
action: 'hide',
onChange: function (value, text, selectedItem) {
setZindex(value);
}
});
$('#contextmenu .dropdown').dropdown({
on: 'hover',
});
$("#displaytime").checkbox();
$('#colorPicker')
.popup({
inline: true,
hoverable: true,
position: 'bottom center',
delay: {
show: 200,
hide: 800
}
});
displayTime();
setInterval(displayTime, 1000);
});
// Trigger action when the contexmenu is about to be shown
$(document).bind("contextmenu", function (event) {
// Avoid the real one
event.preventDefault();
var objects = canvas.getActiveObjects();
if (objects.length > 0) {
// Show contextmenu
$("#contextmenu").finish().toggle(100).// In the right position (the mouse)
css({
top: event.pageY + "px",
left: event.pageX + "px"
});
}
});
// If the document is clicked somewhere
$(document).bind("mousedown", function (e) {
// If the clicked element is not the menu
if (!$(e.target).parents("#contextmenu").length > 0) {
if (!$(e.target).attr("data-action")) {
// Hide it
$("#contextmenu").hide(100);
}
}
});
// If the menu element is clicked
$("#contextmenu .item").click(function () {
// This is the triggered action name
switch ($(this).attr("data-action")) {
// A case for each action. Your actions here
case "copy":
copyObject();
break;
case "paste":
pasteObject();
break;
case "delete":
removeSelectedObjects();
break;
case "bringToFront":
setZindex("bringToFront");
break;
case "sendToBack":
setZindex("sendToBack");
break;
case "bringForward":
setZindex("bringForward");
break;
case "sendBackwards":
setZindex("sendBackwards");
break;
}
// Hide it AFTER the action was triggered
$("#contextmenu").hide(100);
});
/**
* Displays the local time for bottom of screen
* hh:mm
**/
function displayTime() {
var date = new Date();
var min = date.getMinutes();
if (min < 10) min = "0" + min;
var time = date.getHours() + ":" + min;
$('#time2').html(time);
checkTimeDisplay();
}
function setAlign(align) {
var object = canvas.getActiveObject();
if (object.type === "i-text") {
object.textAlign = align;
}
canvas.renderAll();
}
function setZindex(value) {
switch (value) {
case "sendToBack":
canvas.sendToBack(canvas.getActiveObject());
break;
case "bringToFront":
canvas.bringToFront(canvas.getActiveObject());
break;
case "bringForward":
canvas.bringForward(canvas.getActiveObject());
break;
case "sendBackwards":
canvas.sendBackwards(canvas.getActiveObject());
break;
}
canvas.renderAll();
}
// socketio
fabric.Image.prototype.toObject = (function (toObject) {
return function () {
return fabric.util.object.extend(toObject.call(this), {
src: '/images' + this.getSrc().split('images')[1]
});
}
})(fabric.Image.prototype.toObject);
var canvasWidth = document.getElementById('edit').width,
canvasHeight = document.getElementById('edit').height;
var edgedetection = 20;
socket.on('connect', function () {
socket.emit('admin.editSlide', {bundleName: bundle, fileName: file});
});
socket.on('callback.save', function (data) {
if (data.error) {
alert(data.error);
} else {
// alert("slide saved successfully.");
window.close();
}
});
socket.on('callback.edit.updateFileList', function (data) {
if (data.error) {
alert(data.error);
} else {
openImageBrowser();
}
});
socket.on('callback.edit', function (data) {
bundleData = data.bundleData;
canvas.clear();
if (data.slideData.name != null) {
slideName = data.slideData.name;
$("#slideName").val(slideName);
}
$("#duration").val(data.slideData.duration + "");
if (data.slideData.displayTime !== null) {
$("#override").checkbox('set checked');
if (data.slideData.displayTime) {
$("#displaytime").checkbox('set checked');
} else {
$("#displaytime").checkbox('set unchecked');
}
} else {
$("#override").checkbox('set unchecked');
}
var transitionArray = [];
var values = ["bars", "blinds", "blinds3d", "zip", "blocks", "blocks2", "concentric", "warp", "cube", "tiles3d", "tiles3dprev", "slide", "swipe", "dissolve"];
transitionArray.push({name: "default", value: null});
for (var i in values) {
transitionArray.push({name: values[i], value: values[i]});
}
$('#transitions')
.dropdown({
direction: "downward",
values: transitionArray,
action: function (text, value) {
$('#transitions').dropdown("hide");
$('#transitions').dropdown("set selected", value);
$('#currentTransition').text(text);
}
}).dropdown("set selected", data.slideData.transition);
$('#currentTransition').text(data.slideData.transition || "default");
if (data.bundleData.useWebFonts) {
WebFont.load({
google: {
families: [data.bundleData.styleHeader.fontFamily + ":700,900", data.bundleData.styleText.fontFamily + ":700,900"]
},
timeout: 2000,
active: function () {
nextSlide(data, true);
},
inactive: function () {
nextSlide(data, true);
}
});
} else {
nextSlide(data, true);
}
checkTimeDisplay();
setBackground(bundleData.background);
});
function setBackground(background) {
background = "/background/" + bundleData.bundleName + "/" + background;
var video = document.getElementById("bgvid2");
var bg = $("#bg");
var bgImage = document.getElementById("bgimg");
if (background.indexOf(".mp4") !== -1) {
if (parseUrl(video.src) !== background) {
bg.hide();
video.src = background;
video.load();
video.play();
$(video).show();
}
} else {
if (parseUrl(bgImage.src) !== background) {
bgImage.src = background;
bg.show();
video.pause();
video.removeAttribute("src");
try {
video.load();
} catch (err) {
console.log(err);
}
$(video).hide();
}
}
}
function setStyle(object, styleName, value) {
var style = {};
style[styleName] = value;
if (object.setSelectionStyles && object.isEditing) {
object.setSelectionStyles(style);
} else {
object.setOptions({styles: {}});
object.setOptions(style);
}
}
function getStyle(object, styleName) {
if (object.getSelectionStyles && object.isEditing) {
if (object.getSelectionStyles()[styleName]) {
return object.getSelectionStyles()[styleName];
}
return object[styleName];
} else {
return object[styleName];
}
}
function parseUrl(url) {
return '/background' + url.split('background')[1]
}
function drawGrid() {
var w = 1280 / 32 / 8;
// Grid display part
for (var i = 1; i <= (1280 / grid); i++) {
canvas.add(new fabric.Line([i * grid, 0, i * grid, 1280], {
stroke: '#ccc',
strokeDashArray: [w, w],
opacity: 0.5,
selectable: false,
zIndex: 0
}));
canvas.add(new fabric.Line([0, i * grid, 1280, i * grid], {
stroke: '#ccc',
strokeDashArray: [w, w],
opacity: 0.5,
selectable: false,
zIndex: 0
}))
}
canvas.renderAll();
}
function checkTimeDisplay() {
if ($("#override").checkbox('is checked')) {
if ($("#displaytime").checkbox('is checked')) {
$('#time2').removeClass('flipOutX').addClass("flipInX");
} else {
$('#time2').addClass('flipOutX').removeClass("flipInX");
}
} else {
if (bundleData.displayTime) {
$('#time2').removeClass('flipOutX').addClass("flipInX");
} else {
$('#time2').addClass('flipOutX').removeClass("flipInX");
}
}
}
function nextSlide(data) {
canvas.loadFromJSON(data.json, function () {
drawGrid();
canvas.renderAll();
}, function (obj, object) {
if (object.type === "i-text") {
var fill = object.get("fill");
var fontSize = object.get("fontSize");
if (object.id === "header") {
object.setOptions(bundleData.styleHeader);
if (bundleData.styleHeader.fontSize !== fontSize) {
object.setOptions({fontSize: fontSize});
}
if (bundleData.styleHeader.fill !== "") {
object.setShadow({color: "rgba(0,0,0,0.6)", blur: 5, offsetX: 2, offsetY: 2});
}
} else {
object.setOptions(bundleData.styleText);
if (bundleData.styleText.fontSize !== fontSize) {
object.setOptions({fontSize: fontSize});
}
if (bundleData.styleText.fill !== "") {
object.setShadow({color: "rgba(0,0,0,0.6)", blur: 5, offsetX: 2, offsetY: 2});
}
}
if (fill != null) {
object.setOptions({fill: fill});
}
object.lockRotation = true;
object.hasControls = false;
object.lockUniScaling = true;
object.hasRotatingPoint = false;
}
object.lockUniScaling = true;
});
}
function copyObject() {
// clone what are you copying since you
// may want copy and paste on different moment.
// and you do not want the changes happened
// later to reflect on the copy.
canvas.getActiveObject().clone(function (cloned) {
_clipboard = cloned;
});
}
function pasteObject() {
if (_clipboard === null) return;
// clone again, so you can do multiple copies.
_clipboard.clone(function (clonedObj) {
canvas.discardActiveObject();
clonedObj.set({
left: clonedObj.left + 10,
top: clonedObj.top + 10,
evented: true,
});
if (clonedObj.type === 'activeSelection') {
// active selection needs a reference to the canvas.
clonedObj.canvas = canvas;
clonedObj.forEachObject(function (obj) {
canvas.add(obj);
});
// this should solve the unselectability
clonedObj.setCoords();
} else {
canvas.add(clonedObj);
}
_clipboard.top += 10;
_clipboard.left += 10;
canvas.setActiveObject(clonedObj);
canvas.requestRenderAll();
});
}
function addText(content, isHeader) {
let text = new fabric.IText(content, {
id: "normal",
});
let y = 0;
var objects = canvas.getObjects('i-text');
for (let i in objects) {
if (objects[i].top > y) {
y = objects[i].top + objects[i].height;
}
}
if (y === 0) {
y = 30;
}
if (isHeader) {
text.id = "header";
text.setOptions(bundleData.styleHeader);
text.setOptions({top: y + 10, left: 150});
} else {
text.setOptions(bundleData.styleText);
text.setOptions({top: y + 10, left: 250});
}
text.lockRotation = true;
text.hasControls = false;
text.lockUniScaling = true;
text.hasRotatingPoint = false;
text.setShadow({color: "#000", blur: 5, offsetX: 2, offsetY: 2});
canvas.add(text);
}
function addImage(imageUrl, isFullSized) {
fabric.Image.fromURL(imageUrl, function (bgImage) {
var canvasAspect = canvas.width / canvas.height;
var imgAspect = bgImage.width / bgImage.height;
var left, top, scaleFactor;
if (canvasAspect >= imgAspect) {
scaleFactor = canvas.width / bgImage.width;
left = 0;
top = -((bgImage.height * scaleFactor) - canvas.height) / 2;
} else {
scaleFactor = canvas.height / bgImage.height;
top = 0;
left = -((bgImage.width * scaleFactor) - canvas.width) / 2;
}
if (isFullSized) {
bgImage.set({
top: top,
left: left,
originX: 'left',
originY: 'top',
scaleX: scaleFactor,
scaleY: scaleFactor
});
} else {
bgImage.set({
scaleY: 0.5,
scaleX: 0.5,
});
}
bgImage.lockUniScaling = true;
canvas.add(bgImage);
});
$("#imageLayer").modal("hide");
}
function addHeader(content) {
addText(content, true);
}
function removeSelectedObjects() {
let obj = canvas.getActiveObjects();
for (var i in obj) {
canvas.remove(obj[i]);
}
canvas.discardActiveObject();
canvas.requestRenderAll();
}
function cueSlide(id) {
if (id === null) {
var bool = confirm('You are about to display the current slide for ALL DISPLAYS, are you sure?')
if (bool === false) {
return;
}
}
if (confirm('Force display of the current slide?') && bool) {
var duration = null;
if ($.isNumeric($("#duration").val())) {
duration = parseFloat($("#duration").val());
}
var objects = canvas.getObjects('line');
for (let i in objects) {
canvas.remove(objects[i]);
}
let obj = {
json: canvas.toJSON(['id']),
png: canvas.toDataURL('png'),
displayId: id,
duration: duration
};
socket.emit("admin.override", obj);
drawGrid();
}
}
function save() {
canvas.setBackgroundImage(null, null, null);
var objects = canvas.getObjects('line');
for (let i in objects) {
canvas.remove(objects[i]);
}
slideName = $("#slideName").val();
if (slideName === "untitled") {
var texts = canvas.getObjects('i-text');
for (let i in texts) {
if (texts[i].id == "header") {
slideName = texts[i].text;
break;
}
}
}
var duration = null;
if ($.isNumeric($("#duration").val())) {
duration = parseFloat($("#duration").val());
}
var checked = null;
if ($("#override").checkbox('is checked')) {
checked = false;
if ($("#displaytime").checkbox('is checked')) {
checked = true;
}
}
var transition = $("#transitions").dropdown("get value");
if (transition === "null") transition = "";
var obj = {
bundleName: bundle,
name: slideName,
fileName: file,
duration: duration,
json: canvas.toJSON(['id', 'fontSize']),
png: canvas.toDataURL('png'),
displayTime: checked,
transition: transition
};
socket.emit("edit.save", obj);
}
function saveAsFullScreenImage(name = "untitled", imageData) {
canvas.clear();
canvas.setBackgroundImage(null, null, null);
fabric.Image.fromURL(imageData, function (bgImage) {
var canvasAspect = canvas.width / canvas.height;
var imgAspect = bgImage.width / bgImage.height;
var left, top, scaleFactor;
if (canvasAspect >= imgAspect) {
scaleFactor = canvas.width / bgImage.width;
left = 0;
top = -((bgImage.height * scaleFactor) - canvas.height) / 2;
} else {
scaleFactor = canvas.height / bgImage.height;
top = 0;
left = -((bgImage.width * scaleFactor) - canvas.width) / 2;
}
bgImage.set({
top: top,
left: left,
originX: 'left',
originY: 'top',
scaleX: scaleFactor,
scaleY: scaleFactor
});
canvas.add(bgImage);
canvas.renderAll();
var duration = null;
if ($.isNumeric($("#duration").val())) {
duration = parseFloat($("#duration").val());
}
var checked = null;
if ($("#override").checkbox('is checked')) {
checked = $("#displaytime").checkbox('is checked');
}
var transition = $("#transitions").dropdown("get value");
if (transition === "null") transition = null;
var dataurl = canvas.toDataURL('png');
var json =
{
version: "2.6.0",
objects: [{
type: "image",
version: "2.6.0",
width: 1280,
height: 720,
crossOrigin: "",
src: dataurl,
filters: []
}]
};
var obj = {
bundleName: bundle,
name: name,
fileName: file,
duration: duration,
json: json,
png: dataurl,
displayTime: checked,
transition: transition,
};
socket.emit("edit.save", obj);
});
}
function deleteImage(name) {
if (confirm("Really delete image?")) {
socket.emit("edit.deleteImage", {
bundleName: bundle,
name: name,
});
}
}
function changeColor(elem) {
var obj = canvas.getActiveObject();
// console.log(window.getComputedStyle(elem).backgroundColor);
setStyle(obj, "fill", window.getComputedStyle(elem).backgroundColor);
canvas.renderAll();
}
function setCenter(direction) {
switch (direction) {
case "h":
canvas.getActiveObject().viewportCenterH();
break;
case "v":
canvas.getActiveObject().viewportCenterV();
break;
}
}
function fontSize(direction) {
for (var obj of canvas.getActiveObjects()) {
var sizes = [20, 28, 32, 36, 40, 44, 48, 50, 54, 58, 64, 72, 96];
if (obj.type === "i-text") {
var idx = closest(sizes, getStyle(obj, "fontSize"));
if ((idx + direction) < sizes.length && (idx + direction) > 0) {
setStyle(obj, "fontSize", sizes[idx + direction]);
}
}
}
canvas.requestRenderAll();
}
function closest(list, x) {
var min,
chosen = 0;
for (var i in list) {
min = Math.abs(list[chosen] - x);
if (Math.abs(list[i] - x) < min) {
chosen = i;
}
}
return parseInt(chosen);
}
function openImageBrowser() {
$("#imageList").load("/admin/ajax/imagelist?bundle=" + bundle + "&nocache=" + uuidv4(), null, function () {
addImagesFromUploadQueue();
$('#imageLayer').modal('show');
});
}
/** Generate an uuid
* @url https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript#2117523 **/
function uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
let r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}