Skip to content
This repository has been archived by the owner on Jul 8, 2020. It is now read-only.

Commit

Permalink
Merge pull request #106 from comozilla/develop
Browse files Browse the repository at this point in the history
develop -> master (v1.1)
  • Loading branch information
shundroid committed May 17, 2016
2 parents c6e2e83 + da1e912 commit 1b47d63
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 52 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# parapara-projection-mapping

![](https://docs.google.com/drawings/d/1keQDc-fo5cvi54i6KeqGTSZlK0K9XBf_Np-ftDaUIaA/pub?w=2532&h=1407)

## 準備
### 必要なもの
- node.js
Expand Down Expand Up @@ -27,4 +29,5 @@ $ npm run build:browser-sync

browser-syncを使っています。
自動でブラウザが開くと思いますので、確認してください。
`js/build/`以下、`css/`以下、`index.html`を変更した際、ライブリロードされます。
`js/build/`以下、`css/`以下、`index.html`を変更した際、ライブリロードされます。

4 changes: 4 additions & 0 deletions css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ html, body {
border-radius: 20px;
position: relative;
}
#menu-thumbnails canvas {
width: 100%;
height: 100%;
}
#menu-thumbnails .thumbnail-selected {
border-color: cyan;
}
Expand Down
2 changes: 0 additions & 2 deletions js/canvas-model.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import eventPublisher from "./publisher";

// HTMLCanvasElementをラップし, canvasRenderingContext2Dに関する操作を提供する
function CanvasModel(element) {
this.element = element;
Expand Down
72 changes: 60 additions & 12 deletions js/frames-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,44 +5,92 @@ import CanvasModel from "./canvas-model";
// frame の追加・削除、currentFrameの切り替えをModel上で行う
function FramesController(canvas) {
let updateImageDataToNextData;
let updateCurrentFrameImageData;
this.frames = [];
this.currentFrameId = 0;
this.canvasModel = new CanvasModel(canvas);
updateImageDataToNextData = (frameId) => {
let beforeFrame = this.getCurrentFrame();
// beforeFrameは削除されている可能性がある
if (typeof beforeFrame !== "undefined") {
beforeFrame.imageData = this.canvasModel.getImageData();
}
updateCurrentFrameImageData();
this.currentFrameId = frameId;
this.canvasModel.setImageData(this.getCurrentFrame().imageData);
};
updateCurrentFrameImageData = () => {
let currentFrame = this.getCurrentFrame();
// currentFrameは削除されている可能性がある
if (typeof currentFrame !== "undefined") {
currentFrame.imageData = this.canvasModel.getImageData();
}
};

eventPublisher.subscribe("currentFrameId", updateImageDataToNextData);
eventPublisher.subscribe("openMenu", updateCurrentFrameImageData);
}

// パラメータ id : どこの後ろに追加するのか(今は実装していない)
FramesController.prototype.append = function(id) {
// パラメータ frameId : どこの後ろに追加するのか(今は実装していない)
FramesController.prototype.append = function(frameId) {
const frame = new Frame();
// 今はいいが、あとで splice に変える
this.frames.push(frame);
eventPublisher.publish("frames", this.frames);
eventPublisher.publish("frames", {
frames: this.frames,
action: "append",
actionFrame: this.frames.length - 1
});
};

FramesController.prototype.remove = function(id) {
FramesController.prototype.remove = function(frameId) {
if (this.frames.length <= 1) {
throw new Error("残りフレーム数が1なので、削除することができません。");
}
let nextCurrentFrameId = this.currentFrameId;
if (this.currentFrameId >= this.frames.length - 1) {
nextCurrentFrameId--;
}
this.frames.splice(id, 1);
this.frames.splice(frameId, 1);
this.canvasModel.setImageData(
this.getFrameById(nextCurrentFrameId).imageData);
eventPublisher.publish("frames", this.frames);
this.getFrameById(nextCurrentFrameId).imageData);
eventPublisher.publish("frames", {
frames: this.frames,
action: "remove",
actionFrame: frameId
});
eventPublisher.publish("currentFrameId", nextCurrentFrameId);
};

FramesController.prototype.moveFrame = function(frameId, moveDirection) {
this.getCurrentFrame().imageData = this.canvasModel.getImageData();
if (moveDirection === "up") {
if (frameId <= 0) {
// frameIdが0以下だった場合は、上と交換する事ができない
return;
}
let frameTmp = this.frames[frameId - 1];
this.frames[frameId - 1] = this.frames[frameId];
this.frames[frameId] = frameTmp;
// currentFrameの内容が変わった可能性があるため、再描画する
this.canvasModel.setImageData(this.frames[this.currentFrameId].imageData);
eventPublisher.publish("frames", {
frames: this.frames,
action: "moveUp",
actionFrame: frameId
});
} else if (moveDirection === "down") {
if (frameId >= this.frames.length - 1) {
return;
}
let frameTmp = this.frames[frameId + 1];
this.frames[frameId + 1] = this.frames[frameId];
this.frames[frameId] = frameTmp;

this.canvasModel.setImageData(this.frames[this.currentFrameId].imageData);
eventPublisher.publish("frames", {
frames: this.frames,
action: "moveDown",
actionFrame: frameId
});
}
};

FramesController.prototype.setCurrentFrame = function(frameId) {
eventPublisher.publish("currentFrameId", frameId);
};
Expand Down
4 changes: 2 additions & 2 deletions js/view/color-picker-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ function ColorPickerView(elem) {
if (selectedPalette !== null) {
selectedPalette.classList.remove("selected-palette");
}
nextPalette = this.element.querySelector("[data-color=\"" + color + "\"]");
nextPalette = this.element.querySelector(`[data-color=\"${color}\"]`);
if (nextPalette !== null) {
nextPalette.classList.add("selected-palette");
}
Expand All @@ -20,7 +20,7 @@ ColorPickerView.prototype.addPalette = function(color) {
let palette;

if (!isColor(color)) {
throw new Error("不正な色が指定されました。:" + color);
throw new Error(`不正な色が指定されました。:${color}`);
}

palette = document.createElement("li");
Expand Down
3 changes: 3 additions & 0 deletions js/view/menu-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ function MenuView() {
});
document.getElementById("menu-collapsible-btn")
.addEventListener("click", () => {
if (!this.isOpen) {
eventPublisher.publish("openMenu", false);
}
if (this.isPlaying) {
eventPublisher.publish("isPlaying", false);
} else {
Expand Down
166 changes: 131 additions & 35 deletions js/view/sequence-view.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,31 @@
import eventPublisher from "./../publisher";

const DISABLE_FRAME_ID = -1;

function SequencePanel(elem, framesController) {
this.elem = elem;
this.maxFrameId = 0;
this.currentFrameId = 0;
this.framesController = framesController;
eventPublisher.subscribe("currentFrameId", (currentFrameId) => {
this.currentFrameId = currentFrameId;
this.setCurrentFrame(currentFrameId);
});
eventPublisher.subscribe("frames", (frames) => {
this.clear();
for (this.maxFrameId = 0;
this.maxFrameId < frames.length; this.maxFrameId++) {
this.append(this.maxFrameId);
eventPublisher.subscribe("frames", (frameDetail) => {
if (frameDetail.action === "append") {
this.append();
} else if (frameDetail.action === "remove") {
this.remove(frameDetail.actionFrame);
} else if (frameDetail.action === "moveUp") {
this.moveUp(frameDetail.actionFrame);
} else if (frameDetail.action === "moveDown") {
this.moveDown(frameDetail.actionFrame);
}
this.maxFrameId--; // 1つ多くなってしまうから
this.setCurrentFrame(this.currentFrameId);
});
eventPublisher.subscribe("openMenu:after", () => {
this.updateThumbnail(this.framesController.currentFrameId);
});
document.getElementById("sequence-add-btn").addEventListener("click", () => {
this.framesController.append(++this.maxFrameId);
this.framesController.append();
});
}

Expand All @@ -37,60 +43,150 @@ function SequencePanel(elem, framesController) {
</div>
</div>
*/
function getFrameTemplate(
frameId,
mousedownFrameCallback,
mousedownRemoveCallback) {
SequencePanel.prototype.getFrameTemplate = function(frameId) {
let frame = document.createElement("div");
let frameDeleteBtn = document.createElement("button");
let frameUpBtn = document.createElement("button");
let frameDownBtn = document.createElement("button");
let previewCanvas = document.createElement("canvas");
frame.dataset.frameIndex = frameId;
frame.classList.add("thumbnail");
frame.addEventListener("mousedown", mousedownFrameCallback);
frame.addEventListener("mousedown", (event) => {
// 子要素のmousedownによる発生を防ぐ
if (event.target.nodeName === "CANVAS") {
eventPublisher.publish("currentFrameId", frame.dataset.frameIndex);
this.setCurrentFrame(frame);
}
});
frameDeleteBtn.classList.add("frame-delete");
frameUpBtn.classList.add("frame-up");
frameUpBtn.addEventListener("mousedown", () => {
this.framesController.moveFrame(parseInt(frame.dataset.frameIndex), "up");
});
frameDownBtn.classList.add("frame-down");
frameDownBtn.addEventListener("mousedown", () => {
this.framesController.moveFrame(parseInt(frame.dataset.frameIndex), "down");
});
frameDeleteBtn.innerHTML = "<i class=\"fa fa-times\"></i>";
frameDeleteBtn.addEventListener("mousedown", mousedownRemoveCallback);
frameDeleteBtn.addEventListener("mousedown", () => {
// フレーム数が1つの時は、エラーになるため削除しない。
if (this.getMaxFrameId() > 0) {
this.framesController.remove(frame.dataset.frameIndex);
}
});
frameUpBtn.innerHTML = "<i class=\"fa fa-sort-asc\"></i>";
frameDownBtn.innerHTML = "<i class=\"fa fa-sort-desc\"></i>";
frame.appendChild(frameDeleteBtn);
frame.appendChild(frameUpBtn);
frame.appendChild(frameDownBtn);

frame.appendChild(previewCanvas);
return frame;
}
};

SequencePanel.prototype.appendToggleFrameEffect = function(frame, isAppend) {
let direction = isAppend ? "alternate" : "alternate-reverse";
frame.animate(
[{ transformOrigin: "0px 0px", transform: "scaleY(0)" },
{ transformOrigin: "0px 100%", transform: "scaleY(1)" }],
{ direction: direction, duration: 250,
fill: "both", easing: "ease-in-out" });
};
SequencePanel.prototype.appendMoveFrameEffect = function(
frame, isMoveDown, frameHeight) {
let beginningValue = (isMoveDown ? "" : "-") + frameHeight;
frame.animate(
[{ transform: `translateY(${beginningValue})` },
{ transform: "translateY(0px)" }],
{ direction: "alternate", duration: 250,
fill: "both", easing: "ease-in-out" });
};

SequencePanel.prototype.updateThumbnail = function(frameId) {
let canvas = this.elem.querySelector(
`.thumbnail[data-frame-index=\"${frameId}\"] canvas`);
let imageData = this.framesController.frames[frameId].imageData;
if (this.framesController.currentFrameId === frameId) {
imageData = this.framesController.canvasModel.getImageData();
} else {
imageData = this.framesController.frames[frameId].imageData;
}
if (imageData !== null) {
canvas.width = imageData.width;
canvas.height = imageData.height;
let ctx = canvas.getContext("2d");
ctx.putImageData(imageData, 0, 0);
}
};

SequencePanel.prototype.append = function() {
let newFrame = this.getFrameTemplate(0);
// 追加アニメーションを実行
this.appendToggleFrameEffect(newFrame, true);

SequencePanel.prototype.append = function(frameId) {
let newFrame = getFrameTemplate(frameId, (event) => {
// 子要素のmousedownによる発生を防ぐ
if (event.target.classList.contains("thumbnail")) {
eventPublisher.publish("currentFrameId", frameId);
this.setCurrentFrame(newFrame);
}
}, () => {
// フレーム数が1つの時は、エラーになるため削除しない。
if (this.maxFrameId > 0) {
this.framesController.remove(frameId);
}
});
this.elem.appendChild(newFrame);
this.renumber();
this.updateThumbnail(this.framesController.frames.length - 1);
};

SequencePanel.prototype.clear = function() {
this.elem.innerHTML = "";
};

SequencePanel.prototype.remove = function(frame) {
SequencePanel.prototype.remove = function(frameId) {
let frame = this.elem.querySelector(`[data-frame-index=\"${frameId}\"]`);
frame.dataset.frameIndex = DISABLE_FRAME_ID;
this.appendToggleFrameEffect(frame, false);

this.renumber();

setTimeout(() => {
this.elem.removeChild(frame);
}, 250);
};

SequencePanel.prototype.renumber = function() {
let children = this.elem.children;
let disableFrameCount = 0;
let childNode;
let index = 0;
while (
typeof (childNode = children[index + disableFrameCount]) !== "undefined") {
if (typeof childNode.dataset === "undefined" ||
parseInt(childNode.dataset.frameIndex) === -1) {
disableFrameCount++;
continue;
}
childNode.dataset.frameIndex = index++;
}
this.setCurrentFrame(this.currentFrameId);
};

SequencePanel.prototype.moveUp = function() {
// TODO
SequencePanel.prototype.getMaxFrameId = function() {
return this.elem.children.length - 1;
};

SequencePanel.prototype.moveDown = function() {
// TODO
SequencePanel.prototype.moveUp = function(frameId) {
// 表示上では、frameIdの1つ上の要素を下にしているのと同じである。
this.moveDown(frameId - 1);
};

SequencePanel.prototype.moveDown = function(frameId) {
let moveDownFrame =
this.elem.querySelector(`[data-frame-index=\"${frameId}\"]`);
let moveUpFrame =
this.elem.querySelector(`[data-frame-index=\"${(frameId + 1)}\"]`);
this.elem.removeChild(moveDownFrame);
this.elem.insertBefore(moveDownFrame, moveUpFrame);

this.renumber();

this.appendMoveFrameEffect(moveDownFrame, true,
getComputedStyle(moveUpFrame).height);
this.appendMoveFrameEffect(moveUpFrame, false,
getComputedStyle(moveDownFrame).height);

this.updateThumbnail(frameId);
this.updateThumbnail(frameId + 1);
};

SequencePanel.prototype.setCurrentFrame = function(frameIndex) {
Expand Down

0 comments on commit 1b47d63

Please sign in to comment.