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