英文:
How convert vaadin 23 element to itext 7 element?
问题
I have leaflet map in my Vaadin site:
I need export this DIV block (as a picture) into PDF file (i use iText 7 https://kb.itextpdf.com/home):
Here I found the information
*
https://kb.itextpdf.com/home/it7kb/ebooks/itext-7-converting-html-to-pdf-with-pdfhtml/chapter-1-hello-html-to-pdf*
about export HTML to PDF file.
I have problem:
iText 7 need IElement, but I have only vaadin element.
Please tell me how to convert vaadin element to iText element?
I try get OuterHTML from vaadin element:
String HTML = this.getElement().getOuterHTML();
var elements = HtmlConverter.convertToElements(HTML);
for (IElement element : elements) {
pdfExporter.getDocument().add((IBlockElement)element);
}
As a result, I received report without graphics
英文:
I have leaflet map in my Vaadin site:
I need export this DIV block (as a picture) into PDF file (i use iText 7 https://kb.itextpdf.com/home):
Here I found the information
*
https://kb.itextpdf.com/home/it7kb/ebooks/itext-7-converting-html-to-pdf-with-pdfhtml/chapter-1-hello-html-to-pdf*
about export HTML to PDF file.
I have problem:
iText 7 need IElement, but I have only vaadin element.
Please tell me how to convert vaadin element to iText element?
I try get OuterHTML from vaadin element:
String HTML = this.getElement().getOuterHTML();
var elements = HtmlConverter.convertToElements(HTML);
for (IElement element : elements) {
pdfExporter.getDocument().add((IBlockElement)element);
}
As a result , I received report without graphics
答案1
得分: 1
Vaadin中的Element API不会将所有内容保存在服务器端内存中。您应该将其视为一种代理,只传递对客户端和返回客户端所需的内容。getOuterHTML
返回的只是浏览器端实际内容的一部分。几乎您元素内的所有内容都是由LeafletJS渲染的,因此服务器端代理对其内容一无所知。这就是为什么您尝试的方法永远不会起作用的原因。
我看到您有两个选项。首先,您可以使用executeJS来获取完整的HTML。但我会感到惊讶,如果iText能以有意义的方式解释Leaflet提供的相当复杂的结构。
可能更好的解决方案是首先使用某种方式在浏览器端将当前视图渲染为图像,然后将该图像转发给iText。这个HTMLtoCANVAS可能会有所帮助(免责声明:我自己从未使用过)。
英文:
The Element API in Vaadin does not hold everything on the server-side memory. You should think of it more as a proxy that just communicates what is necessary to the client side and back. What the getOuterHTML returns is just a fraction of the actual content on the browser side. Pretty much everything inside your element is rendered by LeafletJS, so the server side proxy knows nothing about its contents. That's why the thing you are trying will never work that way.
I see you have two options. First would be to fetch the full html with executeJS instead. But I would be surprised if iText can interpret the rather complex structure provided by Leaflet in a meaningful way.
Probably a better working solution would be to use something to render the current view on the browser side into an image first and then forward that image to iText. This HTMLtoCANVAS might be helpful (disclaimer: I have never used it myself).
答案2
得分: 0
非常感谢HTMLtoCANVAS插件。
我也遇到了一个问题,图片保存时出现错误。几何形状在地图上的位置不正确。
原来是:
现在是:
我找到了一个解决方案,让Leaflet使用CANVAS而不是SVG来绘制形状。
renderer: L.canvas()
现在插件运行得很好。非常感谢。
英文:
Thank you very much for the HTMLtoCANVAS plugin.
I also had a problem that the picture was incorrect saved.The geometric shapes were located in another place on the map.
It was:
Become:
I found a solution to let Leaflet use CANVAS instead of SVG for shapes.
renderer: L.canvas()
Now the plugin works great. Many thanks.
答案3
得分: 0
如果您需要使用Leaflet地图,可以使用Leaflet-Simple-Map-Screenshoter插件 https://github.com/grinat/leaflet-simple-map-screenshoter
我为此创建了以下类
import com.vaadin.flow.component.internal.PendingJavaScriptInvocation;
import com.vaadin.flow.component.internal.UIInternals;
import com.vaadin.flow.dom.Element;
import com.vaadin.flow.internal.StateNode;
import org.apache.commons.lang3.StringUtils;
import tetramap.gui.MapView;
import java.util.concurrent.CompletableFuture;
public class HtmlToCanvas {
MapView mapView;
public HtmlToCanvas(MapView mapView) {
this.mapView = mapView;
}
public CompletableFuture<String> takeScreenShot(Element e) {
CompletableFuture<String> future = new CompletableFuture<>();
String id = e.getAttribute("id");
if (StringUtils.isEmpty(id)) {
e.setAttribute("id", "elementForScreenShot");
id = e.getAttribute("id");
}
StateNode node = e.getNode();
getJavaScriptInvoke(node, "let element = document.querySelector('#" + id + "');\n" +
"this.simpleMapScreenshoter = L.simpleMapScreenshoter().addTo(" + mapView.getMap().getId() + ")\n" +
"let format = 'canvas' \n" +
"let overridedPluginOptions = {\n" +
" mimeType: 'image/png'\n" +
"}\n" +
"function send(canvas) {\n" +
"canvasValue = canvas.toDataURL()\n" +
"element.dispatchEvent(new Event('canvasReady'));\n" +
"}\n" +
"this.simpleMapScreenshoter.takeScreen(format, overridedPluginOptions).then(canvas => {\n" +
"console.info(canvas)\n" +
"send(canvas);\n" +
"}).catch(e => {\n" +
" console.error(e)\n" +
"})"
);
e.addEventListener("canvasReady", l -> getJavaScriptReturn(node, "canvasValue.valueOf()").then(jsonValue -> future.complete(jsonValue.asString())));
return future;
}
public PendingJavaScriptInvocation getJavaScriptInvoke(StateNode node, String expression) {
UIInternals.JavaScriptInvocation invocation = new UIInternals.JavaScriptInvocation(expression);
PendingJavaScriptInvocation pending = new PendingJavaScriptInvocation(node, invocation);
node.runWhenAttached((ui) -> ui.getInternals().getStateTree().beforeClientResponse(node, (context) -> {
if (!pending isCanceled()) {
context.getUI().getInternals().addJavaScriptInvocation(pending);
}
}));
return pending;
}
public PendingJavaScriptInvocation getJavaScriptReturn(StateNode node, String expression) {
return getJavaScriptInvoke(node, "return " + expression);
}
}
如何使用takeScreenShot()与Vaadin
HtmlToCanvas htmlToCanvas = new HtmlToCanvas(mapView);
CompletableFuture<String> completableFuture = htmlToCanvas.takeScreenShot(mapView.getElement());
completableFuture.thenRun(() -> {
Image image = new Image(completableFuture.get(), "screenshot");
String immagineBase64 = vaadinImage.getSrc().substring(22);
byte[] imageBytes = Base64.getDecoder().decode(immagineBase64.getBytes(StandardCharsets.UTF_8));
// ...
});
英文:
If you need to use a leaflet map, you can use the plugin leaflet-simple-map-screenshoter https://github.com/grinat/leaflet-simple-map-screenshoter
I created the following class for it
import com.vaadin.flow.component.internal.PendingJavaScriptInvocation;
import com.vaadin.flow.component.internal.UIInternals;
import com.vaadin.flow.dom.Element;
import com.vaadin.flow.internal.StateNode;
import org.apache.commons.lang3.StringUtils;
import tetramap.gui.MapView;
import java.util.concurrent.CompletableFuture;
public class HtmlToCanvas {
MapView mapView;
public HtmlToCanvas(MapView mapView) {
this.mapView = mapView;
}
public CompletableFuture<String> takeScreenShot(Element e){
CompletableFuture<String> future = new CompletableFuture<>();
String id = e.getAttribute("id");
if (StringUtils.isEmpty(id)) {
e.setAttribute("id", "elementForScreenShot");
id = e.getAttribute("id");
}
StateNode node = e.getNode();
getJavaScriptInvoke(node, "let element = document.querySelector('#" + id + "');\n" +
"this.simpleMapScreenshoter = L.simpleMapScreenshoter().addTo(" + mapView.getMap().getId() + ")\n" +
"let format = 'canvas' \n" +
"let overridedPluginOptions = {\n" +
" mimeType: 'image/png'\n" +
"}\n" +
"function send(canvas) {\n" +
"canvasValue = canvas.toDataURL()\n" +
"element.dispatchEvent(new Event('canvasReady'));\n" +
"}\n" +
"this.simpleMapScreenshoter.takeScreen(format, overridedPluginOptions).then(canvas => {\n" +
"console.info(canvas)\n" +
"send(canvas);\n" +
"}).catch(e => {\n" +
" console.error(e)\n" +
"})"
);
e.addEventListener("canvasReady", l -> getJavaScriptReturn(node, "canvasValue.valueOf()").then(jsonValue -> future.complete(jsonValue.asString())));
return future;
}
public PendingJavaScriptInvocation getJavaScriptInvoke(StateNode node, String expression) {
UIInternals.JavaScriptInvocation invocation = new UIInternals.JavaScriptInvocation(expression);
PendingJavaScriptInvocation pending = new PendingJavaScriptInvocation(node, invocation);
node.runWhenAttached((ui) -> ui.getInternals().getStateTree().beforeClientResponse(node, (context) -> {
if (!pending.isCanceled()) {
context.getUI().getInternals().addJavaScriptInvocation(pending);
}
}));
return pending;
}
public PendingJavaScriptInvocation getJavaScriptReturn(StateNode node, String expression) {
return getJavaScriptInvoke(node, "return " + expression);
}
}
And how to use takeScreenShot() with Vaadin
HtmlToCanvas htmlToCanvas = new HtmlToCanvas(mapView);
CompletableFuture<String> completableFuture = htmlToCanvas.takeScreenShot(mapView.getElement());
completableFuture.thenRun(() -> {
...
Image image = new Image(completableFuture.get(), "screenshot");
String immagineBase64 = vaadinImage.getSrc().substring(22);
byte[] imageBytes = Base64.getDecoder().decode(immagineBase64.getBytes(StandardCharsets.UTF_8));
...
});
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论