frame viewer, export warnings

master
Beau Blyth 2019-10-03 18:02:08 -07:00
parent 6c0cf01164
commit 2e47bde496
6 changed files with 135 additions and 45 deletions

View File

@ -3,8 +3,8 @@ import { IPin } from './IPin';
export interface IAnimationData {
frameRate: number;
originX: number;
originY: number;
originX: number | null;
originY: number | null;
loop: boolean;
frames: IFrame[];
pins: IPin[];

View File

@ -20,6 +20,7 @@ export class FrameHandler {
private imageElement: HTMLImageElement;
private projectData: IProjectData;
private frameViewer: HTMLElement;
constructor(
animationData: IAnimationData,
@ -28,7 +29,8 @@ export class FrameHandler {
canvasContext: CanvasRenderingContext2D,
frameNumberDiv: HTMLElement,
imageElement: HTMLImageElement,
projectData: IProjectData
projectData: IProjectData,
frameViewer: HTMLElement
) {
this.animationData = animationData;
this.canvasData = canvasData;
@ -38,6 +40,7 @@ export class FrameHandler {
window.requestAnimationFrame(this.windowAnimationUpdate);
this.imageElement = imageElement;
this.projectData = projectData;
this.frameViewer = frameViewer;
}
public GetCurrentFrame(): number {
@ -64,6 +67,7 @@ export class FrameHandler {
this.currentFrame = this.filenames.length - 1;
}
this.GoToFrame(this.currentFrame);
this.RefreshFrameViewer();
}
public GoToFrame(frame: number) {
@ -87,6 +91,54 @@ export class FrameHandler {
return this.filenames;
}
public ConstructFrameUI = () => {
// clear frames
let child = this.frameViewer.lastElementChild;
while (child) {
this.frameViewer.removeChild(child);
child = this.frameViewer.lastElementChild;
}
// construct
for (let i = 0; i < this.animationData.frames.length; i++) {
const newDiv = document.createElement('div');
this.frameViewer.appendChild(newDiv);
newDiv.className = 'frame';
}
};
public RefreshFrameViewer() {
// set all frames to inactive
for (let i = 0; i < this.frameViewer.children.length; i++) {
this.frameViewer.children[i].className = 'frame';
}
// set current frame to active
if (this.frameViewer.children[this.projectData.currentFrame] !== undefined) {
this.frameViewer.children[this.projectData.currentFrame].className = 'frameActive';
}
// check frames for data errors
for (let f = 0; f < this.animationData.frames.length; f++) {
if (this.animationData.pins !== undefined) {
for (let p = 0; p < this.animationData.pins.length; p++) {
if (this.animationData.pins[p] !== undefined) {
const pinIDtoCheck = this.animationData.pins[p].id;
console.log('checking frame ' + f + ' for pinID ' + this.animationData.pins[p].name);
if (this.frameViewer.children[f] !== undefined) {
if (this.animationData.frames[f][pinIDtoCheck] === undefined) {
if (f === this.projectData.currentFrame) {
this.frameViewer.children[f].className = 'frameActiveWarning';
} else {
this.frameViewer.children[f].className = 'frameWarning';
}
break;
}
}
}
}
}
}
}
private RefreshImage() {
if (this.filenames.length === 0) {
this.frameNumberDiv.className = 'warning';
@ -105,12 +157,13 @@ export class FrameHandler {
);
// draw origin +
this.canvasContext.strokeStyle = '#000000';
const originCursorSize: number = 500;
const originX = this.animationData.originX;
const originY = this.animationData.originY;
this.DrawCrossHair(500, this.canvasContext, originX, originY);
if (originX !== null && originY !== null) {
this.DrawCrossHair(500, this.canvasContext, originX, originY);
}
// frame number update
this.frameNumberDiv.className = 'instruction';
this.frameNumberDiv.className = '';
this.frameNumberDiv.innerText =
'Frame ' + (this.currentFrame + 1).toString() + ' / ' + this.filenames.length.toString();
// draw pins

View File

@ -87,7 +87,8 @@ export class Page {
canvasElement.getContext('2d')!,
document.getElementById('frameNumber') as HTMLElement,
imageElement,
this.projectData
this.projectData,
document.getElementById('frameViewer') as HTMLElement
);
// input elements
@ -161,7 +162,7 @@ export class Page {
if (document.activeElement === document.body) {
this.pinHandler.UpdateAnimationPinNames();
if (this.CheckAllFramesForPinData()) {
if (this.ProjectHasNeccesaryData()) {
const zip = new JSZip();
// name of project
const name = this.filenameInput.value;
@ -188,34 +189,47 @@ export class Page {
document.addEventListener('keydown', keyDown);
}
private CheckAllFramesForPinData(): boolean {
const availablePins: number[] = this.pinHandler.GetAvailablePins();
let passTest: boolean = true;
let passPinDataTest: boolean = true;
private ProjectHasNeccesaryData(): boolean {
let pass: boolean = true;
let errorString: string = '';
let pinErrorString: string = '';
for (let frame = 0; frame < this.animationData.frames.length; frame++) {
for (let p = 0; p < availablePins.length; p++) {
// loop through available pinIDs
const pinIDChecking = availablePins[p];
if (this.animationData.frames[frame][pinIDChecking] === undefined) {
pinErrorString += 'Frame ' + frame + ', ' + this.pinHandler.GetPinName(pinIDChecking) + '\n';
passPinDataTest = false;
this.frameHandler.RefreshFrameViewer();
if (this.filenameInput.value === '') {
errorString += '- Missing name\n';
pass = false;
}
if (this.animationData.originX === null || this.animationData.originY === null) {
errorString += '- Missing origin data\n';
pass = false;
}
// check frames for data errors
let pinDataErrorString: string = '';
let passPinData: boolean = true;
for (let f = 0; f < this.animationData.frames.length; f++) {
let errorOnFrame: boolean = false;
if (this.animationData.pins !== undefined) {
for (let p = 0; p < this.animationData.pins.length; p++) {
if (this.animationData.pins[p] !== undefined) {
const pinIDtoCheck = this.animationData.pins[p].id;
console.log('checking frame ' + f + ' for pinID ' + this.animationData.pins[p].name);
if (this.animationData.frames[f][pinIDtoCheck] === undefined) {
if (!errorOnFrame) {
pinDataErrorString += ' Frame ' + f + ' :\n';
}
pinDataErrorString += ' Pin: ' + this.animationData.pins[p].name + '\n';
passPinData = false;
}
}
}
}
}
// construct error string
if (this.animationData.originX === -999 || this.animationData.originY === -999) {
errorString = 'Missing Origin data. \n';
passTest = false;
if (!passPinData) {
errorString += '- Missing pin data on some frames: \n' + pinDataErrorString;
pass = false;
}
if (!passPinDataTest) {
// warn user if missing pin data
errorString += 'Missing the following pin data: \n\n' + pinErrorString;
passTest = false;
if (!pass) {
alert(errorString);
}
this.message.innerText = errorString;
return passTest;
return pass;
}
private handleFileSelect = async (event: DragEvent) => {
@ -242,14 +256,14 @@ export class Page {
this.canvasHandler.ResizeCanvas();
// set framedata initialized to true
this.frameHandler.ConstructFrameUI();
};
private ResetProgram = () => {
// defining blank slate animation data
this.animationData.pins = [];
this.animationData.originX = -999;
this.animationData.originY = -999;
this.animationData.originX = null;
this.animationData.originY = null;
this.animationData.frameRate = 30;
this.animationData.loop = true;
this.animationData.frames = [ { filename: '' } ];
@ -282,9 +296,4 @@ export class Page {
this.frameHandler.TogglePlayingAnimation();
console.log('new frame rate = ' + this.animationData.frameRate);
};
private updateLooping = () => {
this.animationData.loop = this.loopingInput.checked;
console.log('new looping value = ' + this.loopingInput.checked);
};
}

View File

@ -43,6 +43,7 @@ export class PinHandler {
for (let i = 1; i < this.allPinContainers.length; i++) {
console.log(this.allPinContainers[i].children);
const pinName: string = this.GetPinNameFromDiv(this.allPinContainers[i]);
console.log('new pin name = ' + pinName);
if (pinName !== null && pinName !== undefined) {
let newPinData: IPin = {
id: this.GetPinNumberFromID(this.allPinContainers[i].id),
@ -111,6 +112,9 @@ export class PinHandler {
newNameInput.id = 'nameInput_' + this.pins.toString();
newDiv.appendChild(newNameInput);
newNameInput.value = 'PinName_' + this.pins.toString();
newNameInput.addEventListener('focusout', () => {
this.UpdateAnimationPinNames();
});
// button to remove pin
const removePinButton = document.createElement('button');
newDiv.appendChild(removePinButton);
@ -133,6 +137,7 @@ export class PinHandler {
this.RemovePinDataForID(idNumber);
// remove the div itself
newDiv.remove();
this.UpdateAnimationPinNames();
});
// break
newDiv.appendChild(document.createElement('br'));
@ -145,7 +150,9 @@ export class PinHandler {
newDiv.className = 'pinButtonContainerSelected';
this.projectData.currentlySelectedPin = parseInt(newDiv.id.split('_')[1]);
console.log('selected pin ' + this.projectData.currentlySelectedPin);
this.UpdateAnimationPinNames();
});
this.UpdateAnimationPinNames();
};
private RemovePinDataForID = (pinID: number) => {

View File

@ -17,32 +17,53 @@ div {
text-align: center;
}
#frameViewer {
display: flex;
flex-direction: row;
}
.frame {
flex: 1;
width: 32px;
height: 32px;
max-width: 32px;
color: #101e24;
width: 50%;
border: 2px solid #3f4446;
padding: 1px;
background-color: rgb(90, 92, 95);
display: inline-block;
}
.frameActive {
flex: 1;
width: 32px;
height: 32px;
max-width: 32px;
color: #101e24;
width: 50%;
border: 2px solid #0865df;
padding: 1px;
background-color: rgb(35, 75, 185);
display: inline-block;
}
.frameWarning {
flex: 1;
width: 32px;
height: 32px;
max-width: 32px;
color: #101e24;
width: 50%;
border: 2px solid rgb(233, 7, 75);
padding: 1px;
background-color: rgb(83, 14, 20);
display: inline-block;
}
.frameActiveWarning {
flex: 1;
width: 32px;
height: 32px;
max-width: 32px;
color: #101e24;
border: 2px solid rgb(233, 7, 75);
padding: 1px;
background-color: rgb(185, 8, 61);
display: inline-block;
}
.errorMessage {
@ -79,12 +100,14 @@ body {
flex-direction: row;
}
.pinButtonContainer {
max-width: 10%;
flex: 1;
font-size: 12px;
border: 2px solid #6b7578;
padding: 1px;
}
.pinButtonContainerSelected {
max-width: 10%;
flex: 1;
font-size: 12px;
border: 2px solid #0865df;

6
dist/index.html vendored
View File

@ -13,14 +13,12 @@
<p>Drag images onto the page to upload them. Advance frames with arrow keys</p>
</div>
</div>
<!-- <div id="message" class="errorMessage"></div> -->
<div id="frameNumber" class="warning">
<p></p>
</div>
<!-- canvas -->
<div id="canvasStyle">
<canvas id="canvasImage" alt=""></canvas>
</div>
<div id="frameNumber" class="warning"></div>
<div id="frameViewer"></div>
<button id="addpin">Create New Pin</button>
<div id="pinContainer" class="pinContainer">
<div class="pinButtonContainerSelected" id="originPin"><p>Origin</p><button id="selectOrigin">Select</button>