finished gif creator
This commit is contained in:
parent
0559d6fac8
commit
1ba149b3e8
19
package-lock.json
generated
19
package-lock.json
generated
@ -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",
|
||||
|
||||
@ -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": {
|
||||
|
||||
@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@ -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()}} >×</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>);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
}
|
||||
|
||||
.Dropdown {
|
||||
cursor: pointer;
|
||||
color: #eeeeee;
|
||||
font-size: 15pt;
|
||||
display: block;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
}
|
||||
|
||||
.ColorPicker {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
margin-left: 150px;
|
||||
margin-top: 5px;
|
||||
|
||||
@ -41,6 +41,7 @@ input[type="range"]::-webkit-slider-thumb {
|
||||
}
|
||||
|
||||
input[type="range"]::-moz-range-thumb {
|
||||
cursor: pointer;
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
background: #ff5722;
|
||||
|
||||
@ -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"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user