1、1.1、SVGTextContentElement - Web APIs _ MDN.html(https://developer.mozilla.org/en-US/docs/Web/API/SVGTextContentElement)
CSS 'letter-spacing' and 'word-spacing' properties
1.2、二、svg文字之排版 - CSDN博客.html(https://blog.csdn.net/huanhuanq1209/article/details/71438629)
spacing
spacingAndGlyphs
spacing只调整字符之间的间隔;spacingAndGlyphs则会根据一定比例同时调整字符之间的间隔,以及字符本身宽度。
1.3、ZC:属性word-???、属性text-???、属性letter-???
2、
3、测试代码:
3.1、基本和 3.2 一样,只是 有注释 3.2没有注释
<?xml version="1.0" encoding="UTF-8"?> <svg width="1000" height="800" viewBox="-500 -200 1000 800" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:cge="http://iec.ch/TC57/2005/SVG-schema#" xmlns:hzsvg="http://holleygrid.cn/svg"> <style type="text/css"> <![CDATA[ <!-- .fill01 { fill :red; } --> ]]> </style> <script type="text/javascript" > <![CDATA[ <!-- function AttributeMap(_eleTextFrom, _eleTextTo) { // ZC: 在自己绘图的时候,我们未用到 class属性(style属性貌似也没有用到),于是_eleTextFrom中有哪些属性,通过节点遍历一下就行 // ZC: 不需要通过 window.getComputedStyle(...)来全部获取 // ZC: visibility 属性放置在 普通属性的位置 // ZC: 映射(map)来的属性,都放置到style中,这样 删除的时候 只要直接遍历 style里面的属性就行了(也不用将属性写到节点上面去) // ZC: (1) 清空 _eleTextTo的style属性里面的信息 while (_eleTextTo.style.length > 0) _eleTextTo.style.removeProperty(_eleTextTo.style.item(0)); // ZC: (2) 将_eleTextFrom的属性 放入到 _eleTextTo中 var attrs = _eleTextFrom.attributes; //得到所有属性 attrs-->NamedNodeMap(https://developer.mozilla.org/zh-CN/docs/Web/API/NamedNodeMap) for (var i=0; i<attrs.length; i++) { console.log(attrs[i].name + " : " + attrs[i].value); _eleTextTo.style.setProperty(attrs[i].name, attrs[i].value); } } function TextWordwrap_Vertical(_eleText, _eleText_hidden, _iHeight, _strNS, _strText, _bLeft2Right) { if (_strText.length <= 0) return; _eleText.innerHTML = ""; // ZC: 还要将 _eleText_hidden的属性设置成和_eleText的属性 一样的 (font-size / font-family 等) AttributeMap(_eleText, _eleText_hidden); console.log(""); _eleText_hidden.innerHTML = ""; var nodeText_hidden = document.createTextNode(_strText[0]); _eleText_hidden.appendChild(nodeText_hidden); var iFirstSpanWidth = 0;// ZC: _eleText中第一行<span/>的宽度 var iPrevSpanHeight = 0;// ZC: _eleText中上一行<span/>的高度 if (_strText.length > 1) { var iCntPrev = 0; var eleTspan = null; var nodeText = null; var bFirstTspan = true; for (var i=1; i<_strText.length; i++) { //var rtShort = _eleText_hidden.getBBox(); //var iHeightPrev = rtShort.height; //var iHeightPrev = _eleText_hidden.getComputedTextLength(); iCntPrev = _eleText_hidden.firstChild.data.length; _eleText_hidden.firstChild.data += _strText[i]; //var iHeight = _eleText_hidden.getComputedTextLength(); var rtLong = _eleText_hidden.getBBox(); var iHeight = rtLong.height; if (iHeight > _iHeight) { //var pt = _eleText_hidden.getStartPositionOfChar(_eleText_hidden.getNumberOfChars() - 1); //var iHeightPrev = pt.y - rtLong.y; // ZC: 上面的方式:chrome[版本 68.0.3440.106(正式版本)(32 位)] 和 Qt5.3.2的QWebView效果不同 var rtLast = _eleText_hidden.getExtentOfChar(_eleText_hidden.getNumberOfChars() - 1); var iHeightPrev = rtLast.y - rtLong.y; //alert(iHeightPrev + " , " + pt.y + " , " + rtLong.y); _eleText_hidden.firstChild.data = _eleText_hidden.firstChild.data.slice(0, iCntPrev); eleTspan = document.createElementNS(_strNS, "tspan"); _eleText.appendChild(eleTspan); nodeText = document.createTextNode(_eleText_hidden.firstChild.data); eleTspan.appendChild(nodeText); if (bFirstTspan) { var rt = _eleText.getBBox(); iFirstSpanWidth = rt.width; bFirstTspan = false; console.log("iFirstSpanWidth : " + iFirstSpanWidth); } else { eleTspan.setAttribute("dy", (-iPrevSpanHeight) + ""); if (_bLeft2Right) eleTspan.setAttribute("dx", (iFirstSpanWidth) + ""); else eleTspan.setAttribute("dx", (-iFirstSpanWidth) + ""); console.log("dx : " + (-iPrevSpanHeight)); console.log("dy : " + (iFirstSpanWidth)); } _eleText_hidden.firstChild.data = _strText[i]; iPrevSpanHeight = iHeightPrev; console.log(""); }// if }// for if (iCntPrev > 0) { eleTspan = document.createElementNS(_strNS, "tspan"); _eleText.appendChild(eleTspan); nodeText = document.createTextNode(_eleText_hidden.firstChild.data); eleTspan.appendChild(nodeText); eleTspan.setAttribute("dy", (-iPrevSpanHeight) + ""); if (_bLeft2Right) eleTspan.setAttribute("dx", (iFirstSpanWidth) + ""); else eleTspan.setAttribute("dx", (-iFirstSpanWidth) + ""); } }// if } window.onload = function(evt) { /* var text01 = document.getElementById("text01"); console.log("text01.getComputedTextLength() : " + text01.getComputedTextLength()); var rt = text01.getBBox(); console.log(rt.x + " , " + rt.y + " , " + rt.width + " , " + rt.height); //*/ //* var strTextContent = "中文测试text内容。中文测试text内容。中文测试text内容。中文测试text内容。中文测试text内容。中文测试text内容。中文测试text内容。中文测试text内容。"; // var strTextContent = "中文测试text内"; var eleSvg = document.getElementsByTagName("svg")[0]; var strNS = eleSvg.getAttribute("xmlns"); var eleText = document.createElementNS(strNS, "text"); eleSvg.appendChild(eleText); eleText.setAttribute("x", "-100"); eleText.setAttribute("y", "0"); eleText.setAttribute("writing-mode", "tb"); eleText.setAttribute("letter-spacing", "12px"); var textCalcLength = document.getElementById("textCalcLength"); TextWordwrap_Vertical(eleText, textCalcLength, 200, strNS, strTextContent, true); //*/ //* var zzz = document.getElementById("zzz"); var rt = zzz.getBBox(); console.log(rt.x + " , " + rt.y + " , " + rt.width + " , " + rt.height); //console.log(zzz.); console.log(""); console.log("zzz.getComputedTextLength() : " + zzz.getComputedTextLength()); var pt = zzz.getEndPositionOfChar(zzz.getNumberOfChars() - 1); console.log("pt : " + pt +" , "+ pt.x +" , "+ pt.y); pt = zzz.getStartPositionOfChar(zzz.getNumberOfChars() - 2); console.log("pt : " + pt +" , "+ pt.x +" , "+ pt.y); console.log("zzz.getSubStringLength() : " + zzz.getSubStringLength(0, 11)); console.log("zzz : " + zzz); rt = zzz.getExtentOfChar(11); console.log("zzz.getExtentOfChar() : " + rt.x + " , " + rt.y + " , " + rt.width + " , " + rt.height); }; --> ]]> </script> <!-- style="fontSize:10px;" style="fill:blue;" style="visibility:visible; fontSize:10px; visibility:hidden; " font-size="10px" --> <text id="text01" x="-400" y="-150" writing-mode="tb" letter-spacing="5px" zz="cc" class="fill01" style="font-size:10px;" > 测试1,测试2,测试3,测试4,测试5。abcdefg.1234567890. </text> <text x="-300" y="-150" style="writing-mode:tb;" > 测试1,测试2,测试3,测试4,测试5。abcdefg.1234567890. </text> <text x="-200" y="-150" writing-mode="tb" > <tspan >测试1,测试2,测试3,测试4,测试5,</tspan> <tspan dx="21" y="-150">测试6,测试7,测试8,测试9,测试10。</tspan> <tspan dx="21" y="-150">abcdefg.1234567890.</tspan> </text> <!-- visibility="hidden" --> <text id="textCalcLength" /> <text id="zzz" x="100" y="0" writing-mode="tb" > <tspan>中文测试text内容。中</tspan> <!-- <tspan dx="21" dy="-192.109375">文测试text内容</tspan> --> </text> <!-- <text id="zzz" x="100" y="0" writing-mode="tb" >中文测试text内容。中</text> --> <text x="145" y="0" writing-mode="tb" > <tspan>中文测试text内容。中</tspan> <tspan dx="21" >文测试text内容</tspan> </text> <text id="ccc" x="130" y="-100" > <tspan>文测试text内容</tspan> </text> <rect x="89.5" y="0" width="21" height="252" stroke="red" fill="none"/> <!-- <rect x="89.5" y="0" width="21" height="192.109375" stroke="red" fill="none"/> --> <rect x="129" y="-117" width="230.109375" height="21" stroke="red" fill="none"/> <circle cx="93.5" cy="176.109375" r="2" fill="red" /> <rect x="89.5" y="176.109375" width="21" height="16" stroke="blue" fill="none"/> <rect x="0" y="208" width="5" height="5" stroke="blue" fill="none"/> </svg>
3.2、没注释的代码 和3.1一样
<?xml version="1.0" encoding="UTF-8"?> <svg width="1000" height="800" viewBox="-500 -200 1000 800" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:cge="http://iec.ch/TC57/2005/SVG-schema#" xmlns:hzsvg="http://holleygrid.cn/svg"> <style type="text/css"> <![CDATA[ <!-- .fill01 { fill :red; } --> ]]> </style> <script type="text/javascript" > <![CDATA[ <!-- function AttributeMap(_eleTextFrom, _eleTextTo) { while (_eleTextTo.style.length > 0) _eleTextTo.style.removeProperty(_eleTextTo.style.item(0)); var attrs = _eleTextFrom.attributes; for (var i=0; i<attrs.length; i++) _eleTextTo.style.setProperty(attrs[i].name, attrs[i].value); } function TextWordwrap_Horizontal(_eleText, _eleText_hidden, _iWidth, _strNS, _strText) { if (_strText.length <= 0) return; _eleText.innerHTML = ""; AttributeMap(_eleText, _eleText_hidden); _eleText_hidden.innerHTML = ""; var nodeText_hidden = document.createTextNode(_strText[0]); _eleText_hidden.appendChild(nodeText_hidden); var iFirstSpanHeight = 0; var iPrevSpanWidth = 0; if (_strText.length > 1) { var iCntPrev = 0; var eleTspan = null; var nodeText = null; var bFirstTspan = true; for (var i=1; i<_strText.length; i++) { iCntPrev = _eleText_hidden.firstChild.data.length; _eleText_hidden.firstChild.data += _strText[i]; var rtLong = _eleText_hidden.getBBox(); var iWidth = rtLong.width; if (iWidth > _iWidth) { var rtLast = _eleText_hidden.getExtentOfChar(_eleText_hidden.getNumberOfChars() - 1); var iWidthPrev = rtLast.x - rtLong.x; _eleText_hidden.firstChild.data = _eleText_hidden.firstChild.data.slice(0, iCntPrev); eleTspan = document.createElementNS(_strNS, "tspan"); _eleText.appendChild(eleTspan); nodeText = document.createTextNode(_eleText_hidden.firstChild.data); eleTspan.appendChild(nodeText); if (bFirstTspan) { var rt = _eleText.getBBox(); iFirstSpanHeight = rt.height; bFirstTspan = false; } else { eleTspan.setAttribute("dx", (-iPrevSpanWidth) + ""); eleTspan.setAttribute("dy", (iFirstSpanHeight) + ""); } _eleText_hidden.firstChild.data = _strText[i]; iPrevSpanWidth = iWidthPrev; }// if }// for if (iCntPrev > 0) { eleTspan = document.createElementNS(_strNS, "tspan"); _eleText.appendChild(eleTspan); nodeText = document.createTextNode(_eleText_hidden.firstChild.data); eleTspan.appendChild(nodeText); eleTspan.setAttribute("dx", (-iPrevSpanWidth) + ""); eleTspan.setAttribute("dy", (iFirstSpanHeight) + ""); } }// if } function TextWordwrap_Vertical(_eleText, _eleText_hidden, _iHeight, _strNS, _strText, _bLeft2Right) { if (_strText.length <= 0) return; _eleText.innerHTML = ""; AttributeMap(_eleText, _eleText_hidden); _eleText_hidden.innerHTML = ""; var nodeText_hidden = document.createTextNode(_strText[0]); _eleText_hidden.appendChild(nodeText_hidden); var iFirstSpanWidth = 0; var iPrevSpanHeight = 0; if (_strText.length > 1) { var iCntPrev = 0; var eleTspan = null; var nodeText = null; var bFirstTspan = true; for (var i=1; i<_strText.length; i++) { iCntPrev = _eleText_hidden.firstChild.data.length; _eleText_hidden.firstChild.data += _strText[i]; var rtLong = _eleText_hidden.getBBox(); var iHeight = rtLong.height; if (iHeight > _iHeight) { var rtLast = _eleText_hidden.getExtentOfChar(_eleText_hidden.getNumberOfChars() - 1); var iHeightPrev = rtLast.y - rtLong.y; _eleText_hidden.firstChild.data = _eleText_hidden.firstChild.data.slice(0, iCntPrev); eleTspan = document.createElementNS(_strNS, "tspan"); _eleText.appendChild(eleTspan); nodeText = document.createTextNode(_eleText_hidden.firstChild.data); eleTspan.appendChild(nodeText); if (bFirstTspan) { var rt = _eleText.getBBox(); iFirstSpanWidth = rt.width; bFirstTspan = false; } else { eleTspan.setAttribute("dy", (-iPrevSpanHeight) + ""); if (_bLeft2Right) eleTspan.setAttribute("dx", (iFirstSpanWidth) + ""); else eleTspan.setAttribute("dx", (-iFirstSpanWidth) + ""); } _eleText_hidden.firstChild.data = _strText[i]; iPrevSpanHeight = iHeightPrev; }// if }// for if (iCntPrev > 0) { eleTspan = document.createElementNS(_strNS, "tspan"); _eleText.appendChild(eleTspan); nodeText = document.createTextNode(_eleText_hidden.firstChild.data); eleTspan.appendChild(nodeText); eleTspan.setAttribute("dy", (-iPrevSpanHeight) + ""); if (_bLeft2Right) eleTspan.setAttribute("dx", (iFirstSpanWidth) + ""); else eleTspan.setAttribute("dx", (-iFirstSpanWidth) + ""); } }// if } window.onload = function(evt) { /* var text01 = document.getElementById("text01"); console.log("text01.getComputedTextLength() : " + text01.getComputedTextLength()); var rt = text01.getBBox(); console.log(rt.x + " , " + rt.y + " , " + rt.width + " , " + rt.height); //*/ //* var strTextContent = "中文测试text内容。中文测试text内容。中文测试text内容。中文测试text内容。中文测试text内容。中文测试text内容。中文测试text内容。中文测试text内容。"; // var strTextContent = "中文测试text内"; var eleSvg = document.getElementsByTagName("svg")[0]; var strNS = eleSvg.getAttribute("xmlns"); var eleText = document.createElementNS(strNS, "text"); eleSvg.appendChild(eleText); eleText.setAttribute("x", "-100"); eleText.setAttribute("y", "0"); eleText.setAttribute("writing-mode", "tb"); eleText.setAttribute("letter-spacing", "12px"); var textCalcLength = document.getElementById("textCalcLength"); TextWordwrap_Vertical(eleText, textCalcLength, 200, strNS, strTextContent, true); //*/ //* var zzz = document.getElementById("zzz"); var rt = zzz.getBBox(); console.log(rt.x + " , " + rt.y + " , " + rt.width + " , " + rt.height); //console.log(zzz.); console.log(""); console.log("zzz.getComputedTextLength() : " + zzz.getComputedTextLength()); var pt = zzz.getEndPositionOfChar(zzz.getNumberOfChars() - 1); console.log("pt : " + pt +" , "+ pt.x +" , "+ pt.y); pt = zzz.getStartPositionOfChar(zzz.getNumberOfChars() - 2); console.log("pt : " + pt +" , "+ pt.x +" , "+ pt.y); console.log("zzz.getSubStringLength() : " + zzz.getSubStringLength(0, 11)); console.log("zzz : " + zzz); rt = zzz.getExtentOfChar(11); console.log("zzz.getExtentOfChar() : " + rt.x + " , " + rt.y + " , " + rt.width + " , " + rt.height); }; --> ]]> </script> <!-- style="fontSize:10px;" style="fill:blue;" style="visibility:visible; fontSize:10px; visibility:hidden; " font-size="10px" --> <text id="text01" x="-400" y="-150" writing-mode="tb" letter-spacing="5px" zz="cc" class="fill01" style="font-size:10px;" > 测试1,测试2,测试3,测试4,测试5。abcdefg.1234567890. </text> <text x="-300" y="-150" style="writing-mode:tb;" > 测试1,测试2,测试3,测试4,测试5。abcdefg.1234567890. </text> <text x="-200" y="-150" writing-mode="tb" > <tspan >测试1,测试2,测试3,测试4,测试5,</tspan> <tspan dx="21" y="-150">测试6,测试7,测试8,测试9,测试10。</tspan> <tspan dx="21" y="-150">abcdefg.1234567890.</tspan> </text> <!-- visibility="hidden" --> <text id="textCalcLength" /> <text id="zzz" x="100" y="0" writing-mode="tb" > <tspan>中文测试text内容。中</tspan> <!-- <tspan dx="21" dy="-192.109375">文测试text内容</tspan> --> </text> <!-- <text id="zzz" x="100" y="0" writing-mode="tb" >中文测试text内容。中</text> --> <text x="145" y="0" writing-mode="tb" > <tspan>中文测试text内容。中</tspan> <tspan dx="21" >文测试text内容</tspan> </text> <text id="ccc" x="130" y="-100" > <tspan>文测试text内容</tspan> </text> <rect x="89.5" y="0" width="21" height="252" stroke="red" fill="none"/> <!-- <rect x="89.5" y="0" width="21" height="192.109375" stroke="red" fill="none"/> --> <rect x="129" y="-117" width="230.109375" height="21" stroke="red" fill="none"/> <circle cx="93.5" cy="176.109375" r="2" fill="red" /> <rect x="89.5" y="176.109375" width="21" height="16" stroke="blue" fill="none"/> <rect x="0" y="208" width="5" height="5" stroke="blue" fill="none"/> </svg>
3.3、测试的 一些信息
<?xml version="1.0" encoding="UTF-8"?> <svg width="1000" height="800" viewBox="-500 -200 1000 800" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:cge="http://iec.ch/TC57/2005/SVG-schema#" xmlns:hzsvg="http://holleygrid.cn/svg"> <script type="text/javascript" > <![CDATA[ <!-- // ZC: 动态的在SVG中绘制一个矩形 function DynamicCreateRect(_x, _y, _width, _height, _stroke, _strokeWidth, _fill) { var eleSvg = document.getElementsByTagName("svg")[0]; var strNS = eleSvg.getAttribute("xmlns"); var rect = document.createElementNS(strNS, "rect"); eleSvg.appendChild(rect); rect.setAttribute("x", _x); rect.setAttribute("y", _y); rect.setAttribute("width", _width); rect.setAttribute("height", _height); rect.setAttribute("stroke", _stroke); rect.setAttribute("stroke-width", _strokeWidth); rect.setAttribute("fill", _fill); } window.onload = function(evt) { var text01 = document.getElementById("text01"); var text02 = document.getElementById("text02"); var text03 = document.getElementById("text03"); var tspan0201 = document.getElementById("tspan0201"); var tspan0202 = document.getElementById("tspan0202"); var tspan0301 = document.getElementById("tspan0301"); var rt01 = text01.getBBox(); var rt02 = text02.getBBox(); var rt03 = text03.getBBox(); var rt0201 = tspan0201.getBBox(); var rt0202 = tspan0202.getBBox(); var rt0301 = tspan0301.getBBox(); // ZC: 说明 隐藏的 <text/>照样也是绘制出来了,只是肉眼看不到 console.log(rt01.x + ", " + rt01.y + ", " + rt01.width + ", " + rt01.height); console.log(""); // ZC: <text/>的BBox()矩形 和 <tspan/>的BBox()矩形 在数值上是一样的 - (1) console.log(rt02.x + ", " + rt02.y + ", " + rt02.width + ", " + rt02.height); console.log(rt0201.x + ", " + rt0201.y + ", " + rt0201.width + ", " + rt0201.height); console.log(rt0202.x + ", " + rt0202.y + ", " + rt0202.width + ", " + rt0202.height); console.log(""); // ZC: <text/>的BBox()矩形 和 <tspan/>的BBox()矩形 在数值上是一样的 - (2) console.log(rt03.x + ", " + rt03.y + ", " + rt03.width + ", " + rt03.height); console.log(rt0301.x + ", " + rt0301.y + ", " + rt0301.width + ", " + rt0301.height); console.log(""); DynamicCreateRect(-200, 400, 200, 21, "red", "1", "none"); //* // ZC: <text/>没有 innerText属性 var testText01 = document.getElementById("testText01"); for (z in testText01) console.log(z + " ==> " + testText01[z]); console.log(""); var testText01 = document.getElementById("testText01"); console.log("testText01.childNodes.length : " + testText01.childNodes.length); testText01.innerHTML = "";// ZC: 这个时候 console.log("testText01.childNodes.length : " + testText01.childNodes.length); testText01.innerHTML = "A"; console.log("testText01.childNodes.length : " + testText01.childNodes.length + " , " + testText01.childNodes[0].nodeType); //*/ }; --> ]]> </script> <!-- 这里可以看出 tspan的dy是针对上一个tspan而言的(相信dx也是同样的原理) --> <text x="-400" y="-150" > <tspan x="-400">测试1,测试2,测试3,测试4,测试5,</tspan> <tspan x="-400" dy="21">测试6,测试7,测试8,测试9,测试10。</tspan> <tspan x="-400" dy="21">abcdefg.1234567890.</tspan> </text> <!-- 貌似上面说的也不全对...可以理解成:tspan的dy是针对上一个 文本段落而言的(dx应该也是同样的原理) --> <text x="0" y="-150" > 测试1,测试2,测试3,测试4,测试5, <tspan x="0" dy="21">测试6,测试7,测试8,测试9,测试10。</tspan> <tspan x="0" dy="21">abcdefg.1234567890.</tspan> </text> <text id="text01" x="-400" y="-100" visibility="hidden">1234567890</text> <!-- tspan不设置 dx&dy或x&y属性的话,就和一般的 text元素看上去一样 --> <text id="text02" x="-400" y="-50" > <tspan id="tspan0201">测试1,测试2,测试3,测试4,测试5,</tspan> <tspan id="tspan0202">测试6,测试7,测试8,测试9,测试10。</tspan> </text> <text id="text03" x="-400" y="50" > 测试1,测试2,测试3,测试4,测试5, <tspan id="tspan0301">测试6,测试7,测试8,测试9,测试10。</tspan> </text> <rect x="0" y="0" width="100" height="1" stroke="none" fill="blue"/> <text x="-100" y="200" id="text01" > <tspan id="text0101">Whatever text you want</tspan> <tspan id="text0102" dx="0" dy="21">here. 1234567890.1234567890</tspan> </text> <text id="testText01" /> </svg> <?DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"?>
4、
5、