Created
April 8, 2021 20:34
-
-
Save brandonetter/8659a34d8b5eb63bbdbe3e134127cfe2 to your computer and use it in GitHub Desktop.
Animation Flipbook
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script> | |
<!DOCTYPE html> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/lightslider/1.1.6/css/lightslider.css" | |
integrity="sha512-+1GzNJIJQ0SwHimHEEDQ0jbyQuglxEdmQmKsu8KI7QkMPAnyDrL9TAnVyLPEttcTxlnLVzaQgxv2FpLCLtli0A==" | |
crossorigin="anonymous" /> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/lightslider/1.1.6/js/lightslider.js" | |
integrity="sha512-sww7U197vVXpRSffZdqfpqDU2SNoFvINLX4mXt1D6ZecxkhwcHmLj3QcL2cJ/aCxrTkUcaAa6EGmPK3Nfitygw==" | |
crossorigin="anonymous"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"></script> | |
<html> | |
<head> | |
<script src='http://fabricjs.com/lib/fabric.js'></script> | |
<meta charset="UTF-8"> | |
<title>flipbook - </title> | |
<style> | |
:root { | |
--color-black: #141419; | |
--color-red: #A84B38; | |
--color-orange: #EA8220; | |
--color-orange-2: #F1471D; | |
--color-yellow: #FBC707; | |
--color-white: #FFFFFF; | |
} | |
@keyframes pulse { | |
from { | |
transform: scale3d(1, 1, 1); | |
filter: drop-shadow(16px 16px 24px rgba(5, 5, 5, 0.9)) | |
} | |
50% { | |
transform: scale3d(1.5, 1.5, 1.5); | |
filter: drop-shadow(24px 24px 48px rgba(5, 5, 5, 0.5)) | |
} | |
100% { | |
transform: scale3d(1, 1, 1); | |
filter: drop-shadow(16px 16px 24px rgba(5, 5, 5, 0.9)) | |
} | |
} | |
* { | |
margin: 0; | |
padding: 0; | |
} | |
body { | |
font-family: monospace; | |
background: var(--color-black); | |
color: var(--color-orange-2); | |
width: 100%; | |
height: 100%; | |
overflow: hidden; | |
cursor: default; | |
} | |
a { | |
color: var(--color-orange-2); | |
text-decoration: none; | |
} | |
*::selection { | |
background: var(--color-orange-2); | |
color: var(--color-yellow); | |
} | |
header, | |
main { | |
position: relative; | |
top: 1rem; | |
left: 1rem; | |
} | |
header { | |
text-transform: uppercase; | |
} | |
header h1 { | |
font-family: Helvetica, sans-serif; | |
font-size: 3rem; | |
} | |
main div { | |
position: relative; | |
left: 2px; | |
} | |
img.logo { | |
position: absolute; | |
top: 0; | |
bottom: 0; | |
left: 0; | |
right: 0; | |
margin: auto; | |
width: 50vmin; | |
pointer-events: none; | |
} | |
#cc { | |
border: 4px solid rgba(73, 65, 57, 0.315); | |
display: flex; | |
align-items: center | |
} | |
p { | |
color: black; | |
} | |
.frame { | |
background-color: gray; | |
width: 250px; | |
} | |
.frame2 { | |
background-color: beige; | |
} | |
#c { | |
border-right: 4px solid rgba(73, 65, 57, 0.315); | |
display: flex; | |
align-items: center; | |
background-color: beige; | |
} | |
img#logo-haxe { | |
opacity: 0; | |
animation-delay: 0.3s; | |
animation-duration: 1s; | |
animation-fill-mode: both; | |
animation-name: pulse; | |
filter: drop-shadow(16px 16px 24px rgba(5, 5, 5, 0.9)); | |
z-index: 2; | |
} | |
footer { | |
position: fixed; | |
right: 0; | |
bottom: 0; | |
display: none; | |
} | |
p { | |
height: 120px; | |
} | |
.o { | |
height: 120px; | |
} | |
.x { | |
background-color: orange; | |
height: 120px; | |
} | |
</style> | |
</head> | |
<body> | |
<h4 id='Cpath'></h4> | |
<header> | |
<h1>Flipbook</h1> | |
</header> | |
<div id='cc'> | |
<canvas id="c"></canvas> | |
<div style='margin:10px'> | |
<button onclick='lockUnlock()'>Lock/Unlock</button><br> | |
<button onclick='Copy()'>Copy</button> | |
<button onclick='Paste()'>Paste</button><br> | |
<button onclick='groupSelection()'>Group Selection</button><br> | |
<button onclick='ungroupSelection()'>UnGroup Selection</button><br> | |
<input onchange='colorPickChange()' id='lineWidth' type="range" min="1" max="90" value="2"></input><br> | |
<input onchange='colorPickChange()' type='color' id='colorPick'></input> | |
<button onclick='toggleDraw()' id='toggleDrawButton'>Draw</button><br> | |
<button onclick='deleteSelection()'>Delete Selection</button><br> | |
<button onclick='runAnimate()'>Animate</button><br> | |
<button onclick='bringForward()'>Bring Forward</button> | |
</div> | |
</div> | |
<script> | |
window.globals = { | |
gallery: "", | |
c_top: 40, | |
c_left: 120, | |
c_width: 400, | |
c_height: 300, | |
path: '/flipbook/' | |
}; | |
console.log(globals.c_left); | |
const { | |
ipcRenderer | |
} = require('electron'); | |
ipcRenderer.on('send-path', function (event, path) { | |
globals.path = path; | |
console.log(globals.path); | |
document.getElementById('Cpath').innerHTML = globals.path; | |
}); | |
// Some data that will be sent to the main process | |
let Data = { | |
message: "Hi", | |
someData: "Let's go" | |
}; | |
function lockUnlock() { | |
if (!canvas.getActiveObject()) { | |
obj = canvas.getObjects(); | |
obj.forEach(function (item, i) { | |
console.log('plz work'); | |
//item.setColor('red'); | |
if (item.get('name') != 'canvasBorder') | |
item.set('selectable', true); | |
canvas.renderAll(); | |
}); | |
} | |
canvas.getActiveObject().selectable = false; | |
canvas.getActiveObject().set('selectable', false); | |
canvas.getActiveObject().set('name', 'nonsel'); | |
canvas.discardActiveObject(); | |
canvas.requestRenderAll(); | |
} | |
function bringForward() { | |
canvas.bringForward(canvas.getActiveObject()); | |
canvas.requestRenderAll(); | |
} | |
function ungroupSelection() { | |
if (!canvas.getActiveObject()) { | |
return; | |
} | |
if (canvas.getActiveObject().type !== 'group') { | |
return; | |
} | |
canvas.getActiveObject().toActiveSelection(); | |
canvas.requestRenderAll(); | |
} | |
function Copy() { | |
canvas.getActiveObject().clone(function (cloned) { | |
_clipboard = cloned; | |
}); | |
} | |
function Paste() { | |
_clipboard.clone(function (clonedObj) { | |
canvas.discardActiveObject(); | |
clonedObj.set({ | |
left: clonedObj.left + 10, | |
top: clonedObj.top + 10, | |
evented: true, | |
}); | |
if (clonedObj.type === 'activeSelection') { | |
clonedObj.canvas = canvas; | |
clonedObj.forEachObject(function (obj) { | |
canvas.add(obj); | |
}); | |
clonedObj.setCoords(); | |
} else { | |
canvas.add(clonedObj); | |
} | |
_clipboard.top += 10; | |
_clipboard.left += 10; | |
canvas.setActiveObject(clonedObj); | |
canvas.requestRenderAll(); | |
}); | |
} | |
function zeropad(value, padding) { | |
var zeroes = new Array(padding + 1).join("0"); | |
return (zeroes + value).slice(-padding); | |
} | |
function groupSelection() { | |
if (!canvas.getActiveObject()) { | |
return; | |
} | |
if (canvas.getActiveObject().type !== 'activeSelection') { | |
return; | |
} | |
canvas.getActiveObject().toGroup(); | |
canvas.requestRenderAll(); | |
} | |
function colorPickChange() { | |
canvas.freeDrawingBrush.width = parseInt(document.getElementById('lineWidth').value, 10) || 1; | |
canvas.freeDrawingBrush.color = document.getElementById('colorPick').value; | |
} | |
function runAnimate() { | |
for (let i = 0; i < slideArray.length; i++) { | |
setTimeout(function () { | |
canvasLoad(slideArray[i].canvas, i, true); | |
}, (i + 1) * 100); | |
if (i == slideArray.length - 1) { | |
setTimeout(function () { | |
canvasLoad(slideArray[i].canvas, i, true); | |
}, (i + 1) * 270); | |
setTimeout(function () { | |
ipcRenderer.send('request-animate'); | |
}, (i + 1) * 370); | |
} | |
} | |
} | |
function deleteSelection() { | |
canvas.remove(canvas.getActiveObject()); | |
} | |
function toggleDraw() { | |
if (canvas.isDrawingMode) { | |
document.getElementById('toggleDrawButton').innerText = 'Draw'; | |
} else { | |
document.getElementById('toggleDrawButton').innerText = 'Grab'; | |
} | |
canvas.freeDrawingBrush.color = document.getElementById('colorPick').value; | |
canvas.isDrawingMode = !canvas.isDrawingMode; | |
} | |
let LightSlideSettings = { | |
item: 24, | |
currentPagerPosition: 'left' | |
} | |
var canvas = new fabric.Canvas("c"); | |
canvas.setWidth(window.innerWidth * 0.8); | |
canvas.setHeight(window.innerHeight - 210); | |
canvas.calcOffset(); | |
function reportWindowSize() { | |
canvas.setWidth(window.innerWidth * 0.8); | |
canvas.setHeight(window.innerHeight - 210); | |
canvas.calcOffset(); | |
} | |
var green = new fabric.Rect({ | |
top: globals.c_top - 2, | |
left: globals.c_left - 2, | |
width: globals.c_width + 4, | |
height: globals.c_height + 4, | |
fill: 'transparent', | |
strokeWidth: 2, | |
stroke: "#880E4F", | |
"selectable": false, | |
"evented": false, | |
name: 'canvasBorder' | |
}); | |
canvas.add(green); | |
canvas.renderAll(); | |
window.onresize = reportWindowSize; | |
function saveFrame(frame, send) { | |
var s1 = new Slide(JSON.stringify(canvas.toJSON(['selectable', 'evented', 'name'])), frame); | |
let Data1 = { | |
canvas: cropPlusExport(globals.c_width), | |
name: frame | |
}; | |
if (send) { | |
ipcRenderer.send('request-mainprocess-action', Data1); | |
} | |
slideArray[frame] = s1; | |
globals.gallery.destroy(); | |
document.getElementById("lightSlider").innerHTML = ''; | |
for (i = 0; i < slideArray.length; i++) { | |
var s = slideArray[i]; | |
var leadingz = zeropad(i, 3); | |
var fill = "o"; | |
if (i == activeFrame) { | |
fill = "x"; | |
} | |
document.getElementById("lightSlider").innerHTML += "<li class='frame' onclick='canvasLoad(`" + s.canvas + | |
"`," + i + ",false)'><p class='" + fill + "'>" + leadingz + "<br>" + fill + "</p></li>"; | |
} | |
var sn = $("#lightSlider").lightSlider(LightSlideSettings); | |
globals.gallery = sn; | |
globals.gallery.refresh(); | |
} | |
class Slide { | |
constructor(fabricCanvas, name, thumb) { | |
this.canvas = fabricCanvas; | |
this.name = name; | |
this.thumbnail = thumb; | |
} | |
} | |
var slideArray = []; | |
var s1 = new Slide(JSON.stringify(canvas.toJSON(['selectable', 'evented', 'name'])), "000"); | |
let Data1 = { | |
canvas: cropPlusExport(globals.c_width), | |
name: "000" | |
}; | |
ipcRenderer.send('request-mainprocess-action', Data1); | |
slideArray[0] = s1; | |
activeFrame = 0; | |
function canvasLoad(json, frame, send) { | |
saveFrame(activeFrame, send); | |
activeFrame = frame; | |
canvas.loadFromJSON(json); | |
obj = canvas.getObjects(); | |
obj.forEach(function (item, i) { | |
if (item.get('name') == 'canvasBorder') { | |
item.bringToFront(); | |
} | |
}); | |
saveFrame(activeFrame, false); | |
canvas.renderAll(); | |
} | |
function addSlide() { | |
var ct = slideArray.length; | |
var s1 = new Slide(JSON.stringify(canvas.toJSON(['selectable', 'evented', 'name'])), ct); | |
let Data1 = { | |
canvas: cropPlusExport(globals.c_width), | |
name: ct | |
}; | |
ipcRenderer.send('request-mainprocess-action', Data1); | |
slideArray[ct] = s1; | |
var leadingz = zeropad(ct - 1, 3); | |
var slider = "<li class='frame' onclick='canvasLoad(`" + s1.canvas + "`," + ct - 1 + ",false)'><p>" + leadingz + | |
"</p></li>"; | |
globals.gallery.destroy(); | |
document.getElementById("lightSlider").innerHTML = ''; | |
for (i = 0; i < slideArray.length; i++) { | |
var s = slideArray[i]; | |
var fill = "o"; | |
if (i == activeFrame) { | |
fill = "x"; | |
} | |
var leadingz = zeropad(i, 3); | |
document.getElementById("lightSlider").innerHTML += "<li class='frame' onclick='canvasLoad(`" + s.canvas + | |
"`," + i + ")'><p class='" + fill + "'>" + leadingz + "<br>" + fill + "</p></li>"; | |
} | |
var sn = $("#lightSlider").lightSlider(LightSlideSettings); | |
globals.gallery = sn; | |
globals.gallery.refresh(); | |
} | |
function cropPlusExport(global) { | |
var tempCanvas = document.createElement("canvas"), | |
tCtx = tempCanvas.getContext("2d"); | |
console.log(globals); | |
tempCanvas.width = globals.c_width; | |
tempCanvas.height = globals.c_height; | |
var canvas_image = new Image(); | |
canvas_image.src = canvas.toDataURL(); | |
tCtx.drawImage(canvas_image, globals.c_left, globals.c_top, globals.c_width, globals.c_height, 0, 0, globals | |
.c_width, globals.c_height); | |
return (tempCanvas.toDataURL()); | |
} | |
</script> | |
<button onclick='addSlide()' value="asd">CreateFrame</button> | |
<ul id="lightSlider" style='width:500px'> | |
</ul> | |
<script type="text/javascript"> | |
$(document).ready(function () { | |
var slider = $("#lightSlider").lightSlider(LightSlideSettings); | |
globals.gallery = slider; | |
ipcRenderer.send('request-path'); | |
}); | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Modules to control application life and create native browser window | |
const {app, BrowserWindow} = require('electron') | |
const { exec } = require("child_process"); | |
const path = app.getPath('home'); | |
var pathUse = path; | |
var folder = '/project-'+Math.floor(Math.random()*99999)+'/'; | |
console.log(folder); | |
//const mainWindow; | |
//const mainWindow = null; | |
function createWindow () { | |
// Create the browser window. | |
const mainWindow = new BrowserWindow({ | |
width: 800, | |
height: 600, | |
webPreferences: { | |
nodeIntegration: true | |
} | |
}); | |
var fs = require('fs'); | |
fs.writeFile(pathUse+'/flipbook'+folder+'LOG.txt', "run", function (err) { | |
fs.mkdirSync(pathUse+'/flipbook'+folder, { recursive: true }); | |
// path exists unless there was an error | |
}); | |
// and load the index.html of the app. | |
mainWindow.loadFile('index.html') | |
// Open the DevTools. | |
// mainWindow.webContents.openDevTools() | |
} | |
// This method will be called when Electron has finished | |
// initialization and is ready to create browser windows. | |
// Some APIs can only be used after this event occurs. | |
app.whenReady().then(createWindow) | |
// Quit when all windows are closed, except on macOS. There, it's common | |
// for applications and their menu bar to stay active until the user quits | |
// explicitly with Cmd + Q. | |
app.on('window-all-closed', function () { | |
if (process.platform !== 'darwin') { | |
app.quit() | |
} | |
}) | |
app.on('activate', function () { | |
// On OS X it's common to re-create a window in the app when the | |
// dock icon is clicked and there are no other windows open. | |
if (BrowserWindow.getAllWindows().length === 0) { | |
createWindow() | |
} | |
}) | |
// In this file you can include the rest of your app's specific main process | |
// code. You can also put them in separate files and require them here. | |
const {ipcMain} = require('electron'); | |
//const { app } = require('electron'); | |
// Attach listener in the main process with the given ID | |
ipcMain.on('request-animate', (event, arg) => { | |
console.log('asd'); | |
exec("ffmpeg -framerate 5 -y -i "+pathUse+'/flipbook'+folder+"%03d.png -plays 0 "+pathUse+'/flipbook'+folder+"output.mp4", (error, stdout, stderr) => { | |
if (error) { | |
console.log(`error: ${error.message}`); | |
return; | |
} | |
if (stderr) { | |
console.log(`stderr: ${stderr}`); | |
return; | |
} | |
console.log(`stdout: ${stdout}`); | |
}); | |
}); | |
ipcMain.on('request-path',(event,arg)=>{ | |
var windows=BrowserWindow.getAllWindows(); | |
windows[0].webContents.send('send-path', pathUse+'/flipbook'+folder); | |
}); | |
ipcMain.on('request-set-Dev',(event,arg)=>{ | |
pathUse = arg.path; | |
if(arg.mode == false){ | |
pathUse = path; | |
} | |
console.log("dmode:"+arg.mode); | |
console.log("path:"+arg.path); | |
//var windows=BrowserWindow.getAllWindows(); | |
//windows[0].webContents.send('send-path', path); | |
}); | |
ipcMain.on('request-mainprocess-action', (event, arg) => { | |
// Displays the object sent from the renderer process: | |
//{ | |
// message: "Hi", | |
// someData: "Let's go" | |
//} | |
Rexec(arg); | |
}); | |
function zeropad(value, padding) { | |
var zeroes = new Array(padding+1).join("0"); | |
return (zeroes + value).slice(-padding); | |
} | |
Rexec = function(canvas) { | |
var fs = require('fs'); | |
//const dialog = require('electron').remote.dialog; | |
//var canvasBuffer = require('electron-canvas-to-buffer'); | |
//dialog.showSaveDialog({title:'Testing a save dialog',defaultPath:'image.jpg'},saveCallback); | |
//canvas = mainWindow.document.getElementById('c'); | |
// as a buffer | |
//var buffer = canvasBuffer(canvas, 'image/png') | |
// write canvas to file | |
fs = require('fs'); | |
var data = canvas.canvas.replace(/^data:image\/\w+;base64,/, ""); | |
var buf = new Buffer(data, 'base64'); | |
//fs.writeFile('image.png', buf); | |
//var path = '/home/bran/Desktop/fiddle'; | |
//var path = app.getAppPath(); | |
fs.writeFile(pathUse+'/flipbook'+folder+zeropad(canvas.name,3)+'.png', buf, function (err) { | |
if (err) return console.log(err); | |
console.log(pathUse+'/flipbook'+folder+zeropad(canvas.name,3)+'.png'); | |
}); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Empty |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This file is required by the index.html file and will | |
// be executed in the renderer process for that window. | |
// All of the Node.js APIs are available in this process. | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Empty */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment