feature: generate pdf from actor
This commit is contained in:
@@ -2,6 +2,6 @@ export const i18n = () => (<any>game).i18n;
|
|||||||
export const i18nLocalize = (id: string) => i18n().localize(id);
|
export const i18nLocalize = (id: string) => i18n().localize(id);
|
||||||
export const i18nFormat = (id: string, data?: any) => i18n().format(id, data);
|
export const i18nFormat = (id: string, data?: any) => i18n().format(id, data);
|
||||||
|
|
||||||
export const TEXT_SIZE = 10;
|
export const TEXT_SIZE = 8;
|
||||||
export const LABEL_SIZE = 8;
|
export const LABEL_SIZE = 6;
|
||||||
export const MARGINS = { top: 10, left: 10, bottom: 10, right: 10 };
|
export const MARGINS = { top: 10, left: 10, bottom: 10, right: 10 };
|
||||||
|
|||||||
@@ -20,7 +20,13 @@ export abstract class AbstractElement {
|
|||||||
this.maxWidth = maxWidth;
|
this.maxWidth = maxWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract prepareRender(doc: jsPDF, maxWidth?: number): jsPDF;
|
||||||
|
|
||||||
public abstract render(doc: jsPDF, maxWidth?: number): jsPDF;
|
public abstract render(doc: jsPDF, maxWidth?: number): jsPDF;
|
||||||
|
|
||||||
public abstract getHeight(doc?: jsPDF): number;
|
public abstract getHeight(doc?: jsPDF): number;
|
||||||
|
|
||||||
|
public abstract getCheckNewPageHeight(doc?: jsPDF): number;
|
||||||
|
|
||||||
|
public abstract getElements(): AbstractElement[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ export class Box extends AbstractElement {
|
|||||||
this.h = h;
|
this.h = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public prepareRender(doc: jsPDF, _maxWidth?: number): jsPDF {
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
public render(doc: jsPDF, _maxWidth?: number): jsPDF {
|
public render(doc: jsPDF, _maxWidth?: number): jsPDF {
|
||||||
doc.rect(this.x, this.y, this.w, this.h);
|
doc.rect(this.x, this.y, this.w, this.h);
|
||||||
return doc;
|
return doc;
|
||||||
@@ -19,4 +23,12 @@ export class Box extends AbstractElement {
|
|||||||
public getHeight(_doc): number {
|
public getHeight(_doc): number {
|
||||||
return this.h;
|
return this.h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getCheckNewPageHeight(doc?: jsPDF): number {
|
||||||
|
return this.getHeight(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getElements(): AbstractElement[] {
|
||||||
|
return [this];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,20 +9,24 @@ export class Column extends AbstractElement {
|
|||||||
this.elements = elements;
|
this.elements = elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(doc: jsPDF, _maxWidth?: number): jsPDF {
|
public prepareRender(doc: jsPDF, _maxWidth?: number): jsPDF {
|
||||||
const elements = this.elements ?? [];
|
const elements = this.elements ?? [];
|
||||||
|
|
||||||
let currentY = this.y;
|
let currentY = this.y;
|
||||||
for (let i = 0; i < elements.length; i++) {
|
for (let i = 0; i < elements.length; i++) {
|
||||||
const element = elements[i];
|
const element = elements[i];
|
||||||
element.x = this.x;
|
element.x = Math.max(element.x, this.x);
|
||||||
element.y = currentY;
|
element.y = currentY;
|
||||||
element.render(doc);
|
element.prepareRender(doc);
|
||||||
currentY += element.getHeight(doc) + 2;
|
currentY += element.getHeight(doc) + 2;
|
||||||
}
|
}
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public render(doc: jsPDF, _maxWidth?: number): jsPDF {
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
public getHeight(doc): number {
|
public getHeight(doc): number {
|
||||||
return this.elements
|
return this.elements
|
||||||
.map((e) => e.getHeight(doc))
|
.map((e) => e.getHeight(doc))
|
||||||
@@ -33,4 +37,18 @@ export class Column extends AbstractElement {
|
|||||||
return p + c + 2;
|
return p + c + 2;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getCheckNewPageHeight(doc?: jsPDF): number {
|
||||||
|
return this.elements.length > 0
|
||||||
|
? this.elements[0].getCheckNewPageHeight(doc)
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getElements(): AbstractElement[] {
|
||||||
|
const elements: AbstractElement[] = [];
|
||||||
|
for (const element of this.elements) {
|
||||||
|
elements.push(...element.getElements());
|
||||||
|
}
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Box } from './box';
|
import { Box } from './box';
|
||||||
import jsPDF from 'jspdf';
|
import jsPDF from 'jspdf';
|
||||||
|
import { AbstractElement } from './abstract-element';
|
||||||
|
|
||||||
export class Image extends Box {
|
export class Image extends Box {
|
||||||
public imageData: string;
|
public imageData: string;
|
||||||
@@ -19,4 +20,8 @@ export class Image extends Box {
|
|||||||
});
|
});
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getElements(): AbstractElement[] {
|
||||||
|
return [this];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import jsPDF, { TextOptionsLight } from 'jspdf';
|
import jsPDF, { TextOptionsLight } from 'jspdf';
|
||||||
import { Text } from './text';
|
import { Text } from './text';
|
||||||
import { i18nLocalize, LABEL_SIZE, TEXT_SIZE } from '../constants';
|
import { i18nLocalize, LABEL_SIZE, TEXT_SIZE } from '../constants';
|
||||||
|
import { AbstractElement } from './abstract-element';
|
||||||
|
|
||||||
export class LabelledText extends Text {
|
export class LabelledText extends Text {
|
||||||
public label: string;
|
public label: string;
|
||||||
@@ -23,8 +24,12 @@ export class LabelledText extends Text {
|
|||||||
this.updateMaxWidth(maxWidth);
|
this.updateMaxWidth(maxWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(doc: jsPDF, maxWidth?: number): jsPDF {
|
public prepareRender(doc: jsPDF, maxWidth?: number): jsPDF {
|
||||||
this.updateMaxWidth(maxWidth);
|
this.updateMaxWidth(maxWidth);
|
||||||
|
return super.prepareRender(doc, maxWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(doc: jsPDF, _maxWidth?: number): jsPDF {
|
||||||
const yLabel = this.y + this.getHeightFromPx(doc, LABEL_SIZE);
|
const yLabel = this.y + this.getHeightFromPx(doc, LABEL_SIZE);
|
||||||
const yText = yLabel + this.getHeightFromPx(doc, TEXT_SIZE) + 1;
|
const yText = yLabel + this.getHeightFromPx(doc, TEXT_SIZE) + 1;
|
||||||
doc
|
doc
|
||||||
@@ -50,4 +55,12 @@ export class LabelledText extends Text {
|
|||||||
public getHeight(doc): number {
|
public getHeight(doc): number {
|
||||||
return this.getHeightFromPx(doc, TEXT_SIZE + LABEL_SIZE) + 1;
|
return this.getHeightFromPx(doc, TEXT_SIZE + LABEL_SIZE) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getCheckNewPageHeight(doc?: jsPDF): number {
|
||||||
|
return this.getHeight(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getElements(): AbstractElement[] {
|
||||||
|
return [this];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export class LabelledValues extends Row {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(doc: jsPDF, maxWidth?: number): jsPDF {
|
public prepareRender(doc: jsPDF, maxWidth?: number): jsPDF {
|
||||||
const pageWidth = doc.internal.pageSize.width;
|
const pageWidth = doc.internal.pageSize.width;
|
||||||
const rowWidth = pageWidth - this.x - MARGINS.right;
|
const rowWidth = pageWidth - this.x - MARGINS.right;
|
||||||
for (const column of this.elements) {
|
for (const column of this.elements) {
|
||||||
@@ -77,6 +77,10 @@ export class LabelledValues extends Row {
|
|||||||
labelledValue.maxWidth = rowWidth / this.nbrOfCol;
|
labelledValue.maxWidth = rowWidth / this.nbrOfCol;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.render(doc, maxWidth);
|
return super.prepareRender(doc, maxWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(doc: jsPDF, _maxWidth?: number): jsPDF {
|
||||||
|
return doc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export class Row extends AbstractElement {
|
|||||||
this.maxWidths = maxWidths ?? [];
|
this.maxWidths = maxWidths ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(doc: jsPDF, maxWidth?: number): jsPDF {
|
public prepareRender(doc: jsPDF, maxWidth?: number): jsPDF {
|
||||||
const elements = this.elements ?? [];
|
const elements = this.elements ?? [];
|
||||||
let maxWidths = this.maxWidths ?? [];
|
let maxWidths = this.maxWidths ?? [];
|
||||||
let widthPercents = this.widthPercents ?? [];
|
let widthPercents = this.widthPercents ?? [];
|
||||||
@@ -50,12 +50,16 @@ export class Row extends AbstractElement {
|
|||||||
const maxChildWidth = maxWidths[i] ?? percentWidth;
|
const maxChildWidth = maxWidths[i] ?? percentWidth;
|
||||||
element.x = currentX;
|
element.x = currentX;
|
||||||
element.y = this.y;
|
element.y = this.y;
|
||||||
element.render(doc, maxChildWidth);
|
element.prepareRender(doc, maxChildWidth);
|
||||||
currentX += percentWidth;
|
currentX += percentWidth;
|
||||||
}
|
}
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public render(doc: jsPDF, _maxWidth?: number): jsPDF {
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
public getHeight(doc?: jsPDF): number {
|
public getHeight(doc?: jsPDF): number {
|
||||||
let maxHeight = 0;
|
let maxHeight = 0;
|
||||||
for (const element of this.elements) {
|
for (const element of this.elements) {
|
||||||
@@ -63,4 +67,20 @@ export class Row extends AbstractElement {
|
|||||||
}
|
}
|
||||||
return maxHeight;
|
return maxHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getCheckNewPageHeight(doc?: jsPDF): number {
|
||||||
|
let maxHeight = 0;
|
||||||
|
for (const element of this.elements) {
|
||||||
|
maxHeight = Math.max(maxHeight, element.getCheckNewPageHeight(doc));
|
||||||
|
}
|
||||||
|
return maxHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getElements(): AbstractElement[] {
|
||||||
|
const elements: AbstractElement[] = [];
|
||||||
|
for (const element of this.elements) {
|
||||||
|
elements.push(...element.getElements());
|
||||||
|
}
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
39
src/elements/separator.ts
Normal file
39
src/elements/separator.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import { AbstractElement } from './abstract-element';
|
||||||
|
import jsPDF from 'jspdf';
|
||||||
|
import { MARGINS } from '../constants';
|
||||||
|
|
||||||
|
export class Separator extends AbstractElement {
|
||||||
|
constructor(x: number, y: number, maxWidth?: number | undefined) {
|
||||||
|
super(x, y, maxWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getHeight(_doc?: jsPDF): number {
|
||||||
|
return 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCheckNewPageHeight(doc?: jsPDF): number {
|
||||||
|
return this.getHeight(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public prepareRender(doc: jsPDF, _maxWidth?: number): jsPDF {
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(doc: jsPDF, maxWidth?: number): jsPDF {
|
||||||
|
const pageWidth = doc.internal.pageSize.width;
|
||||||
|
const maxPageWidth = pageWidth - MARGINS.left - MARGINS.right;
|
||||||
|
const finalWidth = Math.min(
|
||||||
|
maxWidth ?? this.maxWidth ?? maxPageWidth,
|
||||||
|
maxPageWidth
|
||||||
|
);
|
||||||
|
|
||||||
|
doc.setLineWidth(0.25);
|
||||||
|
doc.line(this.x, this.y, this.x + finalWidth, this.y);
|
||||||
|
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getElements(): AbstractElement[] {
|
||||||
|
return [this];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,11 +17,18 @@ export class Text extends AbstractElement {
|
|||||||
this.textOptions = textOptions;
|
this.textOptions = textOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(doc: jsPDF, maxWidth?: number): jsPDF {
|
public prepareRender(doc: jsPDF, maxWidth?: number): jsPDF {
|
||||||
this.updateMaxWidth(maxWidth);
|
this.updateMaxWidth(maxWidth);
|
||||||
let finalText = [i18nLocalize(this.text)];
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(doc: jsPDF, _maxWidth?: number): jsPDF {
|
||||||
|
let finalText: string[] = [i18nLocalize(this.text)];
|
||||||
if (this.maxWidth != null) {
|
if (this.maxWidth != null) {
|
||||||
finalText = doc.splitTextToSize(finalText[0], maxWidth ?? 0);
|
finalText = doc.splitTextToSize(finalText[0], this.maxWidth ?? 0);
|
||||||
|
}
|
||||||
|
if (finalText.length > 1) {
|
||||||
|
finalText[0] = finalText[0].replace(/(.){3}$/, '...');
|
||||||
}
|
}
|
||||||
const yText = this.y + this.getHeightFromPx(doc, TEXT_SIZE);
|
const yText = this.y + this.getHeightFromPx(doc, TEXT_SIZE);
|
||||||
doc
|
doc
|
||||||
@@ -42,4 +49,12 @@ export class Text extends AbstractElement {
|
|||||||
public getHeight(doc): number {
|
public getHeight(doc): number {
|
||||||
return this.getHeightFromPx(doc, TEXT_SIZE);
|
return this.getHeightFromPx(doc, TEXT_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getCheckNewPageHeight(doc?: jsPDF): number {
|
||||||
|
return this.getHeight(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getElements(): AbstractElement[] {
|
||||||
|
return [this];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export class Texts extends Row {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(doc: jsPDF, maxWidth?: number): jsPDF {
|
public prepareRender(doc: jsPDF, maxWidth?: number): jsPDF {
|
||||||
const pageWidth = doc.internal.pageSize.width;
|
const pageWidth = doc.internal.pageSize.width;
|
||||||
const rowWidth = pageWidth - this.x - MARGINS.right;
|
const rowWidth = pageWidth - this.x - MARGINS.right;
|
||||||
for (const column of this.elements) {
|
for (const column of this.elements) {
|
||||||
@@ -61,6 +61,10 @@ export class Texts extends Row {
|
|||||||
labelledValue.maxWidth = rowWidth / this.nbrOfCol;
|
labelledValue.maxWidth = rowWidth / this.nbrOfCol;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.render(doc, maxWidth);
|
return super.prepareRender(doc, maxWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(doc: jsPDF, _maxWidth?: number): jsPDF {
|
||||||
|
return doc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
311
src/main.ts
311
src/main.ts
@@ -9,6 +9,8 @@ import { ItemData } from '@league-of-foundry-developers/foundry-vtt-types/src/fo
|
|||||||
import { LabelledValues } from './elements/labelled-values';
|
import { LabelledValues } from './elements/labelled-values';
|
||||||
import { Text } from './elements/text';
|
import { Text } from './elements/text';
|
||||||
import { Texts } from './elements/texts';
|
import { Texts } from './elements/texts';
|
||||||
|
import { Column } from './elements/column';
|
||||||
|
import { Separator } from './elements/separator';
|
||||||
|
|
||||||
Hooks.on(
|
Hooks.on(
|
||||||
'renderActorSheetWfrp4eCharacter',
|
'renderActorSheetWfrp4eCharacter',
|
||||||
@@ -37,18 +39,10 @@ Hooks.on(
|
|||||||
|
|
||||||
const labelledRowHeight =
|
const labelledRowHeight =
|
||||||
Util.getHeightFromPx(docBuilder.doc, TEXT_SIZE + LABEL_SIZE) + 1;
|
Util.getHeightFromPx(docBuilder.doc, TEXT_SIZE + LABEL_SIZE) + 1;
|
||||||
const textRowHeight = Util.getHeightFromPx(docBuilder.doc, TEXT_SIZE);
|
|
||||||
const row2Y = labelledRowHeight + MARGINS.top + 2;
|
|
||||||
const row3Y = row2Y + labelledRowHeight + 2;
|
|
||||||
const row4Y = row3Y + labelledRowHeight + 2;
|
|
||||||
const row5Y = row4Y + labelledRowHeight + 2;
|
|
||||||
const row6Y = row5Y + labelledRowHeight + 2;
|
|
||||||
const row7Y = row6Y + labelledRowHeight + 2;
|
|
||||||
const row8Y = row7Y + textRowHeight + 2;
|
|
||||||
|
|
||||||
const skills = new LabelledValues(
|
const skills = new LabelledValues(
|
||||||
0,
|
0,
|
||||||
row8Y,
|
0,
|
||||||
actor.itemCategories.skill
|
actor.itemCategories.skill
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
return {
|
return {
|
||||||
@@ -59,12 +53,9 @@ Hooks.on(
|
|||||||
.sort((a, b) => a.label.localeCompare(b.label))
|
.sort((a, b) => a.label.localeCompare(b.label))
|
||||||
);
|
);
|
||||||
|
|
||||||
const row9Y = row8Y + skills.getHeight(docBuilder.doc) + 2;
|
|
||||||
const row10Y = row9Y + textRowHeight + 2;
|
|
||||||
|
|
||||||
const talents = new LabelledValues(
|
const talents = new LabelledValues(
|
||||||
0,
|
0,
|
||||||
row10Y,
|
0,
|
||||||
actor.itemCategories.talent
|
actor.itemCategories.talent
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
return {
|
return {
|
||||||
@@ -79,12 +70,9 @@ Hooks.on(
|
|||||||
1
|
1
|
||||||
);
|
);
|
||||||
|
|
||||||
const row11Y = row10Y + talents.getHeight(docBuilder.doc) + 2;
|
|
||||||
const row12Y = row11Y + textRowHeight + 2;
|
|
||||||
|
|
||||||
const traits = new Texts(
|
const traits = new Texts(
|
||||||
0,
|
0,
|
||||||
row12Y,
|
0,
|
||||||
actor.itemCategories.trait
|
actor.itemCategories.trait
|
||||||
.map((item) => {
|
.map((item) => {
|
||||||
return item.name;
|
return item.name;
|
||||||
@@ -93,114 +81,201 @@ Hooks.on(
|
|||||||
4
|
4
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const weaponsMelee = new Texts(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
actor.itemCategories.weapon
|
||||||
|
.filter((w) => w.isMelee)
|
||||||
|
.map((item) => {
|
||||||
|
return `${item.name} : ${item.data.data.damage.meleeValue} (${
|
||||||
|
item.mountDamage
|
||||||
|
}), ${item.OriginalQualities.concat(item.OriginalFlaws).join(
|
||||||
|
', '
|
||||||
|
)}`;
|
||||||
|
})
|
||||||
|
.sort((a, b) => a.localeCompare(b)),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
const weaponsRanged = new Texts(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
actor.itemCategories.weapon
|
||||||
|
.filter((w) => w.isRanged)
|
||||||
|
.map((item) => {
|
||||||
|
return `${item.name} : ${item.data.data.damage.rangedValue}, ${
|
||||||
|
item.data.data.range.value
|
||||||
|
}, ${item.OriginalQualities.concat(item.OriginalFlaws).join(', ')}`;
|
||||||
|
})
|
||||||
|
.sort((a, b) => a.localeCompare(b)),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
const ammunitions = new Texts(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
actor.itemCategories.ammunition
|
||||||
|
.map((item) => {
|
||||||
|
return `${item.data.data.quantity.value} ${item.name} : ${
|
||||||
|
item.data.data.damage.value.length > 0
|
||||||
|
? item.data.data.damage.value
|
||||||
|
: '+0'
|
||||||
|
}, (${item.data.data.range.value}), ${item.OriginalQualities.concat(
|
||||||
|
item.OriginalFlaws
|
||||||
|
).join(', ')}`;
|
||||||
|
})
|
||||||
|
.sort((a, b) => a.localeCompare(b)),
|
||||||
|
2
|
||||||
|
);
|
||||||
|
|
||||||
const imageWidth = 25;
|
const imageWidth = 25;
|
||||||
|
const imageY = labelledRowHeight + MARGINS.top + 2;
|
||||||
const actorImageElement =
|
const actorImageElement =
|
||||||
actorImageData != null
|
actorImageData != null
|
||||||
? new Image(0, row2Y, imageWidth, imageWidth, actorImageData)
|
? new Image(0, imageY, imageWidth, imageWidth, actorImageData)
|
||||||
: new Box(0, row2Y, imageWidth, imageWidth);
|
: new Box(0, imageY, imageWidth, imageWidth);
|
||||||
|
|
||||||
docBuilder.build([
|
docBuilder.build([
|
||||||
new Row(0, 0, [
|
|
||||||
new LabelledText(0, 0, 'Name', `${actor.name}`),
|
|
||||||
new LabelledText(0, 0, 'Species', `${actorDetails?.species?.value}`),
|
|
||||||
new LabelledText(0, 0, 'Gender', `${actorDetails?.gender?.value}`),
|
|
||||||
]),
|
|
||||||
actorImageElement,
|
actorImageElement,
|
||||||
new Row(imageWidth + MARGINS.left + 1, row2Y, [
|
new Column(0, 0, [
|
||||||
new LabelledText(0, 0, 'Class', `${careerDetail?.class?.value}`),
|
new Row(0, 0, [
|
||||||
new LabelledText(
|
new LabelledText(0, 0, 'Name', `${actor.name}`),
|
||||||
0,
|
new LabelledText(
|
||||||
0,
|
0,
|
||||||
'Career Group',
|
0,
|
||||||
`${careerDetail?.careergroup?.value}`
|
'Species',
|
||||||
),
|
`${actorDetails?.species?.value}`
|
||||||
new LabelledText(0, 0, 'Career', `${currentCareer?.name}`),
|
),
|
||||||
|
new LabelledText(0, 0, 'Gender', `${actorDetails?.gender?.value}`),
|
||||||
|
]),
|
||||||
|
new Row(imageWidth + MARGINS.left + 1, 0, [
|
||||||
|
new LabelledText(0, 0, 'Class', `${careerDetail?.class?.value}`),
|
||||||
|
new LabelledText(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
'Career Group',
|
||||||
|
`${careerDetail?.careergroup?.value}`
|
||||||
|
),
|
||||||
|
new LabelledText(0, 0, 'Career', `${currentCareer?.name}`),
|
||||||
|
]),
|
||||||
|
new Row(imageWidth + MARGINS.left + 1, 0, [
|
||||||
|
new LabelledText(0, 0, 'Status', `${actorDetails?.status?.value}`),
|
||||||
|
new LabelledText(0, 0, 'Age', `${actorDetails?.age?.value}`),
|
||||||
|
new LabelledText(0, 0, 'Height', `${actorDetails?.height?.value}`),
|
||||||
|
new LabelledText(0, 0, 'Weight', `${actorDetails?.weight?.value}`),
|
||||||
|
new LabelledText(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
'Hair Colour',
|
||||||
|
`${actorDetails?.haircolour?.value}`
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
new Row(imageWidth + MARGINS.left + 1, 0, [
|
||||||
|
new LabelledText(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
'Eye Colour',
|
||||||
|
`${actorDetails?.eyecolour?.value}`
|
||||||
|
),
|
||||||
|
new LabelledText(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
'Distinguishing Mark',
|
||||||
|
`${actorDetails?.distinguishingmark?.value}`
|
||||||
|
),
|
||||||
|
new LabelledText(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
'Star Sign',
|
||||||
|
`${actorDetails?.starsign?.value}`
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
new Row(0, 0, [
|
||||||
|
new LabelledText(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
'CHARAbbrev.WS',
|
||||||
|
`${actorCharacs?.ws?.value}`
|
||||||
|
),
|
||||||
|
new LabelledText(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
'CHARAbbrev.BS',
|
||||||
|
`${actorCharacs?.bs?.value}`
|
||||||
|
),
|
||||||
|
new LabelledText(0, 0, 'CHARAbbrev.S', `${actorCharacs?.s?.value}`),
|
||||||
|
new LabelledText(0, 0, 'CHARAbbrev.T', `${actorCharacs?.t?.value}`),
|
||||||
|
new LabelledText(0, 0, 'CHARAbbrev.I', `${actorCharacs?.i?.value}`),
|
||||||
|
new LabelledText(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
'CHARAbbrev.Ag',
|
||||||
|
`${actorCharacs?.ag?.value}`
|
||||||
|
),
|
||||||
|
new LabelledText(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
'CHARAbbrev.Dex',
|
||||||
|
`${actorCharacs?.dex?.value}`
|
||||||
|
),
|
||||||
|
new LabelledText(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
'CHARAbbrev.Int',
|
||||||
|
`${actorCharacs?.int?.value}`
|
||||||
|
),
|
||||||
|
new LabelledText(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
'CHARAbbrev.WP',
|
||||||
|
`${actorCharacs?.wp?.value}`
|
||||||
|
),
|
||||||
|
new LabelledText(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
'CHARAbbrev.Fel',
|
||||||
|
`${actorCharacs?.fel?.value}`
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
new Row(0, 0, [
|
||||||
|
new LabelledText(0, 0, 'Move', `${actorDetails?.move?.value}`),
|
||||||
|
new LabelledText(0, 0, 'Walk', `${actorDetails?.move?.walk}`),
|
||||||
|
new LabelledText(0, 0, 'Run', `${actorDetails?.move?.run}`),
|
||||||
|
new LabelledText(0, 0, 'Fortune', `${actorStatus?.fortune?.value}`),
|
||||||
|
new LabelledText(0, 0, 'Fate', `${actorStatus?.fate?.value}`),
|
||||||
|
new LabelledText(0, 0, 'Resolve', `${actorStatus?.resolve?.value}`),
|
||||||
|
new LabelledText(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
'Resilience',
|
||||||
|
`${actorStatus?.resilience?.value}`
|
||||||
|
),
|
||||||
|
new LabelledText(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
'Wounds',
|
||||||
|
`${actorStatus?.wounds?.value}/${actorStatus?.wounds?.max}`
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
new Separator(0, 0),
|
||||||
|
new Text(0, 0, 'Skills'),
|
||||||
|
skills,
|
||||||
|
new Separator(0, 0),
|
||||||
|
new Text(0, 0, 'Talents'),
|
||||||
|
talents,
|
||||||
|
new Separator(0, 0),
|
||||||
|
new Text(0, 0, 'Traits'),
|
||||||
|
traits,
|
||||||
|
new Separator(0, 0),
|
||||||
|
new Text(0, 0, 'SHEET.MeleeWeaponHeader'),
|
||||||
|
weaponsMelee,
|
||||||
|
new Separator(0, 0),
|
||||||
|
new Text(0, 0, 'SHEET.RangedWeaponHeader'),
|
||||||
|
weaponsRanged,
|
||||||
|
new Separator(0, 0),
|
||||||
|
new Text(0, 0, 'Ammunition'),
|
||||||
|
ammunitions,
|
||||||
]),
|
]),
|
||||||
new Row(imageWidth + MARGINS.left + 1, row3Y, [
|
|
||||||
new LabelledText(0, 0, 'Status', `${actorDetails?.status?.value}`),
|
|
||||||
new LabelledText(0, 0, 'Age', `${actorDetails?.age?.value}`),
|
|
||||||
new LabelledText(0, 0, 'Height', `${actorDetails?.height?.value}`),
|
|
||||||
new LabelledText(0, 0, 'Weight', `${actorDetails?.weight?.value}`),
|
|
||||||
new LabelledText(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
'Hair Colour',
|
|
||||||
`${actorDetails?.haircolour?.value}`
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
new Row(imageWidth + MARGINS.left + 1, row4Y, [
|
|
||||||
new LabelledText(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
'Eye Colour',
|
|
||||||
`${actorDetails?.eyecolour?.value}`
|
|
||||||
),
|
|
||||||
new LabelledText(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
'Distinguishing Mark',
|
|
||||||
`${actorDetails?.distinguishingmark?.value}`
|
|
||||||
),
|
|
||||||
new LabelledText(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
'Star Sign',
|
|
||||||
`${actorDetails?.starsign?.value}`
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
new Row(0, row5Y, [
|
|
||||||
new LabelledText(0, 0, 'CHARAbbrev.WS', `${actorCharacs?.ws?.value}`),
|
|
||||||
new LabelledText(0, 0, 'CHARAbbrev.BS', `${actorCharacs?.bs?.value}`),
|
|
||||||
new LabelledText(0, 0, 'CHARAbbrev.S', `${actorCharacs?.s?.value}`),
|
|
||||||
new LabelledText(0, 0, 'CHARAbbrev.T', `${actorCharacs?.t?.value}`),
|
|
||||||
new LabelledText(0, 0, 'CHARAbbrev.I', `${actorCharacs?.i?.value}`),
|
|
||||||
new LabelledText(0, 0, 'CHARAbbrev.Ag', `${actorCharacs?.ag?.value}`),
|
|
||||||
new LabelledText(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
'CHARAbbrev.Dex',
|
|
||||||
`${actorCharacs?.dex?.value}`
|
|
||||||
),
|
|
||||||
new LabelledText(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
'CHARAbbrev.Int',
|
|
||||||
`${actorCharacs?.int?.value}`
|
|
||||||
),
|
|
||||||
new LabelledText(0, 0, 'CHARAbbrev.WP', `${actorCharacs?.wp?.value}`),
|
|
||||||
new LabelledText(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
'CHARAbbrev.Fel',
|
|
||||||
`${actorCharacs?.fel?.value}`
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
new Row(0, row6Y, [
|
|
||||||
new LabelledText(0, 0, 'Move', `${actorDetails?.move?.value}`),
|
|
||||||
new LabelledText(0, 0, 'Walk', `${actorDetails?.move?.walk}`),
|
|
||||||
new LabelledText(0, 0, 'Run', `${actorDetails?.move?.run}`),
|
|
||||||
new LabelledText(0, 0, 'Fortune', `${actorStatus?.fortune?.value}`),
|
|
||||||
new LabelledText(0, 0, 'Fate', `${actorStatus?.fate?.value}`),
|
|
||||||
new LabelledText(0, 0, 'Resolve', `${actorStatus?.resolve?.value}`),
|
|
||||||
new LabelledText(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
'Resilience',
|
|
||||||
`${actorStatus?.resilience?.value}`
|
|
||||||
),
|
|
||||||
new LabelledText(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
'Wounds',
|
|
||||||
`${actorStatus?.wounds?.value}/${actorStatus?.wounds?.max}`
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
new Text(0, row7Y, 'Skills'),
|
|
||||||
skills,
|
|
||||||
new Text(0, row9Y, 'Talents'),
|
|
||||||
talents,
|
|
||||||
new Text(0, row11Y, 'Traits'),
|
|
||||||
traits,
|
|
||||||
]);
|
]);
|
||||||
docBuilder.doc.save(`${app.actor.name}.pdf`);
|
docBuilder.doc.save(`${app.actor.name}.pdf`);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,18 +1,61 @@
|
|||||||
import jsPDF, { jsPDFOptions } from 'jspdf';
|
import jsPDF, { jsPDFOptions } from 'jspdf';
|
||||||
import { AbstractElement } from './elements/abstract-element';
|
import { AbstractElement } from './elements/abstract-element';
|
||||||
|
import { MARGINS } from './constants';
|
||||||
|
|
||||||
export class PdfBuilder {
|
export class PdfBuilder {
|
||||||
public doc: jsPDF;
|
public doc: jsPDF;
|
||||||
|
|
||||||
constructor(options: jsPDFOptions) {
|
constructor(options: jsPDFOptions) {
|
||||||
this.doc = new jsPDF(options);
|
this.doc = new jsPDF(options);
|
||||||
this.doc.advancedAPI();
|
|
||||||
console.dir(this.doc.internal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public build(elements: AbstractElement[]) {
|
public build(elements: AbstractElement[]) {
|
||||||
|
const finalElements: AbstractElement[] = [];
|
||||||
for (const element of elements) {
|
for (const element of elements) {
|
||||||
element.render(this.doc);
|
element.prepareRender(this.doc);
|
||||||
|
finalElements.push(...element.getElements());
|
||||||
|
}
|
||||||
|
finalElements.sort((a, b) => {
|
||||||
|
return a.y - b.y;
|
||||||
|
});
|
||||||
|
|
||||||
|
const pageHeight = this.doc.internal.pageSize.height;
|
||||||
|
const yMax = pageHeight - MARGINS.bottom;
|
||||||
|
const pages: AbstractElement[][] = [];
|
||||||
|
|
||||||
|
for (const element of finalElements) {
|
||||||
|
let indexPage = 0;
|
||||||
|
let currentY = element.y;
|
||||||
|
const height = element.getCheckNewPageHeight(this.doc);
|
||||||
|
if (currentY + height > yMax) {
|
||||||
|
while (currentY + height > yMax) {
|
||||||
|
indexPage++;
|
||||||
|
currentY = currentY - yMax + MARGINS.bottom;
|
||||||
|
if (currentY + height <= yMax) {
|
||||||
|
if (pages[indexPage] == null) {
|
||||||
|
pages[indexPage] = [];
|
||||||
|
}
|
||||||
|
element.y = currentY;
|
||||||
|
pages[indexPage].push(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (pages[indexPage] == null) {
|
||||||
|
pages[indexPage] = [];
|
||||||
|
}
|
||||||
|
pages[indexPage].push(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
for (const page of pages) {
|
||||||
|
i++;
|
||||||
|
for (const element of page) {
|
||||||
|
element.render(this.doc);
|
||||||
|
}
|
||||||
|
if (i < pages.length) {
|
||||||
|
this.doc.addPage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ const path = require('path');
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
entry: './src/main.ts',
|
entry: './src/main.ts',
|
||||||
devtool: 'inline-source-map',
|
devtool: 'eval-source-map',
|
||||||
|
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user