areaSelete.js 7.96 KB
import React, { Component } from "react"
import "./areaSelete.css"
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: 10,//圆半径
            circleBorderWidth: 4,//圆边线的半径宽
            circleBorderColor: "#28B1D9",//圆边线的颜色
            circleInColor: "#28B1D9",//圆里里面的颜色
            circleSelectColor:"#FFF",
            lineColor: "#28B1D9",//线的颜色
            lineWidth: 2,//线的宽度
            areaColor: "rgba(40, 177, 217, 0.2)",//选中区域颜色
            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.onresize = this.init.bind(this)
    }
    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 } = 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.clickMove()//点击模式
        // this.mouseMove()//鼠标移动模式
        // this.touchMove()//手指触摸移动模式
        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();
    }
    clickMove() {//鼠标点击移动
        let { id, serviceData } = 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
                })
                this.props.change(serviceData)
            } else {
                this.selectBox(left, top)
                this.setData({
                    serviceData: serviceData
                })
            }
        }
    }
    mouseMove() {//鼠标移动
        let { id, serviceData } = 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)) {
                this.props.change(serviceData)
            }
        };
    }
    touchMove() {//手指触摸移动
        let { id, serviceData } = 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)) {
                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 (<canvas id={id} width={width} height={height}></canvas>)
    }
}