2022-01-15
#js 
オープンソースなベクトルグラフィックESモジュール「Paper-es forked Paper.js」を使って、シンプルな式と小さいデータ量で美しい曲線が描ける「ベジェ曲線」の編集ツールをPaper.jsのサンプルから移植。

hit-testing - Paper-es
いろんな大きさのベジェ曲線によるカタチをマウスやタップで自由に動かしたり、カタチを変形させたりできます。hit-testing(当たり判定)のデモで、ちゃんとクリックしたところにあるカタチや、線を認識しているのがいい感じです。オープンソースなので、気になる人はアルゴリズムをチェックすることもできます。

直感的に違和感なく使う裏にあるプログラムによるシクミ。おもしろいですね!

JavaScriptのプログラムはこちら。ES-Jamに貼り付けて遊んでみましょう。 <!DOCTYPE html><html lang="ja"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width"> <title>hit-testing - Paper-es</title> <style> body { margin: 0; height: 100vh; text-align: center; } canvas { display: block; width: 100%; height: 80%; background-color: #eee; } </style> </head> <body> <h1>hit-testing - Paper-es</h1> <canvas id="canvas" resize></canvas> <button id=btnadd>add more</button> <label><input type="checkbox" id=chkremove>remove</label> <script type="module"> import { Paper, Tool, Path, Rectangle, Point } from "https://code4fukui.github.io/Paper-es/Paper.js"; Paper.install(window); // -> activate project, tool, view Paper.setup("canvas"); const values = { paths: 20, minPoints: 5, maxPoints: 15, minRadius: 30, maxRadius: 500, }; const hitOptions = { segments: true, stroke: true, fill: true, tolerance: 5, }; const createBlob = (center, maxRadius, points) => { const path = new Path(); path.closed = true; for (let i = 0; i < points; i++) { const delta = new Point({ length: (maxRadius * 0.5) + (Math.random() * maxRadius * 0.5), angle: (360 / points) * i }); path.add(center.add(delta)); } path.smooth(); return path; }; const createPaths = () => { const radiusDelta = values.maxRadius - values.minRadius; const pointsDelta = values.maxPoints - values.minPoints; for (let i = 0; i < values.paths; i++) { const radius = values.minRadius + Math.pow(Math.random(), 5) * radiusDelta; const points = values.minPoints + Math.floor(Math.random() * pointsDelta); const path = createBlob(view.size.multiply(Point.random()), radius, points); const lightness = .7; // (Math.random() - 0.5) * 0.4 + 0.4; const hue = Math.random() * 360; const saturation = .5; path.fillColor = { hue, saturation, lightness }; path.strokeColor = "black"; }; }; createPaths(); btnadd.onclick = () => createPaths(); let segment, path; let movePath = false; view.onMouseDown = (event) => { segment = path = null; const hitResult = project.hitTest(event.point, hitOptions); if (!hitResult) { return; } if (event.modifiers.shift || chkremove.checked) { if (hitResult.type == "segment") { hitResult.segment.remove(); } else if (hitResult.type == "fill") { hitResult.item.remove(); } return; } if (hitResult) { path = hitResult.item; if (hitResult.type == 'segment') { segment = hitResult.segment; } else if (hitResult.type == 'stroke') { const location = hitResult.location; segment = path.insert(location.index + 1, event.point); path.smooth(); } } movePath = hitResult.type == "fill"; if (movePath) { project.activeLayer.addChild(hitResult.item); } }; view.onMouseMove = (event) => { project.activeLayer.selected = false; if (event.item) { event.item.selected = true; } }; view.onMouseDrag = (event) => { if (segment) { segment.point.x += event.delta.x; segment.point.y += event.delta.y; path.smooth(); } else if (path) { path.position.x += event.delta.x; path.position.y += event.delta.y; } } </script> </body> </html> (src on GitHub, forked Paper.js - Hit Testing)

Tweet
クリエイティブ・コモンズ・ライセンス
本ブログの記事や写真は「Creative Commons — CC BY 4.0」の下に提供します。記事内で紹介するプログラムや作品は、それぞれに記載されたライセンスを参照ください。
CC BY / @taisukef / アイコン画像 / プロフィール画像 / 「一日一創」画像 / RSS