SnapSVG - parse toDefs() is not a function - svg

I, im trying to embed font references into the section of the svg using snapsvg. Heres my snippet
this.importFonts = function() {
var fonts = [
{
name : 'Oswald',
family : 'Oswald',
url : 'http://fonts.googleapis.com/css?family=Oswald'
}
];
fonts.forEach(function(font){
var snapFont = Snap.parse('<style type="text/css">#import url(' + font.url + ');</style>');
canvas.append(snapFont);
snapFont.toDefs();
});
};
the style tag is being appended to the svg but I am getting an error
Uncaught TypeError: snapFont.toDefs is not a function
Can anyone see where I'm going wrong here.
regards

Found the answer, selecting the element through snapsvg will return a snapelement:
this.importFonts = function() {
var fonts = [
{
name : 'Oswald',
family : 'Oswald',
url : 'http://fonts.googleapis.com/css?family=Oswald'
}
];
var fontGroup = canvas.g();
fonts.forEach(function(font){
var snapFont = Snap.parse('<style type="text/css">#import url(' + font.url + ');</style>');
fontGroup.add(snapFont);
});
fontGroup.selectAll('style').forEach(function(elm){
elm.toDefs();
});
fontGroup.remove();
};

Related

htmlparser2 how to replace a tag by another custom tag with the same attributes that has the tag one

I need to change a tag for another tag with the same properties. For example change this:
<TagOne width="500" height="200">asdfasdf</TagOne>
to this:
<AnotherTag width="500" height="200">sometext</AnotherTag>
With this code I can see the attributes but i don't know how to replace the tag for the other one:
const htmlparser2 = require("htmlparser2");
const DomUtils = require("htmlparser2").DomUtils;
const htmlContent = `<html>
<head></head> <body> <div id="content">
<TagOne width="500" height="200" src="image1.jpg">asdfasdf</TagOne>
<p>asdfasdf</p> </div></body></html>`; const parser = new htmlparser2.Parser(
{
onopentag(name, attribs) {
if (name === "TagOne") {
if(attribs.width ){
var width = attribs.width;
}
if(attribs.height ){
var height = attribs.height;
}
var new_tag = `<AnotherTag width:`+width+`; height:`+height+`;">sometext</div>`;
}
},
ontext(text) {
console.log("-->", text);
},
onclosetag(tagname,new_tag) {
if (tagname === "amp-iframe") {
console.log("That's it?!");
}
},
},
{ decodeEntities: true } );
var content = parser.write(htmlContent);
parser.end();
I have tried to do this on the onclosetag function:
//htmlparser2.DomUtils.removeElement(tagname);
//parser.write(new_tag);
but it gives me an error, it is not the correct way but I can't find anything similar in the documentation. can someone help me? Thanks.

get data from nodejs to frontend js for google maps but stuck in retrieving it looking for ways to solve it

My NodeJS GET route:
router.get('/stores', function (req, res, next) {
errorMsg = req.flash('error')[0];
successMsg = req.flash('success')[0];
Product.find(function (err, products) {
// console.log(products)
res.render('admin/stores', {
layout: 'admin-map.hbs',
stores: products,
errorMsg: errorMsg,
GOOGLE_APIKEY: process.env.GOOGLE_APIKEY,
noErrors: 1
});
});
The route /stores returns json data which holds latitude and longitude and I want it in my script tag of map.html with loop, to render the pins on the map. Below, the script:
<!DOCTYPE html>
<html>
<head>
<script src = "https://maps.googleapis.com/maps/api/js"></script>
<script>
function loadMap() {
alert(this.stores);
var mapOptions = {
center:new google.maps.LatLng(17.433053, 78.412172),
zoom:5
}
var map = new google.maps.Map(document.getElementById("sample"),mapOptions);
var marker = new google.maps.Marker({
position: new google.maps.LatLng(17.433053, 78.412172),
map: map,
draggable:true,
icon:'/scripts/img/logo-footer.png'
});
marker.setMap(map);
var infowindow = new google.maps.InfoWindow({ });
infowindow.open(map,marker);
}
</script>
<!-- ... -->
</head>
</html>
How can I do it?
It seems you need to follow two steps
1. Pass data from hbs to script
Using triple brackets syntax
<script>
let stores = {{{ stores }}}; // the triple brackets
console.log('Data : ', stores);
function loadMap() {
...
Check if data is being printed in console? If yes your data is available in the front-end script and you can
2. Loop through it
...
for (let i = 0; i < stores.length; i++) {
// the JS loop instead of hbs one, because we are on front-end
var marker = new google.maps.Marker({
position: new google.maps.LatLng(stores[i].lat, stores[i].lng), // whatever applies
map: map,
draggable:true,
icon:'/scripts/img/logo-footer.png'
});
}
And donot need to call setMap(), you have already set the map in map: map above
the answer is inside fronted script i can have an object declared globally and this double flower brackets works fine with them
<script>
function loadMap() {
alert(this.stores);
var mapOptions = {
center:new google.maps.LatLng(17.433053, 78.412172),
zoom:5
}
var map = new google.maps.Map(document.getElementById("sample"),mapOptions);
{{#each stores}}
var marker = new google.maps.Marker({
position: new google.maps.LatLng(17.433053, 78.412172),
map: map,
draggable:true,
icon:'/scripts/img/logo-footer.png'
});
{{/each}}
marker.setMap(map);
var infowindow = new google.maps.InfoWindow({ });
infowindow.open(map,marker);
}
</script>

phantomjs - render HTML to PDF

I have problems with rendering a HTML file to a PDF file. I pass two arguments to the command line. The first is the HTML input file and the second the PDF output
/var/bin/phantomjs-2.1.1-linux-x86_64/bin/phantomjs /var/www/nodejs/html_to_pdf.js /root/input.html /root/hello.pdf
code
var page = require('webpage').create(),
args = require('system').args,
f = require('fs').open(args[1], 'r');
page.paperSize = {
format : 'A4',
orientation : 'portrait',
margin : {
top : '1cm',
left : '1cm',
bottom : '1cm',
right : '1cm'
}
};
page.content = f.read();
page.setContent(page.content, page);
page.render(args[2]);
phantom.exit();
No errors is returned and no output PDF file?
Here is the input file
http://www.filedropper.com/input_3
I'd suggest rewrite to page.open a file:
var page = require('webpage').create();
var args = require('system').args;
var fs = require('fs');
function getFileUrl(str) {
var pathName = fs.absolute(str).replace(/\\/g, '/');
// Windows drive letter must be prefixed with a slash
if (pathName[0] !== "/") {
pathName = "/" + pathName;
}
return encodeURI("file://" + pathName);
};
page.paperSize = {
format : 'A4',
orientation : 'portrait',
margin : {
top : '1cm',
left : '1cm',
bottom : '1cm',
right : '1cm'
}
};
page.open(getFileUrl(args[1]), function(){
page.render(args[2]);
phantom.exit();
});
getFileUrl is from this answer

How to get char code of fontawesome icon?

I'd like to use fontawesome icons in SVG scope. I cannot achieve it in common way, but I can add <text> element containing corresponding UTF-8 char and with font set to fontawesome, like that:
<text style="font-family: FontAwesome;">\uf0ac</text>
To make it clear I wrote a switch for getting useful icons:
getFontAwesomeIcon(name) {
switch (name) {
case 'fa-globe':
return '\uf0ac'
case 'fa-lock':
return '\uf023'
case 'fa-users':
return '\uf0c0'
case 'fa-ellipsis-h':
return '\uf141'
default:
throw '# Wrong fontawesome icon name.'
}
}
But of course that's ugly, because I must write it myself im my code. How can I get these values just from fontawesome library?
You can avoid producing such a list and extract the information from the font-awesome stylesheet on the fly. Include the stylesheet and set the classes like usual, i. e.
<tspan class="fa fa-globe"></tspan>
and you can do the following:
var icons = document.querySelectorAll(".fa");
var stylesheet = Array.from(document.styleSheets).find(function (s) {
return s.href.endsWith("font-awesome.css");
});
var rules = Array.from(stylesheet.cssRules);
icons.forEach(function (icon) {
// extract the class name for the icon
var name = Array.from(icon.classList).find(function (c) {
return c.startsWith('fa-');
});
// get the ::before styles for that class
var style = rules.find(function (r) {
return r.selectorText && r.selectorText.endsWith(name + "::before");
}).style;
// insert the content into the element
// style.content returns '"\uf0ac"'
icon.textContent = style.content.substr(1,1);
});
My two answers for two approaches to the problem (both developed thanks to ccprog):
1. Setting char by class definition:
In that approach we can define element that way:
<text class="fa fa-globe"></text>
And next run that code:
var icons = document.querySelectorAll("text.fa");
// I want to modify only icons in SVG text elements
var stylesheets = Array.from(document.styleSheets);
// In my project FontAwesome styles are compiled with other file,
// so I search for rules in all CSS files
// Getting rules from stylesheets is slightly more complicated:
var rules = stylesheets.map(function(ss) {
return ss && ss.cssRules ? Array.from(ss.cssRules) : [];
})
rules = [].concat.apply([], rules);
// Rest the same:
icons.forEach(function (icon) {
var name = Array.from(icon.classList).find(function (c) {
return c.startsWith('fa-');
});
var style = rules.find(function (r) {
return r.selectorText && r.selectorText.endsWith(name + "::before");
}).style;
icon.textContent = style.content.substr(1,1);
});
But I had some problems with that approach, so I developed the second one.
2. Getting char with function:
const getFontAwesomeIconChar = (name) => {
var stylesheets = Array.from(document.styleSheets);
var rules = stylesheets.map(function(ss) {
return ss && ss.cssRules ? Array.from(ss.cssRules) : [];
})
rules = [].concat.apply([], rules);
var style = rules.find(function (r) {
return r.selectorText && r.selectorText.endsWith(name + "::before");
}).style;
return style.content.substr(1,1);
}
Having that funcion defined we can do something like this (example with React syntax):
<text>{getFontAwesomeIconChar('fa-globe')}</text>

html2canvas does not print jsPlumb Connectors

How to print SVG elements that are built by jsPlumb.
Known that getting all SVG Elements drawen by jsPlumb is retrieved by this code :
var uiJsPlumbConnectors=jsPlumb.getAllConnections().map(function(conn){return conn.canvas;})
All connectors are SVG elements :
Using html2canvas to print all connectors (SVG), it does not work :
html2canvas(uiJsPlumbConnectors).then(function(c){
window.open(c.toDataURL('image/png'))
});
An image has been generated , however, it is an emply image .
FIDDLE
It seems that html2canvas does not support yet multi-elements drawing ?
Last time I checked html2canvas was not able to convert SVGs, you will need another script to handle that.
The steps:
transfer html elements to canvas
transfer svg elements to canvas
export canvas
I used https://code.google.com/p/canvg/ to export to the same canvas after using html2canvas. Hope that helps you.
I just implemented this
<%--stuff for printing--%>
<script type="text/javascript" src="../../../../Scripts/Print/html2canvas.js"></script>
<script src="<%=AdminPath%>Scripts/canvg/rgbcolor.js" type="text/javascript"></script>
<script src="<%=AdminPath%>Scripts/canvg/StackBlur.js" type="text/javascript"></script>
<script src="<%=AdminPath%>Scripts/canvg/canvg.js" type="text/javascript"></script>
jsplumb div
<div class="demo statemachine-demo" id="statemachine-demo" style="margin: 0px;">
</div>
hidden div for printing
<div id="canvasDiv" style='visibility:hidden;' >
</div>
function renderImage()
{
var statemachinediv = document.getElementById('statemachine-demo');
html2canvas([statemachinediv], {
onrendered: function (canvas) {
document.getElementById('canvasDiv').appendChild(canvas);
var svgList = $(statemachinediv).find( "svg" );
svgList.each(function(index, value) {
try
{
var svgExample = this;
var serializer = new XMLSerializer();
var svgMarkup = serializer.serializeToString(svgExample);
if(svgMarkup.indexOf("_jsPlumb_connector") > -1)
{
var leftIndex = svgMarkup.indexOf("left: ");
var endOfLeft = svgMarkup.indexOf("px", leftIndex);
var leftPosition = svgMarkup.substring(leftIndex+6, endOfLeft );
var left = parseInt(leftPosition);
var topIndex = svgMarkup.indexOf("top: ");
var endOfTop = svgMarkup.indexOf("px", topIndex);
var topPosition = svgMarkup.substring(topIndex+5, endOfTop );
var top = parseInt(topPosition);
svgMarkup = svgMarkup.replace('xmlns="http://www.w3.org/2000/svg"','');
var connectorCanvas = document.createElement('canvas');
canvg(connectorCanvas, svgMarkup); //add connector to canvas
var context = canvas.getContext('2d');
context.drawImage(connectorCanvas, left, top);
}
}
catch(err)
{
showBalloon('error in print');
}
});
var stateMachineName = $("#stateMachineDropDown option:selected").text();
var data = canvas.toDataURL('image/png');
var mywindow = window.open('', 'my div', 'height=400,width=600');
mywindow.document.write('<html><head><title>' + stateMachineName + '</title>');
mywindow.document.write('</head><body ><table><tr><td>');
mywindow.document.write('</td></tr></table><img src="' + data + '" />');
mywindow.document.write('</body></html>');
mywindow.print();
}
});
return false;
}
Its a old question, but, this helped me. Mode details.
$clone.find('.jtk-connector').each(function () {
// for every SVG element created by JsPlumb for connections...
var left = parseInt(this.style.left, 10) + 'px';
var top = parseInt(this.style.top, 10) + 'px';
this.removeAttribute('style');
this.removeAttribute('position');
this.setAttribute('width', parseInt(this.getAttribute('width'), 10) + 'px');
this.setAttribute('height', parseInt(this.getAttribute('height'), 10) + 'px');
this.setAttribute('preserveAspectRatio', 'xMidYMid meet');
this.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
// this.children[0] is the path for connection line
// this.children[1] is the path for connection arrow shape
this.children[0].setAttribute('xmlns', 'http://www.w3.org/2000/svg');
this.children[1].setAttribute('xmlns', 'http://www.w3.org/2000/svg');
this.setAttribute('viewbox', '0 0 ' + parseInt(this.getAttribute('width'), 10) + ' ' + parseInt(this.getAttribute('height'), 10));
this.children[0].setAttribute('stroke-width', '2px');
this.children[0].setAttribute('stroke', '#c9c9c9');
this.children[1].setAttribute('fill', '#c9c9c9');
this.children[1].setAttribute('stroke', '#c9c9c9');
$clone.find(this).wrap('<span style="position: absolute; left: ' + left + '; top: ' + top + ';"></span>');
});

Resources