# board/annotation.js

    ModuleBase.define("Annotation", ["RestServer", "Error", "TextInfo"], function(RestServer,Error,TextInfo) {

    	/**
         * @desc Annotation构造函数。
         * @constructor
         * @alias Annotation
         */
    	var Annotation = function(boardId, roomHandle, board) {
    		this.roomHandle = roomHandle;
    		this.boardId = boardId; //白板ID
    		this.shapeType = shapeTypeEnum.mouse;  //几何形状 or 操作类型
    		this.color = 'rgba(0,0,0,1)'; //注释设置颜色，默认值为黑色
            this.backgroundColor =  '';
    		this.lineWidth = 2; //线条宽度，默认值为2
    		this.arrowLength = 10; //设置箭头宽度，默认值为10
    		this.arrowtype = arrowTypeEnum.end; //箭头类别
    		this.fillType = fillTypeEnum.none;//是否需要填充
    		this.fillColor = 'none'; //填充颜色
            this.initType = AnnotationInitTypeEnum.full; // 批注层默认填充类型为平铺，铺满整个外部容器

    		this.shapeArray = []; //批注图形数组
    		this.redoArray = [];
    		this.undoArray = []; // 撤销图形数组，用于撤销时恢复记录的操作
            this.zr = null; //zrender对象实例
    		this.annoDiv = null; // 用户传入的白板外部容器div
            this.renderDiv = null; // 计算得到的内部使用的白板容器
            this.renderBackground = null; // 和renderDiv同样大小的背景层，用于控制背景色或背景图

    		this.currentIndex = -1 ;

    		this.drawOrEraser = annoSelectTypeEnum.draw; //注释类型

    		this.isEraser = false; //橡皮擦按下状态
    		this.eraserShape = null;
    		this.eraserImageWidth = 32;
            this.eraserImageHeight = 32;

    		this.otherShapeMap = {}; //其他人
    		this.screenSize = {
    			width:0,
    			height:0
    		};
    		this.hlightPointInfo = {
    			imgUrl:'',
    			width:'',
    			height:'',
    			intervalTime: 200,
    			isSend:true
    		}
    		this.hlightPointShape = null; //TODO 有时间重新整理逻辑    使用map  {userId：hlightPointShape} 可以有多个激光笔
    		this.textTagShape = null;

    		// 移动端属性
    		this.arrowLineStartPoint = {  //定义arrowline的起始坐标，防止点击不拖动时绘制的问题
    			x: 0,
    			y: 0
    		}

    		this.currentX = 0;
            this.currentY = 0;
    		this.x = 0;
    		this.y = 0;
    		this.shapeData = [];
    		this.rhombData = [];
    		this.shapeObj = {};
    		this.shape = null;

    		this.imgZlevel = -99999;
            this.normalZlevel = 10000;
            this.tempHighZlevel = 99999;

    		this.currActiveImg = null;
    		this.isAllowEditImg = false;

    		// 防止图片跳动
            this.dragData = {
                drag: false,
                pos: [0,0]
            }

            this.shapeGroup = new zrender.Group({
                slient: false // 组内子孙元素是否响应鼠标事件
            });

            this.textInfo = null;
            // 缩放的位置信息
            this.positionInfo = {
                scaleWidth: 0, // 缩放目标宽度
                scaleHeight: 0, // 缩放目标高度
                zrWidth: 0, // 当前画布的宽度
                zrHeight: 0, // 当前画布的高度
                scaleRatioX: 1, // 横向缩放比例，缩放目标宽度和当前画布宽度的比值
                scaleRatioY: 1, // 纵向缩放比例，缩放目标高度和当前画布高度的比值
                scaleRatioXR: 1, // 横向缩放比例，当前画布宽度和缩放目标宽度的比值
                scaleRatioYR: 1, // 纵向缩放比例，当前画布宽度和缩放目标宽度的比值,
                originalWidth: 0, // 初始的宽度
                originalHeight: 0 // 初始的高度
            };

            // 图片缩放后鼠标捕获的坐标与图片左上角坐标的偏移量
            this.imgScaleoffset = {
                x: 0,
                y: 0
            };

            this.board = board;

            this.backgroundColor = board.backgroundColor;
    	};

    	var Successright = zrender.Path.extend({
            type: 'Successright',
            shape: {
                // x, y on the cusp
                x:0,
                y:0,
                width:0,
                height:0

            },
            buildPath: function (path, shape) {
                var x1 = shape.x;
                var y1 = shape.y + shape.height/3*2;
                var x2 = shape.x + shape.width/2;
                var y2 = shape.y + shape.height;
                var x3 = shape.x + shape.width;
                var y3 = shape.y;
                path.moveTo(x1,y1);
                path.lineTo(x2,y2);
                path.lineTo(x3,y3);
            }
        });

    	var Failure = zrender.Path.extend({
            type: 'Failure',
            shape: {
                // x, y on the cusp
                x: 0,
                y: 0,
                width:0,
                height:0
            },
            buildPath: function (path, shape) {
                var x = shape.x;
                var y = shape.y;
                var width = shape.width;
                var height = shape.height;
                var leftX = x - width/2;
                var rightX = x + width/2;
                var topY = y - height/2;
                var bottomY = y + height/2;
                path.moveTo(leftX,topY);
                path.lineTo(rightX,bottomY);
                path.closePath();
                path.moveTo(rightX,topY);
                path.lineTo(leftX,bottomY);
                path.closePath();
            }
        });

    	var Arrow = zrender.Path.extend({
            type: 'Arrow',
            shape: {
                // x, y on the cusp
                x: 0,
                y: 0,
                width:0,
                height:0
            },
            buildPath: function (path, shape) {
                var x1 = shape.x;
                var y1 = shape.y + shape.height/3;
                var x2 = shape.x;
                var y2 = shape.y + shape.height/3 * 2;
                var x3 = shape.x + shape.width/3 * 2;
                var y3 = shape.y + shape.height/3 * 2;
                var x4 = shape.x + shape.width/3 * 2;
                var y4 = shape.y + shape.height;
                var x5 = shape.x + shape.width;
                var y5 = shape.y + shape.height/2;
                var x6 = shape.x + shape.width/3 * 2;
                var y6 = shape.y;
                var x7 = shape.x + shape.width/3 * 2;
                var y7 = shape.y + shape.height/3;
                path.moveTo(x1,y1);
                path.lineTo(x2,y2);
                path.lineTo(x3,y3);
                path.lineTo(x4,y4);
                path.lineTo(x5,y5);
                path.lineTo(x6,y6);
                path.lineTo(x7,y7);
                path.closePath();
            }
        });

    	var Texttag = zrender.Path.extend({
            type: 'Texttag',
            shape: {
                // x, y on the cusp
                x: 0,
                y: 0,
                width:0,
                height:0
            },
            buildPath: function (path, shape) {
                var x1 = shape.x;
                var y1 = shape.y + shape.height/4;
                var x2 = shape.x;
                var y2 = shape.y + shape.height/4 * 3;
                var x3 = shape.x + shape.width/5 * 4;
                var y3 = shape.y + shape.height/4 * 3;
                var x4 = shape.x + shape.width/5 * 4;
                var y4 = shape.y + shape.height;
                var x5 = shape.x + shape.width;
                var y5 = shape.y + shape.height/2;
                var x6 = shape.x + shape.width/5 * 4;
                var y6 = shape.y;
                var x7 = shape.x + shape.width/5 * 4;
                var y7 = shape.y + shape.height/4;
                path.moveTo(x1,y1);
                path.lineTo(x2,y2);
                path.lineTo(x3,y3);
                path.lineTo(x4,y4);
                path.lineTo(x5,y5);
                path.lineTo(x6,y6);
                path.lineTo(x7,y7);
                path.closePath();
            }
        });

        /**
         * @description 通过外部盒子和内容盒子的宽高，算出内容盒子撑满外部盒子的宽或者高的结果
         * @param {int} outWidth 外部容器宽
         * @param {int} outHeight 外部容器高
         * @param {int} contentWidth 内容的宽
         * @param {int} contentHeight 内容的高
         */
    	function getCompatibleSize(outWidth, outHeight, contentWidth, contentHeight) {
            var renderWidth = 0;
            var renderHeight = 0;
            // 白板的宽高比
            var contentRatio = contentWidth / contentHeight;
            // 外部容器的宽高比
            var outRatio = outWidth / outHeight;

            if(contentRatio > 1 && outRatio > 1){
                // 说明都是横向
                if(contentRatio > outRatio){
                    // 说明白板比容器比例更宽
                    // 白板的宽度要撑满容器宽度、上下留白
                    renderWidth = outWidth;
                    if(contentWidth > outWidth){
                        // 白板更宽
                        renderHeight = contentHeight / (contentWidth / outWidth)
                    }else{
                        // 容器更宽，撑满容器后，高也要增加
                        renderHeight = contentHeight * (outWidth / contentWidth)
                    }
                }else if(contentRatio < outRatio){
                    // 说明白板比容器比例更窄
                    // 白板的宽度要撑满容器高度、左右留白
                    renderHeight = outHeight;
                    if(contentHeight > outHeight){
                        // 白板更高
                        renderWidth = contentWidth / (contentHeight / outHeight)
                    }else{
                        // 容器更高
                        renderWidth = contentWidth * (outHeight / contentHeight)
                    }
                }else{
                    // 比例相等，那直接撑满容器宽高
                    renderWidth = outWidth
                    renderHeight = outHeight
                }
                // 都要设置白板渲染比例
            }else if(contentRatio > 1 && outRatio <= 1){
                // 白板横向，容器正方形或竖向的时候
                // 白板的宽度要撑满容器宽度、上下留白
                renderWidth = outWidth;
                if(contentWidth > outWidth){
                    // 白板更宽
                    renderHeight = contentHeight / (contentWidth / outWidth)
                }else{
                    // 容器更宽，撑满容器后，高也要增加
                    renderHeight = contentHeight * (outWidth / contentWidth)
                }
            }else if(contentRatio < 1 && outRatio > 1){
                // 白板竖向，容器横向
                // 白板的宽度要撑满容器高度、左右留白
                renderHeight = outHeight;
                if(contentHeight > outHeight){
                    // 白板更高
                    renderWidth = contentWidth / (contentHeight / outHeight)
                }else{
                    // 容器更高
                    renderWidth = contentWidth * (outHeight / contentHeight)
                }
            }else if(contentRatio < 1 && outRatio <= 1){
                // 白板竖向，容器正方形或者竖向
                if(contentRatio < outRatio){
                    // 白板更窄，撑满容器高度，左右留白
                    renderHeight = outHeight;
                    if(contentHeight > outHeight){
                        // 白板更高
                        renderWidth = contentWidth / (contentHeight / outHeight)
                    }else{
                        // 容器更高
                        renderWidth = contentWidth * (outHeight / contentHeight)
                    }
                }else{
                    // 容器更窄，撑满容器宽度，上下留白
                    renderWidth = outWidth;
                    if(contentWidth > outWidth){
                        // 白板更宽
                        renderHeight = contentHeight / (contentWidth / outWidth)
                    }else{
                        // 容器更宽，撑满容器后，高也要增加
                        renderHeight = contentHeight * (outWidth / contentWidth)
                    }
                }
            }else{
                if(contentRatio == 1){
                    if(outRatio > 1){
                        // 直接撑满高，左右留白
                        renderHeight = outHeight;
                        if(contentHeight > outHeight){
                            // 白板更高
                            renderWidth = contentWidth / (contentHeight / outHeight)
                        }else{
                            // 容器更高
                            renderWidth = contentWidth * (outHeight / contentHeight)
                        }
                    }else{
                        // 直接撑满宽，上下留白
                        renderWidth = outWidth;
                        if(contentWidth > outWidth){
                            // 白板更宽
                            renderHeight = contentHeight / (contentWidth / outWidth)
                        }else{
                            // 容器更宽，撑满容器后，高也要增加
                            renderHeight = contentHeight * (outWidth / contentWidth)
                        }
                    }
                }
            }
            log.debug('===annotation getCompatibleSize, outWidht: ' + outWidth + ',outHeight: ' + outHeight + ',contentWidth: ' + contentWidth + ',contentHeight: ' + contentHeight + ',renderWidth: ' + renderWidth + ',renderHeight: ' + renderHeight);
            return [renderWidth, renderHeight];
        }

        Annotation.prototype.initAndGetRenderCanvasByBoardAndWrapBox = function() {
            var self = this;
            var renderCanvas = document.createElement('canvas');
            var renderCanvasWidth = 0;
            var renderCanvasHeight = 0;
            var compatibleSize = getCompatibleSize(self.annoDiv.clientWidth, self.annoDiv.clientHeight, self.board.width, self.board.height);

            renderCanvasWidth = compatibleSize[0];
            renderCanvasHeight = compatibleSize[1];
            renderCanvas.width = renderCanvasWidth;
            renderCanvas.height = renderCanvasHeight;

            renderCanvas.style.width = renderCanvasWidth + 'px';
            renderCanvas.style.height = renderCanvasHeight + 'px';
            renderCanvas.style.background = 'rgba(0,0,0,0)';
            self.board.setRenderWidthAndHeight(renderCanvasWidth, renderCanvasHeight);
            log.debug("===annotation initAndGetRenderCanvasByBoardAndWrapBox, result: bw: " + self.board.width + ',bh: ' + self.board.height + ",ww: " + self.annoDiv.clientWidth + ",wh: " + self.annoDiv.clientHeight + ",rw: " + renderCanvasWidth + ",rh: " + renderCanvasHeight);
            return renderCanvas;
        }

        /**
         * @ignore
         */
        Annotation.prototype.updateBackgroundColor = function (color) {
            if(!this.renderBackground){
                return;
            }
            if(!this.renderBackground instanceof HTMLCanvasElement){
                return;
            }
            var ctx = this.renderBackground.getContext('2d');
            if(color){
                ctx.fillStyle = 'rgba(' + color + ')';
                ctx.fillRect(0, 0, this.renderBackground.width, this.renderBackground.height);
                this.backgroundColor = color;
            }else{
                ctx.clearRect(0, 0, this.renderBackground.width, this.renderBackground.height);
            }
        }

        /**
         * @ignore
         */
        Annotation.prototype.updateBackgroundImage = function (imageUrl) {
    		var deferred = when.defer();
            log.debug('===annotation updateBackgroundImage, imageUrl:'+ imageUrl);
            var self = this;
            if(!imageUrl){
                deferred.reject('===annotation updateBackgroundImage error, reason: imageUrl is invalid!');
            }
            if(!this.renderBackground){
                deferred.reject('===annotation updateBackgroundImage error, reason: board background is not exist!');
            }
            if(!this.renderBackground instanceof HTMLCanvasElement){
                deferred.reject('===annotation updateBackgroundImage error, reason: board background element is not canvas');
            }

            try{
                this.updateBackgroundColor(this.backgroundColor);

                var ctx = this.renderBackground.getContext('2d');
                var tempImageEl = document.createElement('img');
                tempImageEl.src = imageUrl;
                tempImageEl.onload = function(){
                    var compatibleSize = getCompatibleSize(self.renderBackground.width, self.renderBackground.height, tempImageEl.width, tempImageEl.height);
                    var startDrawX = (self.renderBackground.width / 2) - (compatibleSize[0] / 2);
                    var startDrawY = (self.renderBackground.height / 2) - (compatibleSize[1] / 2);
                    log.debug("===annotation updateBackgroundImage, startX:" + startDrawX + ",startY:" + startDrawY + ",compatibleSize:" + compatibleSize);
                    ctx.drawImage(tempImageEl, startDrawX, startDrawY, compatibleSize[0], compatibleSize[1]);
                    deferred.resolve();
                }
            }catch(err){
                log.debug("===annotation updateBackgroundImage, err:" + err);
                deferred.reject(err);
            }
            return deferred.promise;
        }

    	/**
         * @desc 初始化annotation对象
         * @param {HTMLDivElement} annoDiv - 注释所在的应用层容器，只能传入div元素
    	 * @param {String} annotationInitType - 注释初始化类型 可选值: AnnotationInitTypeEnum.proportional, AnnotationInitTypeEnum.full
         */
    	Annotation.prototype.init = function(annoDiv, annotationInitType){
    		var deferred = when.defer();
    		var self = this;

            if(!(annoDiv instanceof HTMLDivElement) && !(annoDiv instanceof HTMLCanvasElement)){
                log.error('===annotation init faild, must be given a div or canvas element!');
                deferred.reject('Must be given a div or canvas element!');
                return deferred.promise;
            }

            self.annoDiv = annoDiv;

            if(annotationInitType && annotationInitType == AnnotationInitTypeEnum.proportional){
                self.initType = annotationInitType;

                // 如果初始化类型是proportional（成比例）则需要给定一个div元素，以便在此div内部创建批注和背景层
                if(!(annoDiv instanceof HTMLDivElement)){
                    log.error('===annotation init faild, proportional type must be given a div element!')
                    deferred.reject('Proportional type must be given a div element!');
                    return deferred.promise;
                }

                annoDiv.style.display = 'flex';
                annoDiv.style.alignItems = 'center';
                annoDiv.style.justifyContent = 'center';

                // 初始化canvas相关
                this.renderDiv = self.initAndGetRenderCanvasByBoardAndWrapBox();
                this.renderBackground = self.initAndGetRenderCanvasByBoardAndWrapBox();
                this.renderDiv.style.position = 'relative';
                this.renderDiv.style.zIndex = 1001;
                annoDiv.appendChild(this.renderDiv);

                // 背景层处理，用于设置背景色或者背景图
                this.renderBackground.style.position = 'absolute';
                // TODO 暂时注释，在佳会中设置下面属性，会导致打开文字功能时，背景层canvas会移位
                // this.renderBackground.style.left = this.renderDiv.offsetLeft + 'px';
                // this.renderBackground.style.top = this.renderDiv.offsetTop + 'px';
                this.renderBackground.style.zIndex = 1000;
                this.renderBackground.className = 'annotation-canvas-background';

                annoDiv.appendChild(this.renderBackground);
            }else{
                this.renderDiv = annoDiv;
            }

    		self.zr = zrender.init(this.renderDiv);
    		self.zr.add(self.shapeGroup);
            self.positionInfo.originalWidth = self.zr.getWidth();
            self.positionInfo.originalHeight = self.zr.getHeight();

    		//因为self.annoDiv.style.width及self.annoDiv.style.height 获取到的是100%,所以取第一个子节点的宽及高
    		if(self.annoDiv.style.width == "100%"){
    			var childDiv= self.annoDiv.firstChild;
    			self.screenSize.width = parseInt(childDiv.style.width);
    		    self.screenSize.height = parseInt(childDiv.style.height);
    		    log.debug("===Annotation.init(),childDiv.style.width:"+childDiv.style.width+",childDiv.style.height:"+ childDiv.style.height);
    		}else{
    			self.screenSize.width = parseInt(self.annoDiv.style.width);
    		    self.screenSize.height = parseInt(self.annoDiv.style.height);
    		    log.debug("===Annotation.init(),annoDiv.style.width:"+annoDiv.style.width+",annoDiv.style.height:"+ annoDiv.style.height);
    		}

            this.updateBackgroundColor(this.backgroundColor);

            // 图片拖拽
            self.zr.on('mousedown', function(e) {
                if(!self.isAllowEditImg){
                    return;
                }

                // 画布拖拽的起始位置是 事件对象中的画布的坐标位置
                self.dragData.pos = [e.event.zrX, e.event.zrY];

                // 画布的拖拽目标
                if(e.target && e.target.type && e.target.type == 'image' && e.target.draggable != null){

                    // 设置当前激活的图片
                    self.currActiveImg = e.target;
    				self.currActiveImg.attr('zlevel', self.tempHighZlevel);

                    // 取图片的父节点，为shapeGroup
                    var shapeGroup = self.currActiveImg.parent;

                    // 给当前激活的图片添加高亮边框，其他图片取消高亮边框
    				shapeGroup.eachChild(function(item){
    					if(item.type === 'image'){
                            if(item.id == self.currActiveImg.id){
                                item.attr('style',{shadowColor:'red',shadowBlur:5});
                            }else{
                                item.attr('style',{shadowColor:undefined,shadowBlur:undefined});
                            }
                        }
    				})

                    if(self.currActiveImg.scale[0] == 1){
                        self.imgScaleoffset.x = 0;
                        self.imgScaleoffset.y = 0;
                    }else{
                        var scale = self.currActiveImg.scale[0] - 1;
                        self.imgScaleoffset.x = self.currActiveImg.getWidth() * scale / 2;
                        self.imgScaleoffset.y = self.currActiveImg.getHeight() * scale / 2;
                    }
                }

                if (e.target === undefined) {
                    self.dragData.drag = false
                } else {
                    self.dragData.drag = true
                }
            })

            self.zr.on('mouseup', function(e) {
                if(!self.isAllowEditImg){
                    return;
                }

                if(!self.currActiveImg){
                    return;
                }

                self.dragData.drag = false;

                self.currActiveImg.customPositionX = self.currActiveImg.position[0] - self.imgScaleoffset.x;
                self.currActiveImg.customPositionY = self.currActiveImg.position[1] - self.imgScaleoffset.y;

                log.debug('===Annotation.drawImg, currActiveImg customPosition: ',[self.currActiveImg.customPositionX, self.currActiveImg.customPositionY].toString())

                self.currActiveImg.attr('zlevel', ++self.imgZlevel);

                self.roomHandle.sendUpdateAnnotation(self.boardId, self.currActiveImg, shapeTypeEnum.img);
            })

            self.zr.on('mouseout', function(e) {
                if(!self.isAllowEditImg){
                    return;
                }
                self.dragData.drag = false;
            })

            self.zr.on('mousemove', function(e) {
                if (self.dragData.drag === false) {
                    if(self.currActiveImg){
                        self.currActiveImg.draggable = false;
                    }
                    return;
                }

                if (self.currActiveImg != null && self.isAllowEditImg === true) {
    				var new_pos = [e.event.zrX, e.event.zrY]
                    var pos = [
                        new_pos[0] - self.dragData.pos[0],
                        new_pos[1] - self.dragData.pos[1]
                    ]

    				//图片拖动中，区域位置不能移出白板之外，放大缩小图片及重设置白板宽高后还有效。 by roymond 2024/11/7
    				var xMin = self.currActiveImg.position[0] + pos[0] * self.positionInfo.scaleRatioXR - self.currActiveImg.style.width * (self.currActiveImg.scaleX -1)/2;
    				var yMin = self.currActiveImg.position[1] + pos[1] * self.positionInfo.scaleRatioYR - self.currActiveImg.style.height * (self.currActiveImg.scaleY -1)/2;

    				var xMax = xMin + self.currActiveImg.style.width  * self.currActiveImg.scaleX;
    				var yMax = yMin + self.currActiveImg.style.height * self.currActiveImg.scaleY;

    				if( xMin <0 ||  yMin<0 || xMax> self.board.width || yMax> self.board.height){
    					return;
    				}
    			    //end

                    self.currActiveImg.position[0] += pos[0] * self.positionInfo.scaleRatioXR;
                    self.currActiveImg.position[1] += pos[1] * self.positionInfo.scaleRatioYR;

    				//console.log("===RRRRRRRRR222222222,"+ self.currActiveImg.position[0] +" , " + self.currActiveImg.position[1]);

                    self.currActiveImg.dirty();
    				self.dragData.pos = new_pos;
                }
            })

    		self.renderDiv.onmousedown = function(e){

    			if(self.isAllowEditImg){
    				return;
    			}
    			if(self.shapeType == shapeTypeEnum.mouse || self.shapeType == shapeTypeEnum.hlight_point){
    				return;
    			}

    			if(self.shapeType == shapeTypeEnum.eraser){
    				self.isEraser = true;
    			}
    			var shapeObj = {};

    			var x,y;
                /**
                 * 之前用的是e.clientX - this.getBoundingClientRect().left这种来计算点击坐标
                 * 其实可以直接使用e.offsetX来
                 */
                var tempPos = self.handleScaledXY(e.clientX - this.getBoundingClientRect().left, e.clientY - this.getBoundingClientRect().top);
                self.currentX = tempPos.x;
    			self.currentY = tempPos.y;

    			shapeData = [];
    			shapeData.push([self.currentX, self.currentY]);
    			var shape = null;
    			switch (self.shapeType){

    				case shapeTypeEnum.failure:
    					shape = new Failure({
    						shape:{
    							x:self.currentX,
    							y:self.currentY,
    							width:20,
    							height:20
    						},
    						style: {
    							stroke: self.color,
    							lineWidth:self.lineWidth
    						},
                            zlevel: self.normalZlevel,
    						onmouseover:mouseOverForEraser
    					})
    					break;

    				case shapeTypeEnum.success:
    					shape = new Successright({
    						shape:{
    							x:self.currentX - 10,
    							y:self.currentY - 10,
    							width:20,
    							height:20
    						},
    						style: {
    							stroke: self.color,
    							fill: 'none',
    							lineWidth:self.lineWidth
    						},
    						onmouseover:mouseOverForEraser
    					})
    					break;

    				case shapeTypeEnum.arrow:
    					shape = new Arrow({
    						shape:{
    							x:self.currentX - 15,
    							y:self.currentY - 10,
    							width:30,
    							height:20
    						},
    						style: {
    							stroke: self.color,
    							fill: self.fillColor,
    							lineWidth:self.lineWidth
    						},
                            zlevel: self.normalZlevel,
    						onmouseover:mouseOverForEraser
    					})
    					break;

    				case shapeTypeEnum.hlight_texttag:
                        var userName = self.roomHandle.selfUser.name;
                        var renderName = userName;
                        if(userName.split('').length > 7){
                            renderName = userName.substr(0, 7) + '...';
                        }
    					if(self.textTagShape){
    						self.textTagShape.attr({
    							shape: {
    								x:self.currentX - 40,
    								y:self.currentY - 20
    							},
    							style:{
    								text: renderName
    							},
                                zlevel: self.normalZlevel,
                                textContent: new zrender.Text({
                                    x: self.currentX - 40 + 5,
                                    y: self.currentY - 20 + 13,
                                    style: {
                                        text: renderName,
                                        fill: '#ffffff',
                                        textRect: {
                                            x: self.currentX - 40 + 5,
                                            y: self.currentY - 20 + 13,
                                            width: 50
                                        },
                                        truncate: {
                                            outerWidth: 50
                                        }
                                    },
                                    zlevel: self.normalZlevel
                                })
    						});
    						self.roomHandle.sendAddAnnotation(self.boardId, self.textTagShape, self.shapeType, self.color, self.lineWidth, self.arrowtype, self.fillType);
    					}else{
    						self.textTagShape = new Texttag({
    							shape:{
    								x:self.currentX - 40,
    								y:self.currentY - 20,
    								width:80,
    								height:40
    							},
    							style: {
    								stroke: "red",
    								fill: "red",
    								text: renderName,
    								truncate:{
    									outerWidth:50
    								},
    								lineWidth:self.lineWidth
    							},
                                zlevel: self.normalZlevel,
                                textContent: new zrender.Text({
                                    x: self.currentX - 40 + 5,
                                    y: self.currentY - 20 + 13,
                                    style: {
                                        text: renderName,
                                        fill: '#ffffff',
                                        textRect: {
                                            x: self.currentX - 40 + 5,
                                            y: self.currentY - 20 + 13,
                                            width: 50
                                        },
                                        truncate: {
                                            outerWidth: 50
                                        }
                                    },
                                    zlevel: self.normalZlevel
                                }),
    							onmouseover:mouseOverForEraser
    						})
    						self.textTagShape.id = Math.uuid();
                            self.shapeGroup.add(self.textTagShape);
    						self.roomHandle.sendAddAnnotation(self.boardId, self.textTagShape, self.shapeType, self.color, self.lineWidth, self.arrowtype, self.fillType);
    					}
    					break;

    				case shapeTypeEnum.rhomb:
    					shape = new zrender.Polygon({
    						shape:{
    							points: [],
    							smooth:0,
    						},
    						style: {
    							stroke: self.color,
    							fill: 'none',
    							lineWidth:self.lineWidth
    						},
                            zlevel: self.normalZlevel,
    						onmouseover:mouseOverForEraser
    					})
    					break;

    				case shapeTypeEnum.line:
    					shape = new zrender.Arrowline({
    						shape:{
    							x1: self.currentX,
    							y1: self.currentY,
    							x2: self.currentX,
    							y2: self.currentY,
    							arrowlength: 10,
    							arrowtype: self.arrowtype
    						},
    						style: {
    							stroke: self.color,
    							lineWidth:self.lineWidth
    						},
                            zlevel: self.normalZlevel,
    						onmouseover:mouseOverForEraser
    					})
    					break;

    				case shapeTypeEnum.polyline:
    					shape = new zrender.Polyline({
    						shape:{
    							points: [],
    							smooth:0,
    						},
    						style: {
    							stroke: self.color,
    							lineWidth:self.lineWidth
    						},
                            zlevel: self.normalZlevel,
    						onmouseover:mouseOverForEraser
    					})
    					break;

    				case shapeTypeEnum.rect:
    					shape = new zrender.Rect({
    						shape:{
    							x:self.currentX,
    							y:self.currentY
    						},
    						style: {
    							stroke: self.color,
    							fill: self.fillColor,
    							lineWidth:self.lineWidth
    						},
                            zlevel: self.normalZlevel,
    						onmouseover:mouseOverForEraser
    					})
    					break;

    				case shapeTypeEnum.ellipse:

    					shape = new zrender.Ellipse({

    						shape:{
    							cx:self.currentX,
    							cy:self.currentY,
    							rx:0,
    							ry:0,
    						},
    						style: {
    							stroke: self.color,
    							fill: self.fillColor,
    							lineWidth:self.lineWidth
    						},
                            zlevel: self.normalZlevel,
    						onmouseover:mouseOverForEraser
    					})
    					break;

    				default:
    					break;
    			}
    			if(shape){
    				shape.id = Math.uuid();
                    self.shapeGroup.add(shape);
    			}else{
    				return;
    			}

    			self.renderDiv.onmousemove = function(e){
    				if(self.isAllowEditImg){
    					return;
    				}

    				if(self.shapeType == shapeTypeEnum.eraser){
    					return;
    				}
                    var tempPos = self.handleScaledXY(e.clientX - this.getBoundingClientRect().left, e.clientY - this.getBoundingClientRect().top);
    				x = tempPos.x;
    				y = tempPos.y;
    				shapeData.push([x, y]);
    				var rhombData = [[self.currentX, self.currentY + (y-self.currentY)/2],[self.currentX + (x - self.currentX)/2, y],[x, self.currentY + (y-self.currentY)/2],[self.currentX + (x - self.currentX)/2, self.currentY]]
    				switch (self.shapeType){

    					case shapeTypeEnum.rhomb:
    						shape.attr('shape',{
    							points: rhombData
    						})
    						break;

    					case shapeTypeEnum.line:
    						shape.attr('shape',{
    							x2:x,
    							y2:y
    						})
    						break;

    					case shapeTypeEnum.polyline:
    						shape.attr('shape',{
    							points: shapeData
    						})
    						break;

    					case shapeTypeEnum.rect:
    						shape.attr('shape',{
    							width:x-self.currentX,
    							height:y-self.currentY
    						})
    						break;

    					case shapeTypeEnum.ellipse:
    						shape.attr('shape',{
    							cx:x + (self.currentX-x)/2,
    							cy:y + (self.currentY-y)/2,
    							rx:Math.abs(x-self.currentX)/2,
    							ry:Math.abs(y-self.currentY)/2,
    						})
    						break;

    					default:
    						break;
    				}
    			}

    			self.renderDiv.onmouseup = function(){
    				self.renderDiv.onmousemove = null;
    				self.renderDiv.onmouseup = null;
    				self.renderDiv.onmouseleave = null;

    				if(self.isAllowEditImg){
    					return;
    				}

    				if(self.shapeType == shapeTypeEnum.eraser){
    					self.isEraser = false;
    					return;
    				}
    				var shapeObj = {
    					shape:shape,
    					shapeType:self.shapeType,
    					color:self.color,
    					lineWidth:self.lineWidth,
    					arrowtype:self.arrowtype,
    					fillType:self.fillType,
    				}
    				self.shapeArray.push(shapeObj);
    				self.undoArray.push({
    					type: 'add',
    					shapeObj: shapeObj
    				})
    				self.redoArray = [];
    				self.roomHandle.sendAddAnnotation(self.boardId, shape, self.shapeType, self.color, self.lineWidth, self.arrowtype, self.fillType);
    			}

    			self.renderDiv.onmouseleave = function(){
    				self.renderDiv.onmousemove = null;
    				self.renderDiv.onmouseup = null;
    				self.renderDiv.onmouseleave = null;

    				if(self.isAllowEditImg){
    					return;
    				}

    				if(self.shapeType == shapeTypeEnum.eraser){
    					self.isEraser = false;
    					return;
    				}
    				var preWidth = parseInt(self.renderDiv.style.width);
    				var preHeight = parseInt(self.renderDiv.style.height);
    				self.shapeArray.push({
    					shape:shape,
    					shapeType:self.shapeType,
    					color:self.color,
    					lineWidth:self.lineWidth,
    					arrowtype:self.arrowtype,
    					fillType:self.fillType,
    				});
    				self.redoArray = [];
    				self.roomHandle.sendAddAnnotation(self.boardId, shape, self.shapeType, self.color, self.lineWidth, self.arrowtype, self.fillType);
    			}
    		}
    		function mouseOverForEraser(params) {
    			if(self.shapeType == shapeTypeEnum.eraser && self.isEraser){
    				for (var i = 0; i < self.shapeArray.length; i++) {
    					var shapeObj = self.shapeArray[i];
    					if(shapeObj.shape.id == params.target.id){
    						self.zr.remove(shapeObj.shape)
                            self.shapeGroup.remove(shapeObj.shape)
    						self.roomHandle.sendRemoveAnnotation(self.boardId,self.shapeType,shapeObj.shape.id)
    						self.undoArray.push({
    							type: 'delete',
    							shapeObj: shapeObj
    						})
    						self.shapeArray.splice(i,1);
    					}
    				}
    			}
    		}

    		self.renderDiv.ontouchstart = function(e){
    			if(self.isAllowEditImg){
    				return;
    			}

    			e.preventDefault(); // 阻止触摸默认滚动页面事件，防止页面滚动

    			if(self.shapeType == shapeTypeEnum.mouse || self.shapeType == shapeTypeEnum.hlight_point){
    				return;
    			}

    			if(self.shapeType == shapeTypeEnum.eraser){
    				self.isEraser = true;
    				return;
    			}

    			//使用更精确的坐标计算
    			var rect = this.getBoundingClientRect();
    			var touch = e.touches[0];
    			var rawX = touch.clientX - rect.left;
    			var rawY = touch.clientY - rect.top;

    			var tempPos = self.handleScaledXY(rawX, rawY);
    			self.currentX = tempPos.x;
    			self.currentY = tempPos.y;

    			self.arrowLineStartPoint.x = self.currentX;
    			self.arrowLineStartPoint.y = self.currentY;

    			self.shapeData = [];
    			self.shapeData.push([self.currentX, self.currentY]);
    			switch (self.shapeType){
    				case shapeTypeEnum.failure:
    					self.shape = new Failure({
    						shape:{
    							x:self.currentX,
    							y:self.currentY,
    							width:20,
    							height:20
    						},
    						style: {
    							stroke: self.color,
    							lineWidth:self.lineWidth
    						},
    					})
    					break;

    				case shapeTypeEnum.success:
    					self.shape = new Successright({
    						shape:{
    							x:self.currentX - 10,
    							y:self.currentY - 10,
    							width:20,
    							height:20
    						},
    						style: {
    							stroke: self.color,
    							fill: 'none',
    							lineWidth:self.lineWidth
    						},
    					})
    					break;

    				case shapeTypeEnum.arrow:
    					self.shape = new Arrow({
    						shape:{
    							x:self.currentX - 15,
    							y:self.currentY - 10,
    							width:30,
    							height:20
    						},
    						style: {
    							stroke: self.color,
    							fill: self.fillColor,
    							lineWidth:self.lineWidth
    						},
    					})
    					break;

    				case shapeTypeEnum.hlight_texttag:
    					if(self.textTagShape){
    						self.textTagShape.attr({
    							shape: {
    								x:self.currentX - 40,
    								y:self.currentY - 20
    							},
    							style:{
    								text: self.roomHandle.selfUser.name
    							}
    						});
    						self.roomHandle.sendAddAnnotation(self.boardId, self.textTagShape, self.shapeType, self.color, self.lineWidth, self.arrowtype, self.fillType);
    					}else{
    						self.textTagShape = new Texttag({
    							shape:{
    								x:self.currentX - 40,
    								y:self.currentY - 20,
    								width:80,
    								height:40
    							},
    							style: {
    								stroke: "red",
    								fill: "red",
    								text: self.roomHandle.selfUser.name,
    								truncate:{
    									outerWidth:50
    								},
    								lineWidth:self.lineWidth
    							},
    						})
    						self.textTagShape.id = Math.uuid();
                            self.shapeGroup.add(self.textTagShape);
    						self.roomHandle.sendAddAnnotation(self.boardId, self.textTagShape, self.shapeType, self.color, self.lineWidth, self.arrowtype, self.fillType);
    					}
    					if(self.shape){
    						self.shape = null; // 如果其他形状存在，清空，防止再重复绘制其他画笔
    					}
    					break;

    				case shapeTypeEnum.rhomb:
    					self.shape = new zrender.Polygon({
    						shape:{
    							points: [],
    							smooth:0,
    						},
    						style: {
    							stroke: self.color,
    							fill: 'none',
    							lineWidth:self.lineWidth
    						},
    					})
    					break;

    				case shapeTypeEnum.line:
    					self.shape = new zrender.Arrowline({
    						shape:{
    							arrowlength: 10,
    							arrowtype: self.arrowtype
    						},
    						style: {
    							stroke: self.color,
    							lineWidth:self.lineWidth
    						},
    					})
    					break;

    				case shapeTypeEnum.polyline:
    					self.shape = new zrender.Polyline({
    						shape:{
    							points: [],
    							smooth:0,
    						},
    						style: {
    							stroke: self.color,
    							lineWidth:self.lineWidth
    						},
    					})
    					break;

    				case shapeTypeEnum.rect:
    					self.shape = new zrender.Rect({
    						shape:{
    							x:self.currentX,
    							y:self.currentY
    						},
    						style: {
    							stroke: self.color,
    							fill: self.fillColor,
    							lineWidth:self.lineWidth
    						},
    					})
    					break;

    				case shapeTypeEnum.ellipse:

    					self.shape = new zrender.Ellipse({

    						shape:{
    							cx:self.currentX,
    							cy:self.currentY,
    							rx:0,
    							ry:0,
    						},
    						style: {
    							stroke: self.color,
    							fill: self.fillColor,
    							lineWidth:self.lineWidth
    						},
    					})
    					break;

    				default:
    					break;
    			}
    			if(self.shape){
    				self.shape.id = Math.uuid();
    				if(self.shapeType == shapeTypeEnum.success || self.shapeType == shapeTypeEnum.failure || self.shapeType == shapeTypeEnum.arrow){
    					var shapeObj = {
    						shape:self.shape,
    						shapeType:self.shapeType,
    						color:self.color,
    						lineWidth:self.lineWidth,
    						arrowtype:self.arrowtype,
    						fillType:self.fillType,
    					}
    					self.shapeArray.push(shapeObj);
    					self.undoArray.push({
    						type: 'add',
    						shapeObj: shapeObj
    					})
    					self.roomHandle.sendAddAnnotation(self.boardId, self.shape, self.shapeType, self.color, self.lineWidth, self.arrowtype, self.fillType);
    				}
                    self.shapeGroup.add(self.shape);
    			}else{
    				return;
    			}

    		}
    		self.renderDiv.ontouchmove = function(e){
    			if(self.isAllowEditImg){
    				return;
    			}

    			//使用更精确的坐标计算
    			var rect = this.getBoundingClientRect();
    			var touch = e.touches[0];
    			var rawX = touch.clientX - rect.left;
    			var rawY = touch.clientY - rect.top;

    			var tempPos = self.handleScaledXY(rawX, rawY);
    			self.x = tempPos.x;
    			self.y = tempPos.y;

    			if(self.shapeType == shapeTypeEnum.eraser){
    				self.isEraser = true;
    				var realX = self.x - self.eraserImageWidth / 2;
    				var realY = self.y - self.eraserImageHeight / 2;
    				if(self.eraserShape){
    					self.eraserShape.attr('position', [realX, realY]);
    				}

    				self.shapeArray.forEach(function(tempShape){
    					switch(tempShape.shapeType){
    						case shapeTypeEnum.line:
    							var shape = tempShape.shape.shape;
    							var x1 = shape.x1;
    							var x2 = shape.x2;
    							var y1 = shape.y1;
    							var y2 = shape.y2;
    							if(x1 < x2 && y1 < y2){
    								if(self.x >= x1 && self.x <= x2 && self.y >= y1 && self.y <= y2){
    								self.excuteRemoveAnnotation(tempShape);
    								}
    							}else if(x1 > x2 && y1 < y2){
    								if(self.x >= x2 && self.x <= x1 && self.y >= y1 && self.y <= y2){
    								self.excuteRemoveAnnotation(tempShape);
    								}
    							}else if(x1 < x2 && y1 > y2){
    								if(self.x >= x1 && self.x <= x2 && self.y >= y2 && self.y <= y1){
    								self.excuteRemoveAnnotation(tempShape);
    								}
    							}else if(x1 > x2 && y1 > y2){
    								if(self.x >= x2 && self.x <= x1 && self.y >= y2 && self.y <= y1){
    								self.excuteRemoveAnnotation(tempShape);
    								}
    							}
    							break;
    						case shapeTypeEnum.polyline:
    							// console.log('+++SDK shapeType polyline')
    							var points = tempShape.shape.shape.points;
    							var minLocationWidth = self.x - self.eraserImageWidth / 2;
    							var maxLocationWidth = self.x + self.eraserImageWidth / 2;
    							var minLocationHeight = self.y - self.eraserImageWidth / 2;
    							var maxLocationHeight = self.y + self.eraserImageWidth / 2;
    							if(points.length > 0){
    								points.forEach(function (point){
    								var pointX = point[0];
    								var pointY = point[1];
    								if(pointX >= minLocationWidth && pointX <= maxLocationWidth && pointY >= minLocationHeight && pointY <= maxLocationHeight){
    									self.excuteRemoveAnnotation(tempShape);
    								}
    								})
    							}
    							break;
    						case shapeTypeEnum.success:
    							var width = tempShape.shape.shape.width;
    							var height = tempShape.shape.shape.height;
    							var successX = tempShape.shape.shape.x;
    							var successY = tempShape.shape.shape.y;
    							if(self.x >= successX && self.x <= successX + width && self.y >= successY && self.y <= successY + height){
    								self.excuteRemoveAnnotation(tempShape);
    							}
    							break;
    						case shapeTypeEnum.failure:
    							var width = tempShape.shape.shape.width;
    							var height = tempShape.shape.shape.height;
    							var failureX = tempShape.shape.shape.x;
    							var failureY = tempShape.shape.shape.y;
    							if(self.x >= failureX && self.x <= failureX + width && self.y >= failureY && self.y <= failureY + height){
    								self.excuteRemoveAnnotation(tempShape);
    							}
    							break;
    						case shapeTypeEnum.rhomb:
    							var pointOne = tempShape.shape.shape.points[0];
    							var pointTwo = tempShape.shape.shape.points[1];
    							var pointThree = tempShape.shape.shape.points[2];
    							var pointFour = tempShape.shape.shape.points[3];

    							var x1 = pointOne[0];
    							var x2 = pointThree[0];
    							var y1 = pointTwo[1];
    							var y2 = pointFour[1];

    							if(self.x >= x1 && self.x <= x2 && self.y >= y1 && self.y <= y2){
    								// console.log('+++SDK 清除菱形1');
    								self.excuteRemoveAnnotation(tempShape);
    								break;
    							}else if(self.x <= x1 && self.x >= x2 && self.y >= y1 && self.y <= y2){
    								// console.log('+++SDK 清除菱形2');
    								self.excuteRemoveAnnotation(tempShape);
    								break;
    							}else if(self.x >= x1 && self.x <= x2 && self.y <= y1 && self.y >= y2){
    								// console.log('+++SDK 清除菱形3');
    								self.excuteRemoveAnnotation(tempShape);
    								break;
    							}else if(self.x <= x1 && self.x >= x2 && self.y <= y1 && self.y >= y2){
    								// console.log('+++SDK 清除菱形4');
    								self.excuteRemoveAnnotation(tempShape);
    								break;
    							}

    							break;
    						case shapeTypeEnum.arrow:
    							var width = tempShape.shape.shape.width;
    							var height = tempShape.shape.shape.height;
    							var arrowX = tempShape.shape.shape.x;
    							var arrowY = tempShape.shape.shape.y;
    							if(self.x >= arrowX && self.x <= arrowX + width && self.y >= arrowY && self.y <= arrowY + height){
    								self.excuteRemoveAnnotation(tempShape);
    							}
    							break;
    						case shapeTypeEnum.ellipse:
    							var cx = tempShape.shape.shape.cx;
    							var cy = tempShape.shape.shape.cy;
    							var rx = tempShape.shape.shape.rx;
    							var ry = tempShape.shape.shape.ry;
    							// 如果点击点在椭圆范围内
    							if(self.x >= cx - rx && self.x <= cx + rx && self.y >= cy - ry && self.y <= cy + ry){
    								self.excuteRemoveAnnotation(tempShape);
    							}
    							break;
    						case shapeTypeEnum.rect:
    							var rectWidth = tempShape.shape.shape.width;
    							var rectHeight = tempShape.shape.shape.height;
    							var rectX = tempShape.shape.shape.x;
    							var rectY = tempShape.shape.shape.y;
    							// 如果点击点在矩形范围内
    							if(rectWidth >= 0 && rectHeight >=0){
    								if(self.x >= rectX && self.x <= rectX + rectWidth && self.y >= rectY && self.y <= rectY + rectHeight){
    								self.excuteRemoveAnnotation(tempShape);
    								}
    							}else if(rectWidth <= 0 && rectHeight >= 0){
    								if(self.x >= rectX + rectWidth && self.x <= rectX && self.y >= rectY && self.y <= rectY + rectHeight){
    								self.excuteRemoveAnnotation(tempShape);
    								}
    							}else if(rectWidth >= 0 && rectHeight <= 0){
    								if(self.x >= rectX && self.x <= rectX + rectWidth && self.y >= rectY + rectHeight && self.y <= rectY){
    								self.excuteRemoveAnnotation(tempShape);
    								}
    							}else if(rectWidth <= 0 && rectHeight <= 0){
    								if(self.x >= rectX + rectWidth && self.x <= rectX && self.y >= rectY + rectHeight && self.y <= rectY){
    								self.excuteRemoveAnnotation(tempShape);
    								}
    							}

    							break;

    						default:
    						break;
    					}
    				})
    				return;
    			}

    			self.shapeData.push([self.x, self.y]);
    			var rhombData = [[self.currentX, self.currentY + (self.y-self.currentY)/2],[self.currentX + (self.x - self.currentX)/2, self.y],[self.x, self.currentY + (self.y-self.currentY)/2],[self.currentX + (self.x - self.currentX)/2, self.currentY]]
    			switch (self.shapeType){

    				case shapeTypeEnum.rhomb:
    					self.shape.attr('shape',{
    						points: rhombData
    					})
    					break;

    				case shapeTypeEnum.line:
    					var shapePoint = {
    						x1: self.arrowLineStartPoint.x,
    						y1: self.arrowLineStartPoint.y,
    						x2:self.x,
    						y2:self.y
    					}
    					self.shape.attr('shape',{
    						x1: self.arrowLineStartPoint.x,
    						y1: self.arrowLineStartPoint.y,
    						x2:self.x,
    						y2:self.y
    					})
    					break;

    				case shapeTypeEnum.polyline:
    					self.shape.attr('shape',{
    						points: self.shapeData
    					})
    					break;

    				case shapeTypeEnum.rect:
    					self.shape.attr('shape',{
    						width:self.x-self.currentX,
    						height:self.y-self.currentY
    					})
    					break;

    				case shapeTypeEnum.ellipse:
    					self.shape.attr('shape',{
    						cx:self.x + (self.currentX-self.x)/2,
    						cy:self.y + (self.currentY-self.y)/2,
    						rx:Math.abs(self.x-self.currentX)/2,
    						ry:Math.abs(self.y-self.currentY)/2,
    					})
    					break;
    				case shapeTypeEnum.hlight_point:
    					var width = self.hlightPointInfo.width;
    					var height = self.hlightPointInfo.height;
    					var realX = self.x - width / 2;
    					var realY = self.y - height / 2;
    					self.hlightPointShape.attr('position',[realX ,realY]);
    					if(self.hlightPointInfo.isSend){
    						self.hlightPointInfo.isSend = false;

    						self.roomHandle.sendAddAnnotation(self.boardId, self.hlightPointShape, shapeTypeEnum.hlight_point, self.color, self.lineWidth, self.arrowtype, self.fillType);
    						setTimeout(function(){
    							self.hlightPointInfo.isSend = true;
    						}, self.hlightPointInfo.intervalTime)
    					}
    					break;

    				default:
    					break;
    			}
    		}

    		self.renderDiv.ontouchend = function(){
    			if(self.isAllowEditImg){
    				return;
    			}

    			if(self.shapeType == shapeTypeEnum.txt || self.shapeType == shapeTypeEnum.hlight_texttag || self.shapeType == shapeTypeEnum.mouse || self.shapeType == shapeTypeEnum.success || self.shapeType == shapeTypeEnum.failure || self.shapeType == shapeTypeEnum.arrow){
    				return;
    			}

    			if(self.shapeType == shapeTypeEnum.eraser){
    				self.isEraser = false;
    				return;
    			}

    			var shapeObj = {
    				shape:self.shape,
    				shapeType:self.shapeType,
    				color:self.color,
    				lineWidth:self.lineWidth,
    				arrowtype:self.arrowtype,
    				fillType:self.fillType,
    			}
    			self.shapeArray.push(shapeObj);
    			self.redoArray = [];
    			if(self.shapeType != shapeTypeEnum.hlight_point){
    				self.undoArray.push({
    					type: 'add',
    					shapeObj: shapeObj
    				})
    				log.debug("++TTTTTTTTTT111111>>>>>>>>>>>");
    				self.roomHandle.sendAddAnnotation(self.boardId, self.shape, self.shapeType, self.color, self.lineWidth, self.arrowtype, self.fillType);
    			}
    		}

            if(self.initType == AnnotationInitTypeEnum.proportional && self.board.backgroundColor != ""){
                self.updateBackgroundColor(self.board.backgroundColor);
            }

            if(self.initType == AnnotationInitTypeEnum.proportional && self.board.backgroundImage != ""){
                self.updateBackgroundImage(self.board.backgroundImage);
            }

            deferred.resolve();
            return deferred.promise;
    	}

        // 橡皮擦清除画笔
        Annotation.prototype.excuteRemoveAnnotation = function(removeShape){
            var self = this;
            self.zr.remove(removeShape.shape)
            self.shapeGroup.remove(removeShape.shape);
            self.roomHandle.sendRemoveAnnotation(self.boardId, self.shapeType, removeShape.shape.id)
            self.shapeArray.forEach(function(shapeObj, index){
            if(shapeObj.shape.id == removeShape.shape.id){
                    self.undoArray.push({
                        type: 'delete',
                        shapeObj: shapeObj
                    })
                    self.shapeArray.splice(index, 1);
            }
            })

            /**
             * desc: 解决重连后重复批注删不掉
            * by: 王博
            * date: 2021/7/15
            */
            var tempList = self.zr.storage._displayList;
            for(var i in tempList){
                if(tempList[i].id == removeShape.shape.id){
                    self.zr.remove(tempList[i]);
                    self.shapeGroup.remove(tempList[i])
                }
            }
        }

    	Annotation.prototype.initEraserShape = function(eraserImgUrl){
    		var self = this;
    		self.eraserShape = new zrender.Image({
    			position: [0, 0],
    			scale: [1, 1],
    			style: {
    				image: eraserImgUrl,
    				width: self.eraserImageWidth,
    				height: self.eraserImageHeight
    			},
    			draggable: true
    		})
            self.shapeGroup.add(self.eraserShape);
    		self.eraserShape.id = Math.uuid();
    	}

    	Annotation.prototype.removeToBoard = function(removeInfo) {
    		log.debug('===annotation removeToBoard');
    		var self = this;
    		var userKey = 'userId' + removeInfo.operUserId;

            var shapeArray = self.shapeArray;
            var displayList = self.zr.storage.getDisplayList();
            var groupChildren = self.shapeGroup.children();

    		if(removeInfo.annotationType == shapeTypeEnum.clear){
    			if(removeInfo.operUserId == self.roomHandle.selfUser.id){
    				for(var k in self.shapeArray){
    					self.zr.remove(self.shapeArray[k].shape);
                        self.shapeGroup.remove(self.shapeArray[k].shape)
    				}
    				self.shapeArray = [];
    			}else{
    				for(var k in self.otherShapeMap){
    					if(k == userKey){
    						for(var j in self.otherShapeMap[k]){
    							self.zr.remove(self.otherShapeMap[k][j].shape);
                                self.shapeGroup.remove(self.otherShapeMap[k][j].shape);

                                for(var i = displayList.length - 1; i >= 0; i--){
                                    if(displayList[i].id == self.otherShapeMap[k][j].shape.id){
                                        self.zr.remove(displayList[i])
                                    }
                                }

                                for(var m = groupChildren.length - 1; m >= 0; m--){
                                    if(groupChildren[m].id == self.otherShapeMap[k][j].shape.id){
                                        self.shapeGroup.remove(groupChildren[m])
                                    }
                                }
    						}
    					}
    				}
    			}

    			delete self.otherShapeMap[userKey];

    		}else if(removeInfo.annotationType == shapeTypeEnum.eraser){
    			if(self.hlightPointShape && self.hlightPointShape.id == removeInfo.annotationId){
    				self.clearCurrHlightPoint();
    			}else if(self.textTagShape && self.textTagShape.id == removeInfo.annotationId){
    				self.clearCurrHlightPoint();
    			}else if(removeInfo.operUserId == self.roomHandle.selfUser.id){
    				for(var k in self.shapeArray){
    					if(self.shapeArray[k].shape.id == removeInfo.annotationId){
    						self.zr.remove(self.shapeArray[k].shape);
                            self.shapeGroup.remove(self.shapeArray[k].shape);
    						self.shapeArray.splice(k,1);
    					}
    				}
    			}else{
    				for(var k in self.otherShapeMap){
    					if(k == userKey){
    						for(var j in self.otherShapeMap[k]){
    							if(self.otherShapeMap[k][j].id == removeInfo.annotationId){
    								self.zr.remove(self.otherShapeMap[k][j].shape);
                                    self.shapeGroup.remove(self.otherShapeMap[k][j].shape);
    							}
    						}
    					}
    				}

    				/**
    				 * desc: 解决重连后重复批注删不掉
    				 * by: 王博
    				 * date: 2021/7/15
    				 */
    				var tempList = self.zr.storage._displayList;
    				for(var i in tempList){
    					if(tempList[i].id == removeInfo.annotationId){
    						self.zr.remove(tempList[i]);
                            self.shapeGroup.remove(tempList[i]);
    					}
    				}
    			}
    		}else if(removeInfo.annotationType == shapeTypeEnum.img){

                for(var k in self.otherShapeMap){
                    if(k == userKey){
                        for(var j = self.otherShapeMap[k].length - 1; j >= 0; j--){
                            // 从各个维护的列表中删除当前批注对象
                            if(self.otherShapeMap[k][j].shape.id == removeInfo.annotationId || (removeInfo.Img && self.otherShapeMap[k][j].shape.id == removeInfo.Img.im.id)){
                                self.zr.remove(self.otherShapeMap[k][j].shape);
                                self.shapeGroup.remove(self.otherShapeMap[k][j].shape);
                                self.otherShapeMap[k].splice(j, 1);
                            }
                        }
                    }
                }
    		}
    	}

    	function replaceRgba(obj){
    		return "rgba(" + obj.r + "," +  obj.g + "," + obj.b + "," + parseFloat(obj.a/255) + ")";
    	}

        function replaceRgb(obj){
    		return "rgb(" + obj.r + "," +  obj.g + "," + obj.b + ")";
    	}

        Annotation.prototype.drawTextToBoard = function(annotationInfo) {
            var self = this;
            var txt = annotationInfo.txt;
            var txi = txt.txi
            var txs = txi.txs
            var objectBase = txt.objectBase.objectBase;
            var shapeType = parseInt(txt.objectBase.type);
    		var lineWidth = parseInt(objectBase.lineWidth);
    		var arrowtype = parseInt(objectBase.arrow);
    		var color = replaceRgba(objectBase.lineColor);
    		var fillColor = replaceRgba(objectBase.fillColor);

            var text = new zrender.Text({
                style: {
                    text: txs[0].content,
                    fontSize: txi.fontSize,
                    fontStyle: txi.fontStyle,
                    fontWeight: txi.fontWeight,
                    fill: replaceRgb(txi.fontColor)
                },

                position: [txt.objectBase.start.x * self.roomHandle.boardInputXRatio, txt.objectBase.start.y * self.roomHandle.boardInputYRatio],
                origin: [txt.objectBase.start.x * self.roomHandle.boardInputXRatio, txt.objectBase.start.y * self.roomHandle.boardInputYRatio],
                onmouseover: mouseOverForEraser
            })

            self.shapeGroup.add(text);

            var shapeObj = {
                id: annotationInfo.annotationId,
                shape: text,
                shapeType: shapeType,
                lineWidth: lineWidth,
                arrowtype: arrowtype,
                color: color,
                fillColor: fillColor
            }

            if(annotationInfo.operUserId === self.roomHandle.selfUser.id){
                self.shapeArray.push(shapeObj);
            }else{
                var userKey = 'userId' +  objectBase.ownerUserId
                if(self.otherShapeMap[userKey]){
                    self.otherShapeMap[userKey].push(shapeObj);
                }else{
                    self.otherShapeMap[userKey] = [];
                    self.otherShapeMap[userKey].push(shapeObj);
                }
            }

            function mouseOverForEraser(params) {
    			if(self.shapeType == shapeTypeEnum.eraser && self.isEraser){
    				for(var k in self.shapeArray){
    					if(self.shapeArray[k].shape.id == params.target.parent.id){
    						self.zr.remove(params.target.parent)
                            self.shapeGroup.remove(params.target.parent)
    						self.roomHandle.sendRemoveAnnotation(self.boardId,self.shapeType,self.shapeArray[k].shape.id)
    						self.undoArray.push({
    							type: 'delete',
    							shapeObj: self.shapeArray[k]
    						})
    						self.shapeArray.splice(k,1);
    					}
    				}
    			}
    		}
        }

    	//远端获取的注释，画在画板上
    	Annotation.prototype.drawToBoard = function(annotationInfo) {
    		var self = this;
    		var shapeType = parseInt(annotationInfo.objectBase.type);
    		var lineWidth = parseInt(annotationInfo.objectBase.lineWidth);
    		var arrowtype = parseInt(annotationInfo.objectBase.arrow);
    		var color = replaceRgba(annotationInfo.objectBase.lineColor);
    		var fillColor = replaceRgba(annotationInfo.objectBase.fillColor);
    		var shape = null;

            function mouseOverForEraser(params) {
                if(self.shapeType == shapeTypeEnum.eraser && self.isEraser){
                    for(var k in self.shapeArray){
                        if(params.target.id && self.shapeArray[k].shape.id == params.target.id){
                            self.zr.remove(self.shapeArray[k].shape)
                            self.shapeGroup.remove(self.shapeArray[k].shape)
                            /**
                             * desc: 解决重连后重复批注删不掉
                                * by: 王博
                                * date: 2021/7/15
                                */
                            var tempList = self.zr.storage._displayList;
                            for(var i in tempList){
                                if(tempList[i].id == params.target.id){
                                    self.zr.remove(tempList[i]);
                                    self.shapeGroup.remove(tempList[i]);
                                }
                            }

                            self.roomHandle.sendRemoveAnnotation(self.boardId,self.shapeType,self.shapeArray[k].shape.id)
                            self.shapeArray.splice(k,1);
                        }
                    }
                }
            }

    		switch (shapeType){

    			case shapeTypeEnum.rhomb:
    				var currentX = annotationInfo.start.x;
    				var currentY = annotationInfo.start.y;
    				var x = annotationInfo.end.x;
    				var y = annotationInfo.end.y;

    				log.debug("===annotation.drawToBoard(),room.boardInputXRatio:"+ self.roomHandle.boardInputXRatio+",room.boardInputYRatio:"+self.roomHandle.boardInputYRatio);
    				log.debug("===annotation.drawToBoard(),shapeTypeEnum.rhomb,currentX:",currentX+",currentY:",currentY+",x:"+x+",y:"+y);

    				var inputCurrentX = Math.round(currentX * self.roomHandle.boardInputXRatio);
    		        var inputCurrentY = Math.round(currentY * self.roomHandle.boardInputYRatio);
    		        var inputX = Math.round(x * self.roomHandle.boardInputXRatio);
    		        var inputY = Math.round(y * self.roomHandle.boardInputYRatio);
    		        log.debug("===annotation.drawToBoard(),ishapeTypeEnum.rhomb,nputCurrentX:",inputCurrentX+",inputCurrentY:",inputCurrentY+",inputX:"+inputX+",inputY:"+inputY);

    				var rhombData = [[inputCurrentX, inputCurrentY + (inputY-inputCurrentY)/2],[inputCurrentX + (inputX - inputCurrentX)/2, inputY],[inputX, inputCurrentY + (inputY-inputCurrentY)/2],[inputCurrentX + (inputX - inputCurrentX)/2, inputCurrentY]]

    				shape = new zrender.Polygon({
    					shape:{
    						points: rhombData,
    						smooth:0,
    					},
    					style: {
    						stroke: color,
    						fill: 'none',
    						lineWidth:lineWidth
    					},
                        zlevel: self.normalZlevel,
    					onmouseover:mouseOverForEraser
    				})
    				break;

    			case shapeTypeEnum.line:
    				var x1 = annotationInfo.start.x;
    				var y1 = annotationInfo.start.y;
    				var x2 = annotationInfo.end.x;
    				var y2 = annotationInfo.end.y;

    				log.debug("===annotation.drawToBoard(),shapeTypeEnum.line,x1:",x1+",y1:",y1+",x2:"+x2+",y2:"+y2);

    				var inputx1 = Math.round(x1 * self.roomHandle.boardInputXRatio);
    		        var inputy1 = Math.round(y1 * self.roomHandle.boardInputYRatio);
    		        var inputx2 = Math.round(x2 * self.roomHandle.boardInputXRatio);
    		        var inputy2 = Math.round(y2 * self.roomHandle.boardInputYRatio);

    		        log.debug("===annotation.drawToBoard(),shapeTypeEnum.line,inputx1:",inputx1+",inputy1:",inputy1+",inputx2:"+inputx2+",inputy2:"+inputy2);

    				shape = new zrender.Arrowline({
    					shape:{
    						x1: inputx1,
    						y1: inputy1,
    						x2: inputx2,
    						y2: inputy2,
    						arrowlength: 10,
    						arrowtype: arrowtype
    					},
    					style: {
    						stroke: color,
    						lineWidth:lineWidth
    					},
                        zlevel: self.normalZlevel,
    					onmouseover:mouseOverForEraser
    				})
    				break;

    			case shapeTypeEnum.failure:
    				var x = annotationInfo.start.x;
    				var y = annotationInfo.start.y;
    				var width = annotationInfo.end.x - annotationInfo.start.x;
    				var height = annotationInfo.end.y - annotationInfo.start.y;

    				log.debug("===annotation.drawToBoard(),shapeTypeEnum.failure,x:",x+",y:",y+",width:"+width+",height:"+height);

    				var inputX = Math.round(x * self.roomHandle.boardInputXRatio);
    		        var inputY = Math.round(y * self.roomHandle.boardInputYRatio);
    		        var inputWidth = Math.round(width * self.roomHandle.boardInputXRatio);
    		        var inputHeight = Math.round(height * self.roomHandle.boardInputYRatio);

    		        log.debug("===annotation.drawToBoard(),shapeTypeEnum.failure,inputX:",inputX+",inputY:",inputY+",inputWidth:"+inputWidth+",inputHeight:"+inputHeight);

    				shape = new Failure({
    					shape:{
    						x:inputX,
    						y:inputY,
    						width:inputWidth,
    						height:inputHeight
    					},
    					style: {
    						stroke: color,
    						lineWidth:lineWidth
    					},
                        zlevel: self.normalZlevel,
    					onmouseover:mouseOverForEraser
    				})

    				break;

    			case shapeTypeEnum.success:

    				var x = annotationInfo.start.x;
    				var y = annotationInfo.start.y;
    				var width = annotationInfo.end.x - annotationInfo.start.x;
    				var height = annotationInfo.end.y - annotationInfo.start.y;

    				log.debug("===annotation.drawToBoard(),shapeTypeEnum.success,x:",x+",y:",y+",width:"+width+",height:"+height);

    				var inputX = Math.round(x * self.roomHandle.boardInputXRatio);
    		        var inputY = Math.round(y * self.roomHandle.boardInputYRatio);
    		        var inputWidth = Math.round(width * self.roomHandle.boardInputXRatio);
    		        var inputHeight = Math.round(height * self.roomHandle.boardInputYRatio);

    		        log.debug("===annotation.drawToBoard(),shapeTypeEnum.success,inputX:",inputX+",inputY:",inputY+",inputWidth:"+inputWidth+",inputHeight:"+inputHeight);

    				shape = new Successright({
    					shape:{
    						x:inputX,
    						y:inputY,
    						width:inputWidth,
    						height:inputHeight
    					},
    					style: {
    						stroke: color,
    						fill: 'none',
    						lineWidth:lineWidth
    					},
                        zlevel: self.normalZlevel,
    					onmouseover:mouseOverForEraser
    				})

    				break;

    			case shapeTypeEnum.arrow:

    				var x = annotationInfo.start.x;
    				var y = annotationInfo.start.y;
    				var width = annotationInfo.end.x - annotationInfo.start.x;
    				var height = annotationInfo.end.y - annotationInfo.start.y;

    				log.debug("===annotation.drawToBoard(),shapeTypeEnum.arrow,x:",x+",y:",y+",width:"+width+",height:"+height);

    				var inputX = Math.round(x * self.roomHandle.boardInputXRatio);
    		        var inputY = Math.round(y * self.roomHandle.boardInputYRatio);
    		        var inputWidth = Math.round(width * self.roomHandle.boardInputXRatio);
    		        var inputHeight = Math.round(height * self.roomHandle.boardInputYRatio);

    		        log.debug("===annotation.drawToBoard(),shapeTypeEnum.arrow,inputX:",inputX+",inputY:",inputY+",inputWidth:"+inputWidth+",inputHeight:"+inputHeight);

    				shape = new Arrow({
    					shape:{
    						x:inputX,
    						y:inputY,
    						width:inputWidth,
    						height:inputHeight
    					},
    					style: {
    						stroke: color,
    						fill: fillColor,
    						lineWidth:lineWidth
    					},
                        zlevel: self.normalZlevel,
    					onmouseover:mouseOverForEraser
    				})

    				break;
    			case shapeTypeEnum.hlight_texttag:
    				var user = self.roomHandle.getUser(annotationInfo.objectBase.ownerUserId);
    				var x = annotationInfo.start.x;
    				var y = annotationInfo.start.y;
    				var width = annotationInfo.end.x - annotationInfo.start.x;
    				var height = annotationInfo.end.y - annotationInfo.start.y;

    				log.debug("===annotation.drawToBoard(),shapeTypeEnum.hlight_texttag,x:",x+",y:",y+",width:"+width+",height:"+height);

    				var inputX = Math.round(x * self.roomHandle.boardInputXRatio);
    		        var inputY = Math.round(y * self.roomHandle.boardInputYRatio);
    		        var inputWidth = Math.round(width * self.roomHandle.boardInputXRatio);
    		        var inputHeight = Math.round(height * self.roomHandle.boardInputYRatio);

    		        log.debug("===annotation.drawToBoard(),shapeTypeEnum.hlight_texttag,inputX:",inputX+",inputY:",inputY+",inputWidth:"+inputWidth+",inputHeight:"+inputHeight);

    				if(!user){
    					return;
    				}
    				if(self.textTagShape){
    					self.textTagShape.attr({
    						shape: {
    							x:inputX,
    							y:inputY
    						},
    						style:{
    							text: user.name
    						},
                            zlevel: self.normalZlevel,
    					});

    				}else{
    					self.textTagShape = new Texttag({
    						shape:{
    							x:inputX,
    							y:inputY,
    							width:inputWidth,
    							height:inputHeight
    						},
    						style: {
    							stroke: "red",
    							fill: "red",
    							text: user.name,
    							truncate:{
    								outerWidth:50
    							},
    							lineWidth:lineWidth
    						},
                            zlevel: self.normalZlevel,
    						onmouseover:mouseOverForEraser
    					})
                        self.shapeGroup.add(self.textTagShape);
    					self.textTagShape.id = annotationInfo.objectBase.annotationId;

    				}
    				break;
    			case shapeTypeEnum.polyline:
    				var points = [];
    				console.log("===annotation.drawToBoard(),shapeTypeEnum.polyline,points：",points);
    				for(var k in annotationInfo.points){
    					var x = annotationInfo.points[k].x;
    					var y = annotationInfo.points[k].y;

    					//console.log("===annotation.drawToBoard(),shapeTypeEnum.polyline,x:",x+",y:",y);

    				    var inputX = Math.round(x * self.roomHandle.boardInputXRatio);
    		            var inputY = Math.round(y * self.roomHandle.boardInputYRatio);

    		            //console.log("===annotation.drawToBoard(),shapeTypeEnum.polyline,inputX:",inputX+",inputY:",inputY);

    					var point = [inputX,inputY]
    					points.push(point);
    				}
    				shape = new zrender.Polyline({
    					shape:{
    						points: points,
    						smooth:0,
    					},
    					style: {
    						stroke: color,
    						lineWidth:lineWidth
    					},
                        zlevel: self.normalZlevel,
    					onmouseover:mouseOverForEraser
    				})
    				break;

    			case shapeTypeEnum.rect:
    				var x = annotationInfo.start.x;
    				var y = annotationInfo.start.y;
    				var width = annotationInfo.end.x - annotationInfo.start.x;
    				var height = annotationInfo.end.y - annotationInfo.start.y;

    				log.debug("===annotation.drawToBoard(),shapeTypeEnum.rect,x:",x+",y:",y+",width:"+width+",height:"+height);

    				var inputX = Math.round(x * self.roomHandle.boardInputXRatio);
    		        var inputY = Math.round(y * self.roomHandle.boardInputYRatio);
    		        var inputWidth = Math.round(width * self.roomHandle.boardInputXRatio);
    		        var inputHeight = Math.round(height * self.roomHandle.boardInputYRatio);

    		        log.debug("===annotation.drawToBoard(),shapeTypeEnum.rect,inputX:",inputX+",inputY:",inputY+",inputWidth:"+inputWidth+",inputHeight:"+inputHeight);

    				shape = new zrender.Rect({
    					shape:{
    						x:inputX,
    						y:inputY,
    						width:inputWidth,
    						height:inputHeight
    					},
    					style: {
    						stroke: color,
    						fill: fillColor,
    						lineWidth:lineWidth
    					},
                        zlevel: self.normalZlevel,
    					onmouseover:mouseOverForEraser
    				})
    				break;

    			case shapeTypeEnum.ellipse:
    			    var startX = annotationInfo.start.x;
    			    var endX =  annotationInfo.end.x;
    			    var startY = annotationInfo.start.y;
    			    var endY = annotationInfo.end.y;
    			    log.debug("===annotation.drawToBoard(),shapeTypeEnum.ellipse,startX :",startX+",endX:",endX+",startY:"+startY+",endY:"+endY);

    			    var inputStartX = Math.round(startX * self.roomHandle.boardInputXRatio);
    		        var inputEndX = Math.round(endX * self.roomHandle.boardInputXRatio);
    		        var inputStartY = Math.round(startY * self.roomHandle.boardInputYRatio);
    		        var inputEndY = Math.round(endY * self.roomHandle.boardInputYRatio);

    			    log.debug("===annotation.drawToBoard(),shapeTypeEnum.ellipse,inputStartX :",inputStartX+",inputEndX:",inputEndX+",inputStartY:"+inputStartY+",inputEndY:"+inputEndY);

    				var rx = (inputEndX - inputStartX)/2;
    				var ry = (inputEndY - inputStartY)/2;
    				var cx = inputStartX + rx;
    				var cy = inputStartY + ry;

    				shape = new zrender.Ellipse({
    					shape:{
    						cx:cx,
    						cy:cy,
    						rx:rx,
    						ry:ry,
    					},
    					style: {
    						stroke: color,
    						fill: fillColor,
    						lineWidth:lineWidth
    					},
                        zlevel: self.normalZlevel,
    					onmouseover:mouseOverForEraser
    				})
    				break;
    			case shapeTypeEnum.hlight_point:
    				var x = annotationInfo.start.x;
    				var y = annotationInfo.start.y;
    				var width = self.hlightPointInfo.width;
    				var height = self.hlightPointInfo.height;

    				console.log("===annotation.drawToBoard(),shapeTypeEnum.hlight_point,x:",x+",y:",y+",width:"+width+",height:"+height);

    				var inputX = Math.round(x * self.roomHandle.boardInputXRatio);
    		        var inputY = Math.round(y * self.roomHandle.boardInputYRatio);
    		        var inputWidth = Math.round(width * self.roomHandle.boardInputXRatio);
    		        var inputHeight = Math.round(height * self.roomHandle.boardInputYRatio);

    		         log.debug("===annotation.drawToBoard(),shapeTypeEnum.hlight_point,inputX:",inputX+",inputY:",inputY+",inputWidth:"+inputWidth+",inputHeight:"+inputHeight);

    				if(!self.hlightPointShape){
    					self.hlightPointShape = new zrender.Image({
    						position: [inputX, inputY],
    			            scale: [1, 1],
    			            style: {
    			                image: self.hlightPointInfo.imgUrl,
    			                width: inputWidth,
    			                height:inputHeight
    			            },
    			            draggable: true,
                            zlevel: self.normalZlevel
    					})
                        self.shapeGroup.add(self.hlightPointShape);
    					self.hlightPointShape.id = annotationInfo.objectBase.annotationId;
    				}else{
    					self.hlightPointShape.attr('position',[inputX - inputWidth / 2 ,inputY - inputHeight / 2]);
    				}

    				break;
    			case shapeTypeEnum.img:
    			    console.log("===annotation.drawToBoard(),shapeTypeEnum.img, annotationInfo:",annotationInfo);

    				var rotate = degree2mathPI(annotationInfo.im.rotate);
                    var img = null;

                    var shapeObj = {
                        id: annotationInfo.im.id,
    					shape: null,
    					shapeType: shapeType,
                        lineWidth: lineWidth,
                        arrowtype: arrowtype,
                        color: color,
                        fillColor: fillColor
    				}

                    // 自己的批注图片渲染（在关闭再打开白板时，自己原有图片再次渲染）
                    if(annotationInfo.objectBase.ownerUserId === self.roomHandle.selfUser.id){
                        for (var i = 0; i < self.roomHandle.annotation2boardId[annotationInfo.objectBase.objectId].storageArr.length; i++) {
                            var tempShape = self.roomHandle.annotation2boardId[annotationInfo.objectBase.objectId].storageArr[i];
                            if (tempShape.annotationType == shapeTypeEnum.img && tempShape.annotationId == annotationInfo.im.id && tempShape.operUserId == self.roomHandle.selfUser.id) {
                                img = tempShape.imgZrender;
                                shapeObj.shape = img;
                                self.shapeArray.push(shapeObj);
                                break;
                            }
                        }

                    }else{
                        // 远端用户的图片渲染
                        img = new zrender.Image({
                            style: {
                                image:annotationInfo.im.file_url,
                                x: annotationInfo.im.x * self.roomHandle.boardInputXRatio,
                                y: annotationInfo.im.y * self.roomHandle.boardInputYRatio,
                                width: annotationInfo.im.w * self.roomHandle.boardInputXRatio,
                                height: annotationInfo.im.h * self.roomHandle.boardInputYRatio
                            },
                            zlevel: annotationInfo.im.layer,
                            id: annotationInfo.im.id,
                            rotation: rotate,
                            originX: annotationInfo.im.x * self.roomHandle.boardInputXRatio + annotationInfo.im.w / 2 * self.roomHandle.boardInputXRatio,
                            originY: annotationInfo.im.y * self.roomHandle.boardInputYRatio + annotationInfo.im.h / 2 * self.roomHandle.boardInputYRatio
                        });

                        shapeObj.shape = img

                        var userKey = 'userId' + annotationInfo.objectBase.ownerUserId;
                        if(self.otherShapeMap[userKey]){
                            for(var i = self.otherShapeMap[userKey].length - 1; i >= 0; i--){
                                // 先删除otherShapeMap里面的已有的图片对象
                                if(self.otherShapeMap[userKey][i].shape.id === annotationInfo.im.id){
                                    self.otherShapeMap[userKey].splice(i, 1);
                                }
                            }
                            self.otherShapeMap[userKey].push(shapeObj);
                        }else{
                            self.otherShapeMap[userKey] = [];
                            self.otherShapeMap[userKey].push(shapeObj);
                        }
                    }

                    self.shapeGroup.add(img);
                    self.setAllowEditImg(false);
    			    break;
    			default:
    				break;
    		}
    		if(shape){
    			var shapeObj = {
    				id:annotationInfo.objectBase.annotationId,
    				shape:shape
    			}
    			self.shapeGroup.add(shape);
    			shape.id = annotationInfo.objectBase.annotationId;
    			if(annotationInfo.objectBase.ownerUserId == self.roomHandle.selfUser.id){
    				self.shapeArray.push({
    					shape:shape,
    					shapeType:shapeType,
    					color:color,
    					lineWidth:lineWidth,
    					arrowtype:arrowtype,
    					fillType:fillTypeEnum.none,
    				});
    			}else{
    				var userKey = 'userId' +  annotationInfo.objectBase.ownerUserId
    				if(self.otherShapeMap[userKey]){
    					self.otherShapeMap[userKey].push(shapeObj);
    				}else{
    					self.otherShapeMap[userKey] = [];
    					self.otherShapeMap[userKey].push(shapeObj);
    				}
    			}
    		}
    	}
        //更新远端获取的注释，更新到画板上 by roymond 2022/8/29
        Annotation.prototype.updateDrawToBoard = function(annotationInfo) {
            var self = this;
            var shapeType = parseInt(annotationInfo.objectBase.type);

            switch (shapeType){
                case shapeTypeEnum.img:

                    self.shapeGroup.eachChild(function(child) {
                        if(child.id === annotationInfo.im.id){
                            self.shapeGroup.remove(child)
                        }
                    })

                    for(var k in self.shapeArray){
                        if(self.shapeArray[k].shape.id == annotationInfo.im.id){
                            self.zr.remove(self.shapeArray[k].shape);
                            // self.shapeGroup.remove(self.shapeArray[k].shape);
                            self.shapeArray.splice(k,1);
                        }
                    }

                    var rotate = degree2mathPI(annotationInfo.im.rotate);
                    var originX = annotationInfo.im.x * self.roomHandle.boardInputXRatio + annotationInfo.im.w * self.roomHandle.boardInputXRatio/2;
                    var originY = annotationInfo.im.y * self.roomHandle.boardInputYRatio + annotationInfo.im.h * self.roomHandle.boardInputYRatio /2;

                    var img = new zrender.Image({
                        style: {
                            image:annotationInfo.im.file_url,
                            x: annotationInfo.im.x * self.roomHandle.boardInputXRatio,
                            y: annotationInfo.im.y * self.roomHandle.boardInputYRatio,
                            width: annotationInfo.im.w * self.roomHandle.boardInputXRatio,
                            height:annotationInfo.im.h * self.roomHandle.boardInputYRatio
                        },
                        zlevel: annotationInfo.im.layer,
                        id: annotationInfo.im.id,
                        rotation: rotate,
                        origin: [annotationInfo.im.x * self.roomHandle.boardInputXRatio + annotationInfo.im.w * self.roomHandle.boardInputXRatio/2,annotationInfo.im.y * self.roomHandle.boardInputYRatio + annotationInfo.im.h * self.roomHandle.boardInputYRatio /2]
                    });

                    if(self.roomHandle.style2annotation[annotationInfo.im.id]){
                        img.attr('style', JSON.parse(self.roomHandle.style2annotation[annotationInfo.im.id].style));
                        img.attr('position', JSON.parse(self.roomHandle.style2annotation[annotationInfo.im.id].position));
                        img.attr('scale', JSON.parse(self.roomHandle.style2annotation[annotationInfo.im.id].scale));
                        img.attr('rotation', JSON.parse(self.roomHandle.style2annotation[annotationInfo.im.id].rotation));
                        img.attr('origin', JSON.parse(self.roomHandle.style2annotation[annotationInfo.im.id].origin));
                    }

                    self.shapeGroup.add(img);

                    var shapeObj = {
                        shape:img,
                        shapeType:self.shapeType
                    }

                    if(annotationInfo.objectBase.ownerUserId === self.roomHandle.selfUser.id){
                        self.shapeArray.push(shapeObj);
                    }else{
                        var userKey = 'userId' + annotationInfo.objectBase.ownerUserId;
                        if(self.otherShapeMap[userKey]){
                            for(var i = self.otherShapeMap[userKey].length - 1; i >= 0; i--){
                                // 先删除otherShapeMap里面的已有的图片对象
                                if(self.otherShapeMap[userKey][i].shape.id === annotationInfo.im.id){
                                    self.otherShapeMap[userKey].splice(i, 1);
                                }
                            }
                            self.otherShapeMap[userKey].push(shapeObj);

                        }else{
                            self.otherShapeMap[userKey] = [];
                            self.otherShapeMap[userKey].push(shapeObj);
                        }
                    }

                    // 图片属性更新，要把本地缓存的属性也要更新，解决发起人关闭白板后再打开之前的图片位置、缩放、旋转角度丢失问题
                    if(self.roomHandle.annotation2boardId[annotationInfo.objectBase.objectId]){
                        for (var i = 0; i < self.roomHandle.annotation2boardId[annotationInfo.objectBase.objectId].storageArr.length; i++) {
                            var tempShape = self.roomHandle.annotation2boardId[annotationInfo.objectBase.objectId].storageArr[i];
                            if (tempShape.Img && tempShape.annotationType == shapeTypeEnum.img && (tempShape.Img.im.id == annotationInfo.im.id || tempShape.annotationId == annotationInfo.im.id) && tempShape.operUserId == annotationInfo.objectBase.ownerUserId) {
                                tempShape.Img.im.x = annotationInfo.im.x;
                                tempShape.Img.im.y= annotationInfo.im.y;
                                tempShape.Img.im.w = annotationInfo.im.w;
                                tempShape.Img.im.h = annotationInfo.im.h;
                                tempShape.Img.im.rotate = annotationInfo.im.rotate;
                                break;
                            }
                        }
                    }

                    break;

                default:
                    break;
            }
        }

        /**
    	 * @desc 注释设置几何形状，如矩形，随机线等   注释类型，如鼠标、注释、橡皮擦
    	 * @param {canvasTypeEnum} type - 几何形 和 注释状态  枚举型
    	 *
    	 * @example
    	 * annotation.setShapeType(shapeTypeEnum.polyline);
    	 */
    	Annotation.prototype.setShapeType = function(shapeType,mouserUrl) {
    		var currentOs = avdEngineHandle.getBrowserDetect().osName;
    		if(this.shapeType == shapeTypeEnum.hlight_point && this.hlightPointShape){
    			this.clearCurrHlightPoint();
    		}
    		if(this.eraserShape){
    			this.clearCurrEraser()
    		}
    		// 判断是否是移动端访问，移动端没有鼠标，所以创建一个鼠标shape当成鼠标
    		if(shapeType == shapeTypeEnum.eraser && mouserUrl && currentOs == 'Android' || currentOs == 'iOS'){
    			this.initEraserShape(mouserUrl)
    		}
    		if(this.shapeType == shapeTypeEnum.hlight_texttag && this.textTagShape){
    			this.clearCurrHlightPoint();
    		}
    		var imgUrl = ""
    		if(mouserUrl){
    			imgUrl = "url("+mouserUrl+"),auto"
    		}

            if(this.textInfo != null){
                if(shapeType == shapeTypeEnum.txt){
                    this.textInfo.setTextEditEnable(true);
                    this.zr.handler.proxy.cursor = 'text';
                }else{
                    this.textInfo.setTextEditEnable(false);
                }
            }else{
                avdEngineHandle.eraserCustomIconPath = imgUrl;
            }
            this.shapeType = parseInt(shapeType);
    	}

    	/**
    	 * @desc 清除橡皮擦
    	 */
        Annotation.prototype.clearCurrEraser = function(){
    		var self = this;
    		if(self.eraserShape){
    			self.zr.remove(self.eraserShape);
                self.shapeGroup.remove(self.eraserShape);
    			self.eraserShape = null;
    		}
    	}

    	/**
    	 * @desc 注释设置颜色
    	 * @param {String} value - 颜色，采用rgb和rgba格式
    	 *
    	 * @example
    	 * annotation.setColor('rgba(255,0,0,1');
    	 */
    	Annotation.prototype.setColor = function(color) {
    		this.color = color;
    		if(this.fillColor != 'none'){
    			this.fillColor = color;
    		}
    	}

    	/**
    	 * @desc 注释设置颜色透明度
    	 * @param {String} value - 颜色，采用rgb和rgba格式
    	 *
    	 * @example
    	 * annotation.setColor('rgba(255,0,0,1');
    	 */
    	Annotation.prototype.setColorOpacity = function(opacity) {

    		var arr = this.color.split(',');
    		arr[arr.length - 1] = opacity + ')';
    		var color = arr.join(',');

    		console.log(color);

    		this.color = color;
    		if(this.fillColor != 'none'){
    			this.fillColor = color;
    		}
    	}

    	/**
    	 * @desc 注释设置线条宽度
    	 * @param {int} value - 线条宽度
    	 *
    	 * @example
    	 * annotation.setLineWidth(1);
    	 */
    	Annotation.prototype.setLineWidth = function(lineWidth) {
    		this.lineWidth = parseInt(lineWidth);
    	}

    	/**
    	 * @desc 注释设置箭头宽度
    	 * @param {int} value - 箭头宽度
    	 *
    	 * @example
    	 * annotation.setArrowLength(10);
    	 */
    	Annotation.prototype.setArrowLength = function(value) {
    		this.arrowLength = parseInt(value);
    	}

    	/**
    	 * @desc 注释设置箭头类别
    	 * @param {arrowTypeEnum} value - 箭头类别，枚举型
    	 *
    	 * @example
    	 * annotation.setArrowType(arrowTypeEnum.double);
    	 */
    	Annotation.prototype.setArrowType = function(value) {
    		this.arrowtype = parseInt(value);
    	}

    	/**
    	 * @desc 下载白板，带批注和背景
    	 * @example
    	 * annotation.download();
    	 */
    	Annotation.prototype.download = function() {
    		if(this.renderBackground == null && this.annoDiv == null){
                return;
            }

    		var backgroundCanvas = document.createElement('canvas');
            backgroundCanvas.width = this.renderDiv.width;
            backgroundCanvas.height = this.renderDiv.height;
            var backgroundCtx = backgroundCanvas.getContext("2d");
            if(this.renderBackground){
                backgroundCtx.drawImage(this.renderBackground, 0, 0);
            }
            backgroundCtx.drawImage(this.renderDiv, 0, 0);

    		downloadimage(backgroundCanvas);

    		function downloadimage(canvas){
    			// 图片导出为 png 格式
    			var type = 'png';
    			// 返回一个包含JPG图片的<img>元素
    			var img_png_src = canvas.toDataURL("image/png");  //将画板保存为图片格式的函数
    			// 加工image data，替换mime type
    			imgData = img_png_src.replace(_fixType(type),'image/octet-stream');
    			// 下载后的问题名
    			var filename = '个人画板_' + (new Date()).getTime() + '.' + type;
    			// download
    			saveFile(imgData,filename);
    		}

    		/**
    		* 在本地进行文件保存
    		* @param  {String} data     要保存到本地的图片数据
    		* @param  {String} filename 文件名
    		*/
    		function saveFile(data, filename){
    		    var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
    		    save_link.href = data;
    		    save_link.download = filename;

    		    var event = document.createEvent('MouseEvents');
    		    event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
    		    save_link.dispatchEvent(event);
    		};

    		/**
    		* 获取mimeType
    		* @param  {String} type the old mime-type
    		* @return the new mime-type
    		*/
    		function _fixType(type) {
    		    type = type.toLowerCase().replace(/jpg/i, 'jpeg');
    		    var r = type.match(/png|jpeg|bmp|gif/)[0];
    		    return 'image/' + r;
    		};
    	}
    	/**
    	 * @desc 注释设置颜色填充类别
    	 * @param {fillTypeEnum} value - 颜色填充类别，枚举型
    	 *
    	 * @example
    	 * annotation.setFillColor(fillTypeEnum.full);
    	 */
    	Annotation.prototype.setFillColor = function(value) {
    		this.fillType = value;
    		if(value == fillTypeEnum.none){
    			this.fillColor = 'none';
    		} else{
    			this.fillColor = this.color;
    		}
    	}

    	/**
    	 * @desc 注释清除
    	 */
    	Annotation.prototype.clear = function() {
    		var self = this;
            var shapeArray = self.shapeArray;
            var displayList = self.zr.storage.getDisplayList();
            var groupChildren = self.shapeGroup.children();

            for(var i = shapeArray.length - 1; i >= 0; i--){
    			self.zr.remove(shapeArray[i].shape);

                for(var j = displayList.length - 1; j >= 0; j--){
                    if(displayList[j].id == shapeArray[i].shape.id){
                        self.zr.remove(displayList[j])
                    }
                }

                for(var k = groupChildren.length - 1; k >= 0; k--){
                    if(groupChildren[k].id == shapeArray[i].shape.id){
                        self.shapeGroup.remove(groupChildren[k])
                    }
                }
    		}

    		self.shapeArray = [];
    //		self.currentIndex = -1;
            self.undoArray = [];
            self.redoArray = [];

    		self.roomHandle.sendRemoveAnnotation(self.boardId,shapeTypeEnum.clear,"")
    	}

        /**
    	 * @desc 注释撤销上一步
    	 */
    	Annotation.prototype.undo = function() {
    		var self = this;

    		if(self.undoArray.length < 1){
    			return;
    		}

    		var undoObj = self.undoArray.pop();
    		self.undoShape(undoObj);

    	}

    	/**
    	 * @desc 执行撤销批注对象
    	 */
    	Annotation.prototype.undoShape = function(undoObj) {
    		var self = this;
    		switch (undoObj.type) {
    			case 'delete':
                    self.shapeGroup.add(undoObj.shapeObj.shape);
    				// 添加到shapeArray中
    				self.shapeArray.push(undoObj.shapeObj);
    				self.roomHandle.sendAddAnnotation(self.boardId, undoObj.shapeObj.shape, undoObj.shapeObj.shapeType, undoObj.shapeObj.color, undoObj.shapeObj.lineWidth, undoObj.shapeObj.arrowtype, undoObj.shapeObj.fillType);
                    self.redoArray.push(undoObj);
    				break;
    			case 'add':
    				self.zr.remove(undoObj.shapeObj.shape);
                    self.shapeGroup.remove(undoObj.shapeObj.shape);
    				// 从shapeArrry中查找并删除
    				deleteFromShapeArray(undoObj.shapeObj.shape.id);
    				self.roomHandle.sendRemoveAnnotation(self.boardId,shapeTypeEnum.eraser,undoObj.shapeObj.shape.id);
                    self.redoArray.push(undoObj);
    				break;
    			default:
    				break;
    		}

    		/**
    		 * @desc 从批注数组中删除指定的批注
    		 * @param {String} shapeId 批注的id
    		 */
    		function deleteFromShapeArray(shapeId) {
    			if(self.shapeArray.length < 1){
    				return;
    			}

    			for(var i = 0; i < self.shapeArray.length; i++){
    				if(self.shapeArray[i].shape.id === shapeId){
    					self.shapeArray.splice(i, 1);
    				}
    			}
    		}
    	}

    	/**
    	 * @desc 注释重做下一步
    	 */
    	Annotation.prototype.redo = function() {

    		var self = this;
            // self.shapeGroup.add(obj.shapeObj.shape);
    		// self.shapeArray.push(obj.shapeObj);
    		// self.roomHandle.sendAddAnnotation(self.boardId, obj.shapeObj.shape, obj.shapeObj.shapeType, obj.shapeObj.color, obj.shapeObj.lineWidth, obj.shapeObj.arrowtype, obj.shapeObj.fillType);

            if(self.redoArray.length < 1){
    			return;
    		}

    		var redoObj = self.redoArray.pop();
    		self.redoShape(redoObj);
    	}

        /**
    	 * @desc 执行撤销批注对象
    	 */
    	Annotation.prototype.redoShape = function(redoObj) {
    		var self = this;
    		switch (redoObj.type) {
    			case 'delete':
                    self.zr.remove(redoObj.shapeObj.shape);
                    self.shapeGroup.remove(redoObj.shapeObj.shape);
                    // 从shapeArrry中查找并删除
                    deleteFromShapeArray(redoObj.shapeObj.shape.id);
                    self.roomHandle.sendRemoveAnnotation(self.boardId,shapeTypeEnum.eraser,redoObj.shapeObj.shape.id);
                    self.undoArray.push(redoObj);
    				break;
    			case 'add':
                    self.shapeGroup.add(redoObj.shapeObj.shape);
    				// 添加到shapeArray中
    				self.shapeArray.push(redoObj.shapeObj);
    				self.roomHandle.sendAddAnnotation(self.boardId, redoObj.shapeObj.shape, redoObj.shapeObj.shapeType, redoObj.shapeObj.color, redoObj.shapeObj.lineWidth, redoObj.shapeObj.arrowtype, redoObj.shapeObj.fillType);
                    self.undoArray.push(redoObj);
    				break;
    			default:
    				break;
    		}

    		/**
    		 * @desc 从批注数组中删除指定的批注
    		 * @param {String} shapeId 批注的id
    		 */
    		function deleteFromShapeArray(shapeId) {
    			if(self.shapeArray.length < 1){
    				return;
    			}

    			for(var i = 0; i < self.shapeArray.length; i++){
    				if(self.shapeArray[i].shape.id === shapeId){
    					self.shapeArray.splice(i, 1);
    				}
    			}
    		}
    	}

    	/**
    	 * @desc 设置激光笔
    	 */
    	Annotation.prototype.hlightPointInit = function(mouserUrl,width,height,intervalTime) {
    		var self = this;
    		self.hlightPointInfo.imgUrl = mouserUrl;
    		self.hlightPointInfo.width = parseInt(width)?parseInt(width):self.hlightPointInfo.width;
    		self.hlightPointInfo.height = parseInt(height)?parseInt(height):self.hlightPointInfo.height;
    		self.hlightPointInfo.intervalTime = parseInt(intervalTime)?parseInt(intervalTime):self.hlightPointInfo.intervalTime;
    	}
    	/**
    	 * @desc 清除激光笔
    	 */
    	Annotation.prototype.clearCurrHlightPoint = function() {
    		var self = this;
    		if(self.hlightPointShape){
    			self.roomHandle.sendRemoveAnnotation(self.boardId,shapeTypeEnum.eraser,self.hlightPointShape.id)
    			self.zr.remove(self.hlightPointShape);
                self.shapeGroup.remove(self.hlightPointShape);
    			self.hlightPointShape = null;
    		}
    		if(self.textTagShape){
    			self.roomHandle.sendRemoveAnnotation(self.boardId,shapeTypeEnum.eraser,self.textTagShape.id)
    			self.zr.remove(self.textTagShape);
                self.shapeGroup.remove(self.textTagShape);
    			self.textTagShape = null;
    		}
    	}

    	/**
    	 * @desc 设置激光笔
    	 */
    	Annotation.prototype.startHlightPoint = function(){
    		var self = this;
    		self.setShapeType(shapeTypeEnum.hlight_point)
    		var width = self.hlightPointInfo.width;
    		var height = self.hlightPointInfo.height;
    		self.hlightPointShape = new zrender.Image({
    			position: [-100, -100],
                scale: [1, 1],
                style: {
                    image: self.hlightPointInfo.imgUrl,
                    width: self.hlightPointInfo.width,
                    height: self.hlightPointInfo.height
                },
                draggable: true
    		})

            self.shapeGroup.add(self.hlightPointShape);
    		self.hlightPointShape.id = Math.uuid();
    		self.renderDiv.onmousemove = function(e){

    			if(self.isAllowEditImg){
    				return;
    			}

    			if(self.shapeType != shapeTypeEnum.hlight_point){
    				return;
    			}

                var tempPos = self.handleScaledXY(e.clientX - this.getBoundingClientRect().left, e.clientY - this.getBoundingClientRect().top);
    			x = tempPos.x;
    			y = tempPos.y;
    			var realX = x - width / 2;
    			var realY = y - height / 2;
    			self.hlightPointShape.attr('position',[realX ,realY]);
    			if(self.hlightPointInfo.isSend){
    				self.hlightPointInfo.isSend = false;

    				self.roomHandle.sendAddAnnotation(self.boardId, self.hlightPointShape, shapeTypeEnum.hlight_point, self.color, self.lineWidth, self.arrowtype, self.fillType);
    				setTimeout(function(){
    					self.hlightPointInfo.isSend = true;
    				}, self.hlightPointInfo.intervalTime)
    			}
    		}
    	}

    	Annotation.prototype.changeScreen = function(newWidth,newHeight){
    		var self = this;
    		if(self.zr && self.shapeArray.length > 0){
    			// self.zr.resize();
                self.boardReRenderWH(newWidth, newHeight);
    			for(var k in self.shapeArray){
    				var x = newWidth/self.screenSize.width;
    				var y = newHeight/self.screenSize.height;
    				console.log("===Annotation.changeScreen(),x:"+x+",y:"+y);
    				self.shapeArray[k].shape.animateTo({
    					scale: [x, y]
    				},function(){
    					console.log('changeScreen');
    				})
    			}
    		}
    		self.screenSize.width = newWidth;
    		self.screenSize.width = newHeight;
    	}

        /**
         * @desc 上传图片
         * @param {String} accessToken 认证串
         * @param {object} fileTarget input:file控件选择的图片文件对象
         * @returns {object} Promise
         */
    	Annotation.prototype.uploadImg = function(accessToken, fileTarget){
    		var deferred = when.defer();
    		var self = this;
    		var file = fileTarget.files[0];

    		if (!file){
    			var error = new Error(ErrorConstant.upload_filer_required);
    			deferred.reject(error);
    		}

    		// 最大上传文件大小
    		var MAX_SIZE = 15 * 1024 * 1024;

    		// 上传文件类型
    		var FILE_TYPES = ['image/jpeg', 'image/png'];

    		var fileSize = file.size,
                fileType = file.type;

    		//console.log("=====================file:",file);

    		log.info('===annotation.uploadImg(),fileSize:'+ fileSize+", fileType"+ fileType);

    		if (!FILE_TYPES.includes(fileType)) {
    			fileTarget.value = '';
    		    var error = new Error(ErrorConstant.upload_filer_fileType);
    			error.message = error.message+",Support jpeg/jpg/png only ";
    		    deferred.reject(error);

    		}else if(fileSize > MAX_SIZE) {
    		   fileTarget.value = '';
    		   var error = new Error(ErrorConstant.upload_filer_fileSize);
    		   error.message = error.message+",Within 15M only";
    		   deferred.reject(error);

    		}else {
    			var restServer = new RestServer();
                    restServer.uploadFile(accessToken, file).then(function(fileUrl){
                        fileTarget.value = '';
                        log.info("===annotation.uploadImg(),fileUrl:" + fileUrl);
                        var img = new Image();
                        img.src = fileUrl;
                        img.onload = function(){
                            var imgWidth = img.width;
                            var imgHeight = img.height;
                            log.info("===annotation.uploadImg(),img width:" + imgWidth+", height:"+ imgHeight);

                            self.drawImg(fileUrl,imgWidth, imgHeight);

                            img = null;
                            deferred.resolve();
                        }
                    }).otherwise(function(error){
                       console.info("===annotation.uploadImg(),error:",error);
                       deferred.reject(error);
                    });
    		}

    		return deferred.promise;
    	}

        // 本端绘制图片（不包括本端关闭白板后再重新打开白板后，重新渲染自己的图片不会走这里）
    	Annotation.prototype.drawImg = function(imgUrl,imgWidth, imgHeight){
    		log.info("===annotation.drawImg(),imgUrl:"+imgUrl+", imgWidth:" + imgWidth+", imgHeight:"+ imgHeight);

    		var MAX_WIDTH = 150;
    		var MAX_HEIGHT = 150;
    		var MAX_WH_RATIO = MAX_WIDTH / MAX_HEIGHT;

    	     var originWHRatio = imgWidth / imgHeight;
    	     var targetWidth = imgWidth;
    	     var targetHeight = imgHeight;

    	     if (imgWidth > MAX_WIDTH || imgHeight > MAX_HEIGHT) {
    			  if (originWHRatio > MAX_WH_RATIO) {
    				targetWidth = MAX_WIDTH;
    				targetHeight = Math.round(targetWidth / originWHRatio);
    			  } else {
    				targetHeight = MAX_HEIGHT;
    				targetWidth = Math.round(targetHeight * originWHRatio);
    			  }
    	    }
    		log.info("===annotation.drawImg(),targetWidth:"+targetWidth+", targetHeight:" + targetHeight);

    		var self = this;

            self.shapeType = shapeTypeEnum.img;

            var img = new zrender.Image({
    		    style: {
    				image:imgUrl,
    		        x: 0,
    		        y: 0,
    		        width: targetWidth,
    				height: targetHeight,
    				shadowColor: 'red',
    				shadowBlur: 5
    		    },
    			zlevel: self.imgZlevel, //zlevel 大的 Canvas 会放在 zlevel 小的 Canvas 的上面。
    			id: Math.uuid(),
                rotation: 0,
                originX: 0,
                originY: 0
    		});

            var shapeObj = {
                shape:img,
                shapeType:self.shapeType,
                color:self.color,
                lineWidth:self.lineWidth,
                arrowtype:self.arrowtype,
                fillType:self.fillType,
            }

            self.shapeArray.push(shapeObj);
            self.shapeGroup.add(img);
            self.undoArray.push({
                type: 'add',
                shapeObj: shapeObj
            })

    	    self.setAllowEditImg(true);
    	    img.attr('zlevel',++self.imgZlevel);
    	    self.currActiveImg = img;

    	    self.shapeGroup.eachChild(function(item){
    	    	if(item.type === 'image'){
                    if(item.id == self.currActiveImg.id){
                        item.attr('style',{shadowColor:'red',shadowBlur:5});
                    }else{
                        item.attr('style',{shadowColor:undefined,shadowBlur:undefined});
                    }
                }
    	    });

    		self.roomHandle.sendAddAnnotation(self.boardId, img, shapeTypeEnum.img, self.color, self.lineWidth, self.arrowtype, self.fillType);
    	}

    	/**
         * @desc 设置图片的编辑状态
         * @param {Boolean} isAllow 白板是否设置为图片模式，在此模式下画笔不生效，设置画笔时请关闭图片模式
         */
    	Annotation.prototype.setAllowEditImg = function(isAllow){
    		var self = this;
    		if(isAllow == undefined){
    		   	this.isAllowEditImg = !this.isAllowEditImg;
    		}else{
    			this.isAllowEditImg = isAllow;

    		}

            this.shapeGroup.eachChild(function(child){
                if(child.type && child.type !== 'image'){
                    child.attr('silent', self.isAllowEditImg)
                }
            })

    		if(!this.isAllowEditImg){
    			this.currActiveImg = null;
    		}else{
                this.setShapeType(shapeTypeEnum.img)
            }

    		this.shapeGroup.eachChild(function(item){
    		    if(item.type === 'image'){
                    if(!self.isAllowEditImg){
                        item.attr('style',{shadowColor:undefined,shadowBlur:undefined});
                    }
                }
    		})

            if(this.textInfo && this.shapeType === shapeTypeEnum.txt){
                this.textInfo.setTextEditEnable(!this.isAllowEditImg)
            }
    	}

    	Annotation.prototype.getAllowEditImg = function(){
    		return this.isAllowEditImg;
    	}

    	/**
         * @desc 缩放当前高亮的图片
         * @param {boolean} isEnlarge 是否放大，true为放大，false为缩小
         * @param {number} percentage 缩放比例，小数，例如0.1
         */
    	Annotation.prototype.scaleImg = function(isEnlarge, percentage){
    		var self = this;
    		if(!this.isAllowEditImg){
    			return;
    		}

    		if(!this.currActiveImg){
    			return;
    		}

    		var x = this.currActiveImg.scale[0];
    		var y = this.currActiveImg.scale[1];
    		if(isEnlarge){
    			x = x + percentage;
    			y = y + percentage;
    		}else{
                // 防止x或者y为0后，继续缩小变为负数，导致放大和缩小效果相反了
                if(x - percentage <= 0.1 || y - percentage <= 0.1){
                    return;
                }
    			x = x - percentage;
    			y = y - percentage;
    		}
    		//设置缩放大小
    		this.currActiveImg.attr('scale',[x,y]);

    		//设置缩放中心
    		this.currActiveImg.attr('origin',[this.currActiveImg.style.width/2, this.currActiveImg.style.height/2]);

            if(isEnlarge){
    			this.currActiveImg.customPositionX = this.currActiveImg.customPositionX - this.currActiveImg.style.width/2 * percentage;
    			this.currActiveImg.customPositionY = this.currActiveImg.customPositionY - this.currActiveImg.style.height/2 * percentage;
    		}else {
    			this.currActiveImg.customPositionX = this.currActiveImg.customPositionX + this.currActiveImg.style.width/2 * percentage;
    			this.currActiveImg.customPositionY = this.currActiveImg.customPositionY + this.currActiveImg.style.height/2 * percentage;
    		}

    		self.roomHandle.sendUpdateAnnotation(this.boardId, this.currActiveImg, shapeTypeEnum.img);
    	}

    	/**
         * @desc 顺时针旋转当前高亮的图片
         */
    	Annotation.prototype.rotateImg = function(){
    		var self = this;
    		if(!this.isAllowEditImg){
    			return;
    		}

    		if(!this.currActiveImg){
    			return;
    		}

    		//设置旋转角度
    		var rotation = this.currActiveImg.rotation - Math.PI/2;
    		this.currActiveImg.attr('rotation',[rotation]);

    		//设置旋转中心
    		this.currActiveImg.attr('origin',[this.currActiveImg.style.width/2, this.currActiveImg.style.height/2]);

    		self.roomHandle.sendUpdateAnnotation(this.boardId, this.currActiveImg, shapeTypeEnum.img);
    	}

    	/**
         * @desc 删除当前高亮的图片
         */
    	Annotation.prototype.delImg = function(){
    		if(!this.isAllowEditImg){
    			return;
    		}

    		if(!this.currActiveImg){
    			return;
    		}

    		this.roomHandle.sendRemoveAnnotation(this.boardId, shapeTypeEnum.img, this.currActiveImg.id);
    		this.shapeGroup.remove(this.currActiveImg);

            for(var i = 0; i < this.shapeArray.length; i++){
                var tempShapeObj = this.shapeArray[i];
                this.undoArray.push({
                    type: 'delete',
                    shapeObj: tempShapeObj
                })
                if(tempShapeObj.shape && (tempShapeObj.shape.id == this.currActiveImg.id)){
                    this.shapeArray.splice(i, 1);
                }
            }

            this.currActiveImg = null;
    	}

        Annotation.prototype.handleScaledXY = function(x, y) {
            var pos = {
                x: x,
                y: y
            }

            if(this.positionInfo.scaleRatioX == 1 && this.positionInfo.scaleRatioX == 1){
                return pos
            }

            if(this.positionInfo.scaleRatioX > 1){
                pos.x /= this.positionInfo.scaleRatioX
            }else if(this.positionInfo.scaleRatioX < 1){
                pos.x *= this.positionInfo.scaleRatioXR
            }

            if(this.positionInfo.scaleRatioY > 1){
                pos.y /= this.positionInfo.scaleRatioY
            }else if(this.positionInfo.scaleRatioY < 1){
                pos.y *= this.positionInfo.scaleRatioYR
            }

            return pos
        }

        /**
         * @description 根据宽高重新渲染画布及画布内的所有批注
         * @param {int} width 宽
         * @param {int} height 高
         */
        Annotation.prototype.boardReRenderWH = function (width, height) {

            /**
             * 在执行缩放时，每次都还原到初始大小再进行缩放，每次都在最开始的宽高进行缩放
             * 防止：先放大再缩小后点击位置偏移
             */
            if(width !== this.positionInfo.originalWidth || height !== this.positionInfo.originalHeight){
                console.log('===scale on based position before scale')
                this.boardReRenderWH(this.positionInfo.originalWidth, this.positionInfo.originalHeight)
            }

            var currWidth = this.zr.getWidth();
            var currHeight = this.zr.getHeight();

            log.debug('===boardReRenderWH, width: '+ width + 'height: ' + height + ' currWidth: ' + currWidth + ' currHeight: ' + currHeight)

            var tempInfo = {
                scaleWidth: width,
                scaleHeight: height,
                zrWidth: currWidth,
                zrHeight: currHeight,
                scaleRatioX: width / currWidth,
                scaleRatioY: height / currHeight,
                scaleRatioXR: currWidth / width,
                scaleRatioYR: currHeight / height,
            }

            if(width === this.positionInfo.originalWidth && height === this.positionInfo.originalHeight){
                tempInfo.scaleRatioXR = 1;
                tempInfo.scaleRatioYR = 1;
            }

            Object.assign(this.positionInfo, tempInfo)

            if(this.positionInfo.scaleRatioX == 1 && this.positionInfo.scaleRatioY==1){
                return;
            }

            // 以当前shapeGroup的缩放为基础更新缩放
            this.positionInfo.scaleRatioX *= this.shapeGroup.scaleX;
            this.positionInfo.scaleRatioY *= this.shapeGroup.scaleY;

            this.zr.resize({
                width: width,
                height: height
            });

            this.zr.dom.style.width = width +'px';
            this.zr.dom.style.height = height +'px';

            if(this.renderBackground){
                this.renderBackground.width = width;
                this.renderBackground.height = height;
                this.renderBackground.style.width = width +'px';
                this.renderBackground.style.height = height +'px';
                if(this.board.backgroundColor){
                    this.updateBackgroundColor(this.board.backgroundColor);
                }
                if(this.board.backgroundImage){
                    this.updateBackgroundImage(this.board.backgroundImage);
                }
            }

            this.shapeGroup.attr({
                scaleX: this.positionInfo.scaleRatioX,
                scaleY: this.positionInfo.scaleRatioY,
                originX: 0,
                originY: 0
            })

            log.debug('===Annotation boardReRenderWH positionInfo: ', this.positionInfo);
        }

        /**
         * @description 开始输入文字
         * @param {object} themeConfig 主题样式，用于自定义文字输入框确认和取消按钮，例如：{confirm: {color: '#000000', text: '确定'}, cancel: {color: '#001100', text: '取消'}}
         */
        Annotation.prototype.startTextInput = function(themeConfig) {
            var self = this;
            self.setShapeType(shapeTypeEnum.txt)
            if(this.isAllowEditImg){
                // 当前为图片编辑模式或者已经初始化过textInfo了，就跳过
                return
            }
            if(!this.isAllowEditImg && this.textInfo != null && this.textInfo.currTextElParentNode != null){
                this.textInfo.setTextEditEnable(true);
                return;
            }
            this.textInfo = new TextInfo(themeConfig, this);
            this.setShapeType(shapeTypeEnum.txt);
            // 判断父元素是否是canvas，如果是canvas则将工具条添加到canvas的兄弟节点
            this.textInfo.setParentElement(this.annoDiv);
            this.textInfo.setCanvasParentElement(this.annoDiv.tagName === 'CANVAS' ? this.annoDiv.parentElement : this.annoDiv);
            this.textInfo.initToolBar();
            this.textInfo.setColorChoosePanelDisplay(false);
            this.textInfo.setTextEditEnable(true);
            this.textInfo.setZrender(self.zr);
            this.textInfo.textEventEmitter.on('confirm', function(textInfo){
                renderByZrender(textInfo)
            })
            log.debug('===Annotation.startTextInput success');

            function renderByZrender(textInfo) {
                var newPos = self.handleScaledXY(textInfo.position[0], textInfo.position[1]);
                var textShape = new zrender.Text({
                    style: {
                        text: textInfo.content,
                        fontSize: textInfo.fontSize,
                        fontStyle: textInfo.fontStyle,
                        fontWeight: textInfo.fontWeight,
                        fill: textInfo.fontColor || '#000000' // 添加默认颜色
                    },
                    zlevel: self.normalZlevel,
                    position: [newPos.x, newPos.y],
                    origin: [newPos.x, newPos.y - 50],
                    onmouseover: mouseOverForEraser
                })
                textShape.id = Math.uuid();

                self.shapeGroup.add(textShape);

                var shapeObj = {
                    shape:textShape,
                    shapeType:self.shapeType,
                    color:self.color,
                    lineWidth:self.lineWidth,
                    arrowtype:self.arrowtype,
                    fillType:self.fillType,
                }
                self.shapeArray.push(shapeObj);
                self.roomHandle.sendAddAnnotation(self.boardId, textShape, shapeTypeEnum.txt, self.color, self.lineWidth, self.arrowtype, self.fillType);
            }

            function mouseOverForEraser(params) {
                if(self.shapeType == shapeTypeEnum.eraser && self.isEraser){
                    for(var k in self.shapeArray){
                        if(self.shapeArray[k].shape.id == params.target.parent.id){
                            self.zr.remove(params.target.parent)
                            self.shapeGroup.remove(params.target.parent)
                            self.roomHandle.sendRemoveAnnotation(self.boardId,self.shapeType,self.shapeArray[k].shape.id)
                            self.undoArray.push({
                                type: 'delete',
                                shapeObj: self.shapeArray[k]
                            })
                            self.shapeArray.splice(k,1);
                        }
                    }
                }
            }
        }
    	return Annotation;
    });