How To Split Html Page In A4 Size In Angular 9
Solution 1:
It is all about dividing the given content to fit into the give page size.
We can create a component that will handle the dividing functionality for us. here is a StackBlitz Demo.
And here is a brief explanation.
Use the ContentChildren
decorator to observe the change in content. every time the content changes we will run the page creation logic.
import {
AfterContentInit,
AfterViewInit,
Component,
ContentChildren,
ElementRef,
Input,
OnInit,
QueryList,
ViewChild
} from "@angular/core";
@Component({
selector: "app-paginated-view",
templateUrl: "paginated-view.component.html",
styleUrls: ["paginated-view.component.scss"]
})
export classPaginatedViewComponentimplementsAfterViewInit{
@Input() pageSize: "A3" | "A4" = "A4";
@ViewChild("paginatedView") paginatedView: ElementRef<HTMLDivElement>;
@ViewChild("contentWrapper") contentWrapper: ElementRef<HTMLDivElement>;
@ContentChildren("pageContent", { read: ElementRef }) elements: QueryList<
ElementRef
>;
constructor() {}
ngAfterViewInit(): void {
this.updatePages();
// when ever childs updated call the updatePagesfunctionthis.elements.changes.subscribe(el => {
this.updatePages();
});
}
updatePages(): void {
// clear paginated viewthis.paginatedView.nativeElement.innerHTML = "";
// get a new page and add it to the paginated view
let page = this.getNewPage();
this.paginatedView.nativeElement.appendChild(page);
let lastEl: HTMLElement;
// add content childrens to the page one by onethis.elements.forEach(elRef => {
const el = elRef.nativeElement;
// if the content child height is larger than the size of the page// then do not add it to the pageif (el.clientHeight > page.clientHeight) {
return;
}
// add the child to the page
page.appendChild(el);
// after adding the child if the page scroll hight becomes larger than the page height// then get a new page and append the child to the new pageif (page.scrollHeight > page.clientHeight) {
page = this.getNewPage();
this.paginatedView.nativeElement.appendChild(page);
page.appendChild(el);
}
lastEl = el;
});
//bring the element in to view port
lastEl.scrollIntoView({ behavior: "smooth", block: "nearest" });
}
getNewPage(): HTMLDivElement {
const page = document.createElement("div");
page.classList.add("page");
page.classList.add(this.pageSize);
return page;
}
}
We can use this component in an application like this.
<app-paginated-view [pageSize]="'A4'"><h1 #pageContent>Hello World!!</h1><p #pageContent>This content will be displayed in an A4 size page</p></app-paginated-view>
We have to provide the template variable #pageContent so that we can select them using @ContentChildren in our PaginatedViewComponent.
Note that we are using native dom APIs here to change the dom structure. it will only move the dom node from one place to another so if you have any event listener added or have any property binding to the content children they will work as it is.
Edit: I have also updated your stackblitz https://stackblitz.com/edit/angular-ivy-zjf8rv
Solution 2:
<div class="page" *ngFor="let page of pages; index as i"
[style.height]="sizePage.height + 'cm'"
[style.width]="sizePage.width + 'cm'"
(click)="clickPage(i)">
<div class="content"
[style.paddingTop]="paddingPage.top + 'cm'"
[style.paddingRight]="paddingPage.right + 'cm'"
[style.paddingBottom]="paddingPage.bottom + 'cm'"
[style.paddingLeft]="paddingPage.left + 'cm'"
[id]="'content-' + i" contenteditable="true"
(input)="inputContent($event['data'], i)">
</div>
</div>
In app.component.css file:
.page {
background: white;
display: block;
margin: 40px auto;
box-shadow: 000.5cmrgba(0, 0, 0, 0.5);
box-sizing: border-box;
}
.page.content {
overflow: auto;
outline: 0;
}
In app.component.ts file:
import { AfterViewChecked, Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export classAppComponentimplementsAfterViewChecked{
sizePage = {
width: 21, //cm
height: 29.7//cm
}
paddingPage = {
top: 2, //cm
right: 2, //cm
bottom: 2, //cm
left: 2//cm
}
pages = [
{
htmlContent: null,
full: false
},
]
currentPage = 0;
currentChar = null;
runAfterViewChecked = false;
clickPage(i) {
this.currentPage = i;
}
inputContent(char, i) {
var element = document.getElementById('content-' + i)
var heightContent = element.offsetHeight * 2.54 / 96; // Convert pixels to cmthis.pages[i].htmlContent = element.innerHTML;
console.log(this.pages);
if (Number(heightContent.toFixed(1)) > this.sizePage.height) {
this.currentChar = char;
this.pages[i].full = true;
if (!this.pages[i + 1]) {
this.pages.push({
htmlContent: null,
full: false
})
}
this.currentPage = i + 1;
this.runAfterViewChecked = true;
}
}
ngAfterViewChecked() {
document.getElementById('content-' + this.currentPage).focus();
if (this.runAfterViewChecked) {
if (this.currentChar) {
var str = this.pages[this.currentPage-1].htmlContent;
var indexLastCloseDiv = str.lastIndexOf("</div>");
var indexLastBr = str.lastIndexOf("<br>");
var lastChar = str[indexLastCloseDiv-1];
if (indexLastBr != -1 && (indexLastBr + 4) == indexLastCloseDiv)
lastChar = ' ';
if (indexLastCloseDiv != -1)
str = str.slice(0, indexLastCloseDiv-1) + str.slice(indexLastCloseDiv);
else
str = str.slice(0, str.length - 1);
this.pages[this.currentPage-1].htmlContent = str;
if (this.pages[this.currentPage].htmlContent)
this.pages[this.currentPage].htmlContent = lastChar + this.pages[this.currentPage].htmlContent;
elsethis.pages[this.currentPage].htmlContent = lastChar;
}
var element = null;
for (let i = 0; i < this.pages.length; i++) {
element = document.getElementById('content-' + i);
element.innerHTML = this.pages[i].htmlContent;
}
this.runAfterViewChecked = false;
}
}
}
Here is a simple example. There are a few mistakes, please give your suggestions for further development.
Some functions such as Backspace, Delete, Scale Page, ... have not been processed.
Solution 3:
If you want to creat html A4 like office word A4 you must use these size:
body{
width: 21cm ;
height: 29.7cm;
margin:30mm45mm30mm45mm;}
Solution 4:
It would be fairly easy to force the web browser to display the page with the same pixel dimensions as A4. However, there may be a few quirks when things are rendered.
Assuming your monitors display 72 dpi, you could add something like this:
<!DOCTYPE html><html><head><style>body {
height: 842px;
width: 595px;
/* to centre page on screen*/margin-left: auto;
margin-right: auto;
}
</style></head><body></body></html>
Here an example in your code with printable A4 size: https://stackblitz.com/edit/angular-ivy-fjhpdu?embed=1&file=src/app/app.component.html
Solution 5:
Actually I cant see any js or css by you that attempts to solve the issue.
But looking at the provided example from xing, they are using static pixel width/height
width: 595px;
height: 842px;
this matches a PPI (pixel per inch) of 72 for the given Format A4 thats the only important thing to take in mind.
Knowing that, you can just check if that height is exceeded while editing and manipulate the DOM accordingly ("create new Page", "split/move elements or parts", etc. ...) You should have everything now to solve yourself. But expect that there is a lot of time going into this, especially regarding keeping font sizes / rendering/printring matching and not to talk about the mobile version ;)
Good luck
Post a Comment for "How To Split Html Page In A4 Size In Angular 9"