我正在尝试使用SVG绘图中的foreignObject标记输出HTML。我正在使用d3来生成元素。 foreignObject标记内的HTML内容出现的唯一时间是foreignObect标记内的内容是纯文本,否则它只显示为空/空白。请参阅此jsfiddle以获取我的问题示例:http://jsfiddle.net/R9e3Y/29/
foreignObject标记内的内容显示在检查元素时:
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
<foreignObject x="40" y="40" width="100" height="100">
<div>test</div>
</foreignObject>
</svg>
但在屏幕上看不到?如何显示内容?
答案 0 :(得分:58)
由于你正在使用d3,你需要告诉d3 div是一个html div而不是svg命名空间中的某个元素。尝试
.append("xhtml:div")
答案 1 :(得分:14)
<foreignObject>
允许嵌入各种标记,而不仅仅是HTML。这意味着,必须有一种方法来确定使用何种语言。这就是命名空间发挥作用的地方。
要告诉SVG您拥有哪种foreignObject
,您必须将内容放在适当的命名空间中。
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
<foreignObject x="40" y="40" width="100" height="100">
<div xmlns="http://www.w3.org/1999/xhtml">test</div>
</foreignObject>
</svg>
在您的示例中,<div>
元素位于SVG名称空间中,即它是SVG元素,而不是HTML元素(尽管是非标准元素)。
<foreignObject>
元素还有一个requiredExtensions
属性来告诉浏览器使用了哪个扩展名,但是不同的浏览器似乎不同地解释了这个属性,因此最好不要设置它。
答案 2 :(得分:4)
确保设置width
和height
参数。
添加xmlns
并没有为我解决问题。事实证明,对我来说问题更简单......我没有添加width
和height
参数,因此foreignObject
内的内容没有显示,即使它存在。两个参数似乎默认为0。
答案 3 :(得分:0)
我为此开发了一些东西。代码如下。更高级的版本使用代理来引入外部非CORS资源。 svg foreignObject
阻止加载任何非CORS跨源请求。我写了一个在Runkit上运行的简单代理。见底部。
这个限制是:没有外部非CORS字体,没有非CORS图像。任何想要帮助改善这一点的人,包括添加对图片和字体的支持,都可以在这里做出贡献:https://github.com/dosyago-coder-0/dompeg.js/blob/master/dompeg.js
网页脚本:
(async function (){
const width = document.scrollingElement.scrollWidth;
const height = document.scrollingElement.scrollHeight;
const doc = document.implementation.createHTMLDocument('');
doc.write(document.documentElement.outerHTML);
doc.documentElement.setAttribute('xmlns', doc.documentElement.namespaceURI);
const styles = [];
for( let i = 0; i < document.styleSheets.length; i++ ) {
const ss = document.styleSheets[i];
if ( ss.cssRules ) {
for( let j = 0; j < ss.cssRules.length; j++ ) {
styles.push( ss.cssRules[j].cssText );
}
} else {
try {
const res = await fetch(ss.href);
const cssText = await res.text();
styles.push(cssText);
} catch(e) {
/** fetch to proxy here as fallback
* uncomment if you set up your proxy server
try {
const res = await fetch(`https://${YOUR PROXY SERVER}.runkit.sh/?url=${btoa(ss.href)}`);
const cssText = await res.text();
styles.push(cssText);
} catch(e) { **/
console.warn(`Exception adding styles from ${ss.href}`, e, e.stack);
/** uncomment if you setup proxy
}
**/
}
}
}
Array.from( doc.querySelectorAll('noscript, link, script')).forEach( el => el.remove() );
stripComments(doc);
Array.from( doc.querySelectorAll('*[style]')).forEach( el => {
const styleText = el.getAttribute('style');
const uniq = (Math.random()+''+performance.now()).replace(/\./g,'x');
const className = `class${uniq}`;
const cssText = `.${className} {${ styleText }}`;
styles.push( cssText );
el.classList.add( className );
});
const styleElement = doc.createElement('style');
styleElement.innerText = styles.join('\n');
doc.documentElement.appendChild(styleElement);
const canvas = document.createElement('canvas');
Object.assign( canvas, {width,height});
const ctx = canvas.getContext('2d');
const data = `
<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}">
<foreignObject width="100%" height="100%">
${(new XMLSerializer).serializeToString(doc).slice(15)}
</foreignObject>
</svg>`;
const DOMURL = window.URL || window.webkitURL || window;
const img = new Image();
const svg = new Blob([data], {type: 'image/svg+xml'});
Object.assign( img, {width,height});
img.crossOrigin = "Anonymous";
img.onload = function() {
ctx.fillStyle = 'white';
ctx.fillRect( 0, 0, canvas.width, canvas.height );
ctx.drawImage(img, 0, 0);
const datauri = canvas.toDataURL('image/jpeg');
const anchor = document.createElement('a');
anchor.download = 'screen.jpg';
anchor.href = datauri;
anchor.target = "_new";
anchor.innerText = 'download screen.jpg';
anchor.addEventListener('click', e => {e.stopPropagation();anchor.remove();}, { capture: true });
document.body.appendChild(anchor);
Object.assign( anchor.style, {
position: 'fixed',
background:'white',
fontSize: '18px',
fontFamily: 'monospace',
color: 'blue',
top: 0,
left: 0,
zIndex: Number.MAX_SAFE_INTEGER
});
}
img.src = buildSvgImageUrl(data);
img.style.position = "absolute";
img.style.zIndex = "10000000";
img.style.backgroundColor = "white";
//document.body.appendChild(img);
function buildSvgImageUrl(svg) {
const b64 = btoa(unescape(encodeURIComponent(svg)));
return "data:image/svg+xml;base64," + b64;
}
function stripComments(docNode){
const commentWalker = docNode.evaluate('//comment()', docNode, null, XPathResult.ANY_TYPE, null);
let comment = commentWalker.iterateNext();
const cuts = [];
while (comment) {
cuts.push(comment);
comment = commentWalker.iterateNext();
}
cuts.forEach( node => node.remove());
}
}());
runkit代理服务器脚本:
const request = require("request");
const rp = require('request-promise');
const {URL} = require('url');
const express = require("@runkit/runkit/express-endpoint/1.0.0");
const b64 = require('base-64');
const bodyParser = require('body-parser');
const page = (url,err) => `
<form method=POST style="
position: fixed;
position: sticky;
display: table;
top: 0px;
z-index:12000000;
background: white;">
<label for=hider99>X</label><input id=hider99 type=checkbox>
<style>
#hider99:checked ~ fieldset {
display: none;
}
</style>
<fieldset><legend>Proxy</legend>
<p>
<input required type=url size=62 name=url placeholder="any url" value="${url||'https://google.com/favicon.ico'}">
<button style=background:lime>Load</button>
${ !! err ? `<p><span style=color:red>${err}</span>` : '' }
</fieldset>
</form>`;
const app = express(module.exports);
app.use(bodyParser.urlencoded({ extended: false }));
app.get("/", async (req,res,next) => {
console.log(req.query.url);
let url;
res.type('html');
res.set('access-control-allow-origin', '*');
try {
url = b64.decode(req.query.url);
new URL(url);
} catch(e) { res.end(page('',"not a url"+e)); return; }
try {
res.type(type(url));
const data = await rp(url);
res.end(data);
} catch(e) { res.end(page('',""+e)); }
});
app.get("/:anything", async (req,res,next) => {
res.type('html');
res.end('404 Not found');
});
function type(s = '') {
return s.split(/\./g).pop() || 'html';
}
void 0;
答案 4 :(得分:-2)
var a = function(a) {
var b = enter code heredocument.createElementNS("http://www.w3.org/1999/xhtml", "div");
b.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg">' + a + "</svg>";
for (var c = document.createDocumentFragment(); b.firstChild.firstChild; ){
c.appendChild(b.firstChild.firstChild);
}
return c;
}
$('#app_canvasContainer svg').append(a('<foreignObject overflow="visible" width="200" height="100" x="'+ x +'" y="'+ y +'" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><textarea class="text-entity" readonly="true" resizeable=false xmlns="http://www.w3.org/1999/xhtml" >'+ val +'</textarea>`enter code here`</foreignObject>'));