How to load a GV file in d3-graphviz? - javascript

I am trying to visualise a GV file with D3-Graphviz library. I have called the GV file directly in my code:
<script src="https://unpkg.com/#hpcc-js/wasm#0.3.11/dist/index.min.js"></script>
<script src="https://unpkg.com/d3-graphviz#3.0.5/build/d3-graphviz.js"></script>
<div id="graph" style="text-align: center;"></div>
<script>
let dots = new FileReader();
dots.readAsText('G.gv')
let dotIndex = 0;
let graphviz = d3.select("#graph").graphviz()
.transition(function () {
return d3.transition("main")
.ease(d3.easeLinear)
.delay(500)
.duration(1500);
})
.logEvents(true)
.on("initEnd", render);
function render() {
var dotLines = dots[dotIndex];
var dot = dotLines.join('');
graphviz
.addImage("images/Officer.png", "50px", "50px")
.addImage("images/Manager.png", "50px", "50px")
.addImage("images/Employee.png", "50px", "50px")
.addImage("images/Service.png", "50px", "50px")
.renderDot(dot);
}
My GV file currently looks like this:
digraph G {
graph [center=true rankdir=LR ratio=compress size="15,10"]
"MainOfficer" [label="MainOfficer" fontsize=10 image="images/MainOfficer.png" shape=plaintext]
"Employee" [label="MainOfficer" fontsize=10 image="images/Employee.png" shape=plaintext]
"Supporter" [label="MainOfficer" fontsize=10 image="images/Manager.png" shape=plaintext]
}
However, when I opened the HTML file, no graph is shown, and when I checked into the console the error is Failed to execute ReadAsText as parameter 1 is not of type "Blob".
I have tried multiple ways to load the G.gv file into the website (from converting it into text and parse to the Javascript code, to rendering GV file to SVG), however none of my approach worked.
So I would like to ask that is there anyway I could load a GV file to d3-Graphviz, so that my graph could be shown without my need to paste the GV file content directly to the Javascript file?
Thank you!

Related

Appending a circle to an svg using javascript called by php

I have been searching for an answer that will work and have been unable to find one.
I have a game map that I am using for an RP guild. I am using the map to display influence which we hold in that game's world. I have no issue displaying the map if I have it all coming through in echo statements in php, however, what I would like to do is only have the influence areas draw on the map as pulled from the database.
I have the following function which works when called from within my .js file:
function drawInfluence(id, x, y, inf, dis) {
svg = document.getElementById("small_map");
var pt = svg.createSVGPoint();
pt.x = x;
pt.y = y;
var c = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
c.setAttribute('id',"c"+id);
c.setAttribute('r',"15");
c.setAttribute('cx',pt.x);
c.setAttribute('cy',pt.y);
c.setAttribute('fill',inf);
c.setAttribute('stroke-width','5');
c.setAttribute('stroke',dis);
svg.appendChild(c);
}
This function works perfect if I call it like this:
$(document).ready(function() {
$("#small_map").load( function() {
drawInfluence(1, 150, 150, "red", "blue");
});
});
However, if I use:
$(document).ready(function() {
$("#small_map").load( function() {
$.ajax({
url: 'scripts/inf_map_load.php',
success: function () {
// There is nothing to do here right now
}
});
});
});
with a PHP file that looks like:
<?php
echo' drawInfluence(1, 150, 150, "red", "blue");';
?>
or like
<?php
echo' <script type="text/javascript">drawInfluence(1, 150, 150, "red", "blue");</script>';
?>
I receive no output at all.
The function is in my .JS file along with my other JQuery callbacks for other functions (which are working perfectly fine.)
I have also tried:
$(document).ready(function() {
$("#small_map").load( function() {
$.ajax({
url: 'scripts/inf_map_load.php',
success: function () {
alert("Testing");
drawInfluence(1, 150, 150, "red", "blue");
}
});
});
});
And the circle will draw where it's supposed to as well as the alert popping up I can't use the drawInfluence from this area though because the end goal is to have the the information for the javascript call to be read from a database which contains multiple rows of data which will each have a unique identifier for hover and click events. Writing the entire document using php echo statements works, but is not the most efficient and I would prefer to use callbacks rather than inline svg javascript.
After playing around with it some more I found that placing an empty div tag with an id and using the following code I was able to get the script to do what I wanted though it draws the influence areas before the map finishes loading. Not a big issue but not aesthetically pleasing either.
In my .JS file:
$(document).ready(function() {
$("#map_load").load("scripts/inf_map_load.php");
});
My PHP file
<?php
echo'<script type="text/javascript">drawInfluence(1, 150, 150, "red", "blue")';
?>
And the empty div which made it work
<div id="map_load"></div>
I still don't know if this was the best way to do what I needed, but it's working now and that was more important at the moment. Appreciate the replies I did get.

Downloading a qrcode.js-generated QR code

I've searched the web countless times trying to find a way to solve this but I've come up empty-handed every time. I have been using qrcode.js to generate QR codes for a website, but I haven't figured out how to download the image once it's been generated. The code I use to generate the QR code looks like this:
var myQR = new QRCode(document.getElementById("qrcode"), {
text: "Made with QR Generator",
width: 128,
height: 128,
colorDark : qrdarkcolor,
colorLight : qrlightcolor,
correctLevel : QRCode.CorrectLevel.H
});
myQR.makeCode(qrdata);
I am trying to find a way to either download the QR code within the div or find the source and create a button that users can click on to download the image. I apologize if this is a commonly asked question, but I've searched many other questions that are similar to this and haven't found a clear answer. I would prefer to keep this site with only HTML, CSS, and Javascript if possible.
Thanks!
The image is generated through the plugin and takes a moment to render, so the method needs to be done with setTimeout. After that, we grab the src of the image and apply it to a download link (a link that has the attribute download in it)
Note this won't work in the snippet sandbox, but it's been tested on a normal web page and works great.
const makeQR = (url, filename) => {
var qrcode = new QRCode("qrcode", {
text: "http://jindo.dev.naver.com/collie",
width: 128,
height: 128,
colorDark: "#000000",
colorLight: "#ffffff",
correctLevel: QRCode.CorrectLevel.H
});
qrcode.makeCode(url);
setTimeout(() => {
let qelem = document.querySelector('#qrcode img')
let dlink = document.querySelector('#qrdl')
let qr = qelem.getAttribute('src');
dlink.setAttribute('href', qr);
dlink.setAttribute('download', 'filename');
dlink.removeAttribute('hidden');
}, 500);
}
makeQR(document.querySelector('#text').value, 'qr-code.png')
#qrcode {
width: 160px;
height: 160px;
margin-top: 15px;
}
<script src="https://cdn.jsdelivr.net/npm/davidshimjs-qrcodejs#0.0.2/qrcode.min.js"></script>
<input id="text" type="text" value="https://stackoverflow.com" style="width:80%" /><br />
<div id="qrcode"></div>
<a id='qrdl' hidden>Download</a>
You can use Qurious to generate QR code in canvas and then download it. Qurious has also its own padding option (it makes white borders around the qr code so it's possible to scan it after download).
Add this at the <head> part:
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrious/4.0.2/qrious.min.js"></script>
Html body:
<canvas id="qrcode"></canvas>
Script:
const makeQR = (your_data) => {
let qrcodeContainer = document.getElementById("qrcode");
qrcodeContainer.innerHTML = "";
new QRious({
element: qrcodeContainer,
value: your_data,
size: 600,
padding:50,
}); // generate QR code in canvas
downloadQR(); // function to download the image
}
function downloadQR() {
var link = document.createElement('a');
link.download = 'filename.png';
link.href = document.getElementById('qrcode').toDataURL()
link.click();
}
makeQR("Your value")
I noticed that the 'qrcodejs' is returning img with blank src on mobile device browsers(Android -> Chrome), whereas it returns an img with valid src (data URI) when you request from mobile as a 'desktop agent'.
You could able to test it by debugging the mobile.

trying to modify the js function so that it gives the same output as it was when called the other js function

I am exporting the content on the webpage to the PDF file, for this i have used jsPDF API and i could able to get it work but now i want to use html2PDF as it resolves few issues which were faced when using jsPDF API.
I have written the function $scope.exportUsingJSPDF which is called when the button Export Using JSPDF is clicked. Similarly i want to implement the function $scope.exportUsingHTML2PDF which uses html2PDF API but could not succeed. Any inputs on how to modify $scope.exportUsingHTML2PDF so that it iterates the divs and shows the div content as shown when invoked using $scope.exportUsingJSPDF by clicking Export using JSPDF API.
Complete online example: https://plnkr.co/edit/454HUFF3rmLlkXLCQkbx?p=preview
js code:
//trying to implement the below function same as $scope.exportUsingJSPDF, so
// that when user click on Export using HTML2PDF button, it exports the content to the PDF and generaes the PDF.
$scope.exportUsingHTML2PDF = function(){
var pdf = new jsPDF('l', 'pt', 'a4');
var pdfName = 'test.pdf';
pdf.canvas.height = 72 * 11;
pdf.canvas.width = 72 * 8.5;
html2pdf(document.getElementByClassName("myDivClass"), pdf, function(pdf){
pdf.save(pdfName);
});
}
$scope.exportUsingJSPDF = function() {
var pdf = new jsPDF('p','pt','a4');
var pdfName = 'test.pdf';
var options = { pagesplit: true};
var $divs = $('.myDivClass') //jQuery object of all the myDivClass divs
var numRecursionsNeeded = $divs.length -1; //the number of times we need to call addHtml (once per div)
var currentRecursion=0;
//Found a trick for using addHtml more than once per pdf. Call addHtml in the callback function of addHtml recursively.
function recursiveAddHtmlAndSave(currentRecursion, totalRecursions){
//Once we have done all the divs save the pdf
if(currentRecursion==totalRecursions){
pdf.save(pdfName);
}else{
currentRecursion++;
pdf.addPage();
//$('.myDivClass')[currentRecursion] selects one of the divs out of the jquery collection as a html element
//addHtml requires an html element. Not a string like fromHtml.
pdf.fromHTML($('.myDivClass')[currentRecursion], 15, 20, options, function(){
console.log(currentRecursion);
recursiveAddHtmlAndSave(currentRecursion, totalRecursions)
});
}
}
pdf.fromHTML($('.myDivClass')[currentRecursion], 15, 20, options, function(){
recursiveAddHtmlAndSave(currentRecursion, numRecursionsNeeded);
});
}
PS: I was trying to modify $scope.exportUsingHTML2PDF so that it gives the same output as generated when clicked on "Export using JSPDF" button which calls the function $scope.exportUsingJSPDF.
The problem lies with your function using exportUsingHTML2PDF, the error is that you need to pass in the html to the function of html2PDF. Manage the page css on the basis of your need.
EDIT: You have wrong library. Please check html2pdf.js library within the plunker
Working plunker: html2pdf
$scope.exportUsingHTML2PDF = function() {
var element = document.getElementById('element-to-print');
html2pdf(element, {
margin: 1,
filename: 'myfile.pdf',
image: {
type: 'jpeg',
quality: 0.98
},
html2canvas: {
dpi: 192,
letterRendering: true
},
jsPDF: {
unit: 'in',
format: 'letter',
orientation: 'portrait'
}
});
}
With JSPDF and HTML2PDF, you have to get used to two fundamentally different coding styles:
JSPDF: imperative (javascript statements)
HTML2PDF: declarative (directives embedded in HTML)
So for page breaks:
JSPDF: pdf.addPage();
HTML2PDF: <div class="html2pdf__page-break"></div>
That should work, however HTML2PDF is buggy and gives a "Supplied data is not a JPEG" error when <div class="html2pdf__page-break"></div> is included (at least it does so for me, in Plunkr), despite being totally what the documentation tells us to do.
I haven't got time to debug it. You'll need to do some research. Someone will have posted a solution somewhere on the web.

how to export SVG graph to pdf

I am using a API which render the line graph in SVG but I am not able to export it into PDF like other graph which render in HTML5 canvas
$(function() {
// let's loop to build tooltips and x labels.
var thelabels = new Array(30);
for (var i = 0; i < 30; i++) {
thelabels[i] = (i % 6 === 0) ? (i + 1) + " september" : "";
}
// build the chart using the "google analytics" template.
$("#chart").chart({
template: "raphael_analytics",
labels: thelabels,
values: values()
});
// start a loop that sets new data in the chart every 5 seconds.
});
Code is available in jsfiddle
while searching I got a link where I can export SVG graph to PDF but the demo what they provided it is not working and they used Perl script to export.
I wanted to export from client/browser to canvas image data
Edited
I have seen one more library in github it allows you to download SVG to PDF from client side. But in the library they have used a object called "RGBColor(fillColor)" this throw an error like RGBColor is not defined so is there any library I need to include..???
I had to convert graphs and pie charts to pdf and wound up using this third party package. It converts HTML to PDF. Just render graph and then pass the URL to the converter. It worked great. Its called HiQPDf
Perhaps you can
print your webpage to PDF.
convert it using any script like svgToPdf.js.
To print as PDF, define a stylesheet for printing
#media print {
body * { visibility: hidden; }
#chart * { visibility: visible; }
#chart { position: absolute; top: 10px; left: 10px; }
}
and call print using javascript
var chart = document.getElementById('chart').innerHTML,
body = document.body.innerHTML;
document.body.innerHTML = chart;
window.print();
document.body.innerHTML = body;
This is not local but works fine. Using http://www.cloudformatter.com/css2pdf to render your chart. I added their javascript and a button to download the PDF.
http://jsfiddle.net/JehdF/1237/
<button onclick="return xepOnline.Formatter.Format('chart',{pageWidth:'11in', pageHeight:'8.5in',render:'download'});">Get PDF</button>
<div id="chart" style="width: 100%; height: 600px"></div>
Use instructions are here: http://www.cloudformatter.com/CSS2Pdf.APIDoc.Usage
Result:

How to display html as firefox panel without using sdk

I need to display html elements as contents of a popup panel using javascript in my firefox addon.
Displaying popup using SDK is what I'm looking for but I don't want to use SDK.
panel:
<popupset id="mainPopupSet">
<panel id="htmlPanel" type="arrow">
i want to use html elements like p,div,span, etc here.
</panel>
</popupset>
javascript to open panel:
document.getElementById('htmlPanel').innerHTML = 'my custom contents';
document.getElementById('htmlPanel').openPopup(null, "before_start", 0, 0, false, false);
it seems some elements are allowed but with different behavior! i also need to set CSS for elements inside panel.
I figure it out how to do it using an iframe
changed the XUL as follow:
<popupset id="mainPopupSet">
<panel id="htmlPanel" type="arrow">
<html:iframe id="htmlContainer"/>
</panel>
</popupset>
and create a javascript function to set html contents:
function setupPanel(contents, width, height)
{
var iframe = document.getElementById("htmlContainer");
iframe.setAttribute("src","data:text/html;charset=utf-8," + escape(contents));
iframe.width = width || 300; //default width=300
iframe.height = height || 300; //default height=300
}
and usage:
setupPanel("<p>this is raw HTML.</p>");
document.getElementById('htmlPanel').openPopup(null, "before_start", 0, 0, false, false);
thanks for your hints.
With animation can copy paste to scratchpad to run it.
var win = Services.wm.getMostRecentWindow('navigator:browser');
var panel = win.document.createElement('panel');
var props = {
type: 'arrow',
style: 'width:300px;height:100px;'
}
for (var p in props) {
panel.setAttribute(p, props[p]);
}
win.document.querySelector('#mainPopupSet').appendChild(panel);
panel.addEventListener('popuphiding', function (e) {
e.preventDefault();
e.stopPropagation();
//panel.removeEventListener('popuphiding', arguments.callee, false); //if dont have this then cant do hidepopup after animation as hiding will be prevented
panel.addEventListener('transitionend', function () {
//panel.hidePopup(); //just hide it, if want this then comment out line 19 also uncomment line 16
panel.parentNode.removeChild(panel); //remove it from dom //if want this then comment out line 18
}, false);
panel.ownerDocument.getAnonymousNodes(panel)[0].setAttribute('style', 'transform:translate(0,-50px);opacity:0.9;transition: transform 0.2s ease-in, opacity 0.15s ease-in');
}, false);
panel.openPopup(null, 'overlap', 100, 100);
to display html in it, do createElementNS('html namespace i cant recall right now','iframe') then set the src of this to the html you want it to display
the type:'arrow' here is important
Since this appears to be an overlay of browser.xul, if your panel will display static content or a simple template, you can take advantage of the fact that the XHTML namespace is already declared.
<popupset id="mainPopupSet">
<panel id="htmlPanel" type="arrow">
<html:div id="htmlplaceholder">
<html:p>Lorem ipsum</html:p>
<html:p>foo <html:strong>bar</html:strong></html:p>
</html:div>
</panel>
</popupset>
The Add-on SDK hosts the html content inside an iframe, perhaps you should consider this for more complex cases.

Categories

Resources