如何缩放GraphicsPathCommand数据?

时间:2017-02-02 19:43:11

标签: actionscript-3

上下文:对于传统的Flex / Actionscript绘图应用,我需要添加简单符号的缩放。该应用程序使用Graffiti lib进行绘制,并使用GraphicsPathCommands lib将生成的形状数据存储为Degrafa序列化为XML以进行保存和重新加载。我需要让用户能够缩放这些图形,然后获得可以序列化的更新路径数据。符号很简单,但比简单几何更复杂。例如:

enter image description here

问题:我将此符号的SVG数据转换为Actionscript GraphicsPathCommands并且能够绘制它,当然翻译很简单 - 但我不是我知道如何缩放它,给定用户在应用程序中拖出一个矩形矩形定义的边界框。

有没有人知道转换命令数据的Actionscript方法,或者我可以移植到Actionscript的缩放SVG的Javascript片段?

作为参考,下面是一个用于绘制星形的动作脚本GraphicsPathCommands的示例。

public function DrawPathExample()
    {
        var star_commands:Vector.<int> = new Vector.<int>(5, true);

        star_commands[0] = GraphicsPathCommand.MOVE_TO;
        star_commands[1] = GraphicsPathCommand.LINE_TO;
        star_commands[2] = GraphicsPathCommand.LINE_TO;
        star_commands[3] = GraphicsPathCommand.LINE_TO;
        star_commands[4] = GraphicsPathCommand.LINE_TO;

        var star_coord:Vector.<Number> = new Vector.<Number>(10, true);
        star_coord[0] = 66; //x
        star_coord[1] = 10; //y 
        star_coord[2] = 23; 
        star_coord[3] = 127; 
        star_coord[4] = 122; 
        star_coord[5] = 50; 
        star_coord[6] = 10; 
        star_coord[7] = 49; 
        star_coord[8] = 109; 
        star_coord[9] = 127;

        graphics.beginFill(0x003366);
        graphics.drawPath(star_commands, star_coord);
    }

解决方案

下面是交互式缩放GraphicsPathCommand数据的完整解决方案。路径数据来自通过此SVGParser的SVG。它以graphics.lineTo(28.4,16.8);的形式生成路径绘制命令。一些实用程序函数将数据与命令分开并将它们存储在Vectors中,以便可以序列化数据。我不需要使用任意SWG,因此我只是对数据进行了硬编码。

enter image description here

package classes
{
    import flash.display.GraphicsPathCommand;
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Point;
    import flash.geom.Rectangle;

    public class DrawSVG extends Sprite
    {   
        private var startPt:Point = new Point();
        private var selectRect:Rectangle = new Rectangle();
        private var viewBox:Rectangle = new Rectangle();

        protected var commands:Vector.<int> = new Vector.<int>();
        protected var drawingData:Vector.<Number> = new Vector.<Number>();
        protected var sourceDrawingData:Vector.<Number> = new Vector.<Number>();

        public function DrawSVG()
        {
            super();
            this.addEventListener(Event.ADDED_TO_STAGE, setup);
            setupWomanData();
        }

        private function setup(event:Event):void
        {
            stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
        }

        private function onMouseDown(event:MouseEvent):void
        {
            stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);

            this.graphics.clear();

            // offset so graphic draws centered on click point
            startPt = new Point(event.stageX - (viewBox.width /2), event.stageY - (viewBox.height /2));
            selectRect = new Rectangle(startPt.x, startPt.y, viewBox.width, viewBox.height);

            var kx:Number = selectRect.width / (viewBox.width);
            var ky:Number = selectRect.height / (viewBox.height);
            var scaleFactor:Number = kx < ky ? kx : ky;

            drawSymbol(scaleFactor);

            this.graphics.lineStyle(1, 0x000000);
            this.graphics.drawRect(selectRect.x, selectRect.y, selectRect.width, selectRect.height);
        }

        private function onMouseMove(event:MouseEvent):void
        {
            selectRect.width = Math.max(viewBox.width, Math.abs(event.stageX - startPt.x));
            selectRect.height = Math.max(viewBox.height, Math.abs(event.stageY - startPt.y));

            var kx:Number = selectRect.width / (viewBox.width);
            var ky:Number = selectRect.height / (viewBox.height);
            var scaleFactor:Number = kx < ky ? kx : ky;

            this.graphics.clear();

            drawSymbol(scaleFactor);

            this.graphics.lineStyle(1, 0x000000);
            this.graphics.drawRect(selectRect.x, selectRect.y, viewBox.width * scaleFactor, viewBox.height * scaleFactor);
        }

        private function onMouseUp(event:MouseEvent):void
        {
            stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
            stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
            this.graphics.clear();
            createSprite(commands, drawingData);
        }

        private function drawSymbol(toScale:Number):void
        {
            drawingData.length = 0;
            for (var i:int = 0; i < sourceDrawingData.length; i++) {
                drawingData[i] = Math.max(sourceDrawingData[i], sourceDrawingData[i] * toScale);
                drawingData[i] += i % 2 == 0 ? startPt.x  : startPt.y ;
            }
            this.graphics.clear();
            this.graphics.lineStyle();
            this.graphics.beginFill(0xff0000);
            this.graphics.drawPath(commands, drawingData);
            this.graphics.endFill();
        }

        private function createSprite(command:Vector.<int>, coord:Vector.<Number>):Shape{
            var s:Shape = new Shape();
            addChild(s);
            s.graphics.beginFill(0xff);
            s.graphics.drawPath(command, coord);
            s.graphics.endFill();
            return s;
        }

        private function setupWomanData():void
        {
            commands = new Vector.<int>();
            drawingData = new Vector.<Number>();
            viewBox= new Rectangle(0, 0, 24.629, 52.336);

            addMoveToCmd(12.31,10.3);
            addCurveToCmd(13.37,10.3,14.3,9.89);
            addCurveToCmd(15.24,9.48,15.94,8.78);
            addCurveToCmd(16.64,8.08,17.05,7.14);
            addCurveToCmd(17.46,6.2,17.46,5.15);
            addCurveToCmd(17.46,4.1,17.05,3.16);
            addCurveToCmd(16.64,2.23,15.94,1.52);
            addCurveToCmd(15.24,0.82,14.3,0.41);
            addCurveToCmd(13.37,0,12.31,0);
            addCurveToCmd(11.26,0,10.33,0.41);
            addCurveToCmd(9.39,0.82,8.69,1.52);
            addCurveToCmd(7.98,2.23,7.57,3.16);
            addCurveToCmd(7.16,4.1,7.16,5.15);
            addCurveToCmd(7.16,6.2,7.57,7.14);
            addCurveToCmd(7.98,8.08,8.69,8.78);
            addCurveToCmd(9.39,9.48,10.33,9.89);
            addCurveToCmd(11.26,10.3,12.31,10.3);
            addLineToCmd(12.314,10.304);

            addMoveToCmd(24.6,26.36);
            addLineToCmd(20.7,12.77);
            addCurveToCmd(20.62,12.3,20.39,11.91);
            addCurveToCmd(20.15,11.51,19.81,11.23);
            addCurveToCmd(19.47,10.94,19.04,10.78);
            addCurveToCmd(18.61,10.62,18.14,10.62);
            addLineToCmd(6.49,10.62);
            addCurveToCmd(6.02,10.62,5.59,10.78);
            addCurveToCmd(5.16,10.94,4.82,11.23);
            addCurveToCmd(4.48,11.51,4.24,11.91);
            addCurveToCmd(4.01,12.3,3.93,12.77);
            addLineToCmd(0.03,26.36);
            addCurveToCmd(0.01,26.4,0.01,26.45);
            addCurveToCmd(-0.01,26.5,-0.01,26.55);
            addCurveToCmd(0.01,26.6,0.01,26.65);
            addCurveToCmd(0.02,26.69,0.03,26.74);
            addCurveToCmd(-0.15,27.95,0.55,28.69);
            addCurveToCmd(1.25,29.44,2.2,29.6);
            addCurveToCmd(3.15,29.77,4.05,29.3);
            addCurveToCmd(4.95,28.84,5.17,27.63);
            addLineToCmd(6.85,21.37);
            addLineToCmd(4.07,34.88);
            addCurveToCmd(3.81,35.51,3.91,36.15);
            addCurveToCmd(4,36.78,4.35,37.3);
            addCurveToCmd(4.7,37.81,5.26,38.13);
            addCurveToCmd(5.81,38.45,6.49,38.45);
            addLineToCmd(6.78,38.45);
            addLineToCmd(6.78,49.72);
            addCurveToCmd(6.78,50.99,7.59,51.62);
            addCurveToCmd(8.41,52.25,9.39,52.25);
            addCurveToCmd(10.37,52.25,11.19,51.62);
            addCurveToCmd(12,50.99,12,49.72);
            addLineToCmd(12,38.45);
            addLineToCmd(12.63,38.45);
            addLineToCmd(12.63,49.72);
            addCurveToCmd(12.63,50.99,13.44,51.62);
            addCurveToCmd(14.26,52.25,15.24,52.25);
            addCurveToCmd(16.22,52.25,17.04,51.62);
            addCurveToCmd(17.85,50.99,17.85,49.72);
            addLineToCmd(17.85,38.45);
            addLineToCmd(18.14,38.45);
            addCurveToCmd(18.82,38.45,19.38,38.13);
            addCurveToCmd(19.93,37.81,20.28,37.3);
            addCurveToCmd(20.63,36.78,20.72,36.14);
            addCurveToCmd(20.81,35.51,20.56,34.87);
            addLineToCmd(17.78,21.37);
            addLineToCmd(19.45,27.58);
            addCurveToCmd(19.67,28.79,20.57,29.27);
            addCurveToCmd(21.47,29.75,22.43,29.6);
            addCurveToCmd(23.38,29.45,24.08,28.7);
            addCurveToCmd(24.78,27.96,24.6,26.74);
            addCurveToCmd(24.61,26.69,24.62,26.65);
            addCurveToCmd(24.63,26.6,24.63,26.55);
            addCurveToCmd(24.63,26.5,24.62,26.45);
            addCurveToCmd(24.62,26.4,24.6,26.36);
            addLineToCmd(24.601,26.356);
        }


        protected function addCurveToCmd(p1:Number, p2:Number, p3:Number, p4:Number):void
        {
            commands.push(GraphicsPathCommand.CURVE_TO);
            sourceDrawingData.push(p1);
            sourceDrawingData.push(p2);
            sourceDrawingData.push(p3);
            sourceDrawingData.push(p4);
        }

        protected function addMoveToCmd(p1:Number, p2:Number):void
        {
            commands.push(GraphicsPathCommand.MOVE_TO);
            sourceDrawingData.push(p1);
            sourceDrawingData.push(p2);
        }

        protected function addLineToCmd(p1:Number, p2:Number):void
        {
            commands.push(GraphicsPathCommand.LINE_TO);
            sourceDrawingData.push(p1);
            sourceDrawingData.push(p2);
        }
    }
}

1 个答案:

答案 0 :(得分:1)

似乎有一种非常简单的方法可以做到这一点。看起来唯一要缩放的是坐标本身,因此您可以只应用比例因子 根据您的示例:

    public function ASEntryPoint() {
        var star_commands:Vector.<int> = new Vector.<int>(5, true);

        star_commands[0] = GraphicsPathCommand.MOVE_TO;
        star_commands[1] = GraphicsPathCommand.LINE_TO;
        star_commands[2] = GraphicsPathCommand.LINE_TO;
        star_commands[3] = GraphicsPathCommand.LINE_TO;
        star_commands[4] = GraphicsPathCommand.LINE_TO;

        var star_coord:Vector.<Number> = new Vector.<Number>(10, true);
        star_coord[0] = 66; //x
        star_coord[1] = 10; //y 
        star_coord[2] = 23; 
        star_coord[3] = 127; 
        star_coord[4] = 122; 
        star_coord[5] = 50; 
        star_coord[6] = 10; 
        star_coord[7] = 49; 
        star_coord[8] = 109; 
        star_coord[9] = 127;

        //reference shape to detect initial size
        var s:Shape = shapeInRect(star_commands, star_coord);
        var bounds:Rectangle = s.getBounds(s);
        s.graphics.lineStyle(1);
        s.graphics.drawRect(bounds.x, bounds.y, bounds.width, bounds.height);
        addChild(s);

        //fit to target
        var targetSize:Rectangle = new Rectangle(150, 100, 75, 60);
        //detect lesser factor - assuming you need to preserve proportions
        var kx:Number = targetSize.width / (bounds.width);
        var ky:Number = targetSize.height / (bounds.height);
        var toUse:Number = kx < ky ? kx : ky;

        //apply to coords
        for (var i:int = 0; i < star_coord.length; i++) {
            //size
            star_coord[i] *= toUse;
            //fix initial offset
            star_coord[i] -= i % 2 == 0 ? bounds.x * toUse : bounds.y * toUse;
        }
        //draw
        addChild(shapeInRect(star_commands, star_coord, targetSize));
    }

    private function shapeInRect(command:Vector.<int>, coord:Vector.<Number>, rect:Rectangle = null):Shape{
        var s:Shape = new Shape();
        addChild(s);
        s.graphics.beginFill(0x003366);
        s.graphics.drawPath(command, coord);
        s.graphics.endFill();
        if (rect){
            s.graphics.lineStyle(1);
            s.graphics.drawRect(0, 0, rect.width, rect.height);
            s.x = rect.x;
            s.y = rect.y;
        }
        return s;
    }