Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
293 views
in Technique[技术] by (71.8m points)

javascript - svg旋转启动时观察到异常行为(Unusual behavior observed on svg rotate start)

I want to rotate svg text about its bottom left corner.

(我想围绕其左下角旋转svg文本。)

The text can be rotated using the circle handle on the top right corner of the svg text.

(可以使用svg文本右上角的圆形手柄旋转文本。)

On start of rotate the text shows unusual behavior of rotating by 180 degrees and then getting normal.

(旋转开始时,文本显示异常的行为,即旋转180度然后恢复正常。)

Please find the below code.

(请找到下面的代码。)

I need help for fixing this unusual behaviour at the start of the svg text rotate.

(在svg文本旋转开始时,我需要帮助修复此异常行为。)

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <style type="text/css">
        svg {
          border: 1px solid #333;
          display: block;
          margin: 0 auto;
          cursor:auto;
        }
        text{cursor:move;}

        circle{
          fill: dodgerblue;
          cursor: alias;
        }
    </style>
</head>
<body>
    <svg width='650' height='600' viewBox='0 0 650 600'>
    </svg>
    <script type="text/javascript">
        var SVG_NS = 'http://www.w3.org/2000/svg';
        var svg = document.querySelector("svg");
        var deg = 180 / Math.PI;
        var rotating = false;
        var dragging = false;
        var impact = {
            x: 0,
            y: 0
        };
        var m = { //mouse
            x: 0,
            y: 0
        };
        var delta = {
            x: 0,
            y: 0
        };
        var textData = {
            properties: {
                text_content: 'Hello World'
            },
            tagName: 'text',
            pos: {
                x: 300,
                y: 300
            }
        }
        function Element(o, index) {
            this.g = document.createElementNS(SVG_NS, 'g'); //creates element g
            this.g.setAttributeNS(null, 'id', index); //adds id eg: 1 to g element
            svg.appendChild(this.g);  // appends g element in svg

            o.parent = this.g; // adds property 'parent' with value g to textData object

            this.el = drawElement(o); // appends text tag in g and returns text tag. So this.el stores text tag

            //Note: drawElement is using transform: translate instead of x and y for relocating svg element

            this.a = 0; // probably for angle
            this.tagName = o.tagName; // initializing a class property with the tagname property of the textData object
            this.elRect = this.el.getBoundingClientRect(); //gets Bounding rectangle meta of g element of textData
            this.svgRect = svg.getBoundingClientRect(); //gets the Bounding rectangle meta of the svg
            this.Left = this.elRect.left - this.svgRect.left; 
            this.Right = this.elRect.right - this.svgRect.left;
            this.Top = this.elRect.top - this.svgRect.top;
            this.Bottom = this.elRect.bottom - this.svgRect.top;

            //Once we have Left, Right, Top, Bottom we are initializing x,y coordinates of 4 corners of g
            this.LT = {
                x: this.Left,
                y: this.Top
            };
            this.RT = {
                x: this.Right,
                y: this.Top
            };
            this.LB = {
                x: this.Left,
                y: this.Bottom
            };
            this.RB = {
                x: this.Right,
                y: this.Bottom
            };
            // this.c stores the coordinates of the center of the element initializing by default with 0,0
            this.c = {
                x: 0, //(this.elRect.width / 2) + this.Left,
                y: 0 //(this.elRect.height / 2) + this.Top
            };

            //here a property with the same name of the object is getting created so don't get confused between this.o and o. We are just storing its x and y value in it
            this.o = {
                x: o.pos.x,
                y: o.pos.y
            };
            //Math.atan2(y,x) gives the angle of point with positive x axis. Here y value taken is (height of g)/2 and x value taken is (width of g)/2. Note element is probably assumed wrt origin
            this.A = Math.atan2(this.elRect.height / 2, this.elRect.width / 2);

            //Internally creating a circle svg element with center left top of g and parent as g. So g will have text tag and circle tag now
            var leftTop = {
                properties: {
                    cx: this.RT.x,
                    cy: this.RT.y,
                    r: 4,
                    fill: "blue"
                },
                parent: this.g,
                tagName: 'circle'
            }

            //appends the circle element in g tag and returns the circle tag. So now this.lt contains circle tag
            this.lt = drawElement(leftTop);

            //update the value of transform attribute of both: text tag and circle tag by the same value. It uses this.a converted in deg for rotate and this.o.x and this.o.y for translate. Note: the value gets updated in svg element tags and not as class properties as they are the source for modification
            this.update = function() {
                var transf = 'translate(' + this.o.x + ', ' + this.o.y + ')' + ' rotate(' + (this.a * deg) + ')';
                this.el.setAttributeNS(null, 'transform', transf);
                this.lt.setAttributeNS(null, 'transform', transf);
            }

        }

        var svg_obj = new Element(textData,1);
        svg_obj.update();
        // EVENTS

        //mousedown is fired when mousebutton is pressed on element. In contrast click is fired when mouse is pressed and released (mousedown + mouseup)
        svg.addEventListener("mousedown", function(evt) {
            console.log('Mousedown');
            var index = parseInt(evt.target.parentElement.id) - 1;              
            if (evt.target.tagName == svg_obj.tagName) {
                dragging = index + 1;
                impact = oMousePos(svg, evt);
                delta.x = svg_obj.o.x - impact.x;
                delta.y = svg_obj.o.y - impact.y;
            }

            if (evt.target.tagName == "circle") {
                rotating = parseInt(evt.target.parentElement.id);
            }

        }, false);

        //mouseup is fired when mouse button is released over the element
        svg.addEventListener("mouseup", function(evt) {
            console.log('Mouseup');
            rotating = false;
            dragging = false;
        }, false);

        //fired on element when cursor is moved out of the element
        svg.addEventListener("mouseleave", function(evt) {
            console.log('Mouseleave');
            rotating = false;
            dragging = false;
        }, false);

        //when mouse is over the element and it is moved
        svg.addEventListener("mousemove", function(evt) {
            console.log('Mousemove');
          m = oMousePos(svg, evt);

          if (dragging) {
            var index = dragging - 1;
            svg_obj.o.x = m.x + delta.x;
            svg_obj.o.y = m.y + delta.y;
            svg_obj.update();
          }

          if (rotating) {
            var index = rotating - 1;
            svg_obj.a = Math.atan2(svg_obj.o.y - m.y, svg_obj.o.x - m.x) + svg_obj.A;
            svg_obj.update();
          }
        }, false);

        function oMousePos(svg, evt) {
            var ClientRect = svg.getBoundingClientRect();
            return { //objeto
                x: Math.round(evt.clientX - ClientRect.left),
                y: Math.round(evt.clientY - ClientRect.top)
            }
        }

        function drawElement(o) {
            var el = document.createElementNS(SVG_NS, o.tagName);
            for (var name in o.properties) {
                console.log(name);
                if(name == 'text_content')
                {
                    var textNode = document.createTextNode(o.properties[name]);
                    el.appendChild(textNode);                       
                }
                else if (o.properties.hasOwnProperty(name)) {
                    el.setAttributeNS(null, name, o.properties[name]);
                }
            }
            o.parent.appendChild(el);
            return el;
        }
    </script>

</body>
</html>
  ask by Vrajesh Doshi translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
等待大神答复

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...