Flex: рисование соединительной линии между фигурами - PullRequest
2 голосов
/ 24 марта 2010

Я создаю инструмент построения диаграмм с помощью Adobe Flex 3. Я собираюсь реализовать соединительные линии и у меня возник вопрос.

Представьте, что у меня на холсте 2 квадрата в случайных местах.Мне нужно нарисовать стрелку соединительной линии между ними.Мне нужно, чтобы он был направлен к центру целевого квадрата, но заканчивался на его границе. альтернативный текст http://i44.tinypic.com/25tw4n4.jpg

Как узнать точные точки, между которыми нужно провести линию?

Спасибо

Ответы [ 3 ]

5 голосов
/ 24 марта 2010

Вот пример того, что вы хотите.

package
{
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.ui.Mouse;

    /**
     * Sample class to draw squares and arrows between them.
     */
    public class SquareArrows extends Sprite
    {
        /**
         * Initialize the scene as soon as we can.
         */
        public function SquareArrows()
        {
            if(stage) {
                init();
            }
            else {
                addEventListener(Event.ADDED_TO_STAGE, init);
            }
        }

        /**
         * Draw two squares and an arrow between them.
         */
        private function init(e : Event = null) : void
        {
            if(hasEventListener(Event.ADDED_TO_STAGE)) {
                removeEventListener(Event.ADDED_TO_STAGE, init);
            }

            // Drawing random-sized squares.
            var squareOne : Shape =
                    getSquareShape((Math.random() * 50) + 20, 0xBBBBBB);
            var squareTwo : Shape =
                    getSquareShape((Math.random() * 50) + 20, 0xDDDDDD);
            addChild(squareOne);
            addChild(squareTwo);

            // Draw the connector.
            var connector : Shape = getConnectorShape(squareOne, squareTwo);
            addChild(connector);
        }

        /**
         * Draw a connector arrow between two square shapes.
         */
        private function getConnectorShape(connectFrom : Shape, connectTo : Shape) : Shape
        {
            // Getting the center of the first square.
            var centerFrom : Point = new Point();
            centerFrom.x = connectFrom.x + (connectFrom.width / 2);
            centerFrom.y = connectFrom.y + (connectFrom.height / 2);

            // Getting the center of the second square.
            var centerTo : Point = new Point();
            centerTo.x = connectTo.x + (connectTo.width / 2);
            centerTo.y = connectTo.y + (connectTo.height / 2);

            // Getting the angle between those two.
            var angleTo : Number =
                Math.atan2(centerTo.x - centerFrom.x, centerTo.y - centerFrom.y);
            var angleFrom : Number =
                Math.atan2(centerFrom.x - centerTo.x, centerFrom.y - centerTo.y);

            // Getting the points on both borders.
            var pointFrom : Point = getSquareBorderPointAtAngle(connectFrom, angleTo);
            var pointTo : Point = getSquareBorderPointAtAngle(connectTo, angleFrom);

            // Calculating arrow edges.
            var arrowSlope : Number = 30;
            var arrowHeadLength : Number = 10;
            var vector : Point =
                new Point(-(pointTo.x - pointFrom.x), -(pointTo.y - pointFrom.y));

            // First edge of the head...
            var edgeOneMatrix : Matrix = new Matrix();
            edgeOneMatrix.rotate(arrowSlope * Math.PI / 180);
            var edgeOneVector : Point = edgeOneMatrix.transformPoint(vector);
            edgeOneVector.normalize(arrowHeadLength);
            var edgeOne : Point = new Point();
            edgeOne.x = pointTo.x + edgeOneVector.x;
            edgeOne.y = pointTo.y + edgeOneVector.y;

            // And second edge of the head.
            var edgeTwoMatrix : Matrix = new Matrix();
            edgeTwoMatrix.rotate((0 - arrowSlope) * Math.PI / 180);
            var edgeTwoVector : Point = edgeTwoMatrix.transformPoint(vector);
            edgeTwoVector.normalize(arrowHeadLength);
            var edgeTwo : Point = new Point();
            edgeTwo.x = pointTo.x + edgeTwoVector.x;
            edgeTwo.y = pointTo.y + edgeTwoVector.y;

            // Drawing the arrow.
            var arrow : Shape = new Shape();
            with(arrow.graphics) {
                lineStyle(2);
                // Drawing the line.
                moveTo(pointFrom.x, pointFrom.y);
                lineTo(pointTo.x, pointTo.y);

                // Drawing the arrow head.
                lineTo(edgeOne.x, edgeOne.y);
                moveTo(pointTo.x, pointTo.y);
                lineTo(edgeTwo.x, edgeTwo.y);
            }
            return arrow;
        }

        /**
         * Utility method to get a point on a square border at a certain angle.
         */
        private function getSquareBorderPointAtAngle(square : Shape, angle : Number) : Point
        {
            // Calculating rays of inner and outer circles.
            var minRay : Number = Math.SQRT2 * square.width / 2;
            var maxRay : Number = square.width / 2;

            // Calculating the weight of each rays depending on the angle.
            var rayAtAngle : Number = ((maxRay - minRay) * Math.abs(Math.cos(angle * 2))) + minRay;

            // We have our point.
            var point : Point = new Point();
            point.x = rayAtAngle * Math.sin(angle) + square.x + (square.width / 2);
            point.y = rayAtAngle * Math.cos(angle) + square.y + (square.height / 2);
            return point;
        }

        /**
         * Utility method to draw a square of a given size in a new shape.
         */
        private function getSquareShape(edgeSize : Number, fillColor : Number) : Shape
        {
            // Draw the square.
            var square : Shape = new Shape();
            with(square.graphics) {
                lineStyle(1);
                beginFill(fillColor);
                drawRect(0, 0, edgeSize, edgeSize);
                endFill();
            }

            // Set a random position.
            square.x = Math.random() * (stage.stageWidth - square.width);
            square.y = Math.random() * (stage.stageHeight - square.height);

            return square;
        }
    }
}

Этот код не полностью оптимизирован. Идея состоит в том, чтобы объяснить, как это работает. По сути, мы определяем два (случайных) квадрата и прослеживаем линию между ними. Чтобы проследить линию, мы вычисляем угол от центра первого квадрата до центра второго и используем специальный метод (getSquareBorderPointAtAngle), чтобы извлечь точку на границе квадрата в правильном направлении.

Этот метод является первой ключевой точкой этого фрагмента. Мы рассчитываем это, используя простую геометрию окружности, с небольшим усложнением того, как заставить точку совпадать с границей, а не с окружностью вокруг или внутри квадрата.

Затем мы рисуем наконечник стрелки. Для этого мы используем класс Flash Matrix, потому что это намного проще, чем вычислять его с нуля.

И вот мы закончили.

4 голосов
/ 28 июля 2010

Я читал здесь ответы месяц назад, так как мне нужно то же самое. Тем временем нашел этот пример чертежа соединителя и подумал, что поделюсь ссылкой.

Пример рисует линии соединителей между компонентами и обновляет линии при перетаскивании соединителей. Хороший!

альтернативный текст http://sammyjoeosborne.com/Images/connectorImage.jpg

http://sammyjoeosborne.com/Examples/Connector/ConnectorExample.html

0 голосов
/ 24 марта 2010

самая простая вещь, вероятно, использует flash.geom.Point. возьмите оба центра c1 и c2. возьмите вектор d в этом их отличие. в зависимости от его угла (от 315 до 45, от 45 до 135, от 135 до 225, от 225 до 315) вы будете знать, какие стороны задействованы (соответственно: справа и слева, сверху и снизу, слева и справа, снизу и сверху). *

затем рассчитайте пересечения между каждой стороной и линией, соединяющей центры.

линия, соединяющая центры, может быть представлена ​​как p=t*v+c1 (говоря в векторах). представьте сторону в виде линии, а затем рассчитайте t так, чтобы оба уравнения дали одну и ту же точку p, то есть пересечение, которое вы ищете.

...