{"id":5282,"date":"2026-04-12T10:44:19","date_gmt":"2026-04-12T02:44:19","guid":{"rendered":"https:\/\/yunbroidery.com\/?page_id=5282"},"modified":"2026-04-23T16:09:34","modified_gmt":"2026-04-23T08:09:34","slug":"execution-animation","status":"publish","type":"page","link":"https:\/\/yunbroidery.com\/en\/execution-animation\/","title":{"rendered":"Embroidery Execution Visualization"},"content":{"rendered":"\n<h5 class=\"wp-block-heading has-text-align-center\">\u672c\u9801\u5c07\u523a\u7e61\u8996\u70ba\u4e00\u7a2e\u300c\u57f7\u884c\u7cfb\u7d71\u300d\u9032\u884c\u8996\u89ba\u5316\u3002<br>\u4e0d\u540c\u65bc\u975c\u614b\u5716\u6848\uff0c\u6b64\u52d5\u756b\u5448\u73fe\u7d50\u69cb\u5982\u4f55\u7531\u9023\u7e8c\u8def\u5f91\u6c7a\u7b56\u9010\u6b65\u751f\u6210\u3002<br>\u6b63\u9762\u91dd\u6cd5\u69cb\u6210\u53ef\u898b\u7d50\u69cb\uff0c\u80cc\u9762\u8def\u5f91\u5247\u7dad\u6301\u9023\u7e8c\u6027\u8207\u6574\u9ad4\u7a69\u5b9a\u3002<br>\u6b64\u8996\u89ba\u5316\u63ed\u793a\u523a\u7e61\u70ba\u4e00\u7a2e\u52d5\u614b\u4e14\u53ef\u57f7\u884c\u7684\u7d50\u69cb\u8a9e\u8a00\u3002<\/h5>\n\n\n\n<h3 class=\"wp-block-heading has-text-align-center\">1.\u57f7\u884c\u52d5\u756b\uff08\u50c5\u6b63\u9762\u8def\u5f91\uff09<\/h3>\n\n\n\n<div style=\"text-align:center;margin:40px 0;\">\n\n<h3>Execution Animation<\/h3>\n\n<canvas id=\"canvas204_insert\" width=\"520\" height=\"520\" style=\"border:1px solid #ccc;\"><\/canvas>\n\n<br><br>\n\n<button id=\"play204_insert\">\u25b6 Play<\/button>\n<button id=\"reset204_insert\">\u27f2 Reset<\/button>\n\n<\/div>\n\n<script>\ndocument.addEventListener(\"DOMContentLoaded\", function () {\n\n  const canvas = document.getElementById(\"canvas204_insert\");\n  if (!canvas) return;\n\n  const ctx = canvas.getContext(\"2d\");\n\n  const nodes = {\n   \"1\":[60,460],\"2\":[160,460],\"3\":[260,460],\"4\":[360,460],\"5\":[460,460],\n   \"6\":[60,360],\"7\":[160,360],\"8\":[260,360],\"9\":[360,360],\"10\":[460,360],\n   \"11\":[60,260],\"12\":[160,260],\"13\":[260,260],\"14\":[360,260],\"15\":[460,260],\n   \"16\":[60,160],\"17\":[160,160],\"18\":[260,160],\"19\":[360,160],\"20\":[460,160],\n   \"21\":[60,60],\"22\":[160,60],\"23\":[260,60],\"24\":[360,60],\"25\":[460,60]\n  };\n\n  const path = [\n   {\"from\":\"1\",\"to\":\"22\",\"type\":\"front\"},\n   {\"from\":\"22\",\"to\":\"6\",\"type\":\"back\"},\n   {\"from\":\"6\",\"to\":\"23\",\"type\":\"front\"},\n   {\"from\":\"23\",\"to\":\"11\",\"type\":\"back\"},\n   {\"from\":\"11\",\"to\":\"24\",\"type\":\"front\"},\n   {\"from\":\"24\",\"to\":\"16\",\"type\":\"back\"},\n   {\"from\":\"16\",\"to\":\"25\",\"type\":\"front\"},\n   {\"from\":\"25\",\"to\":\"1\",\"type\":\"back\"},\n   {\"from\":\"1\",\"to\":\"10\",\"type\":\"front\"},\n   {\"from\":\"10\",\"to\":\"2\",\"type\":\"back\"},\n   {\"from\":\"2\",\"to\":\"15\",\"type\":\"front\"},\n   {\"from\":\"15\",\"to\":\"3\",\"type\":\"back\"},\n   {\"from\":\"3\",\"to\":\"20\",\"type\":\"front\"},\n   {\"from\":\"20\",\"to\":\"4\",\"type\":\"back\"},\n   {\"from\":\"4\",\"to\":\"25\",\"type\":\"front\"}\n  ];\n\n  let step = 0;\n  let timer = null;\n\n  function drawNodes(){\n    ctx.clearRect(0,0,520,520);\n    for(let k in nodes){\n      let [x,y]=nodes[k];\n      ctx.beginPath();\n      ctx.arc(x,y,4,0,Math.PI*2);\n      ctx.fill();\n      ctx.fillText(k,x-10,y-8);\n    }\n  }\n\n  function animate(){\n    if(step >= path.length){\n      clearInterval(timer);\n      return;\n    }\n\n    let seg = path[step];\n\n    if(seg.type === \"front\"){\n      let p1 = nodes[seg.from];\n      let p2 = nodes[seg.to];\n\n      ctx.beginPath();\n      ctx.moveTo(p1[0],p1[1]);\n      ctx.lineTo(p2[0],p2[1]);\n\n      ctx.strokeStyle = \"red\";\n      ctx.lineWidth = 3;\n      ctx.lineCap = \"round\";\n      ctx.stroke();\n    }\n\n    step++;\n  }\n\n  document.getElementById(\"play204_insert\").addEventListener(\"click\", function(){\n    clearInterval(timer);\n    step = 0;\n    drawNodes();\n    timer = setInterval(animate, 500);\n  });\n\n  document.getElementById(\"reset204_insert\").addEventListener(\"click\", function(){\n    clearInterval(timer);\n    step = 0;\n    drawNodes();\n  });\n\n  drawNodes();\n\n});\n<\/script>\n\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-dots\"\/>\n\n\n\n<h3 class=\"wp-block-heading has-text-align-center\">2.\u6b63\u9762<strong>\u8207\u80cc\u9762 \u5c0d\u7167\u57f7\u884c\u52d5\u756b<\/strong><\/h3>\n\n\n\n<h4 class=\"wp-block-heading has-text-align-center\">\u523a\u7e61\u7cfb\u7d71\u5c07\u53ef\u898b\u8207\u4e0d\u53ef\u898b\u7d50\u69cb\u5206\u96e2\u3002<br>\u6b63\u9762\u91dd\u6cd5\u5f62\u6210\u53ef\u89c0\u5bdf\u5716\u6a23\uff0c \u80cc\u9762\u8def\u5f91\u5247\u8ca0\u8cac\u9023\u7e8c\u6027\u8207\u7d50\u69cb\u7a69\u5b9a\u3002<\/h4>\n\n\n\n<div style=\"max-width:1100px;margin:auto;text-align:center;font-family:Arial;\">\n\n<h2>Front vs Back Comparison<\/h2>\n<p style=\"color:#666;font-size:14px;\">\nLeft: Front (Visible Structure) \uff5c Right: Back (Hidden Path)\n<\/p>\n\n<div style=\"display:flex;justify-content:center;gap:20px;flex-wrap:wrap;\">\n\n<!-- Front -->\n<div>\n<h3>Front<\/h3>\n<canvas id=\"frontCanvas\" width=\"400\" height=\"400\" style=\"border:1px solid #ccc;\"><\/canvas>\n<\/div>\n\n<!-- Back -->\n<div>\n<h3>Back<\/h3>\n<canvas id=\"backCanvas\" width=\"400\" height=\"400\" style=\"border:1px solid #ccc;\"><\/canvas>\n<\/div>\n\n<\/div>\n\n<br>\n\n<button id=\"playFB\">\u25b6 Play<\/button>\n<button id=\"resetFB\">\u27f2 Reset<\/button>\n\n<\/div>\n\n<script>\ndocument.addEventListener(\"DOMContentLoaded\", function () {\n\n  const frontCtx = document.getElementById(\"frontCanvas\").getContext(\"2d\");\n  const backCtx = document.getElementById(\"backCanvas\").getContext(\"2d\");\n\n  const nodes = {\n   \"1\":[50,350],\"2\":[125,350],\"3\":[200,350],\"4\":[275,350],\"5\":[350,350],\n   \"6\":[50,275],\"7\":[125,275],\"8\":[200,275],\"9\":[275,275],\"10\":[350,275],\n   \"11\":[50,200],\"12\":[125,200],\"13\":[200,200],\"14\":[275,200],\"15\":[350,200],\n   \"16\":[50,125],\"17\":[125,125],\"18\":[200,125],\"19\":[275,125],\"20\":[350,125],\n   \"21\":[50,50],\"22\":[125,50],\"23\":[200,50],\"24\":[275,50],\"25\":[350,50]\n  };\n\n  const path = [\n   {\"from\":\"1\",\"to\":\"22\",\"type\":\"front\"},\n   {\"from\":\"22\",\"to\":\"6\",\"type\":\"back\"},\n   {\"from\":\"6\",\"to\":\"23\",\"type\":\"front\"},\n   {\"from\":\"23\",\"to\":\"11\",\"type\":\"back\"},\n   {\"from\":\"11\",\"to\":\"24\",\"type\":\"front\"},\n   {\"from\":\"24\",\"to\":\"16\",\"type\":\"back\"},\n   {\"from\":\"16\",\"to\":\"25\",\"type\":\"front\"},\n   {\"from\":\"25\",\"to\":\"1\",\"type\":\"back\"},\n   {\"from\":\"1\",\"to\":\"10\",\"type\":\"front\"},\n   {\"from\":\"10\",\"to\":\"2\",\"type\":\"back\"},\n   {\"from\":\"2\",\"to\":\"15\",\"type\":\"front\"},\n   {\"from\":\"15\",\"to\":\"3\",\"type\":\"back\"},\n   {\"from\":\"3\",\"to\":\"20\",\"type\":\"front\"},\n   {\"from\":\"20\",\"to\":\"4\",\"type\":\"back\"},\n   {\"from\":\"4\",\"to\":\"25\",\"type\":\"front\"}\n  ];\n\n  let step = 0;\n  let timer = null;\n\n  function drawNodes(ctx){\n    ctx.clearRect(0,0,400,400);\n    for(let k in nodes){\n      let [x,y]=nodes[k];\n      ctx.beginPath();\n      ctx.arc(x,y,3,0,Math.PI*2);\n      ctx.fill();\n    }\n  }\n\n  function animate(){\n    if(step >= path.length){\n      clearInterval(timer);\n      return;\n    }\n\n    let seg = path[step];\n    let p1 = nodes[seg.from];\n    let p2 = nodes[seg.to];\n\n    \/\/ Front\n    if(seg.type === \"front\"){\n      frontCtx.beginPath();\n      frontCtx.moveTo(p1[0],p1[1]);\n      frontCtx.lineTo(p2[0],p2[1]);\n      frontCtx.strokeStyle = \"red\";\n      frontCtx.lineWidth = 2;\n      frontCtx.stroke();\n    }\n\n    \/\/ Back\n    if(seg.type === \"back\"){\n      backCtx.beginPath();\n      backCtx.moveTo(p1[0],p1[1]);\n      backCtx.lineTo(p2[0],p2[1]);\n      backCtx.strokeStyle = \"#999\";\n      backCtx.lineWidth = 2;\n      backCtx.setLineDash([5,5]);\n      backCtx.stroke();\n      backCtx.setLineDash([]);\n    }\n\n    step++;\n  }\n\n  document.getElementById(\"playFB\").addEventListener(\"click\", function(){\n    clearInterval(timer);\n    step = 0;\n    drawNodes(frontCtx);\n    drawNodes(backCtx);\n    timer = setInterval(animate, 500);\n  });\n\n  document.getElementById(\"resetFB\").addEventListener(\"click\", function(){\n    clearInterval(timer);\n    step = 0;\n    drawNodes(frontCtx);\n    drawNodes(backCtx);\n  });\n\n  drawNodes(frontCtx);\n  drawNodes(backCtx);\n\n});\n<\/script>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-dots\"\/>\n\n\n\n<h3 class=\"wp-block-heading has-text-align-center\">3.<strong>Canvas 204 \u523a\u7e61\u57f7\u884c\u7d50\u69cb\u5716<\/strong><\/h3>\n\n\n\n<p class=\"has-text-align-center\">\u7d05\u7dda\u70ba\u6b63\u9762\u53ef\u898b\u91dd\u6cd5\uff0c\u7070\u8272\u865b\u7dda\u70ba\u80cc\u9762\u96b1\u85cf\u8def\u5f91\uff0c\u7bad\u982d\u8868\u793a\u57f7\u884c\u65b9\u5411\uff0cS1\u2013S15\u70ba\u6b65\u9a5f\u5e8f\u5217\u3002<br>\u6b64\u7d50\u69cb\u5448\u73fe\u96d9\u5411\u659c\u7dda\u7cfb\u7d71\u8207\u8def\u5f91\u4f9d\u8cf4\u7684\u751f\u6210\u908f\u8f2f\u3002<\/p>\n\n\n\n<div style=\"max-width:1100px;margin:auto;text-align:center;font-family:Arial;\">\n\n<h2>Canvas 204 \u2013 Execution Structure Diagram<\/h2>\n\n<p style=\"font-size:14px;color:#555;\">\nRed: Front (Visible Structure) \uff5c Gray Dashed: Back (Hidden Path) \uff5c Arrows indicate execution direction\n<\/p>\n\n<canvas id=\"canvas204_paper\" width=\"520\" height=\"520\" style=\"border:1px solid #ccc;\"><\/canvas>\n\n<br><br>\n<button id=\"playPaper\">\u25b6 Play<\/button>\n<button id=\"resetPaper\">\u27f2 Reset<\/button>\n\n<\/div>\n\n<script>\ndocument.addEventListener(\"DOMContentLoaded\", function () {\n\nconst canvas = document.getElementById(\"canvas204_paper\");\nconst ctx = canvas.getContext(\"2d\");\n\nconst nodes = {\n \"1\":[60,460],\"2\":[160,460],\"3\":[260,460],\"4\":[360,460],\"5\":[460,460],\n \"6\":[60,360],\"7\":[160,360],\"8\":[260,360],\"9\":[360,360],\"10\":[460,360],\n \"11\":[60,260],\"12\":[160,260],\"13\":[260,260],\"14\":[360,260],\"15\":[460,260],\n \"16\":[60,160],\"17\":[160,160],\"18\":[260,160],\"19\":[360,160],\"20\":[460,160],\n \"21\":[60,60],\"22\":[160,60],\"23\":[260,60],\"24\":[360,60],\"25\":[460,60]\n};\n\nconst path = [\n {\"from\":\"1\",\"to\":\"22\",\"type\":\"front\"},\n {\"from\":\"22\",\"to\":\"6\",\"type\":\"back\"},\n {\"from\":\"6\",\"to\":\"23\",\"type\":\"front\"},\n {\"from\":\"23\",\"to\":\"11\",\"type\":\"back\"},\n {\"from\":\"11\",\"to\":\"24\",\"type\":\"front\"},\n {\"from\":\"24\",\"to\":\"16\",\"type\":\"back\"},\n {\"from\":\"16\",\"to\":\"25\",\"type\":\"front\"},\n {\"from\":\"25\",\"to\":\"1\",\"type\":\"back\"},\n {\"from\":\"1\",\"to\":\"10\",\"type\":\"front\"},\n {\"from\":\"10\",\"to\":\"2\",\"type\":\"back\"},\n {\"from\":\"2\",\"to\":\"15\",\"type\":\"front\"},\n {\"from\":\"15\",\"to\":\"3\",\"type\":\"back\"},\n {\"from\":\"3\",\"to\":\"20\",\"type\":\"front\"},\n {\"from\":\"20\",\"to\":\"4\",\"type\":\"back\"},\n {\"from\":\"4\",\"to\":\"25\",\"type\":\"front\"}\n];\n\nlet step = 0;\nlet timer = null;\n\nfunction drawNodes(){\n ctx.clearRect(0,0,520,520);\n for(let k in nodes){\n   let [x,y]=nodes[k];\n   ctx.beginPath();\n   ctx.arc(x,y,4,0,Math.PI*2);\n   ctx.fill();\n   ctx.fillText(k,x-10,y-8);\n }\n}\n\n\/\/ \ud83d\udd25 \u756b\u7bad\u982d\nfunction drawArrow(p1,p2){\n const headlen = 8;\n const dx = p2[0]-p1[0];\n const dy = p2[1]-p1[1];\n const angle = Math.atan2(dy,dx);\n\n ctx.beginPath();\n ctx.moveTo(p2[0],p2[1]);\n ctx.lineTo(p2[0]-headlen*Math.cos(angle-Math.PI\/6),p2[1]-headlen*Math.sin(angle-Math.PI\/6));\n ctx.lineTo(p2[0]-headlen*Math.cos(angle+Math.PI\/6),p2[1]-headlen*Math.sin(angle+Math.PI\/6));\n ctx.closePath();\n ctx.fill();\n}\n\nfunction animate(){\n if(step >= path.length){\n   clearInterval(timer);\n   return;\n }\n\n let seg = path[step];\n let p1 = nodes[seg.from];\n let p2 = nodes[seg.to];\n\n ctx.beginPath();\n ctx.moveTo(p1[0],p1[1]);\n ctx.lineTo(p2[0],p2[1]);\n\n if(seg.type === \"front\"){\n   ctx.strokeStyle = \"red\";\n   ctx.lineWidth = 3;\n   ctx.setLineDash([]);\n } else {\n   ctx.strokeStyle = \"#999\";\n   ctx.lineWidth = 2;\n   ctx.setLineDash([5,5]);\n }\n\n ctx.stroke();\n ctx.setLineDash([]);\n\n \/\/ \u7bad\u982d\n ctx.fillStyle = (seg.type===\"front\") ? \"red\" : \"#999\";\n drawArrow(p1,p2);\n\n \/\/ Step\u6a19\u8a3b\n ctx.fillStyle = \"blue\";\n ctx.font = \"10px Arial\";\n ctx.fillText(\"S\"+(step+1),(p1[0]+p2[0])\/2,(p1[1]+p2[1])\/2);\n\n step++;\n}\n\ndocument.getElementById(\"playPaper\").addEventListener(\"click\", function(){\n clearInterval(timer);\n step = 0;\n drawNodes();\n timer = setInterval(animate, 1100);\n});\n\ndocument.getElementById(\"resetPaper\").addEventListener(\"click\", function(){\n clearInterval(timer);\n step = 0;\n drawNodes();\n});\n\ndrawNodes();\n\n});\n<\/script>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity is-style-dots\"\/>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4.Canvas 205 \u57f7\u884c<strong>\u52d5\u756b<\/strong>\u904e\u7a0b\uff083 Layer + Step + Direction\uff09<\/h3>\n\n\n\n<p class=\"has-text-align-center\">\u57f7\u884c\u9806\u5e8f\uff1a<br>\u7b2c1\u5c64\uff08\u7da0\uff09\uff1a\u57fa\u790e\u7d50\u69cb\u6e96\u5099<br>\u7b2c2\u5c64\uff08\u7d05\uff09\uff1a\u4e3b\u8981\u7d50\u69cb\u5f62\u6210<br>\u7b2c3\u5c64\uff08\u85cd\uff09\uff1a\u7d50\u69cb\u9396\u5b9a\u8207\u7a69\u5b9a<br>\u8aaa\u660e\uff1a\u57f7\u884c\u9806\u5e8f\u4e0d\u7b49\u65bc\u8996\u89ba\u4e3b\u5c0e\u5c64\uff0c\u6700\u7d42\u7d50\u69cb\u4f86\u81ea\u591a\u5c64\u5e8f\u5217\u7684\u4ea4\u4e92\u4f5c\u7528\u3002<\/p>\n\n\n\n<div style=\"text-align:center;\">\n\n<canvas id=\"c205\" width=\"520\" height=\"520\" style=\"border:1px solid #ccc;\"><\/canvas>\n\n<br><br>\n\n<button onclick=\"play4()\">\u25b6 Play<\/button>\n<button onclick=\"pause4()\">\u23f8 Pause<\/button>\n<button onclick=\"reset4()\">\u27f2 Reset<\/button>\n\n<br><br>\n\n<label><input type=\"checkbox\" checked onchange=\"toggleLayer(1,this)\"> Layer 1 (Green)<\/label>\n<label><input type=\"checkbox\" checked onchange=\"toggleLayer(2,this)\"> Layer 2 (Red)<\/label>\n<label><input type=\"checkbox\" checked onchange=\"toggleLayer(3,this)\"> Layer 3 (Blue)<\/label>\n\n<\/div>\n\n<script>\ndocument.addEventListener(\"DOMContentLoaded\", function () {\n\nconst canvas = document.getElementById(\"c205\");\nconst ctx = canvas.getContext(\"2d\");\n\nconst size = 9;\nconst margin = 60;\nconst step = (520 - margin*2) \/ (size - 1);\n\nlet nodes = {};\nlet id=1;\n\nfor(let r=0;r<size;r++){\n for(let c=0;c<size;c++){\n  nodes[id]=[\n    margin + c*step,\n    520 - (margin + r*step)\n  ];\n  id++;\n }\n}\n\n\/\/ \ud83d\udd37 \u4f60\u7684\u8cc7\u6599\uff08\u5df2\u52063\u5c64\uff09\nconst path = [\n{\"from\":\"55\",\"to\":\"79\",\"type\":\"front\",\"layer\":1},\n{\"from\":\"79\",\"to\":\"27\",\"type\":\"back\",\"layer\":1},\n{\"from\":\"27\",\"to\":\"3\",\"type\":\"front\",\"layer\":1},\n{\"from\":\"3\",\"to\":\"55\",\"type\":\"back\",\"layer\":1},\n\n{\"from\":\"55\",\"to\":\"3\",\"type\":\"front\",\"layer\":1},\n{\"from\":\"3\",\"to\":\"27\",\"type\":\"back\",\"layer\":1},\n{\"from\":\"27\",\"to\":\"79\",\"type\":\"front\",\"layer\":1},\n\n{\"from\":\"79\",\"to\":\"37\",\"type\":\"back\",\"layer\":2},\n{\"from\":\"37\",\"to\":\"77\",\"type\":\"front\",\"layer\":2},\n{\"from\":\"77\",\"to\":\"45\",\"type\":\"back\",\"layer\":2},\n{\"from\":\"45\",\"to\":\"5\",\"type\":\"front\",\"layer\":2},\n{\"from\":\"5\",\"to\":\"37\",\"type\":\"back\",\"layer\":2},\n\n{\"from\":\"37\",\"to\":\"5\",\"type\":\"front\",\"layer\":2},\n{\"from\":\"5\",\"to\":\"45\",\"type\":\"back\",\"layer\":2},\n{\"from\":\"45\",\"to\":\"77\",\"type\":\"front\",\"layer\":2},\n\n{\"from\":\"77\",\"to\":\"75\",\"type\":\"back\",\"layer\":3},\n{\"from\":\"75\",\"to\":\"63\",\"type\":\"front\",\"layer\":3},\n{\"from\":\"63\",\"to\":\"7\",\"type\":\"back\",\"layer\":3},\n{\"from\":\"7\",\"to\":\"19\",\"type\":\"front\",\"layer\":3},\n{\"from\":\"19\",\"to\":\"75\",\"type\":\"back\",\"layer\":3},\n\n{\"from\":\"75\",\"to\":\"19\",\"type\":\"front\",\"layer\":3},\n{\"from\":\"19\",\"to\":\"7\",\"type\":\"back\",\"layer\":3},\n{\"from\":\"7\",\"to\":\"63\",\"type\":\"front\",\"layer\":3}\n];\n\nlet stepIndex=0;\nlet playing=false;\nlet layerVisible = {1:true,2:true,3:true};\n\nfunction drawGrid(){\n ctx.clearRect(0,0,520,520);\n\n for(let k in nodes){\n  let [x,y]=nodes[k];\n  ctx.beginPath();\n  ctx.arc(x,y,3,0,Math.PI*2);\n  ctx.fill();\n }\n}\n\nfunction drawArrow(p1,p2,color){\n let dx=p2[0]-p1[0];\n let dy=p2[1]-p1[1];\n let angle=Math.atan2(dy,dx);\n\n ctx.beginPath();\n ctx.moveTo(p2[0],p2[1]);\n ctx.lineTo(p2[0]-10*Math.cos(angle-0.3), p2[1]-10*Math.sin(angle-0.3));\n ctx.lineTo(p2[0]-10*Math.cos(angle+0.3), p2[1]-10*Math.sin(angle+0.3));\n ctx.closePath();\n ctx.fillStyle=color;\n ctx.fill();\n}\n\nfunction draw(){\n drawGrid();\n\n for(let i=0;i<stepIndex;i++){\n  let seg=path[i];\n\n  if(!layerVisible[seg.layer]) continue;\n\n  let p1=nodes[seg.from];\n  let p2=nodes[seg.to];\n\n  ctx.beginPath();\n  ctx.moveTo(p1[0],p1[1]);\n  ctx.lineTo(p2[0],p2[1]);\n\n  let color = seg.layer==1?\"green\":seg.layer==2?\"red\":\"blue\";\n\n  if(seg.type===\"front\"){\n    ctx.strokeStyle=color;\n    ctx.lineWidth=3;\n    ctx.setLineDash([]);\n    ctx.stroke();\n\n    drawArrow(p1,p2,color);\n\n    \/\/ Step number\n    ctx.fillStyle=color;\n    ctx.fillText(i+1,(p1[0]+p2[0])\/2,(p1[1]+p2[1])\/2);\n\n  }else{\n    ctx.strokeStyle=\"gray\";\n    ctx.lineWidth=1;\n    ctx.setLineDash([4,4]);\n    ctx.stroke();\n  }\n }\n\n ctx.setLineDash([]);\n}\n\nfunction animate(){\n if(!playing) return;\n\n draw();\n stepIndex++;\n\n if(stepIndex<=path.length){\n  setTimeout(animate,400);\n }\n}\n\nwindow.play4=function(){\n playing=true;\n animate();\n};\n\nwindow.pause4=function(){\n playing=false;\n};\n\nwindow.reset4=function(){\n playing=false;\n stepIndex=0;\n draw();\n};\n\nwindow.toggleLayer=function(l,el){\n layerVisible[l]=el.checked;\n draw();\n};\n\ndraw();\n\n});\n<\/script>\n\n\n\n<p class=\"has-text-align-center\">\u672c\u5716\u5c55\u793a\u523a\u7e61\u7d50\u69cb\u7684\u9010\u6b65\u751f\u6210\u904e\u7a0b\uff0c\u6bcf\u4e00\u6b65\u70ba\u4e00\u500b\u8def\u5f91\u57f7\u884c\u55ae\u4f4d\uff0c\u6bcf\u4e00\u5c64\u4ee3\u8868\u4e0d\u540c\u7684\u7d50\u69cb\u89d2\u8272\u3002<br>\u8aaa\u660e\u523a\u7e61\u53ef\u88ab\u8996\u70ba\u4e00\u7a2e\u5177\u6642\u9593\u6027\u8207\u53ef\u57f7\u884c\u6027\u7684\u7d50\u69cb\u8a9e\u8a00\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">5.Canvas 206 \u57f7\u884c<strong>\u52d5\u756b<\/strong>\u904e\u7a0b\u55ae\u8272\uff08\u542b5\u5c64\u7d1a\u8207Auto Layer\uff09<\/h3>\n\n\n\n<div style=\"text-align:center; font-family:Arial;\">\n\n<canvas id=\"c206pro\" width=\"520\" height=\"520\" style=\"border:1px solid #ccc;\"><\/canvas>\n\n<br><br>\n\n<button onclick=\"play()\">\u25b6 Play<\/button>\n<button onclick=\"pause()\">\u23f8 Pause<\/button>\n<button onclick=\"reset()\">\u27f2 Reset<\/button>\n<button onclick=\"autoLayers()\">\ud83d\udd25 Auto Layers<\/button>\n\n<p id=\"info\">Step: 0 | Layer: 1<\/p>\n\n\n\n<label><input type=\"checkbox\" checked onchange=\"toggleLayer(1,this)\"> L1<\/label>\n<label><input type=\"checkbox\" checked onchange=\"toggleLayer(2,this)\"> L2<\/label>\n<label><input type=\"checkbox\" checked onchange=\"toggleLayer(3,this)\"> L3<\/label>\n<label><input type=\"checkbox\" checked onchange=\"toggleLayer(4,this)\"> L4<\/label>\n<label><input type=\"checkbox\" checked onchange=\"toggleLayer(5,this)\"> L5<\/label>\n\n<\/div>\n\n<script>\ndocument.addEventListener(\"DOMContentLoaded\", function (){\n\nconst canvas = document.getElementById(\"c206pro\");\nconst ctx = canvas.getContext(\"2d\");\n\nconst size=9, margin=60;\nconst stepSize=(520-margin*2)\/(size-1);\n\nlet nodes={}, id=1;\n\nfor(let r=0;r<size;r++){\n for(let c=0;c<size;c++){\n  nodes[id]=[margin+c*stepSize,520-(margin+r*stepSize)];\n  id++;\n }\n}\n\n\/\/ \ud83d\udd37 Path\uff08\u542b5\u5c64\uff09\nconst path = [{\"from\":\"46\",\"to\":\"78\",\"type\":\"front\",\"layer\":1},\n{\"from\":\"78\",\"to\":\"36\",\"type\":\"back\",\"layer\":1},\n{\"from\":\"36\",\"to\":\"4\",\"type\":\"front\",\"layer\":1},\n{\"from\":\"4\",\"to\":\"46\",\"type\":\"back\",\"layer\":1},\n{\"from\":\"46\",\"to\":\"4\",\"type\":\"front\",\"layer\":1},\n{\"from\":\"4\",\"to\":\"36\",\"type\":\"back\",\"layer\":1},\n{\"from\":\"36\",\"to\":\"78\",\"type\":\"front\",\"layer\":1},\n{\"from\":\"78\",\"to\":\"37\",\"type\":\"back\",\"layer\":2},\n{\"from\":\"37\",\"to\":\"77\",\"type\":\"front\",\"layer\":2},\n{\"from\":\"77\",\"to\":\"45\",\"type\":\"back\",\"layer\":2},\n{\"from\":\"45\",\"to\":\"5\",\"type\":\"front\",\"layer\":2},\n{\"from\":\"5\",\"to\":\"37\",\"type\":\"back\",\"layer\":2},\n{\"from\":\"37\",\"to\":\"5\",\"type\":\"front\",\"layer\":2},\n{\"from\":\"5\",\"to\":\"45\",\"type\":\"back\",\"layer\":2},\n{\"from\":\"45\",\"to\":\"77\",\"type\":\"front\",\"layer\":2},\n{\"from\":\"77\",\"to\":\"76\",\"type\":\"back\",\"layer\":3},\n{\"from\":\"76\",\"to\":\"54\",\"type\":\"front\",\"layer\":3},\n{\"from\":\"54\",\"to\":\"6\",\"type\":\"back\",\"layer\":3},\n{\"from\":\"6\",\"to\":\"28\",\"type\":\"front\",\"layer\":3},\n{\"from\":\"28\",\"to\":\"76\",\"type\":\"back\",\"layer\":3},\n{\"from\":\"76\",\"to\":\"28\",\"type\":\"front\",\"layer\":3},\n{\"from\":\"28\",\"to\":\"6\",\"type\":\"back\",\"layer\":3},\n{\"from\":\"6\",\"to\":\"54\",\"type\":\"front\",\"layer\":3},\n{\"from\":\"54\",\"to\":\"62\",\"type\":\"back\",\"layer\":4},\n{\"from\":\"62\",\"to\":\"16\",\"type\":\"front\",\"layer\":4},\n{\"from\":\"16\",\"to\":\"20\",\"type\":\"back\",\"layer\":4},\n{\"from\":\"20\",\"to\":\"66\",\"type\":\"front\",\"layer\":4},\n{\"from\":\"66\",\"to\":\"62\",\"type\":\"back\",\"layer\":4},\n{\"from\":\"62\",\"to\":\"66\",\"type\":\"front\",\"layer\":4},\n{\"from\":\"66\",\"to\":\"20\",\"type\":\"back\",\"layer\":4},\n{\"from\":\"20\",\"to\":\"16\",\"type\":\"front\",\"layer\":4},\n{\"from\":\"16\",\"to\":\"26\",\"type\":\"back\",\"layer\":5},\n{\"from\":\"26\",\"to\":\"12\",\"type\":\"front\",\"layer\":5},\n{\"from\":\"12\",\"to\":\"56\",\"type\":\"back\",\"layer\":5},\n{\"from\":\"56\",\"to\":\"70\",\"type\":\"front\",\"layer\":5},\n{\"from\":\"70\",\"to\":\"26\",\"type\":\"back\",\"layer\":5},\n{\"from\":\"26\",\"to\":\"70\",\"type\":\"front\",\"layer\":5},\n{\"from\":\"70\",\"to\":\"56\",\"type\":\"back\",\"layer\":5},\n{\"from\":\"56\",\"to\":\"12\",\"type\":\"front\",\"layer\":5}];\n\n\/\/ \ud83d\udd37 \u72c0\u614b\nlet stepIndex=0;\nlet playing=false;\nlet layerVisible={1:true,2:true,3:true,4:true,5:true};\nlet currentLayer=1;\n\n\/\/ \ud83d\udd37 \u756b\u9ede\nfunction drawGrid(){\n ctx.clearRect(0,0,520,520);\n for(let k in nodes){\n  let [x,y]=nodes[k];\n  ctx.beginPath();\n  ctx.arc(x,y,2,0,Math.PI*2);\n  ctx.fillStyle=\"#aaa\";\n  ctx.fill();\n }\n}\n\n\/\/ \ud83d\udd37 \u756b\u7bad\u982d\nfunction arrow(p1,p2){\n let a=Math.atan2(p2[1]-p1[1],p2[0]-p1[0]);\n ctx.beginPath();\n ctx.moveTo(p2[0],p2[1]);\n ctx.lineTo(p2[0]-8*Math.cos(a-0.3),p2[1]-8*Math.sin(a-0.3));\n ctx.lineTo(p2[0]-8*Math.cos(a+0.3),p2[1]-8*Math.sin(a+0.3));\n ctx.closePath();\n ctx.fillStyle=\"#800080\";\n ctx.fill();\n}\n\n\/\/ \ud83d\udd37 \u756b\u5716\nfunction draw(){\n drawGrid();\n\n for(let i=0;i<stepIndex;i++){\n  let seg=path[i];\n\n  if(!layerVisible[seg.layer]) continue;\n\n  let p1=nodes[seg.from];\n  let p2=nodes[seg.to];\n\n  ctx.beginPath();\n  ctx.moveTo(p1[0],p1[1]);\n  ctx.lineTo(p2[0],p2[1]);\n\n  if(seg.type===\"front\"){\n    ctx.strokeStyle=\"#800080\";\n    ctx.lineWidth=3;\n    ctx.setLineDash([]);\n    ctx.stroke();\n\n    arrow(p1,p2);\n\n    ctx.fillStyle=\"#800080\";\n    ctx.fillText(i+1,(p1[0]+p2[0])\/2,(p1[1]+p2[1])\/2);\n\n  }else{\n    ctx.strokeStyle=\"#999\";\n    ctx.lineWidth=1;\n    ctx.setLineDash([4,4]);\n    ctx.stroke();\n  }\n }\n\n ctx.setLineDash([]);\n}\n\n\/\/ \ud83d\udd37 \u4e00\u822c\u52d5\u756b\nfunction animate(){\n if(!playing) return;\n\n draw();\n stepIndex++;\n\n if(stepIndex <= path.length){\n  setTimeout(animate,350);\n }\n}\n\n\/\/ \ud83d\udd37 \u64ad\u653e\nwindow.play=function(){\n playing=true;\n animate();\n};\n\n\/\/ \ud83d\udd37 \u66ab\u505c\nwindow.pause=function(){\n playing=false;\n};\n\n\/\/ \ud83d\udd37 \u91cd\u7f6e\nwindow.reset=function(){\n playing=false;\n stepIndex=0;\n currentLayer=1;\n layerVisible={1:true,2:true,3:true,4:true,5:true};\n draw();\n updateInfo();\n};\n\n\/\/ \ud83d\udd37 Layer \u958b\u95dc\nwindow.toggleLayer=function(l,el){\n layerVisible[l]=el.checked;\n draw();\n};\n\n\/\/ \ud83d\udd25 \ud83d\udd25 \u81ea\u52d5\u5c64\u751f\u6210\uff08\u6838\u5fc3\uff09\nwindow.autoLayers=function(){\n\n playing=false;\n stepIndex=0;\n currentLayer=1;\n\n layerVisible={1:true,2:false,3:false,4:false,5:false};\n\n function nextLayer(){\n\n  stepIndex=0;\n  playing=true;\n\n  function run(){\n    if(!playing) return;\n\n    draw();\n    stepIndex++;\n\n    if(stepIndex <= path.length){\n      setTimeout(run,200);\n    }else{\n      \/\/ \u4e0b\u4e00\u5c64\n      currentLayer++;\n      if(currentLayer<=5){\n        layerVisible[currentLayer]=true;\n        stepIndex=0;\n        setTimeout(run,500);\n      }\n    }\n\n    updateInfo();\n  }\n\n  run();\n }\n\n nextLayer();\n};\n\n\/\/ \ud83d\udd37 UI\nfunction updateInfo(){\n document.getElementById(\"info\").innerText =\n \"Step: \"+stepIndex+\" | Layer: \"+currentLayer;\n}\n\ndraw();\n\n});\n<\/script>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">6.Canvas 206 \u57f7\u884c<strong>\u52d5\u756b<\/strong>(\u6b63\u9762+\u80cc\u9762)<\/h3>\n\n\n\n<div id=\"yb-206\"><\/div>\n<div style=\"text-align:center; font-family:Arial;\">\n<br>\n<button id=\"playBtn\">\u25b6 Play<\/button>\n\n<\/div>\n<div id=\"videoBox\"><\/div>\n\n<script>\n\ndocument.addEventListener(\"DOMContentLoaded\", function(){\n\n  const container = document.getElementById(\"yb-206\");\n\n  container.innerHTML = `\n    <div style=\"display:flex;gap:20px;\">\n      <canvas id=\"front\" width=\"400\" height=\"400\" style=\"border:1px solid #ccc\"><\/canvas>\n      <canvas id=\"back\" width=\"400\" height=\"400\" style=\"border:1px solid #ccc\"><\/canvas>\n    <\/div>\n  `;\n\n  const ctxF = document.getElementById(\"front\").getContext(\"2d\");\n  const ctxB = document.getElementById(\"back\").getContext(\"2d\");\n\n  const size = 9;\n  const margin = 40;\n  const stepSize = (400 - margin*2) \/ (size - 1);\n\n  let nodes = {};\n  let id = 1;\n\n  for(let r=0;r<size;r++){\n    for(let c=0;c<size;c++){\n      nodes[id] = [\n        margin + c * stepSize,\n        400 - (margin + r * stepSize)\n      ];\n      id++;\n    }\n  }\n\n  function drawBase(ctx){\n    for(let k in nodes){\n      let [x,y] = nodes[k];\n      ctx.beginPath();\n      ctx.arc(x,y,2,0,Math.PI*2);\n      ctx.fillStyle=\"#bbb\";\n      ctx.fill();\n    }\n  }\n\n  const path = [\n{\"from\":46,\"to\":78,\"type\":\"front\"},{\"from\":78,\"to\":36,\"type\":\"back\"},\n{\"from\":36,\"to\":4,\"type\":\"front\"},{\"from\":4,\"to\":46,\"type\":\"back\"},\n{\"from\":46,\"to\":4,\"type\":\"front\"},{\"from\":4,\"to\":36,\"type\":\"back\"},\n{\"from\":36,\"to\":78,\"type\":\"front\"},{\"from\":78,\"to\":37,\"type\":\"back\"},\n{\"from\":37,\"to\":77,\"type\":\"front\"},{\"from\":77,\"to\":45,\"type\":\"back\"},\n{\"from\":45,\"to\":5,\"type\":\"front\"},{\"from\":5,\"to\":37,\"type\":\"back\"},\n{\"from\":37,\"to\":5,\"type\":\"front\"},{\"from\":5,\"to\":45,\"type\":\"back\"},\n{\"from\":45,\"to\":77,\"type\":\"front\"},{\"from\":77,\"to\":76,\"type\":\"back\"},\n{\"from\":76,\"to\":54,\"type\":\"front\"},{\"from\":54,\"to\":6,\"type\":\"back\"},\n{\"from\":6,\"to\":28,\"type\":\"front\"},{\"from\":28,\"to\":76,\"type\":\"back\"},\n{\"from\":76,\"to\":28,\"type\":\"front\"},{\"from\":28,\"to\":6,\"type\":\"back\"},\n{\"from\":6,\"to\":54,\"type\":\"front\"},{\"from\":54,\"to\":62,\"type\":\"back\"},\n{\"from\":62,\"to\":16,\"type\":\"front\"},{\"from\":16,\"to\":20,\"type\":\"back\"},\n{\"from\":20,\"to\":66,\"type\":\"front\"},{\"from\":66,\"to\":62,\"type\":\"back\"},\n{\"from\":62,\"to\":66,\"type\":\"front\"},{\"from\":66,\"to\":20,\"type\":\"back\"},\n{\"from\":20,\"to\":16,\"type\":\"front\"},{\"from\":16,\"to\":26,\"type\":\"back\"},\n{\"from\":26,\"to\":12,\"type\":\"front\"},{\"from\":12,\"to\":56,\"type\":\"back\"},\n{\"from\":56,\"to\":70,\"type\":\"front\"},{\"from\":70,\"to\":26,\"type\":\"back\"},\n{\"from\":26,\"to\":70,\"type\":\"front\"},{\"from\":70,\"to\":56,\"type\":\"back\"},\n{\"from\":56,\"to\":12,\"type\":\"front\"}\n  ];\n\n  let step = 0;\n  let dataset = [];\n\n  function draw(){\n\n    ctxF.clearRect(0,0,400,400);\n    ctxB.clearRect(0,0,400,400);\n\n    drawBase(ctxF);\n    drawBase(ctxB);\n\n    for(let i=0;i<step;i++){\n\n      let seg = path[i];\n      let p1 = nodes[seg.from];\n      let p2 = nodes[seg.to];\n\n      if(seg.type===\"front\"){\n        ctxF.beginPath();\n        ctxF.moveTo(p1[0],p1[1]);\n        ctxF.lineTo(p2[0],p2[1]);\n        ctxF.strokeStyle=\"purple\";\n        ctxF.lineWidth=3;\n        ctxF.stroke();\n      }\n\n      if(seg.type===\"back\"){\n        ctxB.beginPath();\n        ctxB.moveTo(p1[0],p1[1]);\n        ctxB.lineTo(p2[0],p2[1]);\n        ctxB.setLineDash([4,4]);\n        ctxB.strokeStyle=\"#999\";\n        ctxB.stroke();\n        ctxB.setLineDash([]);\n      }\n    }\n  }\n\n  function play(callback){\n\n    step = 0;\n    dataset = [];\n\n    function run(){\n\n      draw();\n\n      if(step < path.length){\n\n        dataset.push({\n          step: step+1,\n          from: path[step].from,\n          to: path[step].to,\n          type: path[step].type\n        });\n\n        step++;\n        setTimeout(run,200);\n\n      }else{\n        draw();\n        if(callback) callback();\n      }\n    }\n\n    run();\n  }\n\n  \/\/ \u25b6 Play\n  document.getElementById(\"playBtn\").onclick = ()=>{\n    play();\n  };\n\n  \/\/ \ud83c\udfac Video\uff08\u96d9\u756b\u9762\u7a69\u5b9a\u7248\uff09\n  document.getElementById(\"videoBtn\").onclick = ()=>{\n\n    const master = document.createElement(\"canvas\");\n    master.width = 800;\n    master.height = 400;\n\n    const mctx = master.getContext(\"2d\");\n\n    function drawMaster(){\n      mctx.clearRect(0,0,800,400);\n      mctx.drawImage(document.getElementById(\"front\"),0,0);\n      mctx.drawImage(document.getElementById(\"back\"),400,0);\n    }\n\n    const stream = master.captureStream(30);\n    const rec = new MediaRecorder(stream);\n    let chunks = [];\n\n    rec.ondataavailable = e=>{\n      if(e.data.size>0) chunks.push(e.data);\n    };\n\n    rec.onstop = ()=>{\n      const blob = new Blob(chunks,{type:\"video\/webm\"});\n      const url = URL.createObjectURL(blob);\n\n      const v = document.createElement(\"video\");\n      v.src = url;\n      v.controls = true;\n      v.width = 800;\n\n      document.getElementById(\"videoBox\").innerHTML=\"\";\n      document.getElementById(\"videoBox\").appendChild(v);\n    };\n\n    rec.start();\n\n    play(()=>{\n      drawMaster();\n      setTimeout(()=>rec.stop(),500);\n    });\n\n    const sync = setInterval(drawMaster,50);\n    setTimeout(()=>clearInterval(sync), path.length*200+1000);\n  };\n\n  \/\/ \ud83d\udcca Dataset\n  document.getElementById(\"dataBtn\").onclick = ()=>{\n\n    const jsonText = JSON.stringify(dataset,null,2);\n\n    let box = document.getElementById(\"dataBox\");\n\n    if(!box){\n      box = document.createElement(\"div\");\n      box.id = \"dataBox\";\n      document.getElementById(\"yb-206\").appendChild(box);\n    }\n\n    box.innerHTML = `\n      <pre style=\"max-height:300px;overflow:auto;background:#f5f5f5;padding:10px;\">\n${jsonText}\n      <\/pre>\n      <button id=\"downloadJson\">\u2b07\ufe0f Download JSON<\/button>\n    `;\n\n    document.getElementById(\"downloadJson\").onclick = ()=>{\n      const blob = new Blob([jsonText],{type:\"application\/json\"});\n      const url = URL.createObjectURL(blob);\n      const a = document.createElement(\"a\");\n      a.href = url;\n      a.download = \"canvas206.json\";\n      a.click();\n    };\n  };\n\n});\n<\/script>\n\n\n\n<h3 class=\"wp-block-heading\">7.Canvas 215\uff5cThread Flow Animation\u7dda\u6d41\u52d5\u614b\u7248<\/h3>\n\n\n\n<p class=\"has-text-align-center\"><strong>1\ufe0f\u20e3\u9023\u7e8c\u6027<\/strong>\u4e00\u689d\u7dda\u8d70\u5b8c\u6574\u500b\u7cfb\u7d71<strong>2\ufe0f\u20e3 \u65b9\u5411\u6027\uff08Flow\uff09<\/strong>\u7bad\u982d = \u8a9e\u6cd5\u65b9\u5411 <strong>3\ufe0f\u20e3 \u5f35\u529b\uff08Tension Proxy\uff09<\/strong>\u984f\u8272\u5f37\u5ea6 = \u7d2f\u7a4d\u5f35\u529b<\/p>\n\n\n\n<iframe style=\"width:100%; height:560px; border:none;\"\nsrcdoc='\n<!DOCTYPE html>\n<html>\n<body style=\"text-align:center; font-family:sans-serif;\">\n\n<div style=\"display:flex; gap:20px; justify-content:center;\">\n<canvas id=\"front\" width=\"400\" height=\"400\"><\/canvas>\n<canvas id=\"back\" width=\"400\" height=\"400\"><\/canvas>\n<\/div>\n\n<br>\n<button onclick=\"play()\">Play<\/button>\n<button onclick=\"pause()\">Pause<\/button>\n<button onclick=\"stop()\">Stop<\/button>\n\n<p id=\"info\">Step: 0<\/p>\n\n<script>\n\nconst path=[\n[1,64,\"f\"],[64,57,\"b\"],[57,8,\"f\"],[8,9,\"b\"],\n[9,63,\"f\"],[63,58,\"b\"],[58,16,\"f\"],[16,56,\"b\"],\n[56,2,\"f\"],[2,7,\"b\"],[7,49,\"f\"],[49,17,\"b\"],\n[17,62,\"f\"],[62,59,\"b\"],[59,24,\"f\"],[24,48,\"b\"],\n[48,3,\"f\"],[3,6,\"b\"],[6,41,\"f\"],[41,25,\"b\"],\n[25,61,\"f\"],[61,60,\"b\"],[60,32,\"f\"],[32,40,\"b\"],\n[40,4,\"f\"],[4,5,\"b\"],[5,33,\"f\"]\n];\n\nconst size=8,gap=40,offset=30;\n\nfunction xy(n){\n let r=Math.floor((n-1)\/size);\n let c=(n-1)%size;\n return [offset+c*gap,offset+r*gap];\n}\n\nconst cf=document.getElementById(\"front\").getContext(\"2d\");\nconst cb=document.getElementById(\"back\").getContext(\"2d\");\n\nlet i=0,running=false,timer;\n\nfunction base(ctx){\n ctx.clearRect(0,0,400,400);\n for(let n=1;n<=64;n++){\n  let [x,y]=xy(n);\n  ctx.beginPath();\n  ctx.arc(x,y,2,0,Math.PI*2);\n  ctx.fillStyle=\"#bbb\";\n  ctx.fill();\n }\n}\n\nfunction arrow(ctx,x1,y1,x2,y2){\n const head=6;\n let dx=x2-x1, dy=y2-y1;\n let ang=Math.atan2(dy,dx);\n\n ctx.beginPath();\n ctx.moveTo(x2,y2);\n ctx.lineTo(x2-head*Math.cos(ang-Math.PI\/6), y2-head*Math.sin(ang-Math.PI\/6));\n ctx.lineTo(x2-head*Math.cos(ang+Math.PI\/6), y2-head*Math.sin(ang+Math.PI\/6));\n ctx.closePath();\n ctx.fill();\n}\n\nfunction draw(){\n base(cf); base(cb);\n\n for(let k=0;k<i;k++){\n  let [a,b,t]=path[k];\n  let [x1,y1]=xy(a),[x2,y2]=xy(b);\n\n  \/\/ FLOW intensity (tension proxy)\n  let alpha = 0.3 + (k\/i)*0.7;\n\n  \/\/ FRONT VIEW\n  cf.beginPath();\n  cf.moveTo(x1,y1);\n  cf.lineTo(x2,y2);\n  if(t===\"f\"){\n    cf.strokeStyle=\"rgba(255,0,0,\"+alpha+\")\";\n    cf.lineWidth=2.5;\n  }else{\n    cf.strokeStyle=\"rgba(0,0,255,0.15)\";\n    cf.lineWidth=1;\n    cf.setLineDash([4,4]);\n  }\n  cf.stroke();\n  cf.setLineDash([]);\n\n  \/\/ arrow\n  if(t===\"f\"){\n    cf.fillStyle=\"red\";\n    arrow(cf,x1,y1,x2,y2);\n  }\n\n  \/\/ BACK VIEW\n  cb.beginPath();\n  cb.moveTo(x1,y1);\n  cb.lineTo(x2,y2);\n  if(t===\"b\"){\n    cb.strokeStyle=\"rgba(0,0,255,\"+alpha+\")\";\n    cb.lineWidth=2.5;\n  }else{\n    cb.strokeStyle=\"rgba(255,0,0,0.15)\";\n    cb.lineWidth=1;\n  }\n  cb.stroke();\n\n  if(t===\"b\"){\n    cb.fillStyle=\"blue\";\n    arrow(cb,x1,y1,x2,y2);\n  }\n }\n\n document.getElementById(\"info\").innerText=\"Step: \"+i;\n}\n\nfunction loop(){\n if(!running) return;\n if(i>=path.length){running=false;return;}\n i++; draw();\n timer=setTimeout(loop,900);\n}\n\nfunction play(){ if(!running){running=true;loop();}}\nfunction pause(){ running=false; clearTimeout(timer);}\nfunction stop(){ running=false; clearTimeout(timer); i=0; draw();}\n\ndraw();\n\n<\/script>\n\n<\/body>\n<\/html>\n'>\n<\/iframe>\n\n\n\n<h3 class=\"wp-block-heading has-text-align-center\">8.Canvas 215\uff5c\u5f35\u529b\u5834\u53ef\u8996\u5316\uff08AI \u6a21\u578b\u7248\u672c\uff09<\/h3>\n\n\n\n<h5 class=\"wp-block-heading has-text-align-center\">\u5f35\u529b\u5834\u662f\u7531\u9023\u7e8c\u523a\u7e61\u8def\u5f91\u5728\u5e03\u9762\u4e0a\u6240\u7522\u751f\u7684\u529b\u5206\u4f48\u7cfb\u7d71<\/h5>\n\n\n\n<iframe style=\"width:100%; height:600px; border:none;\"\nsrcdoc='\n<!DOCTYPE html>\n<html>\n<body style=\"text-align:center; font-family:sans-serif;\">\n\n<div style=\"display:flex; justify-content:center; gap:20px;\">\n<canvas id=\"field\" width=\"400\" height=\"400\"><\/canvas>\n<\/div>\n\n<br>\n<button onclick=\"play()\">Play<\/button>\n<button onclick=\"pause()\">Pause<\/button>\n<button onclick=\"stop()\">Stop<\/button>\n\n<p id=\"info\">Step: 0<\/p>\n\n<script>\n\nconst path=[\n[1,64],[64,57],[57,8],[8,9],\n[9,63],[63,58],[58,16],[16,56],\n[56,2],[2,7],[7,49],[49,17],\n[17,62],[62,59],[59,24],[24,48],\n[48,3],[3,6],[6,41],[41,25],\n[25,61],[61,60],[60,32],[32,40],\n[40,4],[4,5],[5,33]\n];\n\nconst size=8,gap=40,offset=30;\n\nfunction xy(n){\n let r=Math.floor((n-1)\/size);\n let c=(n-1)%size;\n return [offset+c*gap,offset+r*gap];\n}\n\nconst canvas=document.getElementById(\"field\");\nconst ctx=canvas.getContext(\"2d\");\n\nlet i=0,running=false,timer;\n\n\/\/ tension grid\nlet field=[];\nfor(let y=0;y<400;y++){\n field[y]=[];\n for(let x=0;x<400;x++){\n  field[y][x]=0;\n }\n}\n\n\/\/ add tension along line\nfunction addLine(x1,y1,x2,y2){\n let steps=50;\n for(let t=0;t<=1;t+=1\/steps){\n  let x=Math.floor(x1+(x2-x1)*t);\n  let y=Math.floor(y1+(y2-y1)*t);\n\n  for(let dy=-6;dy<=6;dy++){\n   for(let dx=-6;dx<=6;dx++){\n    let nx=x+dx, ny=y+dy;\n    if(nx>=0&&nx<400&#038;&#038;ny>=0&&ny<400){\n      let dist=Math.sqrt(dx*dx+dy*dy);\n      let val=Math.max(0,1-dist\/6);\n      field[ny][nx]+=val*0.3;\n    }\n   }\n  }\n }\n}\n\nfunction drawField(){\n let img=ctx.createImageData(400,400);\n\n for(let y=0;y<400;y++){\n  for(let x=0;x<400;x++){\n    let v=Math.min(1,field[y][x]);\n\n    \/\/ heatmap (blue \u2192 red)\n    let r=Math.floor(255*v);\n    let b=Math.floor(255*(1-v));\n\n    let idx=(y*400+x)*4;\n    img.data[idx]=r;\n    img.data[idx+1]=0;\n    img.data[idx+2]=b;\n    img.data[idx+3]=255;\n  }\n }\n\n ctx.putImageData(img,0,0);\n}\n\nfunction drawPoints(){\n for(let n=1;n<=64;n++){\n  let [x,y]=xy(n);\n  ctx.beginPath();\n  ctx.arc(x,y,2,0,Math.PI*2);\n  ctx.fillStyle=\"#fff\";\n  ctx.fill();\n }\n}\n\nfunction step(){\n if(i>=path.length){running=false;return;}\n\n let [a,b]=path[i];\n let [x1,y1]=xy(a),[x2,y2]=xy(b);\n\n addLine(x1,y1,x2,y2);\n\n ctx.clearRect(0,0,400,400);\n drawField();\n drawPoints();\n\n i++;\n document.getElementById(\"info\").innerText=\"Step: \"+i;\n\n timer=setTimeout(step,1000);\n}\n\nfunction play(){ if(!running){running=true;step();}}\nfunction pause(){ running=false; clearTimeout(timer);}\nfunction stop(){\n running=false;\n clearTimeout(timer);\n i=0;\n for(let y=0;y<400;y++){\n  for(let x=0;x<400;x++){\n   field[y][x]=0;\n  }\n }\n ctx.clearRect(0,0,400,400);\n drawPoints();\n}\n\ndrawPoints();\n\n<\/script>\n\n<\/body>\n<\/html>\n'>\n<\/iframe>\n","protected":false},"excerpt":{"rendered":"<p>\u672c\u9801\u5c07\u523a\u7e61\u8996\u70ba\u4e00\u7a2e\u300c\u57f7\u884c\u7cfb\u7d71\u300d\u9032\u884c\u8996\u89ba\u5316\u3002\u4e0d\u540c\u65bc\u975c\u614b\u5716\u6848\uff0c\u6b64\u52d5\u756b\u5448\u73fe\u7d50\u69cb\u5982\u4f55\u7531\u9023\u7e8c\u8def\u5f91\u6c7a\u7b56\u9010\u6b65\u751f\u6210\u3002\u6b63\u9762\u91dd\u6cd5\u69cb [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"set","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"class_list":["post-5282","page","type-page","status-publish","hentry"],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/yunbroidery.com\/en\/wp-json\/wp\/v2\/pages\/5282","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/yunbroidery.com\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/yunbroidery.com\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/yunbroidery.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/yunbroidery.com\/en\/wp-json\/wp\/v2\/comments?post=5282"}],"version-history":[{"count":5,"href":"https:\/\/yunbroidery.com\/en\/wp-json\/wp\/v2\/pages\/5282\/revisions"}],"predecessor-version":[{"id":5538,"href":"https:\/\/yunbroidery.com\/en\/wp-json\/wp\/v2\/pages\/5282\/revisions\/5538"}],"wp:attachment":[{"href":"https:\/\/yunbroidery.com\/en\/wp-json\/wp\/v2\/media?parent=5282"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}