/* * PS 钢笔工具 控制逻辑 */ define( function ( require, exports, module ) { // 资源引入 var Bezier = require( "graphic/bezier" ), Color = require( "graphic/color" ), Pen = require( "graphic/pen" ), Utils = require( "core/utils" ), Vector = require( "graphic/vector" ), // 引入可绘制的点集合 PointGroup = require( "../ps-pen/demo.pointgroup" ), BezierPoint = require( "graphic/bezierpoint" ); function Controller ( paper ) { this.paper = paper || null; this.bezier = null; this.bezierPoints = null; this.pointGroup = null; this.drawState = false; // 记录当前是否处于更新状态 this.modifyState = false; // 记录更新状态的持久信息 this._modifyStatus = null; // 允许重新拖动编辑的 this.editable = false; } Utils.extend( Controller.prototype, { takeover: function ( paper ) { paper && ( this.paper = paper ); initListener( this ); }, enableDraw: function () { this.drawState = true; }, disableDraw: function () { this.drawState = false; }, enableModify: function () { this.modifyState = true; }, disableModify: function () { this.modifyState = false; }, // 设置更新状态 setModifyStatus: function ( status ) { this._modifyStatus = status; }, clearModifySatus: function () { this._modifyStatus = null; }, getModifyStatus: function () { return this._modifyStatus; }, enableEdit: function () { this.editable = true; }, disableEdit: function () { this.editable = false; }, setBezier: function ( bezier ) { this.bezier = bezier; this.bezierPoints = []; return this; }, getBezier: function () { return this.bezier; }, setPointGroup: function ( pointGroup ) { this.pointGroup = pointGroup; return this; }, getPointGroup: function () { return this.pointGroup; }, addPoint: function ( point ) { this.bezierPoints && this.bezierPoints.push( point ); return this; }, getPoints: function () { return this.bezierPoints; } } ); return Controller; // 私有方法实现 // 初始化交互事件监听器 function initListener ( controller ) { // 记录是否允许所有事件的监听 var isBegin = false, // 记录是否需要更新曲线 isUpdateable = false, paper = controller.paper, currentBezier = null, currentPointGroup = null; paper.on( "mousedown", function ( e ) { var point = null; e.preventDefault(); if ( !controller.drawState ) { return; } // 切换监听状态 if ( !isBegin ) { isBegin = true; currentBezier = createBezier( paper ); currentPointGroup = createPointGroup( paper ); listenPointGroup( currentPointGroup, controller ); //设置当前controller处理的贝塞尔曲线 controller.setBezier( currentBezier ); controller.setPointGroup( currentPointGroup ); } isUpdateable = false; // 获取当前鼠标点击在用户坐标系上的映射点 point = e.getPosition(); updateBezier( controller, point ); } ); // 绘制时 更新控制点 paper.on( "mousemove", function ( e ) { var point = null, bezierPoint = null; e.preventDefault(); if ( !controller.drawState ) { return; } if ( !isBegin || isUpdateable ) { return; } point = e.getPosition(); currentBezier.getLastPoint().setForward( point.x, point.y ); currentPointGroup.getLastPoint().setForward( point.x, point.y ); } ); // 编辑时拖动更新 paper.on( "mousemove", function ( e ) { var mousePoint = null, currentPoint = null, pointIndex = -1; e.preventDefault(); // 不可编辑 if ( !controller.editable ) { return; } mousePoint = e.getPosition(); pointIndex = controller._modifyStatus.pointIndex; currentPoint = currentPointGroup.getPointByIndex( pointIndex ); switch ( controller._modifyStatus.pointType ) { case PointGroup.TYPE_FORWARD: currentPoint.setForward( mousePoint.x, mousePoint.y ); currentBezier.getPoint( pointIndex ).setForward( mousePoint.x, mousePoint.y ); break; case PointGroup.TYPE_BACKWARD: currentPoint.setBackward( mousePoint.x, mousePoint.y ); currentBezier.getPoint( pointIndex ).setBackward( mousePoint.x, mousePoint.y ); break; case PointGroup.TYPE_VERTEX: currentPoint.moveTo( mousePoint.x, mousePoint.y ); currentBezier.getPoint( pointIndex ).moveTo( mousePoint.x, mousePoint.y ); break; } } ); paper.on( "mouseup", function () { if ( controller.drawState ) { isUpdateable = isBegin; } else if ( controller.modifyState ) { controller.disableEdit(); // 清空状态 controller.clearModifySatus(); } } ); } // 画贝塞尔曲线 function updateBezier ( controller, point ) { var bezierPoint = new BezierPoint( point.x, point.y, true ); //添加可绘制控制点 controller.getPointGroup().addPoint( bezierPoint.clone() ); //记录贝塞尔的控制点 controller.addPoint( bezierPoint ); //更新贝塞尔曲线的点 controller.getBezier().setPoints( controller.getPoints() ); } // 创建一个新的贝塞尔 function createBezier ( paper ) { var bezier = new Bezier(); bezier.stroke( new Pen( new Color( "black" ) ).setWidth( 100 ) ); paper.addShape( bezier ); return bezier; } function createPointGroup ( paper ) { var pointGroup = new PointGroup(); paper.addShape( pointGroup ); return pointGroup; } // 监听点上的事件 function listenPointGroup ( pointGroup, controller ) { pointGroup.on( "pointmousedown", function ( e ) { var currentPoint = null, currentType = null, index = -1, vertexWidth = 0; // 非modify状态, 不处理 if ( !controller.modifyState ) { return; } index = e.targetPointIndex; currentType = e.targetPointType; currentPoint = pointGroup.getPointByIndex( index ); // 获取到当前顶点的宽度 vertexWidth = pointGroup.getVertexWidth(); // 检查当前点击的点的控制点是否和顶点重叠 // 如果重叠了, 则认为点击是发生在forward的控制点上的 if ( currentType === PointGroup.TYPE_VERTEX ) { //更新点类型 switch ( checkOverlapping( currentPoint, vertexWidth ) ) { case 1: currentType = PointGroup.TYPE_FORWARD; break; case 2: currentType = PointGroup.TYPE_BACKWARD break; } } // 运行更新 controller.enableEdit(); controller.setModifyStatus( { pointType: currentType, pointIndex: index } ); //更新当前的点 this.selectPoint( index ); } ); } // 工具方法, 检测贝塞尔曲线上的点的控制点和顶点是否重叠在一起 // 参数distance控制了点之间的最小距离, 如果不大于该距离, 则认为是重叠的 // 返回值有: 0: 无重叠, 1: forward重叠, 2: backward重叠 function checkOverlapping ( bezierPoint, distance ) { var forward = bezierPoint.getForward(), backward = bezierPoint.getBackward(), vertex = bezierPoint.getVertex(); if ( Vector.fromPoints( forward, vertex ).length() <= distance ) { // forward重叠 return 1; } else if ( Vector.fromPoints( backward, vertex ).length() <= distance ) { // backward重叠 return 2; } // 无重叠 return 0; } } );