マウスイベント周りの問題、前回Regroupの時はかなり複雑になってから自覚したのでしっかり理解することができなかったが、今回は理解できた
人間にとって好ましい、自然な、「意味の塊」は左のようなもの
しかし現実にはブラウザの仕様によって
Regroupの時はすべてCanvas要素の上で操作されることもあって全部mousedown開始だった
そこでこうした
一見良さそうに見えるがダメ
それを踏まえて今回のこの状況をどう整理すればいいか
これを踏まえて今回どうするか
「選択範囲の移動」と「グループ内の付箋を外に出す」を実装してテストケースを書いてからリファクタリングする
2021-07-21 一晩寝て気づいたこと
状態はテストの対象になるべき
今はローカル変数が状態を持っているが、これをグローバルにする before ts
let isDragging = false;
export const onMouseDown = (...) => {
isDragging = true;
...
};
export const onMouseMove = (...) => {
if (isDragging) {
...
}
};
export const onMouseUp = (...) => {
if (isDragging) {
...
isDragging = false;
}
};
after ts
export const onMouseDown = (...) => {
updateGlobal((g) => {
...
g.mouseState = "selecting";
});
};
export const onMouseMove = (...) => {
const g = getGlobal();
if (g.mouseState === "selecting") {
...
}
};
export const onMouseUp = (...) => {
const g = getGlobal();
if (g.mouseState === "selecting") {
updateGlobal((g) => {
...
g.mouseState = "selecting"; // intentional bug, should be ""
});
}
};
test test.ts
cy.get("#canvas").trigger("mousedown", 50, 100);
cy.getGlobal((g) => g.mouseState).should("to.eql", "selecting");
cy.get("#canvas").trigger("mouseup", 300, 400);
cy.getGlobal((g) => g.mouseState).should("to.eql", ""); // intentional fail
これでおかしな状態になってる時に検知できるようになった
昨日の「dragstartの前にmousedownが来ることに気付いてなかった」をテストケースで検証 test.ts
cy.testid("1").trigger("dragstart", "center");
cy.getGlobal((g) => g.mouseState).should("to.eql", "");
cy.get("#canvas").trigger("drop", 250, 250);
これでfailするかと思ったら、しない、なるほど
これを現実のイベントと同じようにテストするとこうなるか test.ts
it("is not selecting", () => {
cy.testid("1").trigger("mousedown", "center");
cy.testid("1").trigger("mousemove", "center");
cy.testid("1").trigger("dragstart", "center");
cy.getGlobal((g) => g.mouseState).should("to.eql", "");
cy.get("#canvas").trigger("drop", 250, 250);
});
これは期待通りにfailする で、stopPropagationして期待通りに動くことを確認done
ここまではいい。次は朝気づいた「選択後」の状態について
「選択されてないもの」のopacityを下げることで選択されたものをハイライトすることにした
あー、ダメだ、選択範囲の表示をドラッグと選択されたオブジェクトを包むdivが分かれたら「選択範囲の表示」をドラッグしても選択されたオブジェクトが動かないじゃん…
複数個選択してドラッグで移動するところまではできたが「選択範囲の表示」が移動してない
できた
テストケースを書いた結果、期待した位置から縦方向に2ピクセルだけズレてることが明らかになった(苦笑
cy.getGlobal((g) => g.selected_items).should("to.eql", items);
cy.getGlobal((g) => items.map((id) => g.itemStore[id].position)).should(
"to.eql",
[
[0, 0],
[0, 200],
[200, 0],
[200, 200],
]
);
cy.get("#selection-view").trigger("dragstart", 0, 2); // misterious 2px
cy.get("#canvas").trigger("drop", 100, 100);
cy.getGlobal((g) => items.map((id) => g.itemStore[id].position)).should(
"to.eql",
[
[-50, -50],
[-50, 150],
[150, -50],
[150, 150],
]
);