Export svg to png/tiff with foreignObject - javascript
Im using https://github.com/jgraph/drawio (mxgraph) for a project. I use AngularJS for frontend and NodeJS/Express for backend. The idea is to do a diagram design and then be able to export it/print it among other things.
Im able to interact with the backend and do the diagram but having trouble with the printing/rendering.
The problem is that the generated svg contains foreinObject for a QR and Barcode. While the diagram is rendered/displayed on the frontend, i need to generate a png/tiff in order to send it to a printer, but nodejs is not capable to render the foreinObject elements. I
tested canvg, sharp on node but foreignObject are not supported (according to some issues on github).
This is an example svg:
<svg width='600' height='500'>
<g xmlns="http://www.w3.org/2000/svg" fill="#464445" font-family="Lucida Console" pointer-events="none" text-anchor="middle" font-size="72px">
<text x="350" y="135">ABCDEF12345</text>
</g>
<g xmlns="http://www.w3.org/2000/svg">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 130px; margin-left: 300px;">
<div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #774400; ">
<div style="display: inline-block; font-size: 11px; font-family: Arial, Helvetica; color: rgb(119, 68, 0); line-height: 1.2; pointer-events: none; white-space: nowrap;">
<img src="data:image/png;base64,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" />
</div>
</div>
</div>
</foreignObject>
<text x="300" y="133" fill="#774400" font-family="Arial,Helvetica" font-size="11px" text-anchor="middle">[Object]</text>
</switch>
</g>
<g xmlns="http://www.w3.org/2000/svg">
<switch>
<foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 340px; margin-left: 450px;">
<div style="box-sizing: border-box; font-size: 0px; text-align: center;" data-drawio-colors="color: #774400; ">
<div style="display: inline-block; font-size: 11px; font-family: Arial, Helvetica; color: rgb(119, 68, 0); line-height: 1.2; pointer-events: none; white-space: nowrap;">
<div title="Diagram Title">
<canvas style="display: none;" width="200" height="200"></canvas>
<img style="display: block;" src="data:image/png;base64,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" />
</div>
</div>
</div>
</div>
</foreignObject>
<text x="450" y="343" fill="#774400" font-family="Arial,Helvetica" font-size="11px" text-anchor="middle">[Object]</text>
</switch>
</g>
</svg>
And should look like this: Test svg. With sharp/canvg the QR and barcode are not displayed and instead [Object] is displayed on the final png/tiff. Even tryied C# SVG NuGet and htm2canvas for rendering on backend with same issue.
I've seen some posts on how to render canvas.toDataURL to png with but i dont have a object on the document DOM since mxgraph works differently and only have the final available as string. Any ideas on how can i remove the foreignObjects or how to modify the svg manually?
Is possible to "create" a canvas element and render the svg inside and then export it?
So, after #ccprog answer, i realized what i needed to do. I was trying badly to create a new canvas, copy the child element attributes, render again, use libraries to do that with no success.
With that answer the idea was simple: Grab the img src, create new child, remove foreignObject.
I had some issues with the x,y coordinates since the image was not centered (mxgraph uses padding-top and margin-left) and the code end up being this
var newXml = xmlCanvas.root;
for(var i = 0; i < newXml.children.length; i++){
var child = newXml.children[i];
if(child.tagName == 'g' && child.children[0].tagName == "switch"){
var imgChild = child.getElementsByTagName("img")[0];
var foreignObjectChild = child.getElementsByTagName("foreignObject")[0];
var textChild = child.getElementsByTagName("text")[0];
var image = document.createElement("image");
image.setAttribute("href", imgChild.src);
let marginLeft = Number(foreignObjectChild.firstChild.style.marginLeft.replace("px", ""));
image.setAttribute("x", marginLeft - imgChild.naturalWidth/2);
let paddingTop = Number(foreignObjectChild.firstChild.style.paddingTop.replace("px", ""));
image.setAttribute("y", paddingTop - imgChild.naturalHeight/2);
image.setAttribute("xmlns", "http://www.w3.org/2000/svg");
newXml.children[i].firstChild.appendChild(image);
newXml.children[i].firstChild.removeChild(foreignObjectChild);
newXml.children[i].firstChild.removeChild(textChild);
}
}
Its kinda hardcoded for this example but it works. Not expert on javascript but this probably can be optimized/rewrited in a better way.
One issue i encountered is that the final svg has the tags "<a0:image" and "<a1:image" etc... but then i use regex and remove de a0/a1/aN. Dont know why, probably some bug on how i create/append the child elements.
Related
How can I create a Collapsible menu?
How can I create a Collapsible menu on "Cheat Status" and another on the "RainbowSixSiege Cheats". I'm good at structuring sites with html and css but I'm denied with javascript The complete code did not enter, I copied the main part, I hope there is everything you need If you need anything I can send you the complete file, however I only need the javascript code to make these two "Menus" work button { display: inline-block; border: none; background: none; cursor: pointer; } .product-status-box { background-color: #fff; box-shadow: 12px 12px 30px 0px rgba(0, 0, 0, 0.15); padding: 3.2rem 6.4rem; border-radius: 22px; margin-top: 3.2rem; } .product-status { display: flex; justify-content: space-between; align-items: center; width: 100%; } .product-status-title { font-size: 1.8rem; font-weight: 700; } .product-status-icon { width: 2.4rem; } .margin-top { margin-top: 1.6rem; } .hidden-box { } .hidden-box-btn { display: flex; align-items: center; gap: 1.2rem; } .hidden-box-btn h3 { font-size: 1.6rem; font-weight: 600; margin-bottom: 0.4rem; } .product-icon { width: 2rem; } .hidden-2nd-box { display: flex; justify-content: space-between; align-items: center; font-size: 1.4rem; font-weight: 500; } <div class="product-status-box"> <button type="button" class="product-status"> <h2 class="product-status-title">Cheats Status</h2> <svg xmlns="http://www.w3.org/2000/svg" class="product-status-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" > <path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7" /> </svg> </button> <div class="hidden-box"> <button type="button" class="hidden-box-btn margin-top"> <h3>RainbowSixSiege Cheats</h3> <svg xmlns="http://www.w3.org/2000/svg" class="product-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" > <path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7" /> </svg> </button> <div class="hidden-2nd-box"> <p>Klar.gg</p> <p class="green-text">Operational</p> </div> </div> </div>
This is going to be tricky one I will suggest you to add jQuery UI and put these tags in your HTML head element <script src="https://code.jquery.com/jquery-3.6.0.js"></script> <script src="https://code.jquery.com/ui/1.13.1/jquery-ui.js"></script> NOW add this jQuery code in your JavaScript and link it to your html just like you link external CSS in index.html like this <script src=" *your file path of JavaScript* "></script> now add these line in your JavaScript file $(document).ready(function () { $('').click(function () { //add your class or id in the click function $('').slideToggle(); //here you add class or id which you want to show when user click on button }); }); quotes in the above brackets are compulsory don't remove them place your class or id inside them repeat this one with second button with different class or id. Hope this will solve your problem.
Making the div follow autoresize textarea? [closed]
Closed. This question needs to be more focused. It is not currently accepting answers. Want to improve this question? Update the question so it focuses on one problem only by editing this post. Closed 2 years ago. Improve this question PROBLEM I have a comment textarea which i made text responsive thanks to Jack Moores npm package https://www.jacklmoore.com/autosize/. Now this all works fine but i have a div which is usually bottom:75px; and when textarea autoresizes it updates the hight of textarea. This is where the problem occurs i would like to update also bottom of that div for example to keep it from going over textarea. HTML <form action="#"> <textarea type="text" id="text" spellcheck="false" placeholder="Type message..." maxlength="50" ></textarea> </form> <div class="three_dots_messages" onclick="toggleMessagesSettings()"></div> <div class="three_dots_messages_menu"> <div class="three_dots_messages_menu_buttons"> <div class="send_tip_button all_message_buttons" > <span>Send tip</span> <svg xmlns="http://www.w3.org/2000/svg" width="7.886" height="15" viewBox="0 0 7.886 15" style="margin: 2px 0 0 2px ;"> <path id="Icon_awesome-dollar-sign" data-name="Icon awesome-dollar-sign" class="cls-1" d="M5.731,6.838,2.773,5.912a.861.861,0,0,1-.581-.829A.837.837,0,0,1,3,4.219H4.817a1.6,1.6,0,0,1,.937.308.406.406,0,0,0,.534-.059l.953-1a.5.5,0,0,0-.049-.718,3.716,3.716,0,0,0-2.369-.879V.469A.456.456,0,0,0,4.384,0H3.507a.456.456,0,0,0-.438.469V1.875H3a3.133,3.133,0,0,0-2.985,3.5,3.293,3.293,0,0,0,2.3,2.83l2.807.879a.864.864,0,0,1,.581.829.837.837,0,0,1-.808.864H3.075a1.6,1.6,0,0,1-.937-.308.406.406,0,0,0-.534.059l-.953,1a.5.5,0,0,0,.049.718,3.716,3.716,0,0,0,2.369.879v1.406A.456.456,0,0,0,3.507,15h.876a.456.456,0,0,0,.438-.469V13.119a3.108,3.108,0,0,0,2.9-2.13A3.264,3.264,0,0,0,5.731,6.838Z" transform="translate(-0.003)"/> </svg> </div> <div class="chat_rules_button all_message_buttons" > <span>Chat rules</span> <svg xmlns="http://www.w3.org/2000/svg" width="13.125" height="15" viewBox="0 0 13.125 15"> <path id="Icon_awesome-book-dead" data-name="Icon awesome-book-dead" class="cls-1" d="M7.969,3.984A.469.469,0,1,0,7.5,3.516.47.47,0,0,0,7.969,3.984ZM13.125,10.5V.75a.69.69,0,0,0-.75-.75H2.813A2.762,2.762,0,0,0,0,2.813v9.375A2.762,2.762,0,0,0,2.813,15h9.563a.739.739,0,0,0,.75-.75v-.469a.81.81,0,0,0-.281-.562,8.292,8.292,0,0,1,0-2.156.567.567,0,0,0,.281-.562ZM7.031,1.641A2.15,2.15,0,0,1,9.375,3.516a1.778,1.778,0,0,1-.937,1.491v.384a.47.47,0,0,1-.469.469H6.094a.47.47,0,0,1-.469-.469V5.007a1.778,1.778,0,0,1-.937-1.491A2.15,2.15,0,0,1,7.031,1.641Zm-3.375,4.9.185-.431a.233.233,0,0,1,.308-.123l2.88,1.233L9.911,5.988a.233.233,0,0,1,.308.123l.185.431a.233.233,0,0,1-.123.308l-2.06.885,2.06.882a.233.233,0,0,1,.123.308l-.185.431a.233.233,0,0,1-.308.123L7.031,8.244,4.151,9.48a.233.233,0,0,1-.308-.123l-.185-.431a.233.233,0,0,1,.123-.308l2.063-.882L3.779,6.85a.233.233,0,0,1-.123-.308Zm7.5,6.583H2.813a.886.886,0,0,1-.937-.937.939.939,0,0,1,.938-.937h8.344ZM6.094,3.984a.469.469,0,1,0-.469-.469A.47.47,0,0,0,6.094,3.984Z"/> </svg> </div> <div class="muted_users all_message_buttons" > <span>Muted users</span> <svg xmlns="http://www.w3.org/2000/svg" width="16.071" height="15" viewBox="0 0 16.071 15"> <path id="Icon_metro-volume-mute2" data-name="Icon metro-volume-mute2" class="cls-1" d="M18.642,13.15V14.57H17.222l-1.794-1.794L13.634,14.57H12.214V13.15l1.794-1.794L12.214,9.562V8.142h1.421l1.794,1.794,1.794-1.794h1.421V9.562l-1.794,1.794ZM9.535,18.856a.535.535,0,0,1-.379-.157L5.027,14.57H3.106a.536.536,0,0,1-.536-.536V8.677a.536.536,0,0,1,.536-.536H5.027L9.156,4.013a.536.536,0,0,1,.915.379V18.32a.536.536,0,0,1-.536.536Z" transform="translate(-2.571 -3.856)"/> </svg> </div> <div class="close_chat_button all_message_buttons" onclick="toggleMessagesSettings(), toggleMessages() "> <span>Close chat</span> <svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 15 15"> <path id="Icon_material-close" data-name="Icon material-close" class="cls-1" d="M22.5,9.011,20.989,7.5,15,13.489,9.011,7.5,7.5,9.011,13.489,15,7.5,20.989,9.011,22.5,15,16.511,20.989,22.5,22.5,20.989,16.511,15Z" transform="translate(-7.5 -7.5)"/> </svg> </div> </div> </div> CSS .three_dots_messages_menu { position: fixed; width: 15%; height: 130px; min-width: 232px; bottom: -250px; background-color: #363636; border-radius: 5px; opacity: 0; transition: 0.3s; } #text { border: 1px solid #d4af37; background-color: #343333; position: fixed; bottom: 15px; margin: 0 auto; font-size: 17px; width: 13%; padding: 12px 30px 5px 10px; color: white; border-radius: 5px; min-width: 190px; min-height: 33px; height: 33px; max-height: 100px; outline: none; resize: none; } SOME INFORMATION AND QUESTIONS I need to keep it position absolute not just fix this with margins. I know i can do this modifying the js of autosize but i am honestly not skilled enough to completely understand everything that is going on. Is there a way to maybe manipulate the DOM so i can make div children of that textarea ? Do you know maybe easy js fix ? JS for autoresize is too big you can view it from the website
It's best if you simply move the menu to a point before the textarea and remove its fixed positioning, so that it automatically remains in place. If you want to adapt it dynamically, Autosize triggers an event where you can hook some code to update its position. var $text = jQuery('#text'), $menu = jQuery('.three_dots_messages_menu'), baseDistance = 75; $text.on( 'autosize:resized', function() { $menu.css( 'bottom', $text.height() + baseDistance + 'px' ); })
Centering SVG image inside parent SVG
I am preparing a presentation in HTML/CSS/Javascript using the following code. What I want is to centre an SVG image in the main SVG. From what I understand, the viewBox of the main SVG establishes a new coordinate system. So, when I try to centre the image using the half of its width (similar to "text-anchor="middle"") I do not get what I expect, the image is shifted but not enough to be in the centre. <!doctype html> <meta charset="utf-8"> <script src="./js/d3.js"></script> <style> body { margin:0; /*border: 5px solid green; /*for testing*/ display:block; padding-top: 0px; height: 100vh; background-color: rgba(0,0,0,1); font-family: Helvetica; } body svg { /*border: 1px solid #C1543D;*/ /*for testing*/ display:block; margin: auto; } .slideBackground { fill: white; } .slideHeader{ font-size: 38; } </style> <body> <svg width="100%" height="100%" viewBox="0 0 1024 768"> <!-- 1024 and 768 are expressed in units of the SVG's viewport (NOT pixels)--> <rect class="slideBackground" x="0%" y="0%" width="100%" height="100%"/> <!-- rect for viewbox--> <g id="equation"> <svg x="50%" y="70%" width="30%" height="6%" viewBox="0 0 35 5" preserveAspectRatio="xMidYMid"> <image x="0" y="0" width="100%" height="100%" xlink:href="bayesTheorem.svg"></image> </svg> </g> </svg> </body> <script> var eqSVG = document.getElementById("equation"); var rec = eqSVG.getBoundingClientRect().width; d3.select("#equation").attr("transform", "translate(" + (-rec/2) + ",0)") </script>
I fixed the issue. I just changed image x="0" to image="-50%" and removed the D3 selection
How to create an SVG tooltip with help of the Menucool JS plugin?
I have an SVG “map”, and I want to implement a simple tooltip when the mouse is hovered over a rectangle. For the tooltip I want to use this plugin. Here is how I link SVG to HTML: <object data="map.svg" type="image/svg+xml" id="map" width="1840" height="940"></object> The First Try was like this: var svgobject = document.getElementById('map'); if ('contentDocument' in svgobject) { var svgdom = $(svgobject.contentDocument); $("#rect4578").tooltip.pop(this, '#ToltipContent'); } And the tooltip container is as follows: <div style="display:none;"> <div id="ToltipContent"> <h2>Header</h2> <img src="img/img.jpg" style="float:right;" /> Some text </div> </div> I also added the toolpip class to the rect4578 as it is explained on the plugin site. However it didn't work. Then I tried to add the plugin invocation inside onmouseover attribute of the SVG rectangle. onmouseover="tooltip.pop('#rect4578', '#ToltipContent')" And also I got nothing. However, if I change the opacity of the rectangle by using either of above described methods it works. And the question is what is the right way to use this plugin to implement tooltip for the SVG? Thank you.
Since I didn't have access to your object, I used an svg from w3schools and it seemed to work fine. Here's what I did to get it to work: .hide {display:none;} #object {width: 100px; overflow: hidden; margin: 0 auto;} #object svg {padding: 20px;} div#mcTooltip h2 { margin-top: 10px; line-height: 1; } #mcTooltip ul, #mcTooltip ol { padding-left: 20px; } div#mcTooltip { line-height: 16px; border-width: 1px; color: #333; border-color: #bbb; padding: 20px; font-size: 12px; font-family: Verdana, Arial; border-radius: 6px; box-shadow: 0 1px 4px #aaa; } div#mcTooltip, div.mcTooltipInner { background-color: #eee; } div#mcTooltip a { color: #069; } div#mcTooltip a:hover { color: #333; } div#mcTooltipWrapper { position: absolute; visibility: hidden; overflow: visible; z-index: 9999999999; top: 0; } div#mcTooltip { float: left; border-style: solid; position: relative; overflow: hidden; } div.mcTooltipInner { float: left; position: relative; width: auto; height: auto; } div#mcTooltip, div#mcTooltip div { -webkit-box-sizing: content-box; -moz-box-sizing: content-box; box-sizing: content-box; } div#mcttCo { position: absolute; text-align: left; } div#mcttCo em, div#mcttCo b { display: block; width: 0; height: 0; overflow: hidden; } <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script> <script src="http://www.menucool.com/Content/widgets?v=pWIjgyLaRd3JgPu8kRMWTBEFhPIETaPsvP81TXLgnbE1"></script> <div class="hide"> <div id="toolTipContent">Tooltip text goes here</div> </div> <br/> <br/> <br/> <object id="object" type="image/svg+xml" data="http://www.schepers.cc/svg/blendups/smiley.svg"><svg width="100" height="100"> <rect width="100" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" onmouseover="tooltip.pop(this, '#toolTipContent', {position:2})" /> </svg><svg width="100" height="100"> <rect width="100" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" onmouseover="tooltip.pop(this, '#toolTipContent', {position:2})" /> </svg><svg width="100" height="100"> <rect width="100" height="100" style="fill:rgb(0,0,255);stroke-width:1;stroke:rgb(0,0,0)" onmouseover="tooltip.pop(this, '#toolTipContent', {position:2})" /> </svg></object>
It looks like the problem with your original approach is that the object tag does not support 'onmouseover' https://developer.mozilla.org/en-US/docs/Web/HTML/Element/object. I am using the an img tag instead. This is a very minor change from the first answer. var svg = document.getElementById('kiwi'); svg.onmouseover = function() {tooltip.pop(this, '#tooltip');} .hide {display:none;} <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script> <script src="http://www.menucool.com/Content/widgets?v=pWIjgyLaRd3JgPu8kRMWTBEFhPIETaPsvP81TXLgnbE1"></script> <div class=""> <img id="kiwi" height="200" width="200" src="http://s.cdpn.io/3/kiwi.svg"> </div> <div class="hide"> <span id="tooltip" > This is a tooltip. </span> </div>
render one div and it's interactive content by clicking on another div
<div id="1" class="aaa" style="position: relative; left: 50px; top: 50px; width: 300px; height: 200px; border: solid 1px; background: #dddddd; overflow: hidden;"> <div style="position: relative; left: 30px; top: 25px; width: 100px; height: 50px; background: blue;" onmouseenter="this.style.background='red';"></div> <div style="position: relative; left: 160px; top: 70px; width: 100px; height: 50px; background: blue;" onmouseenter="this.style.background='orange';"></div> </div> <div id="2" class="bbb" style="position: relative; left: 250px; top: 100px; width: 50px; height: 20px; border: solid 1px; background: #cccccc; text-align: center; overflow: hidden;">click</div> http://jsfiddle.net/FWyBQ/ I have one div (id="1" class="aaa") which contains multiple interactive divs. State of this interactive content should be able to be rendered as image (gif?) with the click on the other div (id="2" class="bbb"). That image should preferably be opened in a new tab or window. Or maybe just right click > save as in place. p.s. I am aware of scripts like html2canvas and phantomjs, but I have no idea how to implement them in my case. edit: Now I'm trying to implement this solution, which with a little tweaking should work with processing.js (http://cloud.github.com/downloads/processing-js/processing-js/processing-1.4.1.min.js). I guess I just need the right jquery code with processing.js in order to achieve the functionality I need. I've tried this and it doesn't work: $('.bbb').click(function (e) { var canvas = document.getElementById("1"), img = canvas.toDataURL("image/png"); $('.aaa').document.write('<img src="'+img+'"/>'); });
You could use html2canvas for this; include the html2canvas library in your page and try something like this: //element would be your aaa div html2canvas(element, { onrendered: function(canvas) { // canvas is the resulting canvas generated from the element var url = canvas.toDataURL("image/png"); } }); You would then need to post the value of 'url' to a PHP script like in one of the answers to this question. EDIT The reason your new code doesn't work is because the element with an id of "1" is not a canvas element. Its a div. Canvas methods like toDataUrl() can only be called on Canvas elements (which is why I suggested using html2canvas to change your div into a Canvas.) I've forked your jsfiddle to show how the code could work if the element with id "1" was a canvas: http://jsfiddle.net/_Pez/cksGt/1/ _Pez
If I was in your pants, I'd start by switching the first div to SVG notation. It's not that different and there are a ton of ways to export an svg object to png. This should get you started <svg id="1" class="aaa" width="400" height="250"> <g> <rect id="svg_0" height="200" width="300" y="50" x="50" stroke-width="1" stroke="#000000" fill="#dddddd"/> <rect id="svg_1" height="50" width="100" y="75" x="80" stroke-width="5" fill="blue"/> <rect id="svg_2" height="50" width="100" y="120" x="210" stroke-width="5" fill="blue"/> </g> </svg> <div id="2" class="bbb" style="position: relative; left: 250px; top: 100px; width: 50px; height: 20px; border: solid 1px; background: #cccccc; text-align: center; overflow: hidden;">click</div>