I try to create a pdf out of a html using iText:
String html= "<table style=\";border: 2px solid black\">"
+ "<tr>"
+ "<td>Column 1</td>"
+ "<td style=\";border: 1px solid red; width: 80mm\";>Column 2</td>"
+ "</tr>"
+ "</table>";
Document document = new Document(PageSize.A4);
PdfWriter pdfWriter = PdfWriter.getInstance(document, new FileOutputStream("htmlFahrplan.pdf"));
pdfWriter.setLinearPageMode();
pdfWriter.setFullCompression();
document.addCreationDate();
document.open();
HTMLWorker htmlWorker = new HTMLWorker(document);
htmlWorker.parse(new StringReader(html));
document.close();
pdfWriter.close();
But the generated pdf has no style settings: There is no border and
the column width is the same for every column!
Does anyone has any idea how to transform this?
Related
For example:
one
two
three
four
five
six
seven
eight
nine
ten
eleven
twelve
to
one two three
four five six
seven eight nine
ten eleven twelve
I couldn't figure out how to do this and was only able to do vice versa on vscode.
Not a shortcut, but you can easily do such job with find ans replace.
Ctrl+H
Find what: (\w+)\R(\w+)\R(\w+)
Replace with: $1 $2 $3
CHECK Wrap around
CHECK Regular expression
Replace all
Explanation:
(\w+) # group 1, 1 or more word characters
\R # any kind of linebreak
(\w+) # group 2, 1 or more word characters
\R
\R # any kind of linebreak
Screenshot (before):
Screenshot (after):
Not VS Code, but you can do that using this snippet:
Just bookmark this answer if you need it again (or copy and paste the snippet info into an HTML file on your device). Also, I think the "Copy to clipboard" button doesn't work because the snippet runs in a cross-origin iframe, but it should work in a same-origin context.
function splitWordsPerLine (text, wpl = 1) {
let result = '';
wpl = wpl < 1 ? 1 : wpl;
let count = wpl;
for (const word of text.split(/\s+/)) {
count -= 1;
let line = word;
if (count === 0) {
line += '\n';
count = wpl;
}
else line += ' ';
result += line;
}
return result.trim();
}
function getWPL (numberInput) {
if (!numberInput) return 1;
const wpl = parseInt(numberInput.value, 10);
return Number.isNaN(wpl) ? 1 : wpl;
}
function handleInput (event) {
const wpl = getWPL(event.target);
const textInput = document.getElementById('text');
if (!textInput) return;
textInput.value = splitWordsPerLine(textInput.value, wpl);
}
async function handleClick (event) {
let message = 'Copying failed ðŸ˜';
const textInput = document.getElementById('text');
try {
if (!textInput) throw new Error('No input found');
await navigator.clipboard.writeText(textInput.value);
message = 'Text copied ✅';
}
catch {}
textInput?.select();
const setText = str => event.target.textContent = str;
setText(message);
setTimeout(() => setText('Copy to clipboard'), 1500);
}
function handlePaste (event) {
const text = event.clipboardData?.getData('text');
if (!text) return;
const wpl = getWPL(document.getElementById('wpl'));
event.target.value = splitWordsPerLine(text, wpl);
event.preventDefault();
}
document.getElementById('wpl')?.addEventListener('input', handleInput);
document.getElementById('copy')?.addEventListener('click', handleClick);
document.getElementById('text')?.addEventListener('paste', handlePaste);
html {
box-sizing: border-box;
height: 100%;
}
*, *:before, *:after {
box-sizing: inherit;
}
body {
font-family: sans-serif;
height: 100%;
margin: 0;
padding: 1rem;
}
.container {
display: flex;
gap: 0.5rem;
}
.container.vertical {
flex-direction: column;
height: 100%;
}
#copy {
background-color: black;
border: 0;
color: white;
display: inline-flex;
align-items: center;
font-size: 1rem;
padding: 0.5rem;
}
#wpl, #text {
border: 1px solid;
font-family: monospace;
padding: 0.5rem;
}
#wpl {
font-size: 1.5rem;
width: 5rem;
}
#text {
font-size: 1rem;
height: 100%;
width: 100%;
resize: none;
white-space: pre;
}
<div class="container vertical">
<div class="container">
<input id="wpl" type="number" min="1" step="1" value="1" />
<button id="copy">Copy to clipboard</button>
</div>
<textarea id="text" rows="0" cols="0" placeholder="Select number of words per line, then paste your text here"></textarea>
</div>
You can use extension Select By and the command selectby.lineNr
Place the cursor on the first line
execute command: Place cursor based on line number, uses boolean expression
enter expression: c+3k to place a cursor every 3 lines
maybe expression: c+3k && n<50 to limit the end line to use
now use End Space Delete as often as needed
press Esc to exit Multi Cursor Mode
I am currently trying to give my popups different background based on the layer they are found in (i.e. I have a layer called Indigenous Sites where I would like the background of the popup to be different from the other layers).
I have tried giving the popup a className but I am not sure how to call it properly in the CSS.
Below is a sample of the popup script in my html document (script for 2 different layers popups):
// popup for the Other European Sites layer
map.on('click', 'Other European Sites', function (e) {
new mapboxgl.Popup()
.setLngLat(e.lngLat)
.setHTML('<h2>' + 'European Site' + '</h2>' +
'<p>' + e.features[0].properties.placeName + '</p>' +
'<h2>' + 'Story' + '</h2>' +
'<p>' + e.features[0].properties.Story + '</p>' +
'<h2>' + 'Latitude' + '</h2>' +
'<p>' + e.features[0].properties.latitude + '</p>' +
'<h2>' + 'Longitude' + '</h2>' +
'<p>' + e.features[0].properties.longitude + '</p>')
.addTo(map);
});
// popup for the Other Indigenous Sites layer
map.on('click', 'Other Indigenous Sites', function (e) {
new mapboxgl.Popup({className: 'popupCustom'})
.setLngLat(e.lngLat)
.setHTML('<h2>' + 'Indigenous Site' + '</h2>' +
'<p>' + e.features[0].properties.placeName + '</p>' +
'<h2>' + 'Story' + '</h2>' +
'<p>' + e.features[0].properties.Story + '</p>' +
'<h2>' + 'Latitude' + '</h2>' +
'<p>' + e.features[0].properties.latitude + '</p>' +
'<h2>' + 'Longitude' + '</h2>' +
'<p>' + e.features[0].properties.longitude + '</p>')
.addTo(map);
});
Here is my current CSS that gives all of my popups the same background:
.mapboxgl-popup-content {
overflow-y: scroll;
background-color: #000000;
}
How would I go about assigning the popups different classNames and calling them in the CSS so that I can have different backgrounds for each layer?
Thanks so much for any input!
The className is a CSS class name that will be applied to the popup container (which contains the "mapboxgl-popup-content" element). So if you want your "Other Indigenous Sites" layer to have, say, yellow popups, you could do this:
.mapboxgl-popup-content {
overflow-y: scroll;
background-color: #000000;
}
.popupCustom .mapboxgl-popup-content {
background-color: yellow;
}
Note however that this functionality was only very recently added and I don't think it has been released yet. (It's not in the published docs).
I am working with integration of bing maps into the application. When the search button is clicked after entering the zip code information, the div below will display a list of available stores and a map with pushpin on that. Showing an infobox is working when I hover over the pushpin. But my requirement is that, I have to show the particular infobox to the user, when the user hovers over the list in the left of the maps.
For example here, when I hover over the first result on the left, the corresponding infobox should show in the map. I am unable to figure out why it not working. Appreciate your help in advance. Thank you. Please find below what I have tried so far.
for (var i = 0; i < data.length; i++) {
if (storeLoc && (data[i].metadata.LocationTypeSort == "ja")) {
console.log(counter);
console.log(data);
innerTablecontent += "<tr><td><h4 class='h4-mapDetails-storeName'>" + '<div style="display: inline-block; vertical-align: middle"><svg xmlns="http://www.w3.org/2000/svg" width="25" height="25"><circle cx="12.5" cy="12.5" r="12.5"/><text x="50%" y="17" text-anchor="middle" fill="white" font-size="14" font-weight="bold">' + (+counter) + '</text></svg></div>' +
" " + "<b><span style='margin-top:-20px;display:block;margin-left:45px;'>" + data[i].metadata.LocationName + "</span></b>" + "</h4><p class='p-mapDetails'>" + data[i].metadata.AddressLine + "," + data[i].metadata.Locality + "," + data[i].metadata.AdminDistrict + " " + data[i].metadata.PostalCode + "</p>"
+ "<p class='p-mapDetails'>" + data[i].metadata.Phone + "<span><span class='index hidden'>" + i + "</span> | " + '<a style=" font-family:Helvetica Neue LT Pro Roman,sans-serif;color:#00A7CE" href="">View details</a>' + "</span></p>"+ "<span class='miles-mapDetails'>" +(data[i].metadata.__Distance* 0.6214).toFixed(2)+"mi</span></td></tr>"
locations.push(data[i].getLocation());
var pin1 = createCirclePushpin(data[i].getLocation(), 12.5, 'rgb(0, 0, 0)', 'black', 1, counter);
pin1.metadata = {
//title: counter + "." + " " + data[i].metadata.LocationName,
title: " ",
description: '<div style="display: inline-block; vertical-align: middle; margin-right:10px;"><svg xmlns="http://www.w3.org/2000/svg" width="25" height="25"><circle cx="12.5" cy="12.5" r="12.5"/><text font-weight="bold" x="50%" y="17" text-anchor="middle" fill="white" font-size="14">' + (+counter) + '</text></svg></div>' + "<span class='h4-mapDetails-storeName'>" + data[i].metadata.LocationName + "</span><p style='margin-bottom:-3px;font-family:Helvetica Neue LT Pro Roman,Helvetica,sans-serif;font-style:normal !important;color:#000;font-size:14px;'>" + data[i].metadata.AddressLine + ", " + data[i].metadata.Locality + "," + data[i].metadata.AdminDistrict + " " +
data[i].metadata.PostalCode + "<br>" + data[i].metadata.Phone + "</p>" + "<a>" + '<a style="font-size:14px;font-family:Helvetica Neue LT Pro Roman,Helvetica,sans-serif;color:#00A7CE" href="">View details</a>' + "</a>"
};
Microsoft.Maps.Events.addHandler(pin1, 'mouseover', pushpinClicked);
map.entities.push(pin1);
counter++;
}
Function to call when the list is hovered:
$("#mapDetails").on("mouseover", "table td", function() {
sideTabHoverEvent(hoverdata[$(this)[0].getElementsByClassName('index')[0].innerText]);
})
function sideTabHoverEvent(e) {
if (e) {
//Set the infobox options with the metadata of the pushpin.
infobox.setOptions({
location: e.getLocation(),
//title: e.metadata.title,
description: e.metadata.description,
visible: true
});
}
}
In you sideTabHoverEnt function you are assuming e is the pushpin the user interacted with, but that's not what you are passing in. You are passing in a string (index as a string). Try doing the following:
function sideTabHoverEvent(e) {
if (e) {
//Turn the index string value into a number.
var idx = parseInt(e);
var shape = map.entities.get(idx);
//Set the infobox options with the metadata of the pushpin.
infobox.setOptions({
location: shape.getLocation(),
//title: shape.metadata.title,
description: shape.metadata.description,
visible: true
});
}
}
i'm using Google timeline chart, and i want to show the duration in hour even if the duration is over a day. Is it possible?
Thank you
An image with a thousand of samples that demostrate the different behavior 1
As you can see in red the duration is wrong, and in blue a duration calculated and printed.
there are no configuration options to change the content of the tooltip
but a custom tooltip can be provided
see following working snippet
a tooltip column is inserted and populated with information from the data
google.charts.load('current', {
callback: function () {
var container = document.getElementById('chart_div');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({type: 'string', id: 'RowLabel'});
dataTable.addColumn({type: 'string', id: 'BarLabel'});
dataTable.addColumn({type: 'date', id: 'Start'});
dataTable.addColumn({type: 'date', id: 'End'});
dataTable.addRows([
['165414 fine-turbo ers', 'Cpus 24 - 0.543h', new Date(2016,07,20, 13,37,32), new Date(2016,07,20, 15,43,19)],
['165418 fine-turbo ers', 'Cpus 24 - 0.534h', new Date(2016,07,20, 14,47,12), new Date(2016,07,20, 16,40,09)],
['165427 fine-turbo ers', 'Cpus 24 - 0.265h', new Date(2016,07,20, 18,01,23), new Date(2016,07,21, 00,02,53)],
]);
dataTable.insertColumn(2, {type: 'string', role: 'tooltip', p: {html: true}});
var dateFormat = new google.visualization.DateFormat({
pattern: 'M/d/yy hh:mm:ss'
});
for (var i = 0; i < dataTable.getNumberOfRows(); i++) {
var duration = (dataTable.getValue(i, 4).getTime() - dataTable.getValue(i, 3).getTime()) / 1000;
var hours = parseInt( duration / 3600 ) % 24;
var minutes = parseInt( duration / 60 ) % 60;
var seconds = duration % 60;
var tooltip = '<div class="ggl-tooltip"><span>' +
dataTable.getValue(i, 1) + '</span></div><div class="ggl-tooltip"><span>' +
dataTable.getValue(i, 0) + '</span>: ' +
dateFormat.formatValue(dataTable.getValue(i, 3)) + ' - ' +
dateFormat.formatValue(dataTable.getValue(i, 4)) + '</div>' +
'<div class="ggl-tooltip"><span>Duration: </span>' +
hours + 'h ' + minutes + 'm ' + seconds + 's ';
dataTable.setValue(i, 2, tooltip);
}
chart.draw(dataTable, {
tooltip: {
isHtml: true
}
});
},
packages: ['timeline']
});
.ggl-tooltip {
border: 1px solid #E0E0E0;
font-family: Arial, Helvetica;
font-size: 10pt;
padding: 12px 12px 12px 12px;
}
.ggl-tooltip div {
padding: 6px 6px 6px 6px;
}
.ggl-tooltip span {
font-weight: bold;
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
This question already helped me too much, but if someone want change the time format in timeline
hAxis: {
format: 'HH:mm'
},
For my RAP-project I need to show some charts. Because I haven't found any widget for this purpose, my plan was to use the browser widget, so I can use JavaScript-Plugins like Highcharts or Chartsjs. But I can't get it working. If I set an HTML-File in browser.setUrl, the browser widget don't show anything, not even simple HTML. The JavaScript-Console in Chrome says
Not allowed to load local resource
If I enter the HTML-Code with the setText method it shows the HTML, but JavaScript is not working, it don't load external JS-File like the jQuery-library.
Can't this be done this way? Or where is my failure? (Sorry for my bad englisch, I'm not native speaker.)
Here's the Java-Code I tried:
browser = new Browser(composite, SWT.NONE);
browser.setTouchEnabled(true);
browser.setBounds(10, 10, 358, 200);
browser.setUrl("D:\\STATS\\statistiken.html");
Or this:
File file = new File("D:\\STATS\\statistiken.html");
browser = new Browser(composite, SWT.NONE);
browser.setTouchEnabled(true);
browser.setBounds(10, 10, 358, 200);
browser.setUrl(file.toURI().toString());
I tried also some other things, there were not working to.
With HTML in setText-method (I tried external libraries and local libraries in same folder):
browser = new Browser(composite, SWT.NONE);
browser.setBounds(10, 10, 358, 200);
browser.setText(
"<html>" +
"<head>" +
"<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js\"></script>" +
"<script src=\"http://code.highcharts.com/highcharts.js\"></script>" +
"<script src=\"http://code.highcharts.com/modules/exporting.js\"></script>" +
"</head>" +
"<body>" +
"<p>Test</p>" +
"<div id=\"container\" style=\"min-width: 400px; height: 400px; margin: 0 auto\"></div>" +
"</body>" +
"</htm>");
Hope someone can help me with this problem.
Local links will not be resolved and external links will not be loaded(Cross Domain problem) in your case.
I could suggest you 2 Solutions.
Solution 1:
This is useful when you have very few resources(html, javascript, css) to render on Browser and no Hyperlinks(which when cliked will load a different page).
You can use Velocity. Read this to start using Velocity.
You can have all the static content in Velocity Template and inject Dynamic content into it at Runtime.
Here is the excerpt from one of my Projects.
init.vm
<html dir="ltr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style type="text/css">
.transcript {
background-color: #d2d2d2;
}
.messageBlock {
margin-left: 4px;
margin-bottom: -15px;
}
.message {
margin-left: 115px;
word-wrap: break-word;
white-space: -moz-pre-wrap;
_white-space: pre;
white-space: pre-wrap;
}
</style>
</head>
<script type="text/javascript">
function resizeChatWindow() { var divT = document.getElementById("divTranscript"); divT.style.height = (document.body.clientHeight - getTopAreaHeight()) + "px"; divT.style.width = (document.body.clientWidth) + "px"; divT.style.overflow = "auto"; divT.style.position = "absolute"; divT.style.left = "0px"; divT.style.top = getTopAreaHeight() + "px";}
function getTopAreaHeight() { var chatAlert = document.getElementById("chatAlert"); if (chatAlert) { return chatAlert.clientHeight; } return document.getElementById("divBody").clientHeight;}
isChat=false; window.onresize=resizeChatWindow;
</script>
<script type="text/javascript">
$scriptText
</script>
<script type="text/javascript">
function addChat(chatText){
$("#divTranscript").append(chatText);
$("#divTranscript").animate({ scrollTop: $("#divTranscript")[0].scrollHeight }, "slow");
}
</script>
<body onload="resizeChatWindow();">
<div id="divBody"></div>
<div id="divTranscript">$history</div>
</body>
</html>
VelocityUtils
private void init() throws Exception {
ve = new VelocityEngine();
Properties velocityProperties = new Properties();
velocityProperties.put("resource.loader", "class");
velocityProperties.put("class.resource.loader.description", "Velocity Classpath Resource Loader");
velocityProperties.put("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
ve.init(velocityProperties);
//ve.init();
}
public String getInitHtml(String history) throws ResourceNotFoundException, ParseErrorException, Exception {
/* now render the template into a StringWriter */
StringWriter writer = null;
/* next, get the Template */
Template t = ve.getTemplate("templates/init.vm","UTF-8");
/* create a context and add data */
VelocityContext context = new VelocityContext();
String script = IOUtils.toString(VelocityUtils.class.getResourceAsStream("script/jquery.min.js"), "UTF-8");
context.put("scriptText", script); //You can even have all the script content in init.vm rather than injecting it at runtime.
context.put("history", StringUtils.defaultIfBlank(history, StringPool.BLANK));
writer = new StringWriter();
t.merge(context, writer);
/* show the World */
String returnMe = writer.toString();
return returnMe;
}
set the returned String in Browser.setText()
Solution 2:
I explained it here.