areaSelete.js 9.11 KB
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: 10,//圆半径
            circleBorderWidth: 4,//圆边线的半径宽
            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.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, 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(data[i][0]>x) x = data[i][0];
            if(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 } = 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>)
    }
}