I'm trying to embed a google map into a landscape PDF, but somehow, wkhtmltopdf always cuts the map in two parts although the map would fit on one page easily.
I think the problem is, that the map is built with tiles. The tiles are bigger than the map and are cut off, but wkhtmltopdf seems to ignore this and thinks that the cut off tiles also must fit onto the page...
Here's some sample code to reproduce this:
<html>
<head>
<script src="https://maps.google.com/maps/api/js?sensor=false"></script>
<script>
window.onload = function(){
var fenway = new google.maps.LatLng(47.188563,8.480487);
var gmap = new google.maps.Map(document.getElementById("map"),{
center: fenway,
zoom: 14,
mapTypeId: google.maps.MapTypeId.ROADMAP,
disableDefaultUI: true
});
var marker = new google.maps.Marker({
position: fenway,
map:gmap
});
google.maps.event.addListener(gmap,"tilesloaded",function(){
window.status = "ready";
});
}
</script>
</head>
<body>
<div id="map" style="width:1500px;height:800px"></div>
</body>
</html>
And the command to convert it to PDF:
wkhtmltopdf --window-status ready --orientation landscape map.html map.pdf
I'm using the latest version of wkhtmltopdf by the way...
Is there a possibility to make the map fill the page without the cut?
You can use the --page-width and --page-height options to wkhtmltopdf to specify a size with the same aspect ratio as the page. You'll probably still have to combine this with specifying a width and height on the body, but it's useful if you want to completely fill the output PDF with content.
For reference, the 'UnitReal' accepted by the --page-width and --page-height options accept floating point values with units:
(none) == mm
mm
cm == 10mm
m == 1000mm
didot
inch
in == inch
pica
pc == pica
cicero
pixel
px == pixel
point
pt == point
But note that they must both be specified with the same unit.
It's not really disabling page breaks, but setting a body height does render your map on just one page.
<body style="height:1000px;">
<div id="map" style="width:1500px;height:800px;"></div>
</body>
Related
I'm trying to convert some html like a span element and set its font and size
I need to put this paragraph on top of a text area defined in a pdf form.
This is what i do
//define style
PdfFont fontRegular = FindFontInForm(pdf, new PdfName("OpenSans"));
Style regular = new Style();
regular.SetFont(fontRegular).SetFontSize(9);
//convert html IList<IElement> lst = HtmlConverter.ConvertToElements(val);
Paragraph p = (Paragraph)lst[0]; p.AddStyle(regular);
//size of field, need to put html paragraph on top of it
PdfArray position = toSet.GetWidgets()[0].GetRectangle();
float width = (float)(position.GetAsNumber(2).GetValue() - position.GetAsNumber(0).GetValue());
float height = (float)(position.GetAsNumber(3).GetValue() - position.GetAsNumber(1).GetValue());
Rectangle rect = new Rectangle((float)position.GetAsNumber(0).GetValue(), (float)position.GetAsNumber(1).GetValue(), width, height);
//canvas to add paragraph
Canvas canvasField = new Canvas(canvas, pdf, rect);
canvasField.Add(p);
canvas.Rectangle(rect);
But the font is not applied.
Also Could it be possible to set the font and size in the style of a span html element?
Probabbly it is to late but in any case let me tell you how i fixed this.
Basically you are missing following in order to apply the font
FontProvider provider = new FontProvider();
provider.AddFont([your font]);
ConverterProperties properties = new ConverterProperties();
properties.SetFontProvider(provider);
and then use this:
HtmlConverter.ConvertToElements(stringToConvert, properties);
this way i managed to apply my font to converted html element (paragraph)
I would avoid constructions like this:
PdfFont fontRegular = FindFontInForm(pdf, new PdfName("OpenSans"));
Style regular = new Style();
regular.SetFont(fontRegular).SetFontSize(9);
//convert html IList<IElement> lst = HtmlConverter.ConvertToElements(val);
Paragraph p = (Paragraph)lst[0]; p.AddStyle(regular);
This is counter-intuitive when converting HTML to PDF.
Instead, I would work with CSS to define the font and the size and the style of a span element. With iText 7, you can now even define different MediaQueries. For instance: if you want the HTML to use one specific set of styles when shown in an HTML browser, but you want to use another set of styles when converting the HTML to PDF, you could work with a print.css file.
All of this is explained in the HTML to PDF tutorial.
In chapter 2, you learn how to define styles using CSS. Take a look at this example:
You see that the text "Read more about this movie" has a smaller font-size. and that "IMDB" has a different font color.
That's because the HTML was defined this way:
<div class="imdb">Read more about this movie on
IMDB</div>
And the CSS was defined this way:
.imdb {
font-size: 0.8em;
}
a {
color: green;
}
As you can see, the <div> has a class attribute imdb which is defined in the CSS to have a smaller font size. The CSS for the <a>-tag defines that the text color should be green.
All of this is standard HTML and CSS functionality. There's nothing iText-specific here. Whatever is shown in the browser is also shown on the PDF in this case.
The iText code is as simple as this:
HtmlConverter.convertToPdf(new File(src), new File(dest));
Why would you make things complex if it can be as easy as this?
Chapter 3 explains what to do if you want to create a difference between what's rendered on the screen and what's rendered on the PDF. We use the print.css to achieve this (the PDF will mimic what happens when you print the HTML file).
In your HTML, you might have something like this:
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="css/sxsw.css"/>
<link rel="stylesheet" media="print only" href="css/sxsw_print.css">
</head>
The sxsw.css is the CSS that will be used when showing the HTML in a browser; the print.css will be used when printing the HTML from the browser. Again there's nothing specific to iText in this HTML. This is common functionality known to any HTML developer.
With iText, the sxsw.css will be used if you only use the single line mentioned before. If you want to use the print.css instead, you have to change the ConvertorProperties:
ConverterProperties properties = new ConverterProperties();
properties.setBaseUri(baseUri);
MediaDeviceDescription mediaDeviceDescription =
new MediaDeviceDescription(MediaType.PRINT);
properties.setMediaDeviceDescription(mediaDeviceDescription);
HtmlConverter.convertToPdf(
new FileInputStream(src), new FileOutputStream(dest), properties);
Now, because we have changed the MediaDeviceDescription to MediaType.PRINT, the print.css styles will be used.
The code is only slightly different if you need the iText elements so that you can add them in a specific rectangle. That's explained in chapter 1:
List<IElement> elements =
HtmlConverter.convertToElements(new FileInputStream(src), properties);
You might ask yourself: Why can't I do it my way? Why shouldn't I define the font size, styles, etc... in my code?
The answer is simple: Your code will be hard to maintain! If your employer asks you to apply a change, you will have to change your code, compile it, etc...
If you do it the way it's described in the official tutorial, it's easy: you don't have to change your code; you only have to change the CSS. That's much easier!
I want to know whether a given point is inside or outside of a text shape. As you will notice in the sample I provided below, hitTest will return true as soon as the point is inside of the TextItem's bounds, and not only if the point is inside of the character itself. (You can experience this behavior best when you place your mouse pointer in the middle of the #)
Sample: Hit-testing against TextItem
I also tried drawing the character based on paths (as Raphaël is doing in their font samples) to use the paths itself for hit-testing but stumbled upon some quite strange behavior where (some) characters are not drawn correctly. (If you copy the path definition into a vector image software like Inkscape the text shapes are drawn correctly)
Sample: Drawing text as path
What is the most promising way to find out whether a given point is inside or outside of a text shape?
You can hit-test a text shape (or any other mathematically irregular shape) by texting whether the pixel under the mouse is transparent or not.
You can get the pixel-array for the entire canvas using:
var data=context.getImageData(0,0,canvas.width,canvas.height).data;
Then you can fetch the opacity (alpha) value for the pixel under the mouse like this:
var pixelIsTransparent = data[(mouseY*canvas.width+mouseX)*4+3]==0
If the pixel is not transparent then you're over the text shape.
If you have other non-text drawings on the canvas then those non-text drawings might give false-positives for your hit-tests. A workaround for that is to use a second in-memory canvas containing only your text-shape and then do hit testing against the pixels on that second canvas.
Here's example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
ctx.strokeStyle='gray';
ctx.font='300px verdana';
var wasHit=false;
var isHit=false;
draw();
var data=ctx.getImageData(0,0,canvas.width,canvas.height).data;
$("#canvas").mousemove(function(e){handleMouseMove(e);});
function draw(){
ctx.fillStyle=(isHit)?'green':'lightgray';
ctx.fillText("M",25,250);
ctx.strokeText("M",25,250);
}
function handleMouseMove(e){
e.preventDefault();
e.stopPropagation();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
isHit=(data[(mouseY*cw+mouseX)*4+3]>10)
if(!isHit==wasHit){
draw();
wasHit=isHit;
}
}
body{ background-color: ivory; }
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<p>Hit test: Move mouse over letter</p>
<canvas id="canvas" width=300 height=300></canvas>
After spending quite some time debugging paper.js code I finally found the solution for this problem.
Instead of using Path you are supposed to use CompoundPath:
A compound path contains two or more paths, holes are drawn where the paths overlap. All the paths in a compound path take on the style of the backmost path and can be accessed through its item.children list.
I also updated the example from above:
http://jsfiddle.net/64v7s6L9/1/
There is an issue on a site I have been working on that for some reason the SVG image markers are not showing up in IE 11.
I have two sets of markers:
the default zoomed out has PNG markers for the suburbs
zoomed in has address specific numbered SVG ones
I use a fallback for older browsers that don't support SVG (testing it with modernizr). I am using the old Google Chart markers for IE 11 to get it to work (testing the user agent string to id it).
I want to know if anyone has an idea as to:
the cause
whether it is something screwed up with IE11 Edge mode (switch the document mode to 10 to get it to work)
or something that is failing with Google.
The site is:
http://artstrail.org.au/arts-trail.php
You can see it fail if you change the user agent string in IE 11 while leaving it in Edge Document mode.
It seems that Google Maps doesn't really support using SVG images for markers at the moment. This fact is easy to overlook, because it turns out that SVG marker images do actually work in, eg. Chrome and Opera.
However, the Google Maps API (v3) specifically provides Symbol objects for displaying vector paths in map markers. I found that specifying the vector image in SVG path notation allowed it to work in IE and other browsers.
Example (from Google Maps docs, here):
var goldStar = {
path: 'M 125,5 155,90 245,90 175,145 200,230 125,180 50,230 75,145 5,90 95,90 z',
fillColor: 'yellow',
fillOpacity: 0.8,
scale: 1,
strokeColor: 'gold',
strokeWeight: 14
};
var marker = new google.maps.Marker({
position: map.getCenter(),
icon: goldStar,
map: map
});
(Thanks to this answer too)
Actually, for me adding marker optimized: false and icon scaledSize: new google.maps.Size(25, 25) does it for me. So even if what Nick F says is true (that it's not officially supported), it works.
SVG markers start showing up in IE11. It seems that the scaledSize adds a style width and height on the <img> element, unsure what optimized does in this case.
Example:
var marker = new google.maps.Marker({
map: map,
position: poi.geometry.location,
title: poi.name,
zIndex: 99,
optimized: false,
icon: {
url: 'loremipsum.svg',
scaledSize: new google.maps.Size(25, 25),
size: new google.maps.Size(25, 25),
origin: new google.maps.Point(0, 0),
anchor: new google.maps.Point(12.5, 12.5)
}
});
Credit: Google Maps SVG marker doesn't display on IE 11
The IE implementation deviates from the SVG standard in the following ways:
Properties of a marker element inherit at the point of reference, not from the ancestors of the marker element.
References
MS-SVG: The 'marker' element
Add meta to emulate IE10/IE9 if the SVG supports in lower IE versions.
ie) for IE-10 <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE10">
Here's a related image:
I want to achieve something like what's pictured on the right side of my image. But I also have a parent container that has a background image of its own, instead of a solid color.
Any advice?
EDIT: Forgot to add, cross-browser compatibility is important. (Or atleast Firefox).
I can only think of one pure CSS solution and it is simply insane.
Let's say your image has a width of 100px. You'll have to create a div that's 100px wide and give it 100 children that are each 1px wide, that each have the same background (positioned accordingly) and that each have an opacity from 0 (the first child) to .99 (the last child).
Personally, I think it's crazy and I'd never use this method.
Rory O'Kane came with a nice and clean solution and I also have another idea which involves JavaScript.
Basically, the idea is that you use a canvas element (support), draw your image on it, loop through its pixels and adjust the alpha for each.
demo
(scroll down to see the result)
Relevant HTML:
<div class='parent'>
<canvas id='c' width='575' height='431'></canvas>
</div>
Relevant CSS (setting the background image on the parent)
.parent {
background: url(parent-background.jpg);
}
JavaScript:
window.onload = function() {
var c = document.getElementById('c'),
ctxt = c.getContext('2d'),
img = new Image();
img.onload = function() {
ctxt.drawImage(img, 0, 0);
var imageData = ctxt.getImageData(0, 0, 575, 431);
for(var i = 0, n = imageData.data.length; i < n; i += 4) {
imageData.data[i + 3] = 255*((i/4)%575)/575;
}
ctxt.putImageData(imageData, 0, 0);
};
/* images drawn onto the canvas must be hosted on the same web server
with the same domain as the code executing it */
/* or they can be encoded like in the demo */
img.src = 'image-drawn-on-canvas.jpg';
};
check these out maybe helpful
DEMO 1
DEMO 2
Ignoring possible CSS-only methods, you can make the image a PNG with the transparent gradient built in to the image’s alpha channel. All browsers support PNG transparency, except for IE 6 and below. Here’s what your sample image would look like as a PNG with a transparent gradient (try putting this image against other backgrounds):
If the images are user-submitted so you can’t add the gradient ahead of time, you could create and store a gradient-added version of each image at the time that the user uploads them.
CSS only method:
https://gist.github.com/3750808
In our previous version of Flot, the following tickformatter function worked fine. It displayed the value and used the class correctly.
yaxis: {
tickFormatter: function(v, axis) {
return "<span class='axisLabel'>" + v + "%</span>";
}
In the latest version (v. 0.7) it renders the tags literally so next to the graph I see a something like
<span class='axisLabel'>50%</span>
where the y axis tick labels should be. I should only be seeing a list of percentages.
I've done as much debugging as I can but haven't found out what is causing this. Any ideas would be appreciated.
This is due to a recent "improvement" in how the labels are treated, I think. From README.md in the development version:
Axis labels are now drawn with canvas text with some parsing to
support newlines. This solves various issues but also means that they
no longer support HTML markup, can be accessed as DOM elements or
styled directly with CSS.
More specifically, it seems that
function insertAxisLabels() {...}
was replaced by
function drawAxisLabels(){...}
at some point. The former used to place axis labels as a bunch of <div> elements, as follows:
<div class="tickLabels" style="font-size:smaller">
<div class="xAxis x1Axis" style="color:#545454">
<div class="tickLabel" style="position:absolute;text-align:center;left:-14px;top:284px;width:75px"><em>0</em></div>
[... div elements for other labels...]
</div>
</div>
That allowed one to use html code in the tickFormatter. In the latest version, all this is gone, and the labels are added to the canvas directly via
ctx.fillText(your_label, x, y);
No html formatting tags therefore work anymore. Things that used to be simple, like styling the tick labels or turning them into links, are now less straightforward. Maybe flot developers can shed some light on what is the best way to achieve the same functionality in the new version.
I am using flot mostly for barcharts. One (ugly) workaround that seems to work for me is to replace the entire drawAxisLabels function in the newest jquery.flot.js by insertAxisLabels function from the stable version (after renaming it to drawAxisLabels). I additionally have to set manually labelWidth in xaxis options of my plots since otherwise the width of the plots is calculated incorrectly.
function formatter(val, axis) {
return "<span style='font-weight: bold'>" + val / 1000000 + "m</span>";
}
var usersData = { color: "#00FF55", data: [[1, 900000], [2, 926000], [3, 959000], [4, 1056000], [5, 1242300]] };
$(document).ready(function() {
$.plot($("#UserGraph"), [usersData], { xaxis: { ticks: [] }, yaxis: { tickFormatter: formatter } });
});
I could remove the style and the numbers go back to normal non-bold numbers.