jonigata commited on
Commit
1d98bca
·
1 Parent(s): 2cd429d

add undo/redo

Browse files
Files changed (1) hide show
  1. static/poseEditor.js +59 -12
static/poseEditor.js CHANGED
@@ -10,11 +10,13 @@ function distSq(p0, p1) {
10
  return (p0[0] - p1[0]) ** 2 + (p0[1] - p1[1]) ** 2;
11
  }
12
 
13
- // poseDataの形式:[[x1, y1], [x2, y2], ...]
 
 
14
  let poseData = [];
15
 
16
  // サンプルデータ
17
- const sampleCandidateSource = [[235, 158],[234, 220],[193, 222],[138, 263],[89, 308],[276, 220],[325, 264],[375, 309],[207, 347],[203, 433],[199, 523],[261, 347],[262, 430],[261, 522],[227, 148],[245, 148],[208, 158],[258, 154]];
18
  const sampleSubsetElementSource = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17];
19
 
20
  // const sampleCandidateSource = [[618.00, 0.00], [618.00, 44.00], [304.00, 81.00], [482.00, 96.00], [66.00, 270.00], [171.00, 280.00], [618.00, 82.00], [307.00, 112.00], [460.00, 143.00], [0.00, 301.00], [65.00, 301.00], [172.00, 303.00], [584.00, 86.00], [275.00, 119.00], [420.00, 139.00], [0.00, 301.00], [41.00, 301.00], [144.00, 303.00], [544.00, 131.00], [348.00, 139.00], [262.00, 160.00], [0.00, 337.00], [52.00, 339.00], [130.00, 348.00], [570.00, 175.00], [283.00, 177.00], [78.00, 338.00], [172.00, 380.00], [651.00, 78.00], [338.00, 111.00], [505.00, 144.00], [92.00, 301.00], [198.00, 305.00], [661.00, 132.00], [349.00, 156.00], [541.00, 179.00], [106.00, 336.00], [203.00, 348.00], [305.00, 159.00], [665.00, 160.00], [563.00, 192.00], [80.00, 343.00], [181.00, 385.00], [614.00, 205.00], [291.00, 220.00], [432.00, 320.00], [152.00, 372.00], [43.00, 380.00], [0.00, 386.00], [623.00, 281.00], [306.00, 290.00], [92.00, 357.00], [509.00, 434.00], [304.00, 357.00], [622.00, 368.00], [47.00, 394.00], [0.00, 395.00], [142.00, 405.00], [535.00, 565.00], [655.00, 200.00], [337.00, 217.00], [467.00, 322.00], [191.00, 372.00], [83.00, 375.00], [344.00, 282.00], [655.00, 282.00], [103.00, 343.00], [237.00, 368.00], [22.00, 377.00], [0.00, 379.00], [460.00, 459.00], [305.00, 352.00], [638.00, 355.00], [0.00, 401.00], [110.00, 412.00], [411.00, 570.00], [608.00, 0.00], [608.00, 40.00], [297.00, 75.00], [469.00, 84.00], [0.00, 261.00], [58.00, 263.00], [165.00, 275.00], [625.00, 0.00], [625.00, 39.00], [309.00, 74.00], [486.00, 83.00], [71.00, 264.00], [180.00, 276.00], [599.00, 0.00], [599.00, 44.00], [284.00, 80.00], [440.00, 93.00], [48.00, 271.00], [0.00, 272.00], [157.00, 277.00], [634.00, 0.00], [633.00, 41.00], [319.00, 77.00], [79.00, 269.00], [190.00, 277.00]];
@@ -41,6 +43,13 @@ function addPerson() {
41
  sampleCandidateSource.map(point => [point[0] + dx, point[1] + dy]),
42
  sampleSubsetElementSource));
43
 
 
 
 
 
 
 
 
44
  Redraw();
45
  }
46
 
@@ -163,6 +172,33 @@ let dragMarks = [];
163
  let dragMode = "";
164
  let rotateBaseVector = null;
165
  let history = [];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
 
167
  function getCanvasPosition(event) {
168
  const rect = canvas.getBoundingClientRect();
@@ -186,6 +222,11 @@ function handleMouseDown(event) {
186
  const p = getCanvasPosition(event);
187
  const [personIndex, nodeIndex, minDist] = getNearestNode(p);
188
 
 
 
 
 
 
189
  // ドラッグ処理の開始
190
  dragStart = p;
191
  dragMarks = poseData.map(pose => pose.map(node => false));
@@ -202,7 +243,6 @@ function handleMouseDown(event) {
202
  dragMode = "rotate";
203
  rotateBaseVector = [0, 0];
204
  }
205
- console.log(dragMode);
206
  } else if (keyDownFlags["Space"]) {
207
  dragMarks[personIndex] =
208
  dragMarks[personIndex].map(
@@ -222,14 +262,14 @@ function handleMouseMove(event) {
222
  if (isDragging) {
223
  const p = getCanvasPosition(event);
224
  const dragOffset = [p[0] - dragStart[0], p[1] - dragStart[1]];
225
- const lastPoseData = history[history.length - 1];
226
 
227
  if (dragMode == "scale") {
228
  // 拡大縮小
229
  let xScale = 1 + dragOffset[0] / canvas.width;
230
  let yScale = 1 + dragOffset[0] / canvas.height;
231
  forEachMarkedNodes((i, j, node) => {
232
- const lp = lastPoseData[i][j];
233
  node[0] = (lp[0] - dragStart[0]) * xScale + dragStart[0];
234
  node[1] = (lp[1] - dragStart[1]) * yScale + dragStart[1];
235
  });
@@ -244,7 +284,7 @@ function handleMouseMove(event) {
244
  // 回転
245
  let angle = directedAngleTo(rotateBaseVector, dragOffset);
246
  forEachMarkedNodes((i, j, node) => {
247
- const lp = lastPoseData[i][j];
248
  let x = lp[0] - dragStart[0];
249
  let y = lp[1] - dragStart[1];
250
  let sin = Math.sin(angle);
@@ -255,7 +295,7 @@ function handleMouseMove(event) {
255
  } else if (dragMode == "move") {
256
  // 移動
257
  forEachMarkedNodes((i, j, node) => {
258
- const lp = lastPoseData[i][j];
259
  node[0] = lp[0] + dragOffset[0];
260
  node[1] = lp[1] + dragOffset[1];
261
  });
@@ -266,9 +306,9 @@ function handleMouseMove(event) {
266
  }
267
 
268
  function handleMouseUp(event) {
269
- isDragging = false;
270
- history.push(JSON.parse(JSON.stringify(poseData)));
271
- Redraw();
272
  }
273
 
274
  function ModifyDragRange(delta) { dragRange = Math.max(dragRangeDelta, Math.min(512, dragRange + delta)); }
@@ -289,10 +329,17 @@ document.addEventListener("keydown", (event) => {
289
  });
290
  document.addEventListener("keyup", (event) => {
291
  keyDownFlags[event.code] = false;
292
- Redraw();
293
  if (event.code == "KeyA") {
294
  addPerson();
295
  }
 
 
 
 
 
 
 
 
296
  });
297
 
298
  function initializePose(jsonData,w,h) {
@@ -302,7 +349,7 @@ function initializePose(jsonData,w,h) {
302
  } else {
303
  poseData = makePoseDataFromCandidateAndSubset(sampleCandidateSource, [sampleSubsetElementSource]);
304
  }
305
- history.push(JSON.parse(JSON.stringify(poseData)));
306
 
307
  canvas = document.getElementById('canvas');
308
  ctx = canvas.getContext('2d');
 
10
  return (p0[0] - p1[0]) ** 2 + (p0[1] - p1[1]) ** 2;
11
  }
12
 
13
+ // poseDataの形式:[[[x1, y1], [x2, y2], ...]]
14
+ // 各要素が人間
15
+ // 人間の各要素が関節
16
  let poseData = [];
17
 
18
  // サンプルデータ
19
+ const sampleCandidateSource = [[235, 158],[234, 220],[193, 222],[138, 263],[89, 308],[276, 220],[325, 264],[375, 309],[207, 347],[203, 433],[199, 523],[261, 347],[262, 430],[261, 522],[227, 148],[245, 148],[208, 158],[258, 154]].map((p) => [p[0], p[1] - 70]);
20
  const sampleSubsetElementSource = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17];
21
 
22
  // const sampleCandidateSource = [[618.00, 0.00], [618.00, 44.00], [304.00, 81.00], [482.00, 96.00], [66.00, 270.00], [171.00, 280.00], [618.00, 82.00], [307.00, 112.00], [460.00, 143.00], [0.00, 301.00], [65.00, 301.00], [172.00, 303.00], [584.00, 86.00], [275.00, 119.00], [420.00, 139.00], [0.00, 301.00], [41.00, 301.00], [144.00, 303.00], [544.00, 131.00], [348.00, 139.00], [262.00, 160.00], [0.00, 337.00], [52.00, 339.00], [130.00, 348.00], [570.00, 175.00], [283.00, 177.00], [78.00, 338.00], [172.00, 380.00], [651.00, 78.00], [338.00, 111.00], [505.00, 144.00], [92.00, 301.00], [198.00, 305.00], [661.00, 132.00], [349.00, 156.00], [541.00, 179.00], [106.00, 336.00], [203.00, 348.00], [305.00, 159.00], [665.00, 160.00], [563.00, 192.00], [80.00, 343.00], [181.00, 385.00], [614.00, 205.00], [291.00, 220.00], [432.00, 320.00], [152.00, 372.00], [43.00, 380.00], [0.00, 386.00], [623.00, 281.00], [306.00, 290.00], [92.00, 357.00], [509.00, 434.00], [304.00, 357.00], [622.00, 368.00], [47.00, 394.00], [0.00, 395.00], [142.00, 405.00], [535.00, 565.00], [655.00, 200.00], [337.00, 217.00], [467.00, 322.00], [191.00, 372.00], [83.00, 375.00], [344.00, 282.00], [655.00, 282.00], [103.00, 343.00], [237.00, 368.00], [22.00, 377.00], [0.00, 379.00], [460.00, 459.00], [305.00, 352.00], [638.00, 355.00], [0.00, 401.00], [110.00, 412.00], [411.00, 570.00], [608.00, 0.00], [608.00, 40.00], [297.00, 75.00], [469.00, 84.00], [0.00, 261.00], [58.00, 263.00], [165.00, 275.00], [625.00, 0.00], [625.00, 39.00], [309.00, 74.00], [486.00, 83.00], [71.00, 264.00], [180.00, 276.00], [599.00, 0.00], [599.00, 44.00], [284.00, 80.00], [440.00, 93.00], [48.00, 271.00], [0.00, 272.00], [157.00, 277.00], [634.00, 0.00], [633.00, 41.00], [319.00, 77.00], [79.00, 269.00], [190.00, 277.00]];
 
43
  sampleCandidateSource.map(point => [point[0] + dx, point[1] + dy]),
44
  sampleSubsetElementSource));
45
 
46
+ addHistory();
47
+ Redraw();
48
+ }
49
+
50
+ function removePerson(personIndex) {
51
+ poseData.splice(personIndex, 1);
52
+ addHistory();
53
  Redraw();
54
  }
55
 
 
172
  let dragMode = "";
173
  let rotateBaseVector = null;
174
  let history = [];
175
+ let historyIndex = 0;
176
+
177
+ function addHistory() {
178
+ history = history.slice(0, historyIndex);
179
+ history.push(JSON.parse(JSON.stringify(poseData)));
180
+ historyIndex = history.length;
181
+ }
182
+
183
+ function undo() {
184
+ if (1 < historyIndex) {
185
+ historyIndex--;
186
+ poseData = deepCopy(history[historyIndex-1]);
187
+ Redraw();
188
+ }
189
+ }
190
+
191
+ function redo() {
192
+ if (historyIndex < history.length) {
193
+ historyIndex++;
194
+ poseData = deepCopy(history[historyIndex-1]);
195
+ Redraw();
196
+ }
197
+ }
198
+
199
+ function fetchLatestPoseData() {
200
+ return history[historyIndex-1];
201
+ }
202
 
203
  function getCanvasPosition(event) {
204
  const rect = canvas.getBoundingClientRect();
 
222
  const p = getCanvasPosition(event);
223
  const [personIndex, nodeIndex, minDist] = getNearestNode(p);
224
 
225
+ if (keyDownFlags["KeyQ"]) {
226
+ removePerson(personIndex);
227
+ return;
228
+ }
229
+
230
  // ドラッグ処理の開始
231
  dragStart = p;
232
  dragMarks = poseData.map(pose => pose.map(node => false));
 
243
  dragMode = "rotate";
244
  rotateBaseVector = [0, 0];
245
  }
 
246
  } else if (keyDownFlags["Space"]) {
247
  dragMarks[personIndex] =
248
  dragMarks[personIndex].map(
 
262
  if (isDragging) {
263
  const p = getCanvasPosition(event);
264
  const dragOffset = [p[0] - dragStart[0], p[1] - dragStart[1]];
265
+ const latestPoseData = fetchLatestPoseData();
266
 
267
  if (dragMode == "scale") {
268
  // 拡大縮小
269
  let xScale = 1 + dragOffset[0] / canvas.width;
270
  let yScale = 1 + dragOffset[0] / canvas.height;
271
  forEachMarkedNodes((i, j, node) => {
272
+ const lp = latestPoseData[i][j];
273
  node[0] = (lp[0] - dragStart[0]) * xScale + dragStart[0];
274
  node[1] = (lp[1] - dragStart[1]) * yScale + dragStart[1];
275
  });
 
284
  // 回転
285
  let angle = directedAngleTo(rotateBaseVector, dragOffset);
286
  forEachMarkedNodes((i, j, node) => {
287
+ const lp = latestPoseData[i][j];
288
  let x = lp[0] - dragStart[0];
289
  let y = lp[1] - dragStart[1];
290
  let sin = Math.sin(angle);
 
295
  } else if (dragMode == "move") {
296
  // 移動
297
  forEachMarkedNodes((i, j, node) => {
298
+ const lp = latestPoseData[i][j];
299
  node[0] = lp[0] + dragOffset[0];
300
  node[1] = lp[1] + dragOffset[1];
301
  });
 
306
  }
307
 
308
  function handleMouseUp(event) {
309
+ isDragging = false;
310
+ addHistory();
311
+ Redraw();
312
  }
313
 
314
  function ModifyDragRange(delta) { dragRange = Math.max(dragRangeDelta, Math.min(512, dragRange + delta)); }
 
329
  });
330
  document.addEventListener("keyup", (event) => {
331
  keyDownFlags[event.code] = false;
 
332
  if (event.code == "KeyA") {
333
  addPerson();
334
  }
335
+ if (event.ctrlKey && event.code == "KeyZ") {
336
+ if (event.shiftKey) {
337
+ redo();
338
+ } else {
339
+ undo();
340
+ }
341
+ }
342
+ Redraw();
343
  });
344
 
345
  function initializePose(jsonData,w,h) {
 
349
  } else {
350
  poseData = makePoseDataFromCandidateAndSubset(sampleCandidateSource, [sampleSubsetElementSource]);
351
  }
352
+ addHistory();
353
 
354
  canvas = document.getElementById('canvas');
355
  ctx = canvas.getContext('2d');