import React, { Component } from "react" export default class AreaSelete extends Component { constructor() { super(); this.state = { id: new Date().getTime() + Math.floor(Math.random() * (10000 - 1)) + 1, mode: "", width: "100px", height: "100px", circleRadius: 5,//圆半径 circleBorderWidth: 2,//圆边线的半径宽 circleBorderColor: "#28B1D9",//圆边线的颜色 circleInColor: "#28B1D9",//圆里里面的颜色 circleSelectColor: "#FFF", lineColor: "#28B1D9",//线的颜色 lineWidth: 2,//线的宽度 areaColor: "rgba(40, 177, 217, 0.2)",//选中区域颜色 disabled: "false",//判断是否可以移动 title: "",//文字的内容 titleColor: "#000",//文字的颜色 titleFont: "14px bold 黑体",//文字的字体 titleLineHeight: "",//文字的行高 position: [10, 10],//文字的位置 serviceData: [] } } static getDerivedStateFromProps(props, state) { var obj = {}; for (var key in props) { if (props[key] && props[key] !== state[key]) { obj[key] = props[key] } } if (Object.keys(obj).length > 0) { return obj; } else { return null } } shouldComponentUpdate(nextProps) { if (this.props.serviceData.length !== nextProps.serviceData) { return true } else { return false } } componentDidMount() { this.init() window.addEventListener("resize",()=>{ this.init() }) } init() { this.setCanvasSize();//根据父盒子宽高大小设置画布的大小 } setCanvasSize() { let { id } = this.state; var canvasEl = document.getElementById(id) var parentEl = canvasEl.parentNode; var parentWidth = parentEl.offsetWidth;//父标签的宽度 var parentHeight = parentEl.offsetHeight;//父标签的高度 this.setData({ width: parentWidth + "px", height: parentHeight + "px" }) } draw() { let { id, serviceData, width, height, mode, disabled } = this.state; var canvasEl = document.getElementById(id) var ctx = canvasEl.getContext("2d"); ctx.clearRect(0, 0, parseFloat(width), parseFloat(height)); this.drawLine(ctx, serviceData); this.drawCircleAll(ctx, serviceData); this.drawWriting(ctx, serviceData) // this.clickMove()//点击模式 // this.mouseMove()//鼠标移动模式 // this.touchMove()//手指触摸移动模式 if (disabled === "false") { if (mode === 'click') { this.isontouchend() ? this.touchMove() : this.clickMove() } else { this.isontouchend() ? this.touchMove() : this.mouseMove() } } } isontouchend() {//判断是否支持触屏 return "ontouchend" in document ? true : false; } drawCircleAll(ctx, data) {//画所有圆 for (var i = 0; i < data.length; i++) { this.drawCircle(ctx, data[i][0], data[i][1], this.selectedIndex === i) } } drawCircle(ctx, x, y, selected) {//画单个圆 let { circleRadius, circleInColor, circleBorderColor, circleBorderWidth, circleSelectColor } = this.state ctx.fillStyle = selected ? circleSelectColor : circleInColor;//画里面 ctx.beginPath(); ctx.arc(x, y, parseInt(circleRadius), 0, Math.PI * 2, true); ctx.closePath(); ctx.fill(); ctx.beginPath();//画外面的空心圆 ctx.arc(x, y, parseInt(circleRadius), 0, Math.PI * 2, true); ctx.lineWidth = parseInt(circleBorderWidth); ctx.strokeStyle = circleBorderColor; ctx.stroke(); //画空心圆 ctx.closePath(); } drawLine(ctx, data) {//画线 let { lineColor, lineWidth, areaColor } = this.state ctx.beginPath(); for (var i = 0; i < data.length; i++) { if (i === 0) { ctx.moveTo(data[i][0], data[i][1]); } else { ctx.lineTo(data[i][0], data[i][1]); } } ctx.lineWidth = parseInt(lineWidth); ctx.strokeStyle = lineColor; ctx.closePath(); ctx.fillStyle = areaColor; ctx.fill(); ctx.stroke(); } drawWriting(ctx, data) {//写文字 let { title, titleColor, titleFont, titleLineHeight, position } = this.state; ctx.font = titleFont || "18px bold 黑体"; ctx.fillStyle = titleColor || "#fff"; ctx.lineHeight = titleLineHeight || titleFont.split(" ")[0]; ctx.textBaseline = "middle"; var lineHeight = parseInt(titleLineHeight || titleFont.split(" ")[0]) var x = 0; var y = 99999999; for (var i = 0; i < data.length; i++) { if (parseFloat(data[i][0]) > x) x = data[i][0]; if (parseFloat(data[i][1]) < y) y = data[i][1]; } title.split(/\n/).forEach((item, index) => { ctx.fillText(item, x + (position[0] || 15), y + (position[1] || 15) + index * lineHeight); }) } clickMove() {//鼠标点击移动 let { id, serviceData, disabled } = this.state; var canvasEl = document.getElementById(id) canvasEl.onclick = (e) => { var left = e.layerX var top = e.layerY if (this.selectedIndex || this.selectedIndex === 0) {//此时已经选中了点 serviceData[this.selectedIndex] = [left, top] this.selectedIndex = null this.setData({ serviceData: serviceData }) if (disabled === "true") { this.props.change(serviceData) } } else { this.selectBox(left, top) this.setData({ serviceData: serviceData }) } } } mouseMove() {//鼠标移动 let { id, serviceData, disabled } = this.state; var canvasEl = document.getElementById(id) canvasEl.onmousedown = (e) => { var left = e.layerX var top = e.layerY if (this.selectBox(left, top)) { canvasEl.onmousemove = (e) => { serviceData[this.selectedIndex] = [e.layerX, e.layerY]; this.setData({ serviceData: serviceData }) }; } } canvasEl.onmouseup = (e) => { canvasEl.onmousemove = null; this.selectedIndex = null; this.setData({ serviceData: serviceData }) var left = e.layerX var top = e.layerY if (this.selectBox(left, top)) { if (disabled === "true") { this.props.change(serviceData) } } }; } touchMove() {//手指触摸移动 let { id, serviceData, disabled } = this.state; var canvasEl = document.getElementById(id) var parentEl = canvasEl.parentNode; var pingmuTop = parentEl.getBoundingClientRect().top; //画布距离屏幕上面的距离 这里要计算出触摸距离当前画布的距离好进行移动 var pingmuLeft = parentEl.getBoundingClientRect().left; //画布距离屏幕左面的距离 canvasEl.ontouchstart = (e) => { var left = e.touches[0].pageX - pingmuLeft var top = e.touches[0].pageY - pingmuTop if (this.selectBox(left, top)) { canvasEl.ontouchmove = (e) => { serviceData[this.selectedIndex] = [e.touches[0].pageX - pingmuLeft, e.touches[0].pageY - pingmuTop]; this.setData({ serviceData: serviceData }) } } } canvasEl.ontouchend = (e) => { this.selectedIndex = null canvasEl.ontouchmove = null; this.setData({ serviceData: serviceData }) var left = e.changedTouches[0].pageX - pingmuLeft var top = e.changedTouches[0].pageY - pingmuTop if (this.selectBox(left, top)) { if (disabled === "true") { this.props.change(serviceData) } } }; } selectBox(x, y) {//判断是否选中 let { serviceData, circleRadius, circleBorderWidth } = this.state; let rangeMax = circleRadius + circleBorderWidth; this.selectedIndex = null;//选中点后把下面传过去 for (var i = 0; i < serviceData.length; i++) { var dianX = serviceData[i][0]; var dianY = serviceData[i][1]; if ((dianX - x) * (dianX - x) + (dianY - y) * (dianY - y) < rangeMax * rangeMax) { this.selectedIndex = i;//选中后返回下标然后返回真 return true } } if (i == serviceData.length) { return false } } setData(data) {//设置值发生变化重新画 this.setState(data, () => { this.draw() }) } render() { let { id, width, height } = this.state; return () } }