Skip to content

SnapAxis 是一个用于管理吸附轴(如水平轴或垂直轴)的类,支持吸附点的添加、删除、更新以及吸附逻辑的实现。

License

Notifications You must be signed in to change notification settings

refline/snap-axis

Repository files navigation

SnapAxis

SnapAxis 是一个用于管理吸附轴(如水平轴或垂直轴)的类,支持吸附点的添加、删除、更新以及吸附逻辑的实现。适用于拖拽、对齐、辅助线等场景。

snap-axis

安装

使用 npm 或 yarn 安装:

npm install snap-axis

yarn add snap-axis

使用示例

import { SnapAxis } from "snap-axis";

const snapAxis = new SnapAxis({
  snapValues: [
    { value: 10, id: "10" },
    { value: 20, id: "20" },
    { value: 30, id: "30" },
  ],
});

let startPageX = 0;
let result;
const updater = snapAxis.getSnapGroupUpdater([3, 30, 50], startPageX, { distance: 5 });

startPageX++;
result = updater(startPageX);
console.log(result); // { values: [4,31,51], snapped: false }

startPageX++;
result = updater(startPageX);
console.log(result); // { values: [10,37,57], snapped: true }

startPageX++;
result = updater(startPageX);
console.log(result); // { values: [10,37,57], snapped: false }

// ...

Edit SnapAxis

API 示例

getSnapUpdater 吸附更新器

const snapAxis = new SnapAxis({
  snapValues: [
    { value: 10, id: "10" },
    { value: 20, id: "20" },
    { value: 30, id: "30" },
  ],
});
let pageX = 1;
const updater = snapAxis.getSnapUpdater(8, pageX);
pageX++;
const result = updater(pageX);
console.log(result); // { value: 10, snapped: true }

pageX++;
const result = updater(pageX);
console.log(result); // { value: 10, snapped: false }

getSnapGroupUpdater 吸附组更新器

const snapAxis = new SnapAxis({
  snapValues: [
    { value: 10, id: "10" },
    { value: 20, id: "20" },
    { value: 30, id: "30" },
  ],
});
const updater = snapAxis.getSnapGroupUpdater([10, 20], 0);
const result = updater(1);
console.log(result); // { values: [10, 20], snapped: false }

getSnappedValues 获取某个值对应的所有吸附点。

snapAxis.deleteSnapValue({ value: 10, id: "A" });
snapAxis.deleteSnapValue({ value: 10, id: "B" });
const snappedValues = snapAxis.getSnappedValues(10);
console.log(snappedValues); // [{ value: 10, id: "A" },{ value: 10, id: "B" }]

checkSnapped / checkGroupSnapped

判断某个值或一组值是否处于吸附状态。

snapAxis.checkSnapped(10);
snapAxis.checkGroupSnapped([10, 20]);

更多 API

接入示例

UMD 使用示例

<!DOCTYPE html>
<html>
  <head>
    <title>SnapAxis Example</title>
    <meta charset="UTF-8" />
  </head>

  <body>
    <style>
      #app {
        font-family: sans-serif;
        text-align: center;
        font-size: 12px;
      }

      .container {
        height: 100px;
        position: relative;
        margin: 0 auto;
        user-select: none;
        width: 700px;
      }

      .tickWarp {
        position: absolute;
        bottom: 0;
        left: 0;
      }

      .tick {
        height: 5px;
        position: "relative";
        border-bottom: 1px solid #757575;
      }

      .tickItem {
        position: absolute;
        bottom: 0;
        left: 0;
        width: 1px;
        height: 5px;
        background-color: #757575;
      }

      .dragBox {
        position: absolute;
        left: 0;
        bottom: 0;
        height: 40px;
        background-color: #0307f2;
        opacity: 0.3;
      }

      .snappedLabel {
        position: absolute;
        top: 0;
        left: 0;
        pointer-events: none;
        font-size: 12px;
        color: #a3a3a3;
        text-align: left;
      }

      .setting {
        position: absolute;
        top: 0;
        right: 0;
        font-size: 12px;
        color: #a3a3a3;
      }

      .setting label {
        display: flex;
        align-items: center;
      }

      .setting input {
        margin: 0;
        padding: 0;
      }
    </style>
    <div id="app">
      <div class="container" id="demo02">
        <div class="snappedLabel" id="snappedLabel" style="display: none"></div>
        <div class="setting">
          <label>
            禁用吸附:
            <input type="checkbox" id="disableSnap" />
          </label>
        </div>
        <div class="tickWarp">
          <div class="tick" id="tick"></div>
        </div>
        <div class="dragBox" id="dragBox"></div>
      </div>
    </div>

    <script src="./index.mjs" type="module"></script>
  </body>
</html>
// index.mjs
import { SnapAxis } from "snap-axis";

const TickWidth = 700;
const BoxWidth = 60;

// 随机生成刻度
function randomRange(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}
const tickValues = [0, TickWidth, TickWidth / 2];
for (let i = 0; i < 10; i++) {
  tickValues.push(randomRange(0, TickWidth));
}
tickValues.sort((a, b) => a - b);

// 初始化 SnapAxis
const snapAxis = new SnapAxis({
  snapValues: tickValues.map((value, idx) => ({
    id: `snap_${idx}`,
    value,
  })),
});

// 渲染刻度
const tickEl = document.getElementById("tick");
tickEl.style.width = TickWidth + "px";
tickValues.forEach((value) => {
  const div = document.createElement("div");
  div.className = "tickItem";
  div.style.left = value + "px";
  tickEl.appendChild(div);
});

// 拖拽逻辑
let value = 0;
let disableSnap = false;
const dragBox = document.getElementById("dragBox");
dragBox.style.width = BoxWidth + "px";
dragBox.style.left = value + "px";

const snappedLabel = document.getElementById("snappedLabel");
const disableSnapInput = document.getElementById("disableSnap");

function getSnapGroup(val) {
  return [val, val + BoxWidth / 2, val + BoxWidth];
}

function updateUI() {
  // 检查是否吸附
  let isSnapped = false;
  let snappedValues = [];
  const snapGroup = getSnapGroup(value);
  for (let i = 0; i < snapGroup.length; i++) {
    const v = snapGroup[i];
    if (snapAxis.checkSnapped(v)) {
      isSnapped = true;
      snappedValues = snapAxis.getSnappedValues(v);
      break;
    }
  }
  dragBox.className = "dragBox" + (isSnapped ? " snapped" : "");
  dragBox.style.left = value + "px";

  if (isSnapped && snappedValues.length) {
    dragBox.style.backgroundColor = "red";
    snappedLabel.style.display = "";
    snappedLabel.innerHTML =
      `<div>Snapped Values:</div>` +
      snappedValues
        .map((item) => `id=${item.id}, value=${item.value}`)
        .join("<br>");
  } else {
    dragBox.style.backgroundColor = "";
    snappedLabel.style.display = "none";
    snappedLabel.innerHTML = "";
  }
}

dragBox.addEventListener("mousedown", (e) => {
  const snapGroup = getSnapGroup(value);
  // 获取吸附更新器
  const updater = snapAxis.getSnapGroupUpdater(snapGroup, e.clientX, {
    distance: 5,
    disableSnap,
  });

  function onMouseMove(e) {
    // 计算拖动偏移量
    const result = updater(e.clientX);
    const values = result.values;
    value = Math.max(0, Math.min(TickWidth, values[0]));
    updateUI();
  }

  function onMouseUp() {
    document.removeEventListener("mousemove", onMouseMove);
    document.removeEventListener("mouseup", onMouseUp);
    document.body.style.cursor = "";
  }

  document.addEventListener("mousemove", onMouseMove);
  document.addEventListener("mouseup", onMouseUp);
  document.body.style.cursor = "move";
});

disableSnapInput.addEventListener("change", (e) => {
  disableSnap = e.target.checked;
});

updateUI();

相关

About

SnapAxis 是一个用于管理吸附轴(如水平轴或垂直轴)的类,支持吸附点的添加、删除、更新以及吸附逻辑的实现。

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published