pChart image render issue on prod server and same script is working on dev server, while configurations are same - server-side-rendering

I am having the issue with pChart image rendering, The chart image is not displaying on screen on my production server while the same script is working fine on development server.
Even,I have checked and compared configuration of both servers its are almost same.
In only one scenario, The image is display with same script on production server, when i restart my prod server but after some times it not work automatically. I don't know what is the root cause of it.
Please help to solve this issue. Below is the screenshot of code:
<?php
/* CAT:Area Chart */
/* pChart library inclusions */
include("../class/pData.class.php");
include("../class/pDraw.class.php");
include("../class/pImage.class.php");
/* Create and populate the pData object */
$MyData = new pData();
for($i=0;$i<=30;$i++) { $MyData->addPoints(rand(1,15),"Probe 1"); }
$MyData->setSerieTicks("Probe 2",4);
$MyData->setAxisName(0,"Temperatures");
/* Create the pChart object */
$myPicture = new pImage(700,230,$MyData);
/* Turn of Antialiasing */
$myPicture->Antialias = FALSE;
/* Add a border to the picture */
$myPicture->drawGradientArea(0,0,700,230,DIRECTION_VERTICAL,array("StartR"=>240,"StartG"=>240,"StartB"=>240,"EndR"=>180,"EndG"=>180,"EndB"=>180,"Alpha"=>100));
$myPicture->drawGradientArea(0,0,700,230,DIRECTION_HORIZONTAL,array("StartR"=>240,"StartG"=>240,"StartB"=>240,"EndR"=>180,"EndG"=>180,"EndB"=>180,"Alpha"=>20));
/* Add a border to the picture */
$myPicture->drawRectangle(0,0,699,229,array("R"=>0,"G"=>0,"B"=>0));
/* Write the chart title */
$myPicture->setFontProperties(array("FontName"=>"../fonts/Forgotte.ttf","FontSize"=>11));
$myPicture->drawText(150,35,"Average temperature",array("FontSize"=>20,"Align"=>TEXT_ALIGN_BOTTOMMIDDLE));
/* Set the default font */
$myPicture->setFontProperties(array("FontName"=>"../fonts/pf_arma_five.ttf","FontSize"=>6));
/* Define the chart area */
$myPicture->setGraphArea(60,40,650,200);
/* Draw the scale */
$scaleSettings = array("XMargin"=>10,"YMargin"=>10,"Floating"=>TRUE,"GridR"=>200,"GridG"=>200,"GridB"=>200,"GridAlpha"=>100,"DrawSubTicks"=>TRUE,"CycleBackground"=>TRUE);
$myPicture->drawScale($scaleSettings);
/* Write the chart legend */
$myPicture->drawLegend(640,20,array("Style"=>LEGEND_NOBORDER,"Mode"=>LEGEND_HORIZONTAL));
/* Turn on Antialiasing */
$myPicture->Antialias = TRUE;
/* Enable shadow computing */
$myPicture->setShadow(TRUE,array("X"=>1,"Y"=>1,"R"=>0,"G"=>0,"B"=>0,"Alpha"=>10));
/* Draw the area chart */
$Threshold = "";
$Threshold[] = array("Min"=>0,"Max"=>5,"R"=>187,"G"=>220,"B"=>0,"Alpha"=>100);
$Threshold[] = array("Min"=>5,"Max"=>10,"R"=>240,"G"=>132,"B"=>20,"Alpha"=>100);
$Threshold[] = array("Min"=>10,"Max"=>20,"R"=>240,"G"=>91,"B"=>20,"Alpha"=>100);
$myPicture->setShadow(TRUE,array("X"=>1,"Y"=>1,"R"=>0,"G"=>0,"B"=>0,"Alpha"=>20));
$myPicture->drawAreaChart(array("Threshold"=>$Threshold));
/* Draw a line chart over */
$myPicture->drawLineChart(array("ForceColor"=>TRUE,"ForceR"=>0,"ForceG"=>0,"ForceB"=>0));
/* Draw a plot chart over */
$myPicture->drawPlotChart(array("PlotBorder"=>TRUE,"BorderSize"=>1,"Surrounding"=>-255,"BorderAlpha"=>80));
/* Write the thresholds */
$myPicture->drawThreshold(5,array("WriteCaption"=>TRUE,"Caption"=>"Warn Zone","Alpha"=>70,"Ticks"=>2,"R"=>0,"G"=>0,"B"=>255));
$myPicture->drawThreshold(10,array("WriteCaption"=>TRUE,"Caption"=>"Error Zone","Alpha"=>70,"Ticks"=>2,"R"=>0,"G"=>0,"B"=>255));
/* Render the picture (choose the best way) */
//$myPicture->autoOutput("pictures/example.drawAreaChart.threshold.png");
$myPicture->stroke();
?>
Not displaying image like below screenshot:

This issue has been resolved after deep investigation.
I have replaced imagepng() to imagejpeg() in class/pImage.class.php.
I replaced imagepng() to imagejpeg() function at 2 places below are description given:
1) In render function
function render($FileName)
{
if ( $this->TransparentBackground ) { imagealphablending($this->Picture,false); imagesavealpha($this->Picture,true); }
imagejpeg($this->Picture,$FileName);
}
2) In stroke function
function stroke($BrowserExpire=FALSE)
{
if ( $this->TransparentBackground ) { imagealphablending($this->Picture,false); imagesavealpha($this->Picture,true); }
if ( $BrowserExpire )
{
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Cache-Control: no-cache");
header("Pragma: no-cache");
}
header('Content-type: image/png');
imagejpeg($this->Picture);
}

Related

Animate plots using echarts4r when quarto slides are on-screen

I am making a Revealjs presentation using Quarto in R Studio. I am using the package {echarts4r} to make my plots. {echarts4r} comes with default animations. When I render the presentation the default animation has already loaded for all the slides.
I want to run the default echarts4r animations when the slide is active (i.e. when the slide is in view) and reset when some other slide is in view. Could someone help me with this?
Here is the code for the quarto presentation.
---
title: "A Title"
subtitle: "A Subtitle"
author: "First Last"
institute: "Some Institute"
date: today
self-contained: true
format: revealjs
---
## Introduction
Hello There!
## Pie Chart
```{r}
library(tidyverse)
library(echarts4r)
data <- tibble(name = c("A", "B", "C", "D", "E", "F", "G"),
number = c(9.7, 2.1, 2.1, 1.9, 1.9, 1.9, 80.4))
data %>%
e_charts(name) %>%
e_pie(number, radius = c("50%", "70%")) %>%
e_legend(orient = "vertical", right = "5", top = "65%")
```
This isn't a fix or a Quarto method. However, this workaround is dynamic. I worked out what needs to happen with both echarts4r and highcharter because of the comment by #bretauv.
Assign Element IDs
The only thing you'll change with your charts is that you need to give them an element ID. IDs need to be unique across the entire presentation. It's perfectly okay to use something like 'ec0', 'ec1'... and so on for your plots' ids. (You only need to do this to plots that animate.)
Here's an example.
```{r pltEchart, echo=F}
iris |> group_by(Species) |>
e_charts(Sepal.Length, elementId = "pltEcht") |> # <--- id is here
e_scatter(Sepal.Width)
```
For highcharter, and most other widget style packages, adding the element id isn't built in. Here's how you add the id for highcharter.
```{r penquins,echo=F}
hc <- hchart(penguins, "scatter",
hcaes(x = flipper_length_mm, y = bill_length_mm, group = species))
hc$elementId <- "hc_id"
hc
```
Re-Animating Plots
For each of echarts4r plots, to apply this next part you need the slide it's on and it's element id.
For highcharter, you also need to know the order in which it appears in your presentation (only in terms of other highcharter plots).
Whether you use the less dynamic approach or the more dynamic approach, what remains is adding a JS chunk to your QMD. This chunk can go anywhere in the script file. (I usually put any JS in my RMDs/QMDs at the end.)
If you were not aware, JS is built-in. You don't need to do anything new or different to use JS this way. However, if you were to run this chunk in the source pane, it won't do anything. You have to render it to see it in action. If you end up changing the JS or writing more of your own, don't assume what you see in RStudio's viewer or presentation pane is exactly what you'll see in your browser.
I would skim over what you have to change for both methods before you decide! If you're not comfortable using JS, the second is definitely your best bet.
Customized Information For Each Presentation For Each Re-Animated Plot
For each plot you re-animate, you'll have to identify:
a substring of the slide title OR the slide number (where slide numbers are included on the slides via YAML declaration)
plot element ids
plot order (plot order or sequence is for Highcharts only).
For the slide title substring, as you use it in the JS:
it's a substring of the title based on the hash or anchor that is assigned in the background
substring is all lowercase
no special characters
must be unique to that slide
If you're unsure what to use or how to find what's unique—there's an easy way to find that information. If you open your presentation in your browser from the presentation pane in RStudio, the URL of the slides will look similar to this.
Every slide will have the same initial component to the URL, http://localhost:7287/#/, but beyond that, every slide will be unique.
http://localhost:7287/#/another-hc
The string after the # is the title anchor for that slide. You can use exactly what's in the URL (after #/).
Put it Altogether
This continuously checks if the slide has changed (10-millisecond interval). If there's a slide change, it then checks to see if one of the three plots is on that slide. If so, the slide animation is restarted.
What you need to personalize in the JS
ecReloader for charts4r has 2 arguments:
title substring OR slide number
plot element ID
hcReloader for highcharter has 3 arguments:
title substring OR slide number
plot element ID
plot sequence number
In the setInterval function (chunk named customizeMe, you will need to write a function call for each plot you want to re-animate. In my example, I reanimated three plots. This is the ONLY part you modify. (Note that each line needs to end with a semi-colon.)
ecReloader('code', 'pltEcht'); /* slide title. plot element id */
hcReloader('highchart', 'hc_id', 0); /* slide title, id, sequence */
hcReloader(6, 'another_hc_id', 1); /* slide number, id, sequence */
/* assuming only one on slide */
setInterval(function() {
var current = window.location.hash;
tellMe = keepLooking(current);
if(tellMe) { /* if the slide changed, then look */
ecReloader('code', 'pltEcht');
hcReloader('highchart', 'hc_id', 0);
hcReloader(6, 'another_hc_id', 1); /* second highcharter plot */
}
}, 10); // check every 10 milliseconds
In your presentation, you need to take both of the JS chunks to make this work. (Chunk names are customizeMe and reloaders.)
I'm sure there's a way to customize the appearance of the slide numbers; this code is based on the default, though.
Here's all the JS to make this work.
```{r customizeMe,echo=F,engine='js'}
/* assuming only one on slide */
setInterval(function() {
var current = window.location.hash;
tellMe = keepLooking(current);
if(tellMe) { /* if the slide changed, then look */
ecReloader('code', 'pltEcht');
hcReloader('highchart', 'hc_id', 0);
hcReloader(6, 'another_hc_id', 1); /* second highcharter plot */
}
}, 10); // check every 10 milliseconds
```
```{r reloaders,echo=F,engine='js'}
// more dynamic; a couple of key words for each plot
// multiple options for addressing Echarts plots
function ecReloader(slide, id) {
/* slide (string) slide title unique substring (check URL when on the slide)
--or--
(integer) as in the slide number
id (string) element id of the plot to change */
if(typeof slide === 'number') { // slide number provided
which = document.querySelector('div.slide-number'); // page numbers like '6 / 10'
validator = Number(which.innerText.split(' ')[0]);
if(slide === validator) { // slide number matches current slide
var ec = document.getElementById(id);
ele = echarts.init(ec, get_e_charts_opts(ec.id));
thatsIt = get_e_charts_opts(ec.id); /* store data */
ele.setOption({xAxis: {}, yAxis: {}}, true); /* remove data */
ele.setOption(thatsIt, false); /* append original data */
}
} else { // unique element in slide title
if(window.location.hash.indexOf(slide) > -1) {
var ec = document.getElementById(id);
ele = echarts.init(ec, get_e_charts_opts(ec.id));
thatsIt = get_e_charts_opts(ec.id); /* store data */
ele.setOption({xAxis: {}, yAxis: {}}, true); /* remove data */
ele.setOption(thatsIt, false); /* append original data */
}
}
}
// multiple options for addressing Highcharts plots, assumes 1 chart per slide!
function hcReloader(slide, id, order) {
/* slide (string) slide title unique substring (check URL when on the slide)
--or--
(integer) as in the slide number
id (string) element id of the plot to change
order (integer) 0 through the number of charts in the plot, which one is this plot?
(in order of appearance) */
if(typeof slide === 'number') { // slide number provided
which = document.querySelector('div.slide-number'); // page numbers like '6 / 10'
validator = Number(which.innerText.split(' ')[0]);
if(slide === validator) { // slide number matches current slide
var hc1 = document.getElementById(id).firstChild;
Highcharts.chart(hc1, Highcharts.charts[order].options); // re-draw plot
}
} else { // unique element in slide title
if(window.location.hash.indexOf(slide) > -1) {
var hc1 = document.getElementById(id).firstChild;
Highcharts.chart(hc1, Highcharts.charts[order].options); // re-draw plot
}
}
}
/* Current Slide Section (bookmark #) */
oHash = window.location.hash;
/* check if the slide has changed */
function keepLooking (nHash) {
if(oHash === nHash) {
return false;
} else {
oHash = nHash; /* if slide changed, reset the value of oHash */
return true;
}
}
```
Here is the entire QMD script I used to create and test this so you can see how it works.
---
title: "Untitled"
format:
revealjs:
slide-number: true
editor: source
---
## Quarto
```{r basics, echo=F}
library(echarts4r)
library(tidyverse)
library(htmltools)
library(highcharter)
```
```{r data, include=F,echo=F}
data("iris")
data(penguins, package = "palmerpenguins")
```
word
## Bullets
more words
## More Plots; How about Highcharter?
```{r penquins,echo=F}
hc <- hchart(penguins, "scatter",
hcaes(x = flipper_length_mm, y = bill_length_mm, group = species))
hc$elementId <- "hc_id"
hc
```
## Code
`echarts` style plot
```{r pltEcht, echo=F}
iris |> group_by(Species) |>
e_charts(Sepal.Length, elementId = "pltEcht") |> e_scatter(Sepal.Width)
```
## Another HC
```{r penquins2,echo=F}
hc2 <- hchart(iris, "scatter",
hcaes(x = Sepal.Length, y = Sepal.Width, group = Species))
hc2$elementId <- "another_hc_id"
hc2
```
```{r customizeMe,echo=F,engine='js'}
/* assuming only one on slide */
setInterval(function() {
var current = window.location.hash;
tellMe = keepLooking(current);
if(tellMe) { /* if the slide changed, then look */
ecReloader('code', 'pltEcht');
hcReloader('highchart', 'hc_id', 0);
hcReloader(6, 'another_hc_id', 1); /* second highcharter plot */
}
}, 10); // check every 10 milliseconds
```
```{r reloaders,echo=F,engine='js'}
// more dynamic; a couple of key words for each plot
// multiple options for addressing Echarts plots
function ecReloader(slide, id) {
/* slide (string) slide title unique substring (check URL when on the slide)
--or--
(integer) as in the slide number
id (string) element id of the plot to change */
if(typeof slide === 'number') { // slide number provided
which = document.querySelector('div.slide-number'); // page numbers like '6 / 10'
validator = Number(which.innerText.split(' ')[0]);
if(slide === validator) { // slide number matches current slide
var ec = document.getElementById(id);
ele = echarts.init(ec, get_e_charts_opts(ec.id));
thatsIt = get_e_charts_opts(ec.id); /* store data */
ele.setOption({xAxis: {}, yAxis: {}}, true); /* remove data */
ele.setOption(thatsIt, false); /* append original data */
}
} else { // unique element in slide title
if(window.location.hash.indexOf(slide) > -1) {
var ec = document.getElementById(id);
ele = echarts.init(ec, get_e_charts_opts(ec.id));
thatsIt = get_e_charts_opts(ec.id); /* store data */
ele.setOption({xAxis: {}, yAxis: {}}, true); /* remove data */
ele.setOption(thatsIt, false); /* append original data */
}
}
}
// multiple options for addressing Highcharts plots, assumes 1 chart per slide!
function hcReloader(slide, id, order) {
/* slide (string) slide title unique substring (check URL when on the slide)
--or--
(integer) as in the slide number
id (string) element id of the plot to change
order (integer) 0 through the number of charts in the plot, which one is this plot?
(in order of appearance) */
if(typeof slide === 'number') { // slide number provided
which = document.querySelector('div.slide-number'); // page numbers like '6 / 10'
validator = Number(which.innerText.split(' ')[0]);
if(slide === validator) { // slide number matches current slide
var hc1 = document.getElementById(id).firstChild;
Highcharts.chart(hc1, Highcharts.charts[order].options); // re-draw plot
}
} else { // unique element in slide title
if(window.location.hash.indexOf(slide) > -1) {
var hc1 = document.getElementById(id).firstChild;
Highcharts.chart(hc1, Highcharts.charts[order].options); // re-draw plot
}
}
}
/* Current Slide Section (bookmark #) */
oHash = window.location.hash;
/* check if the slide has changed */
function keepLooking (nHash) {
if(oHash === nHash) {
return false;
} else {
oHash = nHash; /* if slide changed, reset the value of oHash */
return true;
}
}
```
You can put the JS anywhere in your QMD.
If you see delays in loading (flashing, that sort of thing), you can lower the milliseconds between intervals. (That number is at the end of the setInterval function, where you see }, 10).
If something goes wrong, you can just set the JS to eval=F. You didn't actually change anything in your presentation permanently.

CSS for mobile landscape rotated-left vs rotated-right?

Is there a CSS-only solution yet to differentiate rotate-left-landscape from rotate-right-landscape?
We've got orientation, but not left or right.
#media screen and (orientation:landscape) /* true for both left and right */
If I want to build around an iPhone notch, safe areas help but are activated on both sides. E.g. if you rotate an iPhone left, both left and right insets activate. But I only care about the notch side. I'd like to use the extra 47px on the other.
/* If we rotate phone 90deg left */
env(safe-area-inset-left) /* shows 47px */
env(safe-area-inset-right) /* shows 47px */
We've had the JS orientation api since 2007!
window.orientation // 90
// Deprecated
window.addEventListener("orientationchange", () => {
// update styles, add remove css classes, etc
}, false);
window.onorientationchange = (event) => {
console.log("the orientation of the device is now " + event.target.screen.orientation.angle);
};

iOS 13 Safari: Bug(s) in window.innerHeight

As I understand it, the window.innerHeight should return the size of the viewport without the browser chrome (address bar, navigation, tabs, etc.). But this doesn't seem to be the case in the latest version of iOS13. Instead there are two problems:
(Sometimes* too small in portrait) If you rotate from portrait mode to landscape mode with no tabs open and then back to portrait mode, the window.innerHeight value ends up being too small (by about the size of the bottom navigation bar) giving this horrible white bar at the bottom of the screen. See this discussion on macrumors for more details: https://forums.macrumors.com/threads/is-this-a-mobile-safari-bug-white-space-appears-at-bottom-after-rotating-iphone.2209551/
(Sometimes* too big in landscape) If you have a bunch of tabs open, "Show tab bar" turned on and then rotate from portrait mode into landscape mode, then window.innerHeight is too big and the bottom of the screen gets cut off.
Even after turning on every conceivable viewport tag and all permutations thereof, it doesn't seem to work. I've also looked at several "tutorials" on how to handle this problem in iOS Safari, and to date every one that I've checked is broken.
I've also tried all variations of the window.innerHeight, with more or less the same result:
The new visual viewport API returns the same results, no different than window.innerHeight. Bottom is still truncated in landscape with tab bar and portrait mode still has the white bar at the bottom.
document.documentElement.clientHeight with various permutations of CSS (using 100vh, 100%, etc.) gives the same result. Ditto for getBoundingClientRect on various divs and combinations of div elements.
window.outerHeight and screen.height give the size of the full screen without browser chrome, which is generally too big and causes an overflow.
Also tried a bunch of other random things that I've forgotten by now (should have taken notes).
You can manually fudge it on a per-device basis if you can guess the size of the top and bottom browser chrome, but this is extremely fragile. I'm looking for a solution that doesn't involve building a giant look up table of every iOS device and software configuration.
I'm trying to make a fullscreen canvas element for a web game and this issue is blocking my ability to ship. As far as I know this issue is only present in iOS13. After looking around for weeks I still haven't found a good fix.
I have had the same issue recently and I was able to solve it like this:
CSS (only relevant parts shown):
html {
height: 100%;
min-height: 100%;
max-height: 100%;
background: #99f; /* Safari for iOS and Opera for Android in fullscreen mode?!?! */
}
body {
padding: 0;
margin: 0;
color: #000;
width: 100%; /* I was desperate! This was a wild guess... And worked! */
height: 100%;
min-height: 100%;
max-height: 100%;
overflow: hidden;
background: #99f;
}
TypeScript (only relevant parts shown):
// Assume everything here is in the global scope
function detectIOSOrSafari(): boolean {
// https://stackoverflow.com/q/9038625/3569421
if ((navigator.userAgent.indexOf("Chrome") <= 0 && navigator.userAgent.indexOf("Safari") >= 0) ||
(navigator.userAgent.indexOf("Mac") >= 0 && ("ontouchend" in document)))
return true;
switch (navigator.platform) {
case "iPad Simulator":
case "iPhone Simulator":
case "iPod Simulator":
case "iPad":
case "iPhone":
case "iPod":
return true;
}
return false;
}
const isIOSOrSafari = detectIOSOrSafari();
function adjustWindowSize(): void {
let widthCss = window.innerWidth,
heightCss = window.innerHeight;
if (document.documentElement && ("clientWidth" in document.documentElement)) {
widthCss = document.documentElement.clientWidth;
heightCss = document.documentElement.clientHeight;
}
if (isIOSOrSafari) {
let bodyRect: DOMRect = null;
// Another act out of desperation...
if (document.documentElement && ("getBoundingClientRect" in document.documentElement))
bodyRect = document.documentElement.getBoundingClientRect();
else if (("getBoundingClientRect" in document.body))
bodyRect = document.body.getBoundingClientRect();
if (bodyRect) {
widthCss = bodyRect.right - bodyRect.left;
heightCss = bodyRect.bottom - bodyRect.top;
}
}
// Rest of the code, where I use widthCss and heightCss to compute my canvas' size
}
window.onresize = adjustWindowSize;
You can check out the entire source code in the project's repository: https://github.com/carlosrafaelgn/pixel

Why mousewheel event is not working some times with my code?

I'm trying to make a fullpage component in Angular :
I want each sections take a 100% height of my screen, and when I scroll in a section (up or down) it goes to the next / previous section. I declared this function to do that, and it works :
#HostListener('wheel', ['$event'])
onScroll(event: WheelEvent) {
if (event.deltaY < 0) {
this.slidePrev();
} else {
this.slideNext();
}
}
Now, I want to update a little to slide to the previous slide only if the scrollbar is on the top, or slide to the next only if the scrollbar is to the bottom. I Used JQuery to do that, this way :
#HostListener('mousewheel', ['$event'])
onScroll(event: WheelEvent) {
if (this.isSliding) {
event.preventDefault();
return;
}
let $section = $(event.target).closest(".section");
//$section.css("opacity", "0.99");
//setTimeout(() => {
// $section.css("opacity", "1");
//}, 100);
if (event.deltaY < 0) {
if ($section.scrollTop() == 0) this.slidePrev();
} else {
if ($section.scrollTop() == $section.prop("scrollHeight") - $section.height()) this.slideNext();
}
}
It works the first time, but if I slide down to the next slide, when I want to sroll to move my scrollbar, it doesn't move.
I noticed that after the website trigger an update (example : css :hover event that update style) the scrollbar move again. So, if I uncomment my 4 commented lines, it works again because the style is updated.
Can someone tell me why ? And is there a better way to fix that issue ?
EDIT :
in slideNext() and slidePrev() I'm using $().animate("scrollTop", ...) function, and it's the function that breaks my scroll

How to print on a specific paper

I'm having problems with printing some text on a A4 paper that has 24 labels.
Basically, in every row there are 3 labels in which comes the name, surname and adress of a person and that label will be used for mails ( it's a sticky label that is sticked on a mail).
So this is the paper. Its characteristics:
There are 10 rows.
The first and last row are the smallest and have height:0.5mm;.
In first and last row there are no cells.
All the rest rows have height:36mm;.
All the cells have width:70mm; and height:36mm;.
In every cell comes a text that is text-align:center; and vertical-align:middle;.
I'm using normalize.css for css reset.
CSS
html,body,table{
width: 100%;
height: 100%;
}
.first, .last{
width: 100%;
height: 5mm;
}
.row{
width: 100%;
height: 36mm;
}
.cell{
width: 70mm;
height: 36mm;
text-align: center;
vertical-align: middle;
}
I'm using Chrome and I turned off the margins on printing.
But still, the last two rows are printed on the next page.
I need all 10 rows on the same page and that their position is fixed ( doesn't shift ) in case if there are multiple pages.
How to fix/achieve that ? Or is there a simpler solution ?
Here is an example of the code.
I've used FPDF class to create a pdf for my labels.
require_once ABSPATH . '/path/to/fpdf.php';
class PDF_MC_Table extends FPDF{
var $widths;
var $aligns;
function SetWidths($w){
//Set the array of column widths
$this->widths=$w;
}
function SetAligns($a){
//Set the array of column alignments
$this->aligns=$a;
}
function Row($data){
//Calculate the height of the row
$nb=0;
for($i=0;$i<count($data);$i++)
$nb=max($nb,$this->NbLines($this->widths[$i],$data[$i]));
$h = 36;// again trial and error until you fnd the desired height of your label
//Issue a page break first if needed
$this->CheckPageBreak($h);
//Draw the cells of the row
for($i=0;$i<count($data);$i++){
$w=$this->widths[$i];
$a=isset($this->aligns[$i]) ? $this->aligns[$i] : 'L';
//Save the current position
$x=$this->GetX();
$y=$this->GetY();
//Draw the border. reset the parameters of the function below as you desire.
$this->Rect($x,$y,$w,$h);
//Print the text. reset the parameters of the function below as you desire. changing the values will resize the boxs.
$this->MultiCell($w,3,$data[$i],0,$a);
//Put the position to the right of the cell. reset the parameters of the function below as you desire. changing the $x and $y will shift the cells.
$this->SetXY($x+$w,$y);
}
//Go to the next line
$this->Ln($h+3);
}
function CheckPageBreak($h){
//If the height h would cause an overflow, add a new page immediately
if($this->GetY()+$h>$this->PageBreakTrigger)
$this->AddPage($this->CurOrientation);
}
function NbLines($w,$txt){
//Computes the number of lines a MultiCell of width w will take
$cw=&$this->CurrentFont['cw'];
if($w==0)
$w=$this->w-$this->rMargin-$this->x;
$wmax=($w-2*$this->cMargin)*1000/$this->FontSize;
$s=str_replace("\r",'',$txt);
$nb=strlen($s);
if($nb>0 and $s[$nb-1]=="\n")
$nb--;
$sep=-1;
$i=0;
$j=0;
$l=0;
$nl=1;
while($i<$nb){
$c=$s[$i];
if($c=="\n"){
$i++;
$sep=-1;
$j=$i;
$l=0;
$nl++;
continue;
}
if($c==' ')
$sep=$i;
$l+=$cw[$c];
if($l>$wmax){
if($sep==-1){
if($i==$j)
$i++;
}
else
$i=$sep+1;
$sep=-1;
$j=$i;
$l=0;
$nl++;
}
else
$i++;
}
return $nl;
}
}
$pdf=new PDF_MC_Table();
$pdf->SetMargins(4, 2);
$pdf->AddPage();
$pdf->SetFont('Arial','',8);
// displays the empty row in the top
$pdf->SetRightMargin(2);
$pdf->SetLeftMargin(4);
$pdf->Cell(0,10,'',1);
$pdf->Ln(10);
$pdf->SetWidths(array(50,50,50));// these are the widths of your cells. this is a trial and error process. increase the values until you find the suitable ones.
$count = 0;
$lables = array(); // your labels array
$l = array();
$j = 0;
// i used this foreach for breaking my plain array into a 2dimentional array- an array of arrays consisting 3 labels in each.
foreach($lables as $i=>$lbl ){
$l[$j][] = $lbl;
if($i%3==2){$j++;} // $i=0,1,2 > $j=0; $i=3,4,5 > $j=2 etc this will break the main labels array as 2D array.
}
// displays the empty row in the bottom.
$pdf->Ln(1);
$pdf->Cell(0,10,'',1);
$pdf->Output();
for further information about the class and methods please refer to http://www.fpdf.org/ At best you need to understand three methods- Multicell(), Cell() and Rect() methods. There are pretty nice explanation of these methods with examples in the site.
Here i've posted my solution and i've changed some code based on your problem. Most of the things are self explanatory. If you need further assist please feel free to comment. Thanks.
reduce the cell and row height sizes if you are no using the sizes in specific, what happens even after turning off margins, printing data goes out of paper length and printer moves it to another page automatically.
thats the best solution i think you can try.
p.s: these kinds of sticky labels usually come with their design software cd which you usually use to set the margins with preview. if you dont have it, only thing you can do is maually adjust the heights as i told above, print on a normal A4 plain paper and tele with the sticky label paper. I used to do it too... worked for me though
Try borderless printing if your printer supports this feature.
Try adding in the styling below and playing with the #page attributes. More info in #page can be found here: https://developer.mozilla.org/en-US/docs/CSS/#page
I've had good luck using the styles defined below to print perfectly on 8.5x11 documents where I can set my own margin and have consistent results out of the browser.
<style type="text/css" media="print">
#page {
size: auto; /* auto is the initial value */
margin: 0mm; /* this affects the margin in the printer settings */
}
body {
background-color: #fff;
border: solid 1px #000 ;
margin: 0px; /* this affects the margin on the content before sending to printer */
padding: 0.25in 0.5in;
}
</style>

Resources