Drag
Example where the box becomes draggable on pointer down.
import { CenterAlignedPosition, ClockComposer, Simulator, GateConditionalVector, Kinetics, SpringEngine,} from "@yyyoichi/chrono-kinesis";import { ElementPhysics, ElementRect, PrimaryPointerDownGateClock, PrimaryPointerPositionClock, WindowResizeTriggerClock,} from "@yyyoichi/chrono-kinesis/dom";
const simulation = new Simulator({ fixedStepSec: 1 / 20 });
const boxEl = document.getElementById("drag-box")!;
// pointerElに対するpointerdownを監視します。const pointerDownGateClock = new PrimaryPointerDownGateClock(boxEl);// gate=1のときのみpointerの位置を追跡します。const pointerPositionClock = new PrimaryPointerPositionClock( document.getElementById("drag-pointer-container")!, { gate: pointerDownGateClock, initPosition: pointerDownGateClock, },);
const boxRect = new ElementRect(boxEl, { trigger: new WindowResizeTriggerClock(),});// ドラッグ中はpointer位置をターゲットとして、ドラッグしていないときは初期位置をターゲットとするベクトルです。const target = new GateConditionalVector( pointerDownGateClock, // ドラッグが開始されればPointerの位置をターゲットとします。 // pointerPositionClockの位置をpointerDomの中心にオフセットするために使用します。 new CenterAlignedPosition(pointerPositionClock, boxRect), // ドラッグが開始されていなければ初期位置をターゲットとします。 boxRect,);simulation.add({ // いずれかがトリガーしている間はアクティブです。 clock: new ClockComposer(pointerDownGateClock, pointerPositionClock), target: target, kinetics: new Kinetics(target.vector(), { engine: new SpringEngine({ settleMs: 800, zeta: 0.7 }), }), physics: new ElementPhysics(boxEl),});simulation.run();<div id="drag-pointer-container" > <div id="drag-box" style="touch-action: none; width: 4rem; height: 4rem; background-color: cadetblue" > </div></div>---type Props = Omit<astroHTML.JSX.HtmlHTMLAttributes, "id">;---
<div id="drag-pointer-container" {...Astro.props}> <div id="drag-box" style="touch-action: none; width: 4rem; height: 4rem; background-color: cadetblue" > </div></div>
<script> import { CenterAlignedPosition, ClockComposer, Simulator, GateConditionalVector, Kinetics, SpringEngine, } from "@yyyoichi/chrono-kinesis"; import { ElementPhysics, ElementRect, PrimaryPointerDownGateClock, PrimaryPointerPositionClock, WindowResizeTriggerClock, } from "@yyyoichi/chrono-kinesis/dom";
const simulation = new Simulator({ fixedStepSec: 1 / 20 });
const boxEl = document.getElementById("drag-box")!;
// pointerElに対するpointerdownを監視します。 const pointerDownGateClock = new PrimaryPointerDownGateClock(boxEl); // gate=1のときのみpointerの位置を追跡します。 const pointerPositionClock = new PrimaryPointerPositionClock( document.getElementById("drag-pointer-container")!, { gate: pointerDownGateClock, initPosition: pointerDownGateClock, }, );
const boxRect = new ElementRect(boxEl, { trigger: new WindowResizeTriggerClock(), }); // ドラッグ中はpointer位置をターゲットとして、ドラッグしていないときは初期位置をターゲットとするベクトルです。 const target = new GateConditionalVector( pointerDownGateClock, // ドラッグが開始されればPointerの位置をターゲットとします。 // pointerPositionClockの位置をpointerDomの中心にオフセットするために使用します。 new CenterAlignedPosition(pointerPositionClock, boxRect), // ドラッグが開始されていなければ初期位置をターゲットとします。 boxRect, ); simulation.add({ // いずれかがトリガーしている間はアクティブです。 clock: new ClockComposer(pointerDownGateClock, pointerPositionClock), target: target, kinetics: new Kinetics(target.vector(), { engine: new SpringEngine({ settleMs: 800, zeta: 0.7 }), }), physics: new ElementPhysics(boxEl), }); simulation.run();</script>Example of drag interaction constrained to a specified region.
import { CenterAlignedPosition, ClockComposer, Simulator, GateConditionalVector, PositionInRegionGate, SpringEngine, TeleportKinetics, TriggerReducer,} from "@yyyoichi/chrono-kinesis";import { PrimaryPointerDownGateClock, PrimaryPointerPositionClock, ElementRect, WindowResizeTriggerClock, ParentSwitchTrigger, ElementPhysics,} from "@yyyoichi/chrono-kinesis/dom";
// 1. ドラッグ開始// 2. ドラッグ中->ボックスをドラッグ座標に追従させる// 3. ポインターがリージョンを跨いだらボックスを移動(appendChild)させる// 4. ドロップ終了->本来のボックスの描画座標(padding-box)に移動させる
const simulation = new Simulator({ fixedStepSec: 1 / 20 });
const containerEl = document.getElementById("drag-to-region-container")!;const regionEl = document.getElementById("drag-to-region-region")!;const boxEl = document.getElementById("drag-to-region-box")!;const windowResizeTriggerClock = new WindowResizeTriggerClock();// ドラッグ先矩形。windowリサイズ時に座標を再計測します。const regionRect = new ElementRect(regionEl, { space: "padding-box", trigger: windowResizeTriggerClock,});// マウスポインターconst pointerDownGateClock = new PrimaryPointerDownGateClock(boxEl);const pointerPositionClock = new PrimaryPointerPositionClock(containerEl, { gate: pointerDownGateClock, initPosition: pointerDownGateClock,});// ポインターの位置がリージョン内にあるかどうかを判定するゲート。const inRegionGate = new PositionInRegionGate( pointerPositionClock, regionRect, regionRect,);// inRegionGateが1のときはregionElを親要素に、0のときはcontainerElを親要素にして座標を取得します。const parentSwitchedTrigger = new ParentSwitchTrigger( boxEl, inRegionGate, regionEl, containerEl, { // マウスがdownしているときにのみ切替を許可します。 switchGate: pointerDownGateClock, },);// 追従する矩形。const boxRect = new ElementRect(boxEl, { space: "padding-box", // ウィンドウリサイズ時と親要素切替時に座標を再計測します。 trigger: new TriggerReducer( "OR", windowResizeTriggerClock, parentSwitchedTrigger, ),});
// ポインターに追従するシミュレーション。simulation.add({ clock: new ClockComposer( pointerDownGateClock, pointerPositionClock, windowResizeTriggerClock, ), target: new GateConditionalVector( pointerDownGateClock, new CenterAlignedPosition(pointerPositionClock, boxRect), boxRect, ), kinetics: new TeleportKinetics(boxRect, { engine: new SpringEngine({ settleMs: 800, zeta: 0.7 }), }), physics: new ElementPhysics(boxEl),});simulation.run();
window.addEventListener("beforeunload", () => { simulation.destroy();});<div > <div id="drag-to-region-container" style="position: relative; display: flex; justify-content: flex-end; width: 100%; height: 100%; touch-action: none;" > <!-- ドラッグされるボックス --> <div id="drag-to-region-box" style="position: absolute; top: 0; left: 0; width: 4rem; height: 4rem; margin: 0; touch-action: none; background-color: cadetblue;" > </div> <!-- ドラッグエリア(リージョン) --> <div style="width: 50%; height: 100%; margin: 0; border: 1rem lightgray dashed;" > <div id="drag-to-region-region" style="position: relative; width: 100%; height: 100%; margin: 0;" > <!-- ここにボックスが配置されます。 --> </div> </div> </div></div>---type Props = Omit<astroHTML.JSX.HtmlHTMLAttributes, "id">;---
<div {...Astro.props}> <div id="drag-to-region-container" style="position: relative; display: flex; justify-content: flex-end; width: 100%; height: 100%; touch-action: none;" > <!-- ドラッグされるボックス --> <div id="drag-to-region-box" style="position: absolute; top: 0; left: 0; width: 4rem; height: 4rem; margin: 0; touch-action: none; background-color: cadetblue;" > </div> <!-- ドラッグエリア(リージョン) --> <div style="width: 50%; height: 100%; margin: 0; border: 1rem lightgray dashed;" > <div id="drag-to-region-region" style="position: relative; width: 100%; height: 100%; margin: 0;" > <!-- ここにボックスが配置されます。 --> </div> </div> </div></div>
<script> import { CenterAlignedPosition, ClockComposer, Simulator, GateConditionalVector, PositionInRegionGate, SpringEngine, TeleportKinetics, TriggerReducer, } from "@yyyoichi/chrono-kinesis"; import { PrimaryPointerDownGateClock, PrimaryPointerPositionClock, ElementRect, WindowResizeTriggerClock, ParentSwitchTrigger, ElementPhysics, } from "@yyyoichi/chrono-kinesis/dom";
// 1. ドラッグ開始 // 2. ドラッグ中->ボックスをドラッグ座標に追従させる // 3. ポインターがリージョンを跨いだらボックスを移動(appendChild)させる // 4. ドロップ終了->本来のボックスの描画座標(padding-box)に移動させる
const simulation = new Simulator({ fixedStepSec: 1 / 20 });
const containerEl = document.getElementById("drag-to-region-container")!; const regionEl = document.getElementById("drag-to-region-region")!; const boxEl = document.getElementById("drag-to-region-box")!; const windowResizeTriggerClock = new WindowResizeTriggerClock(); // ドラッグ先矩形。windowリサイズ時に座標を再計測します。 const regionRect = new ElementRect(regionEl, { space: "padding-box", trigger: windowResizeTriggerClock, }); // マウスポインター const pointerDownGateClock = new PrimaryPointerDownGateClock(boxEl); const pointerPositionClock = new PrimaryPointerPositionClock(containerEl, { gate: pointerDownGateClock, initPosition: pointerDownGateClock, }); // ポインターの位置がリージョン内にあるかどうかを判定するゲート。 const inRegionGate = new PositionInRegionGate( pointerPositionClock, regionRect, regionRect, ); // inRegionGateが1のときはregionElを親要素に、0のときはcontainerElを親要素にして座標を取得します。 const parentSwitchedTrigger = new ParentSwitchTrigger( boxEl, inRegionGate, regionEl, containerEl, { // マウスがdownしているときにのみ切替を許可します。 switchGate: pointerDownGateClock, }, ); // 追従する矩形。 const boxRect = new ElementRect(boxEl, { space: "padding-box", // ウィンドウリサイズ時と親要素切替時に座標を再計測します。 trigger: new TriggerReducer( "OR", windowResizeTriggerClock, parentSwitchedTrigger, ), });
// ポインターに追従するシミュレーション。 simulation.add({ clock: new ClockComposer( pointerDownGateClock, pointerPositionClock, windowResizeTriggerClock, ), target: new GateConditionalVector( pointerDownGateClock, new CenterAlignedPosition(pointerPositionClock, boxRect), boxRect, ), kinetics: new TeleportKinetics(boxRect, { engine: new SpringEngine({ settleMs: 800, zeta: 0.7 }), }), physics: new ElementPhysics(boxEl), }); simulation.run();
window.addEventListener("beforeunload", () => { simulation.destroy(); });</script>