n向区域选择(图片)

介绍

  1. 本文以 react 举例,其他框架实现基本上一致(vue则是@mouseMove 、 @click…)
  2. 实现原理:对图片进行位置区域选中,判断当前鼠标位置是否在这个区域内,如果在区域内则进行可点击鼠标切换(cursor: pointer),如果此时点击则判断出当前点击的位置是哪块区域。
  3. 具体需求如果有类似的可以看看逻辑,然后也可以在这个基础上更改
  4. 本文主要作于笔记,方便以后对类似问题处理。

区域计算(可被点击、可设置hover效果)

  1. 计算四向圆形区域(规则圆形区域)
    . 在这里插入图片描述
import { useState } from 'react';
const w = 155;
const h = 155;
const positionInfo = {
  top: [w / 2, 22],
  left: [22, h / 2],
  right: [w - 22, h / 2],
  bottom: [w / 2, h - 22],
  center: [w / 2, h / 2],
}
/**
 * 圆形区域计算
 * @param param0 Array<number> 中心点位置([centerX, centerY])
 * @param radius number 圆半径
 * @param param2 Array<number> 鼠标当前的x轴与y轴的位置([x, y])
 * @returns Boolean 判断当前鼠标位置是否在给定的区域内;
 */
const cirCountRule = ([cx, cy]: Array<number>, radius: number, [x, y]: Array<number>) => Math.sqrt(Math.pow(Math.abs(cx - x), 2) + Math.pow(Math.abs(cy - y), 2)) < radius;
// 机器人车体控制 当前位置是否可被点击
const positionObj = ([x, y]: any) => ({
  top: cirCountRule(positionInfo.top, 16, [x, y]),
  left: cirCountRule(positionInfo.left, 16, [x, y]),
  right: cirCountRule(positionInfo.right, 16, [x, y]),
  bottom: cirCountRule(positionInfo.bottom, 16, [x, y]),
  center: cirCountRule(positionInfo.center, 25, [x, y]),
})
const Page = () => {
  const [cursor, setCursor] = useState(false); // true pointer;false default
  const xxMouse = (e: any) => setCursor(
    Object.values(
      positionObj([e.nativeEvent.offsetX, e.nativeEvent.offsetY])
    )
      .reduce((pre, value: any) => pre || value, false)
  );
  const xxClick = (e: any) => {
    try {
      Object.entries(
        positionObj([e.nativeEvent.offsetX, e.nativeEvent.offsetY])
      )
        .reduce((pre, [key, value]: any) => {
          // 同时只会有一种出现
          if (pre || value) {
            throw [key, value]
          }
          return pre || value;
        }, false)
    } catch (info: any) {
      // 点击后的逻辑描写处
      console.log(info[0])
    }
  }
  return <img
    src={require('@/assets/images/picture.png')}
    alt=""
    style={{
      width: '155px',
      height: '155px',
      pointerEvents: 'auto',
      cursor: !cursor ? 'auto' : 'pointer'
    }}
    onMouseMove={xxMouse}
    onClick={xxClick}
  />
}
export default Page

效果图
在这里插入图片描述

  1. 不规则区域四方点击效果(以下)
    在这里插入图片描述
import { useState } from 'react';
const zPositionInfo = {
  top: [45 + 20, 135 + 15],
  left: [135 + 20, 225 + 15],
  right: [315 + 20, 45 + 15],
  bottom: [225 + 20, 315 + 15],
}
/**
 * 圆形区域计算
 * @param param0 Array<number> 中心点位置([centerX, centerY])
 * @param radius number 圆半径
 * @param param2 Array<number> 鼠标当前的x轴与y轴的位置([x, y])
 * @returns Boolean 判断当前鼠标位置是否在给定的区域内;
 */
const cirCountRule = ([cx, cy]: Array<number>, radius: number, [x, y]: Array<number>) => Math.sqrt(Math.pow(Math.abs(cx - x), 2) + Math.pow(Math.abs(cy - y), 2)) < radius;

// 判断当前鼠标位置在哪个区域:区域如下
// 2 1
// 3 4
const areaJudge = ([cx, cy]: any, [x, y]: any) => cx - x > 0 ? (cy - y > 0 ? 90 : 180) : cy - y > 0 ? 0 : 270;
/**
 * 
 * @param param0 Array<number> 限制区域角度:([45°, 90°]);限制:0 - 360;
 * @param param1 Array<number> 圆中心点位置:([centerX, centerY])
 * @param param2 Array<number> 当前鼠标位置:([x, y])
 * @param innerRadio Number 内部圆圈的半径
 * @param outRadio Number 外部圆圈的半径
 * @returns 
 */
const limitCirRule = ([beginAngle, endAngle]: any, [cx, cy]: any, [x, y]: any, innerRadio: any, outRadio: any) => {
  // 内部空白宽度
  const unlessWidth = 6;
  const a = Math.abs(y - cy);
  const b = Math.abs(x - cx);
  const c = Math.sqrt(Math.pow(b, 2) + Math.pow(a, 2));
  const arrJudgeNumber = areaJudge([cx, cy], [x, y]);
  let angle = 0;
  if (arrJudgeNumber < 90) {
    angle = a / c;
  } else if (arrJudgeNumber < 180) {
    angle = b / c;
  } else if (arrJudgeNumber < 270) {
    angle = a / c;
  } else {
    angle = b / c;
  }
  const resultAngle = angle * 90 + arrJudgeNumber;
  // 内部圆区域
  if (innerRadio > 0 && cirCountRule([cx, cy], innerRadio + unlessWidth, [x, y])) return false;
  if (innerRadio < 1 && c > outRadio) {
    return false
  }
  if (c > outRadio) return false;
  if (endAngle < beginAngle) return beginAngle < resultAngle || resultAngle < endAngle;
  return beginAngle < resultAngle && resultAngle < endAngle;

}
// 当前位置是否可被点击
const zPositionObj = ([x, y]: any) => ({
  top: limitCirRule(zPositionInfo.top, [155 / 2, 155 / 2], [x, y], 34, 155 / 2),
  bottom: limitCirRule(zPositionInfo.bottom, [155 / 2, 155 / 2], [x, y], 34, 155 / 2),
  right: limitCirRule(zPositionInfo.right, [155 / 2, 155 / 2], [x, y], 34, 155 / 2),
  left: limitCirRule(zPositionInfo.left, [155 / 2, 155 / 2], [x, y], 34, 155 / 2),
  centerTop: limitCirRule([0, 180], [155 / 2, 155 / 2 - 2], [x, y], 0, 32),
  centerBottom: limitCirRule([180, 0], [155 / 2, 155 / 2 + 2], [x, y], 0, 32),
})
const ImgPosition = () => {
  const [cursor, setCursor] = useState(false); // true pointer;false default
  const xxMouse = (e: any) => setCursor(
    Object.values(
      zPositionObj([e.nativeEvent.offsetX, e.nativeEvent.offsetY])
    )
      .reduce((pre, value: any) => pre || value, false)
  );
  const xxClick = (e: any) => {
    try {
      Object.entries(
        zPositionObj([e.nativeEvent.offsetX, e.nativeEvent.offsetY])
      )
        .reduce((pre, [key, value]: any) => {
          // 同时只会有一种出现
          if (pre || value) throw [key, value]
          return pre || value;
        }, false)
    } catch (info: any) {
      // 点击后的逻辑描写处
      console.log(info?.[0])
    }
  }
  return <img
    src={require('@/assets/images/picture2.jpg')}
    alt=""
    style={{
      width: '155px',
      height: '155px',
      pointerEvents: 'auto',
      cursor: !cursor ? 'auto' : 'pointer'
    }}
    onMouseMove={xxMouse}
    onClick={xxClick}
  />
}
export default ImgPosition

使用

import ImgPosition from '@/components/ImgPosition';

const HomePage: React.FC = () => {
  return (
    <div><
		<ImgPosition></ImgPosition>
	/div>
  );
};
export default HomePage;

效果图
在这里插入图片描述

  1. 不规则区域2号(代码原理跟第二个一模一样,只是传递的参数不一样了)
    在这里插入图片描述
import { useState } from 'react';
const zPositionInfo = {
  top: [0, 90],
  left: [90, 180],
  bottom: [180, 270],
  right: [270, 0],
}
/**
 * 圆形区域计算
 * @param param0 Array<number> 中心点位置([centerX, centerY])
 * @param radius number 圆半径
 * @param param2 Array<number> 鼠标当前的x轴与y轴的位置([x, y])
 * @returns Boolean 判断当前鼠标位置是否在给定的区域内;
 */
const cirCountRule = ([cx, cy]: Array<number>, radius: number, [x, y]: Array<number>) => Math.sqrt(Math.pow(Math.abs(cx - x), 2) + Math.pow(Math.abs(cy - y), 2)) < radius;

// 判断当前鼠标位置在哪个区域:区域如下
// 2 1
// 3 4
const areaJudge = ([cx, cy]: any, [x, y]: any) => cx - x > 0 ? (cy - y > 0 ? 90 : 180) : cy - y > 0 ? 0 : 270;
/**
 * 
 * @param param0 Array<number> 限制区域角度:([45°, 90°]);限制:0 - 360;
 * @param param1 Array<number> 圆中心点位置:([centerX, centerY])
 * @param param2 Array<number> 当前鼠标位置:([x, y])
 * @param innerRadio Number 内部圆圈的半径
 * @param outRadio Number 外部圆圈的半径
 * @returns 
 */
const limitCirRule = ([beginAngle, endAngle]: any, [cx, cy]: any, [x, y]: any, innerRadio: any, outRadio: any) => {
  // 内部空白宽度
  const unlessWidth = 6;
  const a = Math.abs(y - cy);
  const b = Math.abs(x - cx);
  const c = Math.sqrt(Math.pow(b, 2) + Math.pow(a, 2));
  const arrJudgeNumber = areaJudge([cx, cy], [x, y]);
  let angle = 0;
  if (arrJudgeNumber < 90) {
    angle = a / c;
  } else if (arrJudgeNumber < 180) {
    angle = b / c;
  } else if (arrJudgeNumber < 270) {
    angle = a / c;
  } else {
    angle = b / c;
  }
  const resultAngle = angle * 90 + arrJudgeNumber;
  // 内部圆区域
  if (innerRadio > 0 && cirCountRule([cx, cy], innerRadio + unlessWidth, [x, y])) return false;
  if (innerRadio < 1 && c > outRadio) {
    return false
  }
  if (c > outRadio) return false;
  if (endAngle < beginAngle) return beginAngle < resultAngle || resultAngle < endAngle;
  return beginAngle < resultAngle && resultAngle < endAngle;

}
// 当前位置是否可被点击
const zPositionObj = ([x, y]: any) => ({
  topRight: limitCirRule(zPositionInfo.top, [155 / 2 + 4, 155 / 2 - 8], [x, y], 26, 155 / 2),
  LeftBottom: limitCirRule(zPositionInfo.bottom, [155 / 2 - 4, 155 / 2], [x, y], 34, 155 / 2),
  bottomRight: limitCirRule(zPositionInfo.right, [155 / 2 + 4, 155 / 2], [x, y], 34, 155 / 2),
  leftTop: limitCirRule(zPositionInfo.left, [155 / 2 - 4, 155 / 2 - 8], [x, y], 26, 155 / 2),
  center: cirCountRule([155 / 2, 155 / 2 - 4], 32, [x, y]),
})
const ImgPosition = () => {
  const [cursor, setCursor] = useState(false); // true pointer;false default
  const xxMouse = (e: any) => setCursor(
    Object.values(
      zPositionObj([e.nativeEvent.offsetX, e.nativeEvent.offsetY])
    )
      .reduce((pre, value: any) => pre || value, false)
  );
  const xxClick = (e: any) => {
    try {
      Object.entries(
        zPositionObj([e.nativeEvent.offsetX, e.nativeEvent.offsetY])
      )
        .reduce((pre, [key, value]: any) => {
          // 同时只会有一种出现
          if (pre || value) throw [key, value]
          return pre || value;
        }, false)
    } catch (info: any) {
      // 点击后的逻辑描写处
      console.log(info?.[0])
    }
  }
  return <img
    src={require('@/assets/images/picture3.jpg')}
    alt=""
    style={{
      width: '155px',
      height: '155px',
      pointerEvents: 'auto',
      cursor: !cursor ? 'auto' : 'pointer'
    }}
    onMouseMove={xxMouse}
    onClick={xxClick}
  />
}
export default ImgPosition

效果图
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值