areaSelete.js 13.4 KB
import React, { Component } from "react"
import imgCom from "../imgCom/imgCom";
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: 5,//圆半径
            circleBorderWidth: 2,//圆边线的半径宽
            circleBorderColor: "#28B1D9",//圆边线的颜色
            circleInColor: "#28B1D9",//圆里里面的颜色
            circleSelectColor: "#FFF",
            lineColor: "#28B1D9",//线的颜色
            lineWidth: 2,//线的宽度
            areaColor: "rgba(40, 177, 217, 0.2)",//选中区域颜色
            disabled: "false",//判断是否可以移动  false是可以移动
            title: "",//文字的内容
            titleColor: "#000",//文字的颜色
            titleFont: "14px bold 黑体",//文字的字体
            titleLineHeight: "",//文字的行高
            titleBackgroundColor: "",//字的北京颜色支持rgba
            titlePadding: "10px",//文字的padding
            titleTextAlign: "center",
            titleWidth: 100,
            titleFillColor: "",
            inputStyle:{},
            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"
        })
    }
    removeTags(tagName, tagClass) {//删除标签
        var tagElements = document.getElementsByTagName(tagName);
        for (var m = tagElements.length - 1; m >= 0; m--) {//从大到小因为没次删除都是动态的,数组会越来越小
            if (tagElements[m].className == tagClass) {
                tagElements[m].parentNode.removeChild(tagElements[m]);
            }
        }
    }
    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.removeTags("input", this.props.listId?this.props.listId:id + "");
        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, titlePadding, disabled } = 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])
        if (disabled === "true") {
            this.ctxWnzi(ctx, data)
        } else {
            var x = 0;
            var y = 99999999;
            for (var i = 0; i < data.length; i++) {
                if (parseFloat(data[i][0]) > x) x = parseFloat(data[i][0]);
                if (parseFloat(data[i][1]) < y) y = parseFloat(data[i][1]);
            }
            if(title){
                title.split(/\n/).forEach((item, index) => {
                    this.inputStyleCreate(item, x + (position[0] || 15), y + (position[1] || 15) + index * (lineHeight + 3 * parseInt(titlePadding)), index)
                })
            }
        }
    }
    ctxWnzi(ctx, data) {//画布写文字
        let { title, titleColor, titleFont, titleLineHeight, position, titleWidth, titlePadding, titleFillColor } = this.state;
        ctx.font = titleFont || "18px bold 黑体";
        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 = parseFloat(data[i][0]);
            if (parseFloat(data[i][1]) < y) y = parseFloat(data[i][1]);
        }
        title.split(/\n/).forEach((item, index) => {
            ctx.fillStyle = titleFillColor||"rgba(15, 62, 166, 0.2)";
            ctx.fill();
            ctx.fillRect(x + (position[0] || 15), y + (position[1] || 15) + index * (lineHeight + 2 * parseInt(titlePadding)) - parseFloat(lineHeight / 2) - parseFloat(parseInt(titlePadding) / 2), titleWidth + parseInt(titlePadding), lineHeight + parseInt(titlePadding));
            ctx.fillStyle = titleColor || "#fff";;
            ctx.fillText(item, x + (position[0] || 15) + parseFloat(parseInt(titlePadding) / 2), y + (position[1] || 15) + index * (lineHeight + 2 * parseInt(titlePadding)))
        })
    }
    inputStyleCreate(title, x, y,index) {
        let { title:titleY,titleColor, titleFont, titleTextAlign,inputStyle, titleLineHeight, titleBackgroundColor,titleWidth, titlePadding, id } = this.state;
        var canvasEl = document.getElementById(id)
        var parentEl = canvasEl.parentNode;
        var input = document.createElement("input");
        input.style.font = titleFont;
        input.style.lineHeight = titleLineHeight;
        input.style.color = titleColor;
        input.style.backgroundColor = titleBackgroundColor || "rgba(40, 177, 217, 0.2)";
        input.style.padding = titlePadding;
        input.style.textAlign = titleTextAlign;
        input.style.position = "absolute";
        input.style.border = "none";
        input.style.left = x + "px";
        input.style.top = y + "px";
        input.style.zIndex = "100";
        input.style.width = titleWidth + "px";
        if(Object.keys(inputStyle).length>0){//判断是否有自定义样式,有的话进行循环追加
            for(var key in inputStyle){
                input.style[key] = inputStyle[key]
            }
        }
        input.value = title;
        input.className = this.props.listId?this.props.listId+"":id + "";
        input.oninput = (e) => {
            var arr = titleY.split(/\n/)
            arr[index] = e.target.value
            this.setState({title:arr.join("\n")})
            this.props.wenziChange(arr.join("\n"))
        }
        parentEl.appendChild(input)
    }
    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.sendFather(serviceData)
            } else {
                this.selectBox(left, top)
                this.setData({
                    serviceData: serviceData
                })
            }
        }
    }
    mouseMove() {//鼠标移动
        let { id } = this.state;
        var serviceDataw = ""
        var canvasEl = document.getElementById(id)
        canvasEl.onmousedown = (e) => {
            var { serviceData } = this.state;
            serviceDataw = serviceData
            var left = e.layerX
            var top = e.layerY
            if (this.selectBox(left, top)) {
                canvasEl.onmousemove = (e) => {
                    serviceData[this.selectedIndex] = [e.layerX, e.layerY];
                    serviceDataw = serviceData
                    this.setData({
                        serviceData: serviceData
                    })
                };
            }
        }
        canvasEl.onmouseup = (e) => {
            canvasEl.onmousemove = null;
            this.selectedIndex = null;
            this.setData({
                serviceData: this.state.serviceData
            })
            var left = e.layerX
            var top = e.layerY
            if (this.selectBox(left, top)) {
                this.sendFather(this.state.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.sendFather(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;//选中后返回下标然后返回真
                break;
            }
        }
        if (i == serviceData.length) {
            return false
        } else {

            return true
        }
    }
    sendFather(serviceData) {//向父亲发送里面的值
        if (this.state.disabled !== "true") {
            this.props.change(serviceData)
        }
    }
    setData(data) {//设置值发生变化重新画
        this.setState(data, () => {
            this.draw()
        })
    }
    render() {
        let { id, width, height } = this.state;
        return (<canvas style={{ position: "absolute", top: 0, left: 0 }} id={id} width={width} height={height}></canvas>)
    }
}