React 热区组件

您所在的位置:网站首页 华荣交换机替代华为 React 热区组件

React 热区组件

2023-09-16 06:29| 来源: 网络整理| 查看: 265

在这里插入图片描述

概念:啥是热区组件

是指在一张图片上选取一些区域,每个区域链接到指定的地址。可以在图片上设置多个热区区域并配置相应的数据。

在正式开始之前,先了解几个概念

HTML 元素 在图片上定义一个热点区域,可以关联一个超链接。元素仅在元素内部使用。

了解更多:https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/area

HTML 属性 与 属性一起使用来定义一个图像映射(一个可点击的链接区域)。

了解更多:https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/map

基本的热区实现 DOCTYPE html> Document

上面的区域是我们提前在代码中编写好的,但我们更加希望可以动态的框选区域。

注:以下使用 React 框架作为演示

React 实现框选区域成为热区

分析:其实我们只需要知道 x, y, width, height ,就可以绘制热区。

/* eslint-disable no-template-curly-in-string */ import React from 'react' import MultiCrops from 'react-multi-crops' import img from './test.webp' class App extends React.Component { state = { coordinates: [], x: 0, y: 0, width: 0, height: 0, str: '', imgShow: false } changeCoordinate = (coordinate, index, coordinates) => { this.setState({ coordinates, }) // 在变化的时候,拿到此刻裁剪区域的数据 setTimeout(() => { let {x, y, width, height} = this.state.coordinates[0] this.setState({ str: `${x},${y},${width},${height}` }) this.setState({ imgShow: true }) }, 1000) } deleteCoordinate = (coordinate, index, coordinates) => { this.setState({ coordinates, }) } render() { const { str, imgShow } = this.state console.log(str) return ( { imgShow ? img} coordinates={this.state.coordinates} onChange={this.changeCoordinate} onDelete={this.deleteCoordinate} /> } useState, useEffect } from "react"; const ImgCrop = ({ file }) => { const { url } = file; const [originImg, setOriginImg] = useState(); // 源图片 const [contentNode, setContentNode] = useState(); // 最外层节点 const [canvasNode, setCanvasNode] = useState(); // canvas节点 const [startCoordinate, setStartCoordinate] = useState([0, 0]); // 开始坐标 const [dragging, setDragging] = useState(false); // 是否可以裁剪 const [curPoisition, setCurPoisition] = useState(null); // 当前裁剪框坐标信息 const [hotAreaCoordStr, setHotAreaCootdStr] = useState(""); const [imgShow, setImgShow] = useState(false); // 初始化 const initCanvas = () => { // url为上传的图片链接 if (url == null) { return; } // contentNode为最外层DOM节点 if (contentNode == null) { return; } // canvasNode为canvas节点 if (canvasNode == null) { return; } const image = new Image(); setOriginImg(image); // 保存源图 image.addEventListener("load", () => { const ctx = canvasNode.getContext("2d"); // 擦除一次,否则canvas会一层层叠加,节省内存 ctx.clearRect(0, 0, canvasNode.width, canvasNode.height); // 若源图宽度大于最外层节点的clientWidth,则设置canvas宽为clientWidth,否则设置为图片的宽度 const clientW = contentNode.clientWidth; const size = image.width / clientW; if (image.width > clientW) { canvasNode.width = clientW; canvasNode.height = image.height / size; } else { canvasNode.width = image.width; canvasNode.height = image.height; } // 调用drawImage API将版面图绘制出来 ctx.drawImage(image, 0, 0, canvasNode.width, canvasNode.height); }); image.crossOrigin = "anonymous"; // 解决图片跨域问题 image.src = url; }; useEffect(() => { initCanvas(); }, [canvasNode, url]); // 点击鼠标事件 const handleMouseDownEvent = (e) => { // 开始裁剪 setDragging(true); const { offsetX, offsetY } = e.nativeEvent; // 保存开始坐标 setStartCoordinate([offsetX, offsetY]); }; // 移动鼠标事件 const handleMouseMoveEvent = (e) => { if (!dragging) { return; } const ctx = canvasNode.getContext("2d"); // 每一帧都需要清除画布(取最后一帧绘图状态, 否则状态会累加) ctx.clearRect(0, 0, canvasNode.width, canvasNode.height); const { offsetX, offsetY } = e.nativeEvent; // 计算临时裁剪框的宽高 const tempWidth = offsetX - startCoordinate[0]; const tempHeight = offsetY - startCoordinate[1]; // 调用绘制裁剪框的方法 drawTrim(startCoordinate[0], startCoordinate[1], tempWidth, tempHeight); }; // 松开鼠标 const handleMouseRemoveEvent = () => { // 结束裁剪 setDragging(false); // 处理裁剪按钮样式 if (curPoisition == null) { return; } const { startX, startY, width, height } = curPoisition; setHotAreaCootdStr(`${startX},${startY},${width},${height}`); setImgShow(true); }; // 绘制裁剪框的方法 const drawTrim = (x, y, w, h) => { const ctx = canvasNode.getContext("2d"); // 绘制蒙层 ctx.save(); ctx.fillStyle = "rgba(0,0,0,0.6)"; // 蒙层颜色 ctx.fillRect(0, 0, canvasNode.width, canvasNode.height); // 将蒙层凿开 ctx.globalCompositeOperation = "source-atop"; // 裁剪选择框 ctx.clearRect(x, y, w, h); // 绘制8个边框像素点 ctx.globalCompositeOperation = "source-over"; drawBorderPixel(ctx, x, y, w, h); // 保存当前区域坐标信息 setCurPoisition({ width: w, height: h, startX: x, startY: y, position: [ (x, y), (x + w, y), (x, y + h), (x + w, y + h), (x + w / 2, y), (x + w / 2, y + h), (x, y + h / 2), (x + w, y + h / 2), ], canvasWidth: canvasNode.width, // 用于计算移动端版面图缩放比例 }); ctx.restore(); // 再次调用drawImage将图片绘制到蒙层下方 ctx.save(); ctx.globalCompositeOperation = "destination-over"; ctx.drawImage(originImg, 0, 0, canvasNode.width, canvasNode.height); ctx.restore(); }; // 绘制边框像素点的方法 const drawBorderPixel = (ctx, x, y, w, h) => { ctx.fillStyle = "#f5222d"; const size = 5; // 自定义像素点大小 ctx.fillRect(x - size / 2, y - size / 2, size, size); // ...同理通过ctx.fillRect再画出其余像素点 ctx.fillRect(x + w - size / 2, y - size / 2, size, size); ctx.fillRect(x - size / 2, y + h - size / 2, size, size); ctx.fillRect(x + w - size / 2, y + h - size / 2, size, size); ctx.fillRect(x + w / 2 - size / 2, y - size / 2, size, size); ctx.fillRect(x + w / 2 - size / 2, y + h - size / 2, size, size); ctx.fillRect(x - size / 2, y + h / 2 - size / 2, size, size); ctx.fillRect(x + w - size / 2, y + h / 2 - size / 2, size, size); }; return ( {imgShow ? ( `${curPoisition.canvasWidth}`} alt="Planets" /> ) : ( setCanvasNode} onMouseDown={handleMouseDownEvent} onMouseMove={handleMouseMoveEvent} onMouseUp={handleMouseRemoveEvent} /> )} let obj = { file: { url: "https://cdn.pixabay.com/photo/2021/07/18/14/59/family-6475821__480.jpg", }, }; return


【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3