SVG内部利用foreignObject嵌入XHTML元素

<foreignObject>元素的作用是可以在其中使用具有其它XML命名空间的XML元素,换句话说借助<foreignObject>标签,我们可以直接在SVG内部嵌入XHTML元素,举个简单的例子:

<svg xmlns="http://www.w3.org/2000/svg">
<foreignObject width="120" height="50">
<body xmlns="http://www.w3.org/1999/xhtml">
<p>文字。</p>
</body>
</foreignObject>
</svg>

可以看到<foreignObject>标签里面有一个设置了xmlns="http://www.w3.org/1999/xhtml"命名空间的<body>标签,此时<body>标签及其子标签都会按照XHTML标准渲染,实现了SVG和XHTML的混合使用。

SVG forginObject实现文本自动换行

SVG要实现文本换行,往往需要手动阻断,类似下面的代码:

<svg xmlns="http://www.w3.org/2000/svg">
<text font-size="12">
<tspan x="0" y="10">一段需要word wrap</tspan>
<tspan x="0" y="26">的文字。</tspan>
</text>
</svg>

需要2<tspan>元素,这一点都不工程。虽然Chrome浏览器可以对<text>标签进行white-space:normal的强制设置,但也只是Chrome浏览器可以。

但是如果使用<foreignObject>元素,则自动换行就是小菜:

<svg xmlns="http://www.w3.org/2000/svg">
<foreignObject width="120" height="50">
<body xmlns="http://www.w3.org/1999/xhtml">
<p style="font-size:12px;margin:0;">一段需要word wrap的文字。</p>
</body>
</foreignObject>
</svg>

SVG forginObject生成图片

除了轻松实现文本换行,SVG <foreignObject>元素还有其他更高级的应用,就是可以将页面上的DOM元素轻松变成图片,原理如下:

  1. 获取对应DOM元素的outerHTML代码;
  2. 放在<foreignObject>元素中;
  3. 图片方式显示我们的SVG图形,例如:
    <img width="300" height="150" src='data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg"><foreignObject width="120" height="50"><body xmlns="http://www.w3.org/1999/xhtml"><p style="font-size:12px;margin:0;">一段需要word wrap的文字。</p></body></foreignObject></svg>'>
  4. 上一步的图片本质还是SVG,我们可以借助canvas drawImage()方法将图片放在画布上,然后使用canvas.toDataURL()方法转换成pngjpg图片,核心代码:
    var canvas = document.createElement('canvas');
    var context = canvas.getContext('2d');
    canvas.drawImage(img, 0, 0);
    img.src = canvas.toDataURL('image/png');

一旦我们可以把DOM元素转换成图片,我们就可以轻轻松松配合JS在前端实现网页截图功能。

之前项目中有将highcharts.js的表格转换成图片,代码如下:

        private generateTable(chartSetting: Core.ChartConfig) {
if (chartSetting.firstColColor.toLocaleLowerCase() == "rgb(255,255,254)") {
chartSetting.firstColColor = chartSetting.bgColor;
}
if (chartSetting.firstRowColor.toLocaleLowerCase() == "rgb(255,255,254)") {
chartSetting.firstRowColor = chartSetting.bgColor;
}
var tableHtml = document.createElement("table");
tableHtml.style.border = "1px solid";
tableHtml.style.borderCollapse = "collapse";
tableHtml.style.fontSize = "14px";
tableHtml.style.lineHeight = "26px"; //tableHtml.style.backgroundColor = (chartSetting.bgColor.toLocaleLowerCase().replace(")", "") + "," + (1 - chartSetting.opacityValue) + ")").replace("rgb", "rgba");
tableHtml.style.color = chartSetting.fontColor;
tableHtml.style.borderColor = chartSetting.borderColor;
tableHtml.style.fontFamily = chartSetting.fontFamily;
var tableData: any = chartSetting.chartData;
var series = [];
for (var i = 1; i < tableData[0].length - 1; i++) {
var y = tableData[0][i];
if (y == '' || y == null) {
break;
}
series.push(y);
}
for (var i = 0; i < tableData.length - 1; i++) {
var x = tableData[i][0];
if (i != 0 && (x == '' || x == null)) {
break;
}
var tr = document.createElement("TR");
tableHtml.appendChild(tr); for (var j = 0; j < tableData[i].length - 1; j++) {
if (j != 0 && (tableData[0][j] == null || tableData[0][j] == "")) {
break;
}
//var y: any = parseFloat(tableData[i][j]);
var td = document.createElement("TD");
tr.appendChild(td);
td.style.border = "1px solid " + chartSetting.borderColor;
td.style.padding = "0px 7px 0px 7px";
if (tableData[i][j] || i == 0 || j == 0) {
td.innerHTML = tableData[i][j];
} else {
td.innerHTML = "";
}
if (i != 0 && j == 0) {
td.style.backgroundColor = (chartSetting.firstColColor.toLocaleLowerCase().replace(")", "") + "," + (1 - chartSetting.opacityValue) + ")").replace("rgb", "rgba");
} else if (i == 0) {
td.style.backgroundColor = (chartSetting.firstRowColor.toLocaleLowerCase().replace(")", "") + "," + (1 - chartSetting.opacityValue) + ")").replace("rgb", "rgba");
} else {
td.style.backgroundColor = (chartSetting.bgColor.toLocaleLowerCase().replace(")", "") + "," + (1 - chartSetting.opacityValue) + ")").replace("rgb", "rgba");
}
}
}
var table_img_div = document.getElementById("table_img");
table_img_div.innerHTML = tableHtml.outerHTML.replace(/\n/g, "<br>");
var tableW = $(table_img_div).width();
var tableH = $(table_img_div).height();
var img_svg = '<svg width="' + (tableW) + 'px" height="' + tableH + 'px" xmlns = "http://www.w3.org/2000/svg" ><desc>Created with Highcharts 4.2.4</desc> <switch> <foreignObject width="' + (tableW) + '" height="' + tableH + '" requiredFeatures = "http://www.w3.org/TR/SVG11/feature#Extensibility"><body style="margin:0" xmlns="http://www.w3.org/1999/xhtml">' + tableHtml.outerHTML
+ ' </body></foreignObject><text font-size="10" font-family="Verdana"><tspan x= "10" y= "10" > 请使用其他浏览器,</tspan><tspan x= "10" y= "20" > 以正常显示表格。</tspan> </text></switch></svg>';
img_svg = img_svg.replace(/\n/g, "<br/>");
return {
svg: img_svg,
width: tableW,
height: tableH
};
}

svg foreignObject的作用(文本换行,生成图片)的更多相关文章

  1. 小程序canvas文本换行生成图片

    一.图片透明及旋转 let ctx = wx.createCanvasContext('shareImg') ctx.drawImage('../../../' + res[0].path, 0, 0 ...

  2. 文本换行word-wrap、word-break与white-space

    本文同步至微信公众号:http://mp.weixin.qq.com/s?__biz=MzAxMzgwNDU3Mg==&mid=401671055&idx=1&sn=b88c9 ...

  3. CSS学习笔记:文本换行显示(word-wrap)

    在CSS3中新定义了文本换行属性,word-wrap: nomal属性值表示控制连续文本换行. break-word属性值表示内容将在边界内换行.如果需要,词内换行(word-break)也会发生. ...

  4. Vue插值文本换行问题

    问题背景: 后端返回的字符串带有\n换行符,但Vue将其插值渲染成div内部文本后,文本并不换行,换行符显示为一个空格. 目标: 让文本在换行符处换行. 解决方法: 思路:实现文本换行有两种方法,一是 ...

  5. arcgis api 3.x for js 解决 textSymbol 文本换行显示(附源码下载)

    前言 关于本篇功能实现用到的 api 涉及类看不懂的,请参照 esri 官网的 arcgis api 3.x for js:esri 官网 api,里面详细的介绍 arcgis api 3.x 各个类 ...

  6. wbr 文本换行规则标签

    <wbr/>标签规定在文本中的何处适合添加换行符.如果文本太长,浏览器可能会在错误的位置换行,那么可以使用<wbr/>标签来添加单词换行时机. Talk is cheap. S ...

  7. Asp.Net中文本换行

    Asp.Net中文本换行 VB.NET Function HtmlCode(ByVal fString)        If fString <> "" Then    ...

  8. Eclipse console文本换行

    Eclipse换行主要有3个方面 格式化时编辑器文本换行 源代码注释文本换行 Eclipse控制台console显示文本换行 1和2参考 http://hi.baidu.com/ae6623/item ...

  9. clipboard让复制的文本换行

    https://clipboardjs.com/dist/clipboard.min.js 用clipboard实现复制时, 想让复制的文本换行, 有两咱方法: 第一种, HTML实现: <!- ...

随机推荐

  1. 2019dx#7

    Solved Pro.ID Title Ratio(Accepted / Submitted)   1001 A + B = C 10.48%(301/2872)   1002 Bracket Seq ...

  2. CodeForces 1083 E The Fair Nut and Rectangles 斜率优化DP

    The Fair Nut and Rectangles 题意:有n个矩形,然后你可以选择k个矩形,选择一个矩形需要支付代价 ai, 问 总面积- 总支付代价 最大能是多少, 保证没有矩形套矩形. 题解 ...

  3. poj1651 Multiplication Puzzle(简单区间dp)

    题目链接:http://poj.org/problem?id=1651 题意:一系列的数字,除了头尾不能动,每次取出一个数字,这个数字与左右相邻数字的乘积为其价值, 最后将所有价值加起来,要求最小值. ...

  4. 中南林业科技大学第十一届程序设计大赛 有趣的二进制 牛客网 java大数的一些方法

    链接:https://www.nowcoder.com/acm/contest/124/C来源:牛客网 题目描述 小新在学C语言的时候,邝老师告诉他double类型的数据在表示小数的时候,小数点后的有 ...

  5. Git暂存本地代码,强制获取远程最新代码

    一:git stash  // 把本地修改的代码压到git栈中去 二:git pull  // 本地代码压栈之后,pull远程代码会完全覆盖本地代码 三:git stash list  // 可以查看 ...

  6. Vue组件间通信方式

    一.Props传递数据 在父组件中使用子组件,本质通过v-bind绑定属性传入子组件,子组件通过props接收父组件传入的属性 <template> <div> 父组件:{{m ...

  7. I don't Blame You that You don't Understand Me

    I don't Blame You that You don't Understand Me Every one has a dead corner in himself, with no entry ...

  8. windows平台:查看端口占用情况,请杀死端口对应进程PID

    //查看 netstat -ano | findstr //杀死 taskkill /f /PID

  9. 4、链栈的实现(java代码)

    1.链节点 public class Node<T> { public T data; public Node next; } 2.实现代码 public class Stack<T ...

  10. springMvc 注解@JsonFormat 日期格式化

    1:一定要加入依赖,否则不生效: <!--日期格式化依赖--> <dependency> <groupId>com.fasterxml.jackson.core&l ...