距离提示辅助线so easy

566 阅读2分钟

距离提示辅助线

位置与大小格式

{
x:100,
y:200,
width:300,
height:400
}

一个点到一个矩形的距离

  • 点到左边

  • 点到右边

  • 点到上边

  • 点到下边

一个矩形与另一个矩形的距离

  • 矩形 1 的左边 vs 矩形 2 的左边,矩形 2 的右边

  • 矩形 1 的右边 vs 矩形 2 的左边,矩形 2 的右边

  • 矩形 1 的上边 vs 矩形 2 的上边,矩形 2 的下边

  • 矩形 1 的下边 vs 矩形 2 的上边,矩形 2 的下边

取矩形 1 每个情况的最小值就是对应边到矩形 2 的距离

function getXDistance(props, rect) {
  return [
    Math.abs(rect.x - props.x),
    Math.abs(rect.x + rect.width - props.x),
    Math.abs(rect.x - (props.x + props.width)),
    Math.abs(rect.x + rect.width - (props.x + props.width))
  ];
}
function getYDistance(props, rect) {
  return [
    Math.abs(rect.y - props.y),
    Math.abs(rect.y + rect.height - props.y),
    Math.abs(rect.y - (props.y + props.height)),
    Math.abs(rect.y + rect.height - (props.y + props.height))
  ];
}

判断一个矩形是否在附近

参考矩形另一个矩形的距离在 nearD 范围内即在附近,绘制对应的辅助线. 当某个边重合,距离为 0 不进行绘制。

//附近距离
let nearD = 160;
export function setNearDistance(d) {
  nearD = d;
}
/**
 * 检查组件是否在选框范围内
 * @param {Object} props 组件位置大小数据
 * @returns {Boolean}
 */
function checkNear(props, rect) {
  let xD = getXDistance(props, rect);
  let yD = getYDistance(props, rect);
  if (Math.min(...xD) <= nearD || Math.min(...yD) <= nearD) {
    return true;
  }

  return false;
}

interactJs 拖拉拽改变大小和位置

文档地址如下:

interactjs.io/docs/

具体代码地址

github.com/xiaolidan00…

策略模式获取最短距离


const XLine = {
 0: (props, rect) => {
   return Math.min(rect.x, props.x);
 },
 1: (props, rect) => {
   return Math.min(rect.x + rect.width, props.x);
 },
 2: (props, rect) => {
   return Math.min(rect.x, props.x + props.width);
 },
 3: (props, rect) => {
   return Math.min(rect.x + rect.width, props.x + props.width);
 }
};

const YLine = {
 0: (props, rect) => {
   return Math.min(rect.y, props.y);
 },
 1: (props, rect) => {
   return Math.min(rect.y + rect.height, props.y);
 },
 2: (props, rect) => {
   return Math.min(rect.y, props.y + props.height);
 },
 3: (props, rect) => {
   return Math.min(rect.y + rect.height, props.y + props.height);
 }
};

当前矩形需要绘制包围框,包括:相对于父容器的上下边界和距离,左右边界,宽高

let posH = [
    //左距离
    {
      style: {
        left: 0,
        top: top + height * 0.5 - 16 + 'px',
        width: left + 'px'
      },
      value: left
    },
    //右距离
    {
      style: {
        right: 0,
        top: top + height * 0.5 - 16 + 'px',
        width: screenWidth - (left + width) + 'px'
      },
      value: screenWidth - (left + width)
    },
    //宽度
    {
      style: {
        left: left + 'px',
        top: top + height * 0.5 - 16 + 'px',
        width: width + 'px',
        justifyContent: 'flex-start',
        border: 'none',
        paddingLeft: '10px'
      },
      value: height
    },
    //上边界
    {
      style: {
        left: 0,
        top: top + 'px',
        width: '100%',
        borderBottom: 'dashed 1px rgb(37, 124, 245)'
      }
    },
    //下边界
    {
      style: {
        left: 0,
        top: top + height + 'px',
        width: '100%',
        borderBottom: 'dashed 1px rgb(37, 124, 245)'
      }
    }
  ];
  let posV = [
    //上距离
    {
      style: {
        left: left + width * 0.5 + 'px',
        top: 0,
        height: top + 'px'
      },
      value: top
    },
    //下距离
    {
      style: {
        left: left + width * 0.5 + 'px',
        bottom: 0,
        height: screenHeight - (top + height) + 'px'
      },
      value: screenHeight - (top + height)
    },
    //高度
    {
      style: {
        left: left + width * 0.5 + 'px',
        top: top + 'px',
        height: height + 'px',
        alignItems: 'flex-start',
        border: 'none',

        paddingTop: '10px'
      },
      value: height
    },
    //左边界
    {
      style: {
        left: left + 'px',
        top: 0,
        height: '100%',
        borderLeft: 'dashed 1px rgb(37, 124, 245)'
      }
    },
    //右边界
    {
      style: {
        left: left + width + 'px',
        top: 0,
        height: '100%',
        borderLeft: 'dashed 1px rgb(37, 124, 245)'
      }
    }
  ];

获取辅助线:遍历所有组件,对比最短距离,在范围内则加入辅助线



/**
 *
 * @param {Object} activeElement 参考元素
 * @param {Array} elmts 元素list
 * @param {DOM} el 父元素id
 * @returns {Object} {h:横向辅助线,v:纵向辅助线}
 */
export function getGuideLine(activeElement, elmts, el) {
  let { x: left, y: top, width, height } = activeElement.props;
  let container = document.querySelector(el);
  let screenWidth = container.offsetWidth;
  let screenHeight = container.offsetHeight;
  let posH...
  let posV...
  let nearLineH = [];
  let nearLineV = [];
  elmts.forEach((elmt) => {
    if (elmt.id != activeElement.id && checkNear(elmt.props, activeElement.props)) {
      //横向距离
      let xD = getXDistance(elmt.props, activeElement.props);

      let isLeft1 = false;
      let isLeft2 = false;
      for (let i = 0; i < xD.length; i++) {
        let d = xD[i];
        //去重
        if (i == 2 && isLeft1) {
          continue;
        }
        if (i == 3 && isLeft2) {
          continue;
        }
        if (d > 0 && d <= nearD) {
          let s = XLine[i](elmt.props, activeElement.props, d);
          if (i == 0) {
            isLeft1 = true;
          }
          if (i == 1) {
            isLeft2 = true;
          }
          nearLineH.push({
            style: {
              left: s + 'px',
              top: elmt.props.y + elmt.props.height * 0.5 - 16 + 'px',
              width: d + 'px'
            },
            value: d
          });
        }
      }

      let yD = getYDistance(elmt.props, activeElement.props);

      let isTop1 = false;
      let isTop2 = false;
      for (let i = 0; i < yD.length; i++) {
        let d = yD[i];
         //去重
        if (i == 2 && isTop1) {
          continue;
        }
        if (i == 3 && isTop2) {
          continue;
        }
        if (d > 0 && d <= nearD) {
          let s = YLine[i](elmt.props, activeElement.props, d);
          if (i == 0) {
            isTop1 = true;
          }
          if (i == 1) {
            isTop2 = true;
          }
          nearLineV.push({
            style: {
              left: elmt.props.x + elmt.props.width * 0.5 + 'px',
              top: s + 'px',
              height: d + 'px'
            },
            value: d
          });
        }
      }
    }
  });

  return {
    h: posH.concat(nearLineH),
    v: posV.concat(nearLineV)
  };
}