demo 演示記錄鼠標在一個區域內的動做,並記錄下來。點擊回放時,按時序回放動做,包括移動,點擊,拖拽html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>鼠標事件記錄並回放</title> <style> * { margin: 0; padding: 0; } .container { display: flex; height: 600px; } .ctrls { display: flex; } .ctrls div { flex: 1 1 auto; } .p-action, .p-repay { width: 100%; height: 100%; position: relative; display: flex; flex-wrap: wrap; flex-direction: row; } .p-action { background: #f0f0f0; } .p-repay { background: #5aab94; } .mouse-img { width: 30px; position: absolute; left: 0; top: 0; } .btn { width: 60px; height: 30px; line-height: 2em; margin: 2em; background-color: #eee; display: flex; justify-content: center; align-items: center; } .btn.hover { background-color: #888888; } .metas { position: absolute; /* bottom: 40px; left: 40px; */ } .metas img { width: 40px; left: 0px; top: 480px; position: absolute; } .metas .meta2 { left: 60px; } .metas .meta3 { left: 120px; } .metas .meta4 { left: 180px; } .metas .meta5 { left: 240px; } .metas .meta6 { left: 300px; } </style> </head> <body> <div class="ctrls"> <button class="btn" onclick="start()">開始記錄</button> <button class="btn" onclick="replay()">開始播放</button> </div> <div class="container"> <div class="p-action"> <button class="btn btn1" onclick="btnClicked(1)">button1</button> <button class="btn btn2" onclick="btnClicked(2)">button2</button> <button class="btn btn3" onclick="btnClicked(3)">button3</button> <button class="btn btn4" onclick="btnClicked(4)">button4</button> <div class="metas"> <img class="meta1" src="./square.png" alt=""> <img class="meta2" src="./circle.png" alt=""> <img class="meta3" src="./triangle.png" alt=""> <img class="meta4" src="./square.png" alt=""> <img class="meta5" src="./circle.png" alt=""> <img class="meta6" src="./triangle.png" alt=""> </div> <img class="mouse-img" style="left:0;top:0;display: none;" src="./timg.png" alt=""> </div> <!-- <div class="p-repay"> <button class="btn btn-r-1" onclick="btnClicked(1)">button1</button> <button class="btn btn-r-2" onclick="btnClicked(2)">button2</button> <button class="btn btn-r-3" onclick="btnClicked(3)">button3</button> <button class="btn btn-r-4" onclick="btnClicked(4)">button4</button> <div class="metas"> <img class="meta-1-r" src="./square.png" alt=""> <img class="meta-2-r" src="./circle.png" alt=""> <img class="meta-3-r" src="./triangle.png" alt=""> <img class="meta-4-r" src="./square.png" alt=""> <img class="meta-5-r" src="./circle.png" alt=""> <img class="meta-6-r" src="./triangle.png" alt=""> </div> <img class="mouse-img" style="left:0;top:0;" src="./timg.png" alt=""> </div> --> </div> </body> <script> const eventL = []; const rootEl = document.getElementsByClassName("p-action")[0]; const rootElTop = rootEl.getBoundingClientRect().y, rootElLeft = rootEl.getBoundingClientRect().x; const mouseImg = document.getElementsByClassName("mouse-img")[0]; let startTime; let replayLastEvtTime = 0; // 上一個事件的時間(用於計算下一次事件須要等待時間) let isMouseDown = false; // 鼠標是否按下去 // 頁面上可操做的元素 const metaList = [ { className: "meta1", points: [[40, 480], [80, 480], [80, 520], [40, 520]] }, { className: "meta2", points: [[60, 480], [100, 480], [100, 520], [60, 520]] }, { className: "meta3", points: [[120, 480], [160, 480], [160, 520], [100, 520]] }, { className: "meta4", points: [[180, 480], [220, 480], [220, 520], [180, 520]] }, { className: "meta5", points: [[240, 480], [280, 480], [280, 520], [240, 520]] }, { className: "meta6", points: [[280, 480], [320, 480], [320, 520], [280, 520]] }, ]; // 鼠標按下事件 function mouseDown() { isMouseDown = true; } // 記錄鼠標軌跡 function mouseMove(e) { const x = e.clientX - rootElLeft, y = e.clientY - rootElTop; console.log("x,y:", x, y) store({ evtType: isMouseDown ? "drag" : "mousemove", data: { x: x, y: y } }); // 執行當前元素拖拽動做 // if (isMouseDown) { // const meta = getDragMeta([x, y]); // console.log(meta); // if (meta) { // meta.style.left = x + "px"; // meta.style.top = y + "px"; // } // } } // 鼠標擡起事件 function mouseUp() { isMouseDown = false; } // 記錄按鈕點擊事件 function btnClicked(id) { store({ evtType: "click", data: { metaId: id, } }); } /*** * 記錄當前事件 */ function store(data) { // 記錄當前事件的時間(等待時間:即開始點擊開始記錄後,多少毫秒後執行這個動做) const time = new Date().getTime(); eventL.push(Object.assign(data, { time: time - startTime })); } // 重現 function replay() { console.log("事件總數:", eventL.length); rootEl.removeEventListener("mousemove", mouseMove, false); rootEl.removeEventListener("mousemove", mouseMove, false); rootEl.removeEventListener("mouseup", mouseUp, false); mouseImg.style.display = "inline"; replayMeta(); }; function replayMeta() { let currentEvt = eventL.shift(); if (!currentEvt) { replayLastEvtTime = 0; console.log("end……") return; } // 等待本次事件的時間到了才執行,完成後下一次事件進入等待 awateEvtTime(currentEvt.time - replayLastEvtTime) .then(() => { switch (currentEvt.evtType) { case "mousemove": console.log("do mousemove"); mouseImg.style.left = currentEvt.data.x + "px"; mouseImg.style.top = currentEvt.data.y + "px"; break; case "drag": const meta = getDragMeta([currentEvt.data.x, currentEvt.data.y]); if (meta) { meta.style.left = currentEvt.data.x + "px"; meta.style.top = currentEvt.data.y + "px"; } // 拖拽同時鼠標也要跟着移動 mouseImg.style.left = currentEvt.data.x + "px"; mouseImg.style.top = currentEvt.data.y + "px"; break; case "click": console.log("do click"); let btn = document.getElementsByClassName("btn" + currentEvt.data.metaId)[0]; btn.classList.add("hover"); setTimeout(() => { btn.classList.remove("hover"); }, 800); break; } replayLastEvtTime = currentEvt.time; replayMeta(); }); } // 本次事件的須要等待的時間 function awateEvtTime(timeout) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(); }, timeout); }) } function start() { rootEl.addEventListener("mousedown", mouseDown, false); rootEl.addEventListener("mousemove", mouseMove, false); rootEl.addEventListener("mouseup", mouseUp, false); mouseImg.style.display = "none"; startTime = new Date().getTime(); } // 獲得拖動的對象 function getDragMeta(point) { for (let i = 0; i < metaList.length; i++) { let meta = metaList[i]; if (pointInPolygon(point, meta.points)) { return document.getElementsByClassName(meta.className)[0]; } } } /** * 判斷點是否在另外一平面圖中 * {Array} point [x,y] 這個點 * {Array} vs [[x,y],[x,y]]平面點集合 */ function pointInPolygon(point, vs) { console.log(point, vs); const x = point[0], y = point[1]; let inside = false; for (let i = 0, j = vs.length - 1; i < vs.length; j = i++) { const xi = vs[i][0], yi = vs[i][1]; const xj = vs[j][0], yj = vs[j][1]; const intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); if (intersect) { inside = !inside; } } console.log(inside); return inside; } </script> </html>
沒有gif -_-!!!ide