我正在编写一个应用程序,用于创建包含许多嵌入式SVG的HTML文档。
该应用程序具有以下特征:
它必须在服务器环境中无头运行
它使用操作DOM的现有代码来创建文档中的SVG和其他项目
现有代码使用getBBox()
方法来确定各种动态创建元素的大小,以便计算SVG的布局。
作为附加信息,虽然我认为它不会影响这个问题:SVG生成代码是用Javascript编写的,并使用D3库。我正在使用node-java来促进这一点。但是,我目前遇到的问题很容易在纯Java SSCE中复制(见下文)。
我正在尝试使用Apache Batik来提供SVG DOM实现。
我的问题是,在SVG元素嵌入到较大的XML文档中的情况下,到目前为止,我无法让getBBox()
返回非空值。
以下是一个说明问题的示例:
import org.w3c.dom.*;
import org.w3c.dom.svg.*;
import org.apache.batik.anim.dom.SVGDOMImplementation;
import org.apache.batik.bridge.UserAgent;
import org.apache.batik.bridge.UserAgentAdapter;
import org.apache.batik.bridge.DocumentLoader;
import org.apache.batik.bridge.BridgeContext;
import org.apache.batik.bridge.GVTBuilder;
class BatikDomEmbedded {
public static void main(String [ ] args) {
DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();
SVGDocument doc = (SVGDocument) impl.createDocument(null, "html", null);
Element html = doc.getDocumentElement();
Element body = doc.createElement("body");
html.appendChild(body);
Element svg = doc.createElementNS(SVGDOMImplementation.SVG_NAMESPACE_URI, "svg");
svg.setAttributeNS(null, "width", "500");
svg.setAttributeNS(null, "height", "100");
body.appendChild(svg);
UserAgent userAgent = new UserAgentAdapter();
DocumentLoader loader = new DocumentLoader(userAgent);
BridgeContext ctx = new BridgeContext(userAgent, loader);
ctx.setDynamicState(BridgeContext.DYNAMIC);
GVTBuilder builder = new GVTBuilder();
builder.build(ctx, svg);
Element rect = doc.createElementNS(SVGDOMImplementation.SVG_NAMESPACE_URI, "rect");
rect.setAttributeNS(null, "x", "100");
rect.setAttributeNS(null, "y", "100");
rect.setAttributeNS(null, "width", "150");
rect.setAttributeNS(null, "height", "200");
svg.appendChild(rect);
SVGRect bbox = ((SVGLocatable)rect).getBBox();
System.out.println("X: " + bbox.getX() + "\nY: " + bbox.getY() +
"\nHeight: " + bbox.getHeight() + "\nWidth: " + bbox.getWidth());
}
}
在解除引用bbox时,运行此代码会导致空指针异常。
如果我稍微更改代码以使文档成为独立的SVG文档,那么它可以正常工作。
这些场景之间的主要区别(除了SVG元素不是根文档元素)是在工作的情况下,对builder.build(ctx, ...);
的调用提供了一个SVGDocument作为第二个参数,但是在非 - 工作案例它是一个SVGElement(类型' svg')。
有没有办法让getBBox()
在这种情况下工作,其中svg元素嵌入在一个更大的文档中(事实上,本文档中可能有多个SVG)?
答案 0 :(得分:0)
val impl: DOMImplementation = SVGDOMImplementation.getDOMImplementation()
val doc = impl.createDocument(SVGConstants.SVG_NAMESPACE_URI, "svg", null) as SVGDocument
val userAgent: UserAgent = UserAgentAdapter()
val loader = DocumentLoader(userAgent)
val ctx = BridgeContext(userAgent, loader)
ctx.setDynamicState(BridgeContext.DYNAMIC)
val builder = GVTBuilder()
builder.build(ctx, doc)
val rect: Element = doc.createElementNS(SVGDOMImplementation.SVG_NAMESPACE_URI, "rect")
rect.setAttributeNS(null, "x", "100")
rect.setAttributeNS(null, "y", "100")
rect.setAttributeNS(null, "width", "150")
rect.setAttributeNS(null, "height", "200")
doc.documentElement.appendChild(rect)
val bbox = (rect as SVGLocatable).bBox
println("X: " + bbox.x + "\nY: " + bbox.y +
"\nHeight: " + bbox.height + "\nWidth: " + bbox.width)
尝试此代码。
首先,在创建文档或元素时始终输入svg namespace_url。
第二秒,不要在SvgDocument中将qualifiedName设置为“ html”。如果要创建html文档,请使用HtmlDocument。
p.s这个代码是kotlin。