finished gif creator

This commit is contained in:
JuliusHerrmann 2021-12-14 02:26:20 +01:00
parent 0559d6fac8
commit 1ba149b3e8
10 changed files with 178 additions and 29 deletions

19
package-lock.json generated
View File

@ -18,6 +18,7 @@
"react-dom": "^17.0.2",
"react-nvd3": "^0.5.7",
"react-scripts": "4.0.3",
"reactjs-popup": "^2.0.5",
"web-vitals": "^1.0.1"
}
},
@ -15714,6 +15715,18 @@
"node": ">=0.10.0"
}
},
"node_modules/reactjs-popup": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/reactjs-popup/-/reactjs-popup-2.0.5.tgz",
"integrity": "sha512-b5hv9a6aGsHEHXFAgPO5s1Jw1eSkopueyUVxQewGdLgqk2eW0IVXZrPRpHR629YcgIpC2oxtX8OOZ8a7bQJbxA==",
"engines": {
"node": ">=10"
},
"peerDependencies": {
"react": ">=16",
"react-dom": ">=16"
}
},
"node_modules/read-pkg": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
@ -33056,6 +33069,12 @@
}
}
},
"reactjs-popup": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/reactjs-popup/-/reactjs-popup-2.0.5.tgz",
"integrity": "sha512-b5hv9a6aGsHEHXFAgPO5s1Jw1eSkopueyUVxQewGdLgqk2eW0IVXZrPRpHR629YcgIpC2oxtX8OOZ8a7bQJbxA==",
"requires": {}
},
"read-pkg": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",

View File

@ -13,6 +13,7 @@
"react-dom": "^17.0.2",
"react-nvd3": "^0.5.7",
"react-scripts": "4.0.3",
"reactjs-popup": "^2.0.5",
"web-vitals": "^1.0.1"
},
"scripts": {

View File

@ -11,8 +11,13 @@ class GIFGenerator extends React.Component {
this.animationId = 0;
}
generateGIF = () => {
//clean input
if(!Math.abs(Number(this.state.duration)) > 0) {
console.log("Only numbers are allowed in duration!");
return;
}
this.setState({duration: Math.abs(this.state.duration)});
var gif = new GIF( {
workers: 2,
@ -20,10 +25,22 @@ class GIFGenerator extends React.Component {
repeat: this.state.loop? 0 : -1,
background: this.state.background
});
//set download trigger
gif.on('finished', function(blob) {
window.open(URL.createObjectURL(blob));
const link = document.createElement('a');
// create a blobURI pointing to our Blob
link.href = URL.createObjectURL(blob);
link.download = "simulationGIF";
// some browser needs the anchor to be in the doc
document.body.append(link);
link.click();
link.remove();
// in case the Blob uses a lot of memory
setTimeout(() => URL.revokeObjectURL(link.href), 7000);
});
let stepBehtmlFore = this.state.step;
let stepBefore = this.state.step;
//clear playing animation
clearInterval(this.animationId);
@ -31,15 +48,15 @@ class GIFGenerator extends React.Component {
this.props.setState({step: 0}, () => {
this.stepTime = 1;
//this.animationId = setInterval(this.visualizeOneStep, this.stepTime);
this.animationId = setInterval(this.grabImageAndNextStep.bind(null, gif, stepBehtmlFore), this.stepTime);
this.animationId = setInterval(this.grabImageAndNextStep.bind(null, gif, stepBefore), this.stepTime);
this.props.setState({playing: true});
});
}
grabImageAndNextStep = (gif, stepBehtmlFore) => {
grabImageAndNextStep = (gif, stepBefore) => {
//check if we are at the end
if (this.props.state.step > this.props.animationLength) {
this.props.setState({step: stepBehtmlFore});
this.props.setState({step: stepBefore});
this.props.visualizeOneStep(false);
clearInterval(this.animationId);
gif.render();
@ -57,18 +74,28 @@ class GIFGenerator extends React.Component {
render() {
return (
<div id="generateGIFPopup">
<label htmlFor="gifDuration" id="gifLengthLabel">Duration In Seconds: </label>
<input htmlFor="gifDuration" type="number" id="gifLengthInput"
value={this.state.duration} onChange={(e) => this.setState({duration: e.target.value})}/>
<label htmlFor="gifBackground" id="gifBackgroundLabel">Background Color: </label>
<input htmlFor="gifBackground" id="gifBackgroundInput" type='color'
value={this.state.background}
onChange={(e) => this.setState({background: e.target.value})}/>
<label htmlFor="gifLoop" id="gifLoopLabel">Loop: </label>
<input htmlFor="gifLoop" id="gifLoopInput" type="checkbox" checked={this.state.loop}
onChange={(e) =>
this.setState({loop: e.target.checked})}/>
<button onClick ={this.generateGIF} >Generate GIF</button>
<div className="popupHeader">
GIF Generator
</div>
<div className="popupSection">
<label htmlFor="gifDuration" id="gifLengthLabel">Duration In Seconds: </label>
<input htmlFor="gifDuration" type="number" id="gifLengthInput"
value={this.state.duration} onChange={(e) => this.setState({duration: e.target.value})}/>
</div>
<div className="popupSection">
<label htmlFor="gifBackground" id="gifBackgroundLabel">Background Color: </label>
<input htmlFor="gifBackground" id="gifBackgroundInput" type='color'
value={this.state.background}
onChange={(e) => this.setState({background: e.target.value})}/>
</div>
<div className="popupSection">
<label htmlFor="gifLoop" id="gifLoopLabel">Loop: </label>
<input htmlFor="gifLoop" id="gifLoopInput" type="checkbox" checked={this.state.loop}
onChange={(e) =>
this.setState({loop: e.target.checked})}/>
</div>
<button className="popupButton" onClick={this.generateGIF} >Generate GIF 📸</button>
</div>
);
}

View File

@ -1,5 +1,6 @@
import React from 'react';
import CytoscapeComponent from 'react-cytoscapejs';
import Popup from 'reactjs-popup';
import '../../css/Graph.css';
import Slider from '../Slider';
import GIFGenerator from './GIFGenerator';
@ -201,14 +202,23 @@ class Graph extends React.Component {
//we want this to be a "tabbed" approach
return (<div id="graphDiv">
<button id="runSimulationButton" onClick={this.visualizeSimulation}>{playPauseString}</button>
<div>
<h3 id="durationDescription">Duration (seconds): </h3>
<input id="animationDuration" type="number" onChange={this.changeAnimationDuration} value={this.state.animationDuration}/>
<Popup trigger={<button id="gifGeneratorButton">Generate GIF 📸</button>} modal>
{close => (
<div className="modal">
<button className="close" onClick={() => {close()}} >&times;</button>
<GIFGenerator setState={this.setState.bind(this)} state={this.state} visualizeOneStep={this.visualizeOneStep} animationLength={this.props.animationLength}/>
</div>
)}
</Popup>
<div id="durationWrapper">
<h3 id="durationDescription">Duration (seconds): </h3>
<input id="animationDuration" type="number" onChange={this.changeAnimationDuration} value={this.state.animationDuration}/>
</div>
<Slider description="Step" min="0" max={this.props.animationLength} currentValue={this.state.step} handleChange={this.visualizeSpecificStep}/>
<CytoscapeComponent id="cy" userZoomingEnabled={false} userPanningEnabled={false}
cy={(cy) => { this.cy = cy }} elements={this.props.graphData}/>
<GIFGenerator setState={this.setState.bind(this)} state={this.state} visualizeOneStep={this.visualizeOneStep} animationLength={this.props.animationLength}/>
</div>);
}
}

View File

@ -5,6 +5,7 @@
}
.Dropdown {
cursor: pointer;
color: #eeeeee;
font-size: 15pt;
display: block;

View File

@ -1,6 +1,69 @@
#generateGIFPopup {
position: absolute;
top: 0;
left: 0;
border: solid black;
.popup-overlay {
background: rgba(0, 0, 0, 0.5);
}
.popup-content {
background-color: #2d4059;
/*background-color: #222831;*/
padding: 1em;
border-radius: 30px;
filter: opacity(1);
max-width: 85%;
}
.modal {
font-size: 13pt;
font-family: 'Roboto', sans-serif;
color: #eeeeee; text-align: left;
}
.modal > .close {
color: white;
cursor: pointer;
position: absolute;
display: block;
padding: 2px 5px;
line-height: 20px;
right: -5px;
top: -5px;
font-size: 24px;
background: #ff5722;
border-radius: 18px;
border: 1px solid #ff5722;
}
.popupHeader {
font-size: 20pt;
}
.popupSection {
display: block;
margin-top: 10px;
}
.popupButton {
cursor: pointer;
margin: auto;
font-size: 16pt;
display: block;
margin-top: 10px;
border: none;
outline: none;
color: #eeeeee;
background-color: #0a8e4e;
border-radius: 10px;
padding: 5px 10px;
margin-top: 10px;
}
#gifLengthInput {
display: inline-block;
width: 1.55em;
/*transform: translateY(-3px);*/
margin-left: 2%;
background-color: #222831;
color: #ff5722;
border-color: #ff5722;
border-style: none;
border-radius: 3px;
font-size: 12pt;
outline: solid;
}
.gifLengthInput:focus {
outline-width: 0;
outline: solid;
}

View File

@ -1,4 +1,5 @@
#recalculate {
cursor: pointer;
margin-right: 20px;
margin-bottom: 20px;
border: none;
@ -11,6 +12,7 @@
}
#switchView {
cursor: pointer;
margin-right: 20px;
margin-bottom: 20px;
border: none;
@ -25,7 +27,9 @@
}
#runSimulationButton {
cursor: pointer;
margin-right: 20px;
margin-bottom: 20px;
border: none;
outline: none;
font-size: 25pt;
@ -37,6 +41,23 @@
min-width: 295px;
}
#gifGeneratorButton {
cursor: pointer;
border: none;
outline: none;
font-size: 25pt;
color: #eeeeee;
background-color: #0A8E4E;
border-radius: 10px;
padding: 5px 10px;
text-align: left;
min-width: 260px;
}
#durationWrapper {
margin-top: -10px;
}
#durationDescription {
display: inline-block;
margin-right: 20px;

View File

@ -3,6 +3,7 @@
}
.ColorPicker {
cursor: pointer;
display: inline-block;
margin-left: 150px;
margin-top: 5px;

View File

@ -41,6 +41,7 @@ input[type="range"]::-webkit-slider-thumb {
}
input[type="range"]::-moz-range-thumb {
cursor: pointer;
height: 14px;
width: 14px;
background: #ff5722;

View File

@ -9345,7 +9345,7 @@
"strip-ansi" "6.0.0"
"text-table" "0.2.0"
"react-dom@*", "react-dom@^17.0.2", "react-dom@>=0.14.0", "react-dom@>=15.0.0":
"react-dom@*", "react-dom@^17.0.2", "react-dom@>=0.14.0", "react-dom@>=15.0.0", "react-dom@>=16":
"integrity" "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA=="
"resolved" "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz"
"version" "17.0.2"
@ -9448,7 +9448,7 @@
optionalDependencies:
"fsevents" "^2.1.3"
"react@*", "react@^17.0.2", "react@>= 16", "react@>=0.14.0", "react@>=15.0.0", "react@17.0.2":
"react@*", "react@^17.0.2", "react@>= 16", "react@>=0.14.0", "react@>=15.0.0", "react@>=16", "react@17.0.2":
"integrity" "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA=="
"resolved" "https://registry.npmjs.org/react/-/react-17.0.2.tgz"
"version" "17.0.2"
@ -9456,6 +9456,11 @@
"loose-envify" "^1.1.0"
"object-assign" "^4.1.1"
"reactjs-popup@^2.0.5":
"integrity" "sha512-b5hv9a6aGsHEHXFAgPO5s1Jw1eSkopueyUVxQewGdLgqk2eW0IVXZrPRpHR629YcgIpC2oxtX8OOZ8a7bQJbxA=="
"resolved" "https://registry.npmjs.org/reactjs-popup/-/reactjs-popup-2.0.5.tgz"
"version" "2.0.5"
"read-pkg-up@^7.0.1":
"integrity" "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg=="
"resolved" "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz"