tcpdf position adding white block at bottom of page - tcpdf

As you can see from this screenshot, there a white area about 100 px tall being added to the bottom of the page that is also pushing the whole page up and off the top of the page. I'm trying to get the text to be on the blue area of the page footer, in white text. I've tried several related suggestions and cant get them to work. Any assistance is greatly appreciated!
Screenshot: http://screencast.com/t/lt3J1Wle76Dm
CODE:
function downloadFile($rid,$count,$userid,$orderid,$email,$user_password,$owner_password) {
global $wpdb;
$rid = intval($rid);
$query = "
SELECT
filehash,filename,filesize,productid
FROM {$this->dbtable}_product
WHERE rid = {$rid}
";
$res = $wpdb->get_results($query);
$r = $res[0];
$file_location = $this->getplugindir()."uploads/".$r->filehash.".file";
if (!file_exists($file_location)) { exit('File does not exist.'); }
if ($count === true) {
$res = $wpdb->query("UPDATE {$this->dbtable}_product SET download_count = download_count+1 WHERE rid = {$rid}");
$this->auditLog($r->productid, $rid, $userid, 'Downloaded');
}
$filename = str_replace(' ', '_', $r->filename);
require_once($this->getplugindir() . 'fpdf/tcpdf/tcpdf.php');
require_once($this->getplugindir() . 'fpdf/tcpdf/tcpdi.php');
//require_once($this->getplugindir() . 'fpdf/tcpdf/wpds.php');
if ($orderid === false) { $orderid = '12345'; }
$pdf = new TCPDI();
$pagecount = $pdf->setSourceFile($file_location);
$pdf->SetAutoPageBreak(false);
for ($i = 1; $i <= $pagecount; $i++){
$pdf->addPage();
$tplidx = $pdf->importPage($i);
$pdf->useTemplate($tplidx);
$pdf->SetAlpha(0.5);
$pdf->SetFont('Courier', 'I', 6);
$pdf->SetTextColor(255,0,0);
$pdf->SetXY(5, -5);
/*
$pdf->StartTransform();
$pdf->Rotate(5);
*/
$pdf->Write(0, "This guide individually licensed to $email ($orderid)");
/*
$pdf->Rotate(0);
$pdf->StopTransform();
*/
$pdf->SetAlpha(1);
}
$pdf->SetProtection(array(
'modify','copy','annot-forms','fill-forms','extract','assemble'
),$user_password,$owner_password,3);
$pdf->Output($filename,'D');
exit();
}

To move your text, change his position with setXY()
Replace :
$pdf->SetXY(5, -5);
By :
$pdf->SetXY(5, -100); // change Y value to be on blue area

Related

Highcharts sankey node without links

I have a highcharts sankey diagram with two sides:
There are situations where some of my nodes have empty links (=with 0 weight). I would like the node to being displayed despite having no link from or to it.
Any chance I can achieve this?
I read on this thread that I have to fake it with weight=1 connexions, I could make the link transparent, and twitch the tooltip to hide those, but that's very painful for something that feels pretty basic.
Maybe a custom call of the generateNode call or something?
Thanks for the help
You can use the following wrap to show a node when the weight is 0.
const isObject = Highcharts.isObject,
merge = Highcharts.merge
function getDLOptions(
params
) {
const optionsPoint = (
isObject(params.optionsPoint) ?
params.optionsPoint.dataLabels : {}
),
optionsLevel = (
isObject(params.level) ?
params.level.dataLabels : {}
),
options = merge({
style: {}
}, optionsLevel, optionsPoint);
return options;
}
Highcharts.wrap(
Highcharts.seriesTypes.sankey.prototype,
'translateNode',
function(proceed, node, column) {
var translationFactor = this.translationFactor,
series = this,
chart = this.chart,
options = this.options,
sum = node.getSum(),
nodeHeight = Math.max(Math.round(sum * translationFactor),
this.options.minLinkWidth),
nodeWidth = Math.round(this.nodeWidth),
crisp = Math.round(options.borderWidth) % 2 / 2,
nodeOffset = column.sankeyColumn.offset(node,
translationFactor),
fromNodeTop = Math.floor(Highcharts.pick(nodeOffset.absoluteTop, (column.sankeyColumn.top(translationFactor) +
nodeOffset.relativeTop))) + crisp,
left = Math.floor(this.colDistance * node.column +
options.borderWidth / 2) + Highcharts.relativeLength(node.options.offsetHorizontal || 0,
nodeWidth) +
crisp,
nodeLeft = chart.inverted ?
chart.plotSizeX - left :
left;
node.sum = sum;
proceed.apply(this, Array.prototype.slice.call(arguments, 1));
if (1) {
// Draw the node
node.shapeType = 'rect';
node.nodeX = nodeLeft;
node.nodeY = fromNodeTop;
let x = nodeLeft,
y = fromNodeTop,
width = node.options.width || options.width || nodeWidth,
height = node.options.height || options.height || nodeHeight;
if (chart.inverted) {
x = nodeLeft - nodeWidth;
y = chart.plotSizeY - fromNodeTop - nodeHeight;
width = node.options.height || options.height || nodeWidth;
height = node.options.width || options.width || nodeHeight;
}
// Calculate data label options for the point
node.dlOptions = getDLOptions({
level: (this.mapOptionsToLevel)[node.level],
optionsPoint: node.options
});
// Pass test in drawPoints
node.plotX = 1;
node.plotY = 1;
// Set the anchor position for tooltips
node.tooltipPos = chart.inverted ? [
(chart.plotSizeY) - y - height / 2,
(chart.plotSizeX) - x - width / 2
] : [
x + width / 2,
y + height / 2
];
node.shapeArgs = {
x,
y,
width,
height,
display: node.hasShape() ? '' : 'none'
};
} else {
node.dlOptions = {
enabled: false
};
}
}
);
Demo:
http://jsfiddle.net/BlackLabel/uh6fp89j/
In the above solution, another node arrangement would be difficult to achieve and may require a lot of modifications beyond our scope of support.
You can consider using mentioned "tricky solution", since might return a better positioning result. This solution is based on changing 0 weight nodes on the chart.load() event and converting the tooltip as well, so it may require adjustment to your project.
chart: {
events: {
load() {
this.series[0].points.forEach(point => {
if (point.weight === 0) {
point.update({
weight: 0.1,
color: 'transparent'
})
}
})
}
}
},
tooltip: {
nodeFormatter: function() {
return `${this.name}: <b>${Math.floor(this.sum)}</b><br/>`
},
pointFormatter: function() {
return `${this.fromNode.name} → ${this.toNode.name}: <b>${Math.floor(this.weight)}</b><br/>`
}
},
Demo:
http://jsfiddle.net/BlackLabel/0dqpabku/

Highcharts Showing Uncaught TypeError: Cannot read properties of undefined (reading 'chart')

I've had this HighCharts spider chart working fine for a while now, but we upgraded to the latest HighCharts code and I noticed that the mouseovers are no longer working. My PHP code looks like this:
// Create a new Highchart
$chart = new Highchart();
$chart->includeExtraScripts();
$chart->chart->renderTo = "control_maturity_spider_chart";
$chart->chart->polar = true;
$chart->chart->type = "line";
$chart->chart->width = 1000;
$chart->chart->height = 1000;
$chart->title->text = "Current vs Desired Maturity by Control Family";
$chart->title->x = -80;
$chart->pane->size = "80%";
$chart->xAxis->categories = $categories;
$chart->xAxis->tickmarkPlacement = "on";
$chart->xAxis->lineWidth = 0;
$chart->yAxis->gridLineInterpolation = "polygon";
$chart->yAxis->lineWidth = 0;
$chart->yAxis->min = 0;
$chart->yAxis->max = 5;
$chart->yAxis->tickInterval = 1;
$chart->tooltip->shared = true;
$chart->tooltip->pointFormat = '<span style="color:{series.color}">{series.name}: <b>{point.y}</b><br/>';
$chart->legend->align = "center";
$chart->legend->verticalAlign = "top";
$chart->legend->layout = "vertical";
// Draw the Current Maturity series
$chart->series[0]->name = $escaper->escapeHtml($lang['CurrentControlMaturity']);
$chart->series[0]->data = empty($categories_current_maturity_average) ? [] : $categories_current_maturity_average;
$chart->series[0]->pointPlacement = "on";
// Draw the Desired Maturity series
$chart->series[1]->name = $escaper->escapeHtml($lang['DesiredControlMaturity']);
$chart->series[1]->data = empty($categories_desired_maturity_average) ? [] : $categories_desired_maturity_average;
$chart->series[1]->pointPlacement = "on";
$chart->credits->enabled = false;
echo "<figure class=\"highcharts-figure\">\n";
echo " <div id=\"control_maturity_spider_chart\"></div>\n";
echo "</figure>\n";
echo "<script type=\"text/javascript\">";
echo $chart->render("control_maturity_spider_chart");
echo "</script>\n";
The actual chart renders just fine, but if you mouse over it, you just get this message in the javascript console over and over again:
HighCharts Error Message
If we comment out these two lines of code, the mouseover works:
$chart->tooltip->shared = true;
$chart->tooltip->pointFormat = '<span style="color:{series.color}">{series.name}: <b>{point.y}</b><br/>';
Any thoughts on what we are doing wrong here, or what changed, would be greatly appreciated. Thank you.
this is the bug which you can track here: https://github.com/highcharts/highcharts/issues/17472
As a temporary workaround, add the following wrap function to your code:
(function(H) {
const isObject = H.isObject;
H.Pointer.prototype.findNearestKDPoint = function(series, shared, e) {
var chart = this.chart;
var hoverPoint = chart.hoverPoint;
var tooltip = chart.tooltip;
if (hoverPoint &&
tooltip &&
tooltip.isStickyOnContact()) {
return hoverPoint;
}
var closest;
/** #private */
function sort(p1, p2) {
var isCloserX = p1.distX - p2.distX,
isCloser = p1.dist - p2.dist,
isAbove = ((p2.series.group && p2.series.group.zIndex) -
(p1.series.group && p1.series.group.zIndex));
var result;
// We have two points which are not in the same place on xAxis
// and shared tooltip:
if (isCloserX !== 0 && shared) { // #5721
result = isCloserX;
// Points are not exactly in the same place on x/yAxis:
} else if (isCloser !== 0) {
result = isCloser;
// The same xAxis and yAxis position, sort by z-index:
} else if (isAbove !== 0) {
result = isAbove;
// The same zIndex, sort by array index:
} else {
result =
p1.series.index > p2.series.index ?
-1 :
1;
}
return result;
}
series.forEach(function(s) {
var noSharedTooltip = s.noSharedTooltip && shared,
compareX = (!noSharedTooltip &&
s.options.findNearestPointBy.indexOf('y') < 0),
point = s.searchPoint.call(s.polar, e, compareX);
if ( // Check that we actually found a point on the series.
isObject(point, true) && point.series &&
// Use the new point if it is closer.
(!isObject(closest, true) ||
(sort(closest, point) > 0))) {
closest = point;
}
});
return closest;
};
}(Highcharts))
Demo:
https://jsfiddle.net/BlackLabel/8b2mhqf0/

I cannot catch mouse signals on widgets within a wibox.container.scroll

I am constructing widgets dynamically from from the output of iw dev interface scan I then add them to a scroll box held in a wibox. The problem I find is that the mouse::enter and mouse::leave signals I connect the widgets to do not catch the mouse signals when inside the wibox.container.scroll. All the rest of the code works as intended and the signals are caught as intended if I omit the wibox.container.scroll wrapper.
The widget template to be added to the scroll container:
function wifitbox.new(ssid, screen, interface)
tbox = wibox.widget{
{
{
wibox.widget.textbox(ssid[2] .. " " .. ssid[3]),
{
wibox.widget.textbox(ssid[4]),
halign = "right",
widget = wibox.container.place
},
layout = wibox.layout.ratio.horizontal
},
margins = beautiful.xresources.apply_dpi(10, screen),
widget = wibox.container.margin
},
id = "tbox",
bg = beautiful.wifi_tbox_bg or "#928374",
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, 5)
end,
widget = wibox.container.background
}
awful.spawn.easy_async('bash -c "sudo iw dev ' .. interface .. ' station dump | awk \'FNR == 1 {print($2)}\'"', function(stdout)
if(gears.string.split(stdout, "\n")[1] == ssid[1]) then
tbox.bg = "#b16286"
end
end)
tbox:connect_signal("mouse::enter", function()
tbox.bg_cache = tbox.bg
tbox.bg = "#689d6a"
end)
tbox:connect_signal("mouse::leave", function()
tbox.bg = tbox.bg_cache
end)
return tbox
end
The two :signal_connect() statements are the ones in questions.
The widgets are added to the scroll container a follows:
awful.spawn.with_line_callback(cmd, {
stdout = function(line)
local ssid = gears.string.split(line, "\t")
wifitbox_table:get_children_by_id("tbox_list")[1]:add(wifitbox(ssid, screen, interface))
end,
output_done = function()
self:set_widget(wifitbox_table)
end
})
The widget the containing the scroll container is as follows:
local wifitbox_table = wibox.widget{
scrollbtn,
{
id = "scroll_box",
speed = 100,
extra_space = beautiful.xresources.apply_dpi(5, screen),
layout = wibox.container.scroll.vertical,
step_function = wibox.container.scroll.step_functions.linear_increase,
{
id= "tbox_list",
spacing = beautiful.xresources.apply_dpi(5, screen),
layout = wibox.layout.fixed.vertical()
}
},
spacing = beautiful.xresources.apply_dpi(5, screen),
layout = wibox.layout.fixed.vertical,
}
As I mentioned before if i remove the "scroll_box" widget around the "tbox_list" widget the signals connect without issue. But then obviously I don't get scrolling.
And finally all of it put together:
local awful = require('awful')
local wibox = require('wibox')
local gears = require('gears')
local beautiful = require('beautiful')
local wifimodal = { mt = {} }
local wifitbox = { mt = {} }
local setmetatable = setmetatable
function wifitbox.new(ssid, screen, interface)
tbox = wibox.widget{
{
{
wibox.widget.textbox(ssid[2] .. " " .. ssid[3]),
{
wibox.widget.textbox(ssid[4]),
halign = "right",
widget = wibox.container.place
},
layout = wibox.layout.ratio.horizontal
},
margins = beautiful.xresources.apply_dpi(10, screen),
widget = wibox.container.margin
},
id = "tbox",
bg = beautiful.wifi_tbox_bg or "#928374",
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, 5)
end,
widget = wibox.container.background,
}
awful.spawn.easy_async('bash -c "sudo iw dev ' .. interface .. ' station dump | awk \'FNR == 1 {print($2)}\'"', function(stdout)
if(gears.string.split(stdout, "\n")[1] == ssid[1]) then
tbox.bg = "#b16286"
end
end)
tbox:connect_signal("mouse::enter", function()
tbox.bg_cache = tbox.bg
tbox.bg = "#689d6a"
end)
tbox:connect_signal("mouse::leave", function()
tbox.bg = tbox.bg_cache
end)
return tbox
end
function wifitbox.mt.__call(_, ...)
return wifitbox.new(...)
end
setmetatable(wifitbox, wifitbox.mt)
function wifimodal.new(screen, interface, curSSID)
self = wibox {
screen = screen,
width = screen.geometry.width / 5,
type = 'modal',
height = screen.workarea.height/2,
x = screen.geometry.width - screen.geometry.width/5,
y = beautiful.xresources.apply_dpi(beautiful.wibar_height or 25, screen),
ontop = true,
visible = true,
bg = beautiful.bg_normal,
fg = "black",
opacity = 0.8,
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, 5)
end
}
self:connect_signal('mouse::leave', function()
self.visible = false
self = nil
end)
local scrollbtn = wibox.widget{
{
{
widget = wibox.widget.imagebox,
resize = true,
image = gears.filesystem.get_configuration_dir() .. "widgets/wifi/arrow_up.png",
forced_height = beautiful.xresources.apply_dpi(25, screen),
},
widget = wibox.container.place,
valign = "center",
},
shape = function(cr, width, height)
gears.shape.rounded_rect(cr, width, height, 5)
end,
widget = wibox.container.background,
bg = beautiful.wifi_scroll_btn_bg or "#d79921",
}
scrollbtn:connect_signal("mouse::enter", function()
scrollbtn:emit_signal_recursive("scroll::continue")
scrollbtn.bg = beautiful.wifi_scroll_btn_bg_hover or "#458588"
end)
scrollbtn:connect_signal("mouse::leave", function()
scrollbtn:emit_signal_recursive("scroll::pause")
scrollbtn.bg = beautiful.wifi_scroll_btn_bg or "#d79921"
end)
local scan_awk = gears.filesystem.get_configuration_dir() .. "widgets/wifi/scan.awk"
local cmd = 'bash -c "sudo iw ' .. interface .. ' scan | awk -f ' .. scan_awk .. '"'
local wifitbox_table = wibox.widget{
scrollbtn,
{
id = "scroll_box",
speed = 100,
extra_space = beautiful.xresources.apply_dpi(5, screen),
layout = wibox.container.scroll.vertical,
step_function = wibox.container.scroll.step_functions.linear_increase,
{
id= "tbox_list",
spacing = beautiful.xresources.apply_dpi(5, screen),
layout = wibox.layout.fixed.vertical()
}
},
spacing = beautiful.xresources.apply_dpi(5, screen),
layout = wibox.layout.fixed.vertical,
}
local scrollbox = wifitbox_table:get_children_by_id("scroll_box")[1]
scrollbox:pause()
wifitbox_table:connect_signal("scroll::continue", function()
scrollbox:continue()
end)
wifitbox_table:connect_signal("scroll::pause", function()
scrollbox:pause()
end)
awful.spawn.with_line_callback(cmd, {
stdout = function(line)
local ssid = gears.string.split(line, "\t")
wifitbox_table:get_children_by_id("tbox_list")[1]:add(wifitbox(ssid, screen, interface))
end,
output_done = function()
self:set_widget(wifitbox_table)
end
})
return self
end
function wifimodal.mt.__call(_, ...)
return wifimodal.new(...)
end
return setmetatable(wifimodal, wifimodal.mt)
Here is a screen shot for some context:
Also, if you don't have the answer but notice something else you can critic feel free. Thank you
The problem I find is that the mouse::enter and mouse::leave signals I connect the widgets to do not catch the mouse signals when inside the wibox.container.scroll
The third sentence on https://awesomewm.org/doc/api/classes/wibox.container.scroll.html is:
Please note that mouse events do not propagate to widgets inside of the scroll container.
So, this is "working as intended".
Also: https://github.com/awesomeWM/awesome/issues/3076

PHPPowerpoint set Hyperlink in table cell

I want to set an Hyperlink in a table cell:
/* ADD TABLE ROW */
foreach ($entries as $entry) {
$row = $tableShape->createRow();
$row->getFill()->setFillType(Fill::FILL_SOLID)
->setStartColor(new Color('FFFFFFFF'))
->setEndColor(new Color('FFFFFFFF'));
$row->nextCell()->createTextRun(date_format($entry->getDate(), "d.m.Y"));
$row->nextCell()->createTextRun($entry->getTonality()->getName());
$row->nextCell()->createTextRun($entry->getAccountname());
$row->nextCell()->createTextRun($entry->getContent());
$row->nextCell()->createTextRun($entry->getFollower());
$row->nextCell()->createTextRun($entry->getLink());
}
This code doesn't work:
$row->nextCell()->createTextRun('Link')->setUrl($entry->getLink())
->setTooltip('Link');;
I'm doing it now by adding a shape on the right position.
/* SET HYPERLINK WITH SHAPE */
$shape = $slide->createRichTextShape();
$shape->setWidth($this->cell_link_width)
->setHeight($this->cell_height)
->setOffsetX($this->cell_link_offsetX)
>setOffsetY($this->tableOffsetY + $height);
$textLink = $shape->createTextRun('Link');
$textLink->getHyperlink()->setUrl('http://' . $entry->getLink())
>setTooltip('http://' . $entry->getLink());
I have write an algorithmus and define a variable line_height to set the link on the right position.
Here is my complete function:
public function createTableSlide($objPHPPowerPoint, $pathLogo, $user, $entries) {
$slide = $this->createTemplatedSlide($objPHPPowerPoint, $pathLogo, $user);
/* CREATE TABLE WITH COLUMNS */
$tableShape = $this->getTable($slide, 6);
$this->setTableSlideHeader($slide, 'Social Media', 'Twitter', $tableShape);
/* ADD TABLE ROW */
$i = 1;
$height = 22;
$height_tmp = 0;
$max_height = 554;
foreach ($entries as $entry) {
$height += $height_tmp;
$modulId = $entry->getModul()->getId();
/* NEW SLIDE IF TABLE HEIGHT AT END OF SLIDE */
if($height >= $max_height){
$slide = $this->createTemplatedSlide($objPHPPowerPoint, $pathLogo, $user);
/* CREATE TABLE WITH COLUMNS */
$tableShape = $this->getTable($slide, 6);
$this->setTableSlideHeader($slide, 'Social Media', 'Twitter', $tableShape);
$i = 1;
$height = 22;
$height_tmp = 0;
}
$row_in_cell = ceil(strlen($entry->getContent()) / $this->char_in_row);
if ($row_in_cell > 2) {
$height_tmp = $row_in_cell * $this->line_height + $this->line_height;
} else {
$height_tmp = $this->line_height * 3 + 0.8;
}
$row = $tableShape->createRow();
$row->setHeight($this->cell_height);
$row->getFill()->setFillType(Fill::FILL_SOLID)
->setStartColor(new Color('FFFFFFFF'))
->setEndColor(new Color('FFFFFFFF'));
$row->nextCell()->createTextRun(date_format($entry->getDate(), "d.m.Y"));
$row->nextCell()->createTextRun($entry->getTonality()->getName());
$row->nextCell()->createTextRun($entry->getAccountname());
$row->nextCell()->createTextRun($entry->getContent());
$row->nextCell()->createTextRun($entry->getFollower());
$row->nextCell()->createTextRun($modulId);
/* SET HYPERLINK WITH SHAPE */
$shape = $slide->createRichTextShape();
$shape->setWidth($this->cell_link_width)
->setHeight($this->cell_height)
->setOffsetX($this->cell_link_offsetX)
->setOffsetY($this->tableOffsetY + $height);
$textLink = $shape->createTextRun('Link');
$textLink->getHyperlink()->setUrl('http://' . $entry->getLink())
->setTooltip('http://' . $entry->getLink());
$i++;
}
}
Hope it can help you if you search for the same solution. If anyone has a better solution he can answer me :)
The issue has been fixed in the develop branch.
Link : https://github.com/PHPOffice/PHPPowerPoint/commit/43bea92220396a3c7178f649afbc961be28828c1

How to vary the width of TextBox views using Rikulo Anchor Layout

I am new to Dart and Rikulo.
class NameView extends Section
{
View parentVu;
// the inputs
DropDownList titleDdl, suffixDdl;
TextBox firstNameTBox, middleNameTBox, lastNameTBox;
// the labels
TextView titleLbl, firstNameLbl, middleNameLbl, lastNameLbl, suffixLbl;
List<String> titles = [ 'Dr', 'Hon', 'Miss', 'Mr', 'Mrs', 'Prof', 'Sir' ];
List<String> suffixes = ['I', 'II', 'III', 'IV', 'Junior', 'Senior'];
NameView()
{
parentVu = new View()
..style.background = 'cyan'
..addToDocument();
titleLbl = new TextView( 'Title' );
parentVu.addChild( titleLbl );
titleDdl = new DropDownList( model : new DefaultListModel( titles ) )
..profile.anchorView = titleLbl
..profile.location = 'east center';
parentVu.addChild( titleDdl );
firstNameLbl = new TextView( 'First' )
..profile.anchorView = titleDdl
..profile.location = 'east center';
parentVu.addChild(firstNameLbl );
firstNameTBox = new TextBox( null, 'text' )
..profile.anchorView = firstNameLbl
..profile.location = 'east center';
//..profile.width = 'flex';
parentVu.addChild( firstNameTBox );
}
The program renders. However, it does not uses the entire width of the browser (FireFox).
I have tried for the TextBoxes
profile.width = 'flex'
but it does not work.
Any help is appreciated.
Firefox? Did you test it with Dartium? Notice that you have to compile it to JS before you can test it with browsers other than Dartium.
BTW, from your implementation, NameView seems not related to parentVu at all. If it is just a controller, it needs not to extend from Section (i.e., it doesn't have to be a view).
If a view is anchored to another, both location and size will depend on the view it anchors. In your case, if specifying flex to TextBox, its width will be the same as FirstNameLb1. It is why it is so small.
You can listen to the layout event such as:
firstNameTBox.on.layout.listen((_) {
firstNameTBox.width = parentVu.width;
});
Note: You need to do some calculation to get the right width.
See also Layout Overview

Resources