adding removing pins, pin name reference

master
Beau Blyth 2019-09-30 21:40:16 -07:00
parent bf0e66c77c
commit def4998ec4
12 changed files with 232 additions and 53 deletions

View File

@ -1,6 +0,0 @@
export interface ICanvasData {
width: number;
height: number;
widthRatio: number;
heightRatio: number;
}

View File

@ -2,5 +2,5 @@ import { IFramePinData } from './IFramePinData';
export interface IFrame { export interface IFrame {
filename: string; filename: string;
pinData: IFramePinData[]; [index: number]: IFramePinData;
} }

View File

@ -0,0 +1,8 @@
export interface IProjectData {
currentFrame: number;
currentlySelectedPin: number;
width: number;
height: number;
widthRatio: number;
heightRatio: number;
}

View File

@ -1,25 +1,26 @@
import { IAnimationData } from './Interfaces/IAnimationData'; import { IAnimationData } from './Interfaces/IAnimationData';
import { ICanvasData } from './Interfaces/ICanvasData'; import { IProjectData } from './Interfaces/IProjectData';
import { IFramePinData } from './Interfaces/IFramePinData';
// I display the canvas and am clickable // I display the canvas and am clickable
export class CanvasHandler { export class CanvasHandler {
private canvasImage: HTMLCanvasElement; private canvasImage: HTMLCanvasElement;
private imageElement: HTMLImageElement; private imageElement: HTMLImageElement;
private animationData: IAnimationData; private animationData: IAnimationData;
private canvasData: ICanvasData; private projectData: IProjectData;
private orginInfo: HTMLElement; private orginInfo: HTMLElement;
private targetImageSize: number = 256; private targetImageSize: number = 256;
constructor( constructor(
animationData: IAnimationData, animationData: IAnimationData,
canvasData: ICanvasData, canvasData: IProjectData,
canvasImage: HTMLCanvasElement, canvasImage: HTMLCanvasElement,
imageElement: HTMLImageElement, imageElement: HTMLImageElement,
originInfo: HTMLElement originInfo: HTMLElement
) { ) {
this.animationData = animationData; this.animationData = animationData;
this.canvasData = canvasData; this.projectData = canvasData;
this.canvasImage = canvasImage; this.canvasImage = canvasImage;
this.imageElement = imageElement; this.imageElement = imageElement;
this.orginInfo = originInfo; this.orginInfo = originInfo;
@ -45,8 +46,8 @@ export class CanvasHandler {
} }
private UpdateCanvasDataSize() { private UpdateCanvasDataSize() {
this.canvasData.width = this.canvasImage.width; this.projectData.width = this.canvasImage.width;
this.canvasData.height = this.canvasImage.height; this.projectData.height = this.canvasImage.height;
} }
private mouseDown = (event: MouseEvent) => { private mouseDown = (event: MouseEvent) => {
@ -57,12 +58,25 @@ export class CanvasHandler {
const pixelX: number = Math.floor(event.offsetX / ratioWidth); const pixelX: number = Math.floor(event.offsetX / ratioWidth);
const pixelY: number = Math.floor(event.offsetY / ratioHeight); const pixelY: number = Math.floor(event.offsetY / ratioHeight);
console.log('CLICK X:' + pixelX + ' Y:' + pixelY); console.log('CLICK X:' + pixelX + ' Y:' + pixelY);
// update animation data if (this.projectData.currentlySelectedPin === 0) {
this.animationData.originX = pixelX; // update animation data
this.animationData.originY = pixelY; this.animationData.originX = pixelX;
this.animationData.originY = pixelY;
} else {
console.log('current pin id = ' + this.projectData.currentlySelectedPin);
const newPinData: IFramePinData = {
id: this.projectData.currentlySelectedPin,
x: pixelX,
y: pixelY
};
this.animationData.frames[this.projectData.currentFrame][
this.projectData.currentlySelectedPin
] = newPinData;
}
// update canvas data // update canvas data
this.canvasData.widthRatio = ratioWidth; this.projectData.widthRatio = ratioWidth;
this.canvasData.heightRatio = ratioHeight; this.projectData.heightRatio = ratioHeight;
// update origin number display // update origin number display
this.orginInfo.innerText = 'Origin X: ' + this.animationData.originX + ' Y: ' + this.animationData.originY; this.orginInfo.innerText = 'Origin X: ' + this.animationData.originX + ' Y: ' + this.animationData.originY;
}; };

View File

@ -1,5 +1,6 @@
import { IAnimationData } from './Interfaces/IAnimationData'; import { IAnimationData } from './Interfaces/IAnimationData';
import { ICanvasData } from './Interfaces/ICanvasData'; import { IProjectData } from './Interfaces/IProjectData';
import { IFramePinData } from './Interfaces/IFramePinData';
export class FrameHandler { export class FrameHandler {
private start: number = 0; private start: number = 0;
@ -7,7 +8,7 @@ export class FrameHandler {
private frameNumberDiv: HTMLElement; private frameNumberDiv: HTMLElement;
private animationData: IAnimationData; private animationData: IAnimationData;
private canvasData: ICanvasData; private canvasData: IProjectData;
private filenames: string[] = []; private filenames: string[] = [];
private currentFrame: number = 0; private currentFrame: number = 0;
@ -18,13 +19,16 @@ export class FrameHandler {
private imageElement: HTMLImageElement; private imageElement: HTMLImageElement;
private projectData: IProjectData;
constructor( constructor(
animationData: IAnimationData, animationData: IAnimationData,
canvasData: ICanvasData, canvasData: IProjectData,
htmlCanvasElement: HTMLCanvasElement, htmlCanvasElement: HTMLCanvasElement,
canvasContext: CanvasRenderingContext2D, canvasContext: CanvasRenderingContext2D,
frameNumberDiv: HTMLElement, frameNumberDiv: HTMLElement,
imageElement: HTMLImageElement imageElement: HTMLImageElement,
projectData: IProjectData
) { ) {
this.animationData = animationData; this.animationData = animationData;
this.canvasData = canvasData; this.canvasData = canvasData;
@ -33,6 +37,7 @@ export class FrameHandler {
this.frameNumberDiv = frameNumberDiv; this.frameNumberDiv = frameNumberDiv;
window.requestAnimationFrame(this.windowAnimationUpdate); window.requestAnimationFrame(this.windowAnimationUpdate);
this.imageElement = imageElement; this.imageElement = imageElement;
this.projectData = projectData;
} }
public GetCurrentFrame(): number { public GetCurrentFrame(): number {
@ -57,6 +62,7 @@ export class FrameHandler {
public GoToFrame(frame: number) { public GoToFrame(frame: number) {
this.currentFrame = frame; this.currentFrame = frame;
this.RefreshImage(); this.RefreshImage();
this.projectData.currentFrame = this.currentFrame;
} }
public TogglePlayingAnimation() { public TogglePlayingAnimation() {
@ -88,21 +94,37 @@ export class FrameHandler {
this.htmlCanvasElement.height this.htmlCanvasElement.height
); );
// draw origin + // draw origin +
this.canvasContext.strokeStyle = '#000000';
const originCursorSize: number = 500; const originCursorSize: number = 500;
const originX = this.animationData.originX * this.canvasData.widthRatio; const originX = this.animationData.originX;
const originY = this.animationData.originY * this.canvasData.heightRatio; const originY = this.animationData.originY;
this.canvasContext.beginPath(); this.DrawCrossHair(500, this.canvasContext, originX, originY);
this.canvasContext.moveTo(originX, originY - originCursorSize); // frame number update
this.canvasContext.lineTo(originX, originY + originCursorSize);
this.canvasContext.moveTo(originX - originCursorSize, originY);
this.canvasContext.lineTo(originX + originCursorSize, originY);
this.canvasContext.stroke();
this.frameNumberDiv.className = 'instruction'; this.frameNumberDiv.className = 'instruction';
this.frameNumberDiv.innerText = this.frameNumberDiv.innerText =
'Frame ' + (this.currentFrame + 1).toString() + ' / ' + this.filenames.length.toString(); 'Frame ' + (this.currentFrame + 1).toString() + ' / ' + this.filenames.length.toString();
// draw pins
for (let i = 0; i < 10; i++) {
this.canvasContext.strokeStyle = '#FF0000';
let currentSelectedPinData: IFramePinData = this.animationData.frames[this.projectData.currentFrame][i];
if (currentSelectedPinData !== null && currentSelectedPinData !== undefined) {
this.DrawCrossHair(50, this.canvasContext, currentSelectedPinData.x, currentSelectedPinData.y);
}
}
} }
} }
private DrawCrossHair(size: number, canvasContext: CanvasRenderingContext2D, x: number, y: number) {
x *= this.canvasData.widthRatio;
y *= this.canvasData.heightRatio;
canvasContext.beginPath();
canvasContext.moveTo(x, y - size);
canvasContext.lineTo(x, y + size);
canvasContext.moveTo(x - size, y);
canvasContext.lineTo(x + size, y);
canvasContext.stroke();
}
private windowAnimationUpdate = (timestamp: number) => { private windowAnimationUpdate = (timestamp: number) => {
if (this.start === 0) { if (this.start === 0) {
this.start = timestamp; this.start = timestamp;

View File

@ -4,7 +4,7 @@ import { CanvasHandler } from './canvas_handler';
import { FileHandler } from './file_handler'; import { FileHandler } from './file_handler';
import { FrameHandler } from './frame_handler'; import { FrameHandler } from './frame_handler';
import { IAnimationData } from './Interfaces/IAnimationData'; import { IAnimationData } from './Interfaces/IAnimationData';
import { ICanvasData } from './Interfaces/ICanvasData'; import { IProjectData } from './Interfaces/IProjectData';
import { IFrame } from './Interfaces/IFrame'; import { IFrame } from './Interfaces/IFrame';
import { PinHandler } from './pin_handler'; import { PinHandler } from './pin_handler';
@ -27,7 +27,7 @@ export class Page {
private canvasImage: HTMLCanvasElement; private canvasImage: HTMLCanvasElement;
private canvasContext: CanvasRenderingContext2DSettings; private canvasContext: CanvasRenderingContext2DSettings;
private canvasData: ICanvasData; private projectData: IProjectData;
private filenameInput: HTMLInputElement; private filenameInput: HTMLInputElement;
public Load() { public Load() {
@ -40,13 +40,14 @@ export class Page {
loop: true, loop: true,
frames: [ frames: [
{ {
filename: '', filename: ''
pinData: []
} }
] ]
}; };
// blank slate canvas data // blank slate canvas data
this.canvasData = { this.projectData = {
currentFrame: 0,
currentlySelectedPin: 0,
width: 0, width: 0,
height: 0, height: 0,
widthRatio: 0, widthRatio: 0,
@ -59,13 +60,17 @@ export class Page {
this.pinHandler = new PinHandler( this.pinHandler = new PinHandler(
document.getElementById('addpin') as HTMLElement, document.getElementById('addpin') as HTMLElement,
document.getElementById('pinSettings') as HTMLElement document.getElementById('pinSettings') as HTMLElement,
document.getElementById('pinContainer') as HTMLElement,
document.getElementById('originPin') as HTMLElement,
this.projectData,
this.animationData
); );
// setup canvas // setup canvas
this.canvasHandler = new CanvasHandler( this.canvasHandler = new CanvasHandler(
this.animationData, this.animationData,
this.canvasData, this.projectData,
canvasElement, canvasElement,
imageElement, imageElement,
document.getElementById('originInfo') as HTMLElement document.getElementById('originInfo') as HTMLElement
@ -74,11 +79,12 @@ export class Page {
// setup frame handler // setup frame handler
this.frameHandler = new FrameHandler( this.frameHandler = new FrameHandler(
this.animationData, this.animationData,
this.canvasData, this.projectData,
canvasElement, canvasElement,
canvasElement.getContext('2d')!, canvasElement.getContext('2d')!,
document.getElementById('frameNumber') as HTMLElement, document.getElementById('frameNumber') as HTMLElement,
imageElement imageElement,
this.projectData
); );
// input elements // input elements
@ -148,6 +154,8 @@ export class Page {
} }
case 83: { case 83: {
this.pinHandler.UpdateAnimationPinNames();
const zip = new JSZip(); const zip = new JSZip();
// name of project // name of project
const name = this.filenameInput.value; const name = this.filenameInput.value;
@ -183,8 +191,7 @@ export class Page {
for (let i = 0; i < event.dataTransfer!.files.length; i++) { for (let i = 0; i < event.dataTransfer!.files.length; i++) {
newFrames.push({ newFrames.push({
filename: event.dataTransfer!.files[i].name, filename: event.dataTransfer!.files[i].name
pinData: []
}); });
} }

View File

@ -1,26 +1,103 @@
import { IProjectData } from './Interfaces/IProjectData';
import { IPin } from './Interfaces/IPin';
import { IAnimationData } from './Interfaces/IAnimationData';
export class PinHandler { export class PinHandler {
private addPinButton: HTMLElement; private addPinButton: HTMLElement;
private pinSettingsDiv: HTMLElement; private pinSettingsDiv: HTMLElement;
private pins: number = 1; private pins: number = 1;
private pinContainer: HTMLElement;
private allPinContainers: HTMLElement[];
private projectData: IProjectData;
private animationData: IAnimationData;
constructor(addPinButton: HTMLElement, pinSettingsDiv: HTMLElement) { constructor(
addPinButton: HTMLElement,
pinSettingsDiv: HTMLElement,
pinContainer: HTMLElement,
originPin: HTMLElement,
projectData: IProjectData,
animationData: IAnimationData
) {
this.addPinButton = addPinButton; this.addPinButton = addPinButton;
this.pinSettingsDiv = pinSettingsDiv; this.pinSettingsDiv = pinSettingsDiv;
this.UpdatePinSettingsDiv(); this.pinContainer = pinContainer;
this.projectData = projectData;
this.animationData = animationData;
// add origin click behaviour
originPin.addEventListener('click', () => {
this.DeselectAllPinContainers();
originPin.className = 'pinButtonContainerSelected';
projectData.currentlySelectedPin = 0;
});
// put origin into pincontainer array
this.allPinContainers = [ originPin ];
// this.UpdatePinSettingsDiv();
this.addPinButton.addEventListener('click', this.AddPinButtonPressed); this.addPinButton.addEventListener('click', this.AddPinButtonPressed);
} }
private UpdatePinSettingsDiv() { public UpdateAnimationPinNames = () => {
let html: string = ''; const animationPinData: IPin[] = [];
for (let i = 0; i < this.pins; i++) { for (let i = 1; i < this.allPinContainers.length; i++) {
html += '<input type="text" id="pinname' + i + '" value="pinname' + i + '">'; console.log(this.allPinContainers[i].children);
let pinName: string = this.allPinContainers[i].getElementsByTagName('input')[0].value;
if (pinName !== null && pinName !== undefined) {
let newPinData: IPin = {
id: parseInt(this.allPinContainers[i].id.split('_')[1]),
name: pinName
};
animationPinData.push(newPinData);
}
} }
this.pinSettingsDiv.innerHTML = html; this.animationData.pins = animationPinData;
} console.log('updated animationPinData to ' + animationPinData);
};
private AddPinButtonPressed() { private UpdatePinSettingsDiv = () => {
this.pins += 1; // create info window div and append to pincontainer
const newDiv = document.createElement('div');
this.allPinContainers.push(newDiv);
this.pinContainer.appendChild(newDiv);
newDiv.id = 'pinID_' + this.pins.toString();
newDiv.className = 'pinButtonContainer';
// text input field for pin name
const newNameInput = document.createElement('input');
newNameInput.id = 'nameInput_' + this.pins.toString();
newDiv.appendChild(newNameInput);
newNameInput.value = 'PinName_' + this.pins.toString();
// button to remove pin
const removePinButton = document.createElement('button');
newDiv.appendChild(removePinButton);
removePinButton.textContent = 'X';
removePinButton.className = 'removeButton';
removePinButton.addEventListener('click', () => {
newDiv.remove();
});
// break
newDiv.appendChild(document.createElement('br'));
// select pin to place
const selectPinButton = document.createElement('button');
newDiv.appendChild(selectPinButton);
selectPinButton.textContent = 'Select';
selectPinButton.addEventListener('click', () => {
this.DeselectAllPinContainers();
newDiv.className = 'pinButtonContainerSelected';
this.projectData.currentlySelectedPin = parseInt(newDiv.id.split('_')[1]);
console.log('selected pin ' + this.projectData.currentlySelectedPin);
});
};
private DeselectAllPinContainers = () => {
for (let i = 0; i < this.allPinContainers.length; i++) {
this.allPinContainers[i].className = 'pinButtonContainer';
}
};
private AddPinButtonPressed = () => {
this.UpdatePinSettingsDiv(); this.UpdatePinSettingsDiv();
} this.pins += 1;
};
} }

View File

@ -42,3 +42,26 @@ body {
border: 2px solid #6b7578; border: 2px solid #6b7578;
image-rendering: pixelated; image-rendering: pixelated;
} }
.pinContainer {
display: flex;
flex-direction: row;
}
.pinButtonContainer {
flex: 1;
font-size: 12px;
border: 2px solid #6b7578;
padding: 1px;
}
.pinButtonContainerSelected {
flex: 1;
font-size: 12px;
border: 2px solid #0865df;
padding: 1px;
background-color: rgb(35, 75, 185);
}
.removeButton {
background-color: rgb(158, 15, 34);
color: rgb(227, 227, 236);
}

8
dist/bundle.js vendored Normal file

File diff suppressed because one or more lines are too long

5
dist/index.html vendored
View File

@ -22,7 +22,10 @@
<canvas id="canvasImage" alt=""></canvas> <canvas id="canvasImage" alt=""></canvas>
</div> </div>
<button id="addpin">Create New Pin</button> <button id="addpin">Create New Pin</button>
<div id="pinSettings"></div> <div id="pinContainer" class="pinContainer">
<div class="pinButtonContainerSelected" id="originPin"><p>Origin</p><button id="selectOrigin">Select</button>
</div>
</div>
<div id="settings"> <div id="settings">
Name: <input type = "text" id="filename"><br> Name: <input type = "text" id="filename"><br>
<div id = "originInfo">Click image to set Origin</div> <div id = "originInfo">Click image to set Origin</div>

1
help Normal file
View File

@ -0,0 +1 @@
pnpm run start:dev

22
pnpm-debug.log Normal file
View File

@ -0,0 +1,22 @@
{
"0 debug pnpm:scope": {
"selected": 1,
"workspacePrefix": null
},
"1 error pnpm": {
"message": {
"errno": 1,
"code": "ELIFECYCLE",
"pkgid": "animationtool@1.0.0",
"stage": "start:dev",
"script": "webpack-dev-server --config webpack/dev.config.js",
"pkgname": "animationtool"
},
"err": {
"name": "Error",
"message": "animationtool@1.0.0 start:dev: `webpack-dev-server --config webpack/dev.config.js`\nExit status 1",
"code": "ELIFECYCLE",
"stack": "Error: animationtool@1.0.0 start:dev: `webpack-dev-server --config webpack/dev.config.js`\nExit status 1\n at EventEmitter.proc.on (C:\\Users\\tekno\\AppData\\Roaming\\npm\\node_modules\\pnpm\\lib\\node_modules\\@zkochan\\npm-lifecycle\\index.js:302:16)\n at EventEmitter.emit (events.js:198:13)\n at ChildProcess.<anonymous> (C:\\Users\\tekno\\AppData\\Roaming\\npm\\node_modules\\pnpm\\lib\\node_modules\\@zkochan\\npm-lifecycle\\lib\\spawn.js:55:14)\n at ChildProcess.emit (events.js:198:13)\n at maybeClose (internal/child_process.js:982:16)\n at Process.ChildProcess._handle.onexit (internal/child_process.js:259:5)"
}
}
}