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

View File

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

View File

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

View File

@ -1,26 +1,103 @@
import { IProjectData } from './Interfaces/IProjectData';
import { IPin } from './Interfaces/IPin';
import { IAnimationData } from './Interfaces/IAnimationData';
export class PinHandler {
private addPinButton: HTMLElement;
private pinSettingsDiv: HTMLElement;
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.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);
}
private UpdatePinSettingsDiv() {
let html: string = '';
for (let i = 0; i < this.pins; i++) {
html += '<input type="text" id="pinname' + i + '" value="pinname' + i + '">';
public UpdateAnimationPinNames = () => {
const animationPinData: IPin[] = [];
for (let i = 1; i < this.allPinContainers.length; 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() {
this.pins += 1;
private UpdatePinSettingsDiv = () => {
// 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.pins += 1;
};
}

View File

@ -42,3 +42,26 @@ body {
border: 2px solid #6b7578;
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>
</div>
<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">
Name: <input type = "text" id="filename"><br>
<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)"
}
}
}