介绍
- 本文以 react 举例,其他框架实现基本上一致(vue则是@mouseMove 、 @click…)
- 实现原理:对图片进行位置区域选中,判断当前鼠标位置是否在这个区域内,如果在区域内则进行可点击鼠标切换(cursor: pointer),如果此时点击则判断出当前点击的位置是哪块区域。
- 具体需求如果有类似的可以看看逻辑,然后也可以在这个基础上更改
- 本文主要作于笔记,方便以后对类似问题处理。
区域计算(可被点击、可设置hover效果)
- 计算四向圆形区域(规则圆形区域)
.
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
效果图
- 不规则区域四方点击效果(以下)
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;
效果图
- 不规则区域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
效果图