]>
git.kianting.info Git - clo/blob - src/libclo/index.ts
1 import { isKeyObject
, isStringObject
} from
"util/types";
2 import {tkTree
} from
"../parser";
3 import {FontStyle
, TextStyle
, TextWeight
} from
"../canva";
4 import { JSDOM
} from
"jsdom";
16 export enum Direction
{
24 * frame box is a subclass of box
25 * - directionInsideLine : text direction inside a line
26 * - baselineskip : the distance between baselines in px
28 export interface FrameBox
extends Box
{
29 directionInsideLine
: Direction
,
30 baseLineskip
: number | null,
45 textStyle
: TextStyle
| null,
46 direction
: Direction
,
49 content
: string | Box
[] | null,
56 export const A4_IN_PX
= {"width" : 793.7,
59 export const defaultTextStyle
: TextStyle
= {
62 textWeight
: TextWeight
.REGULAR
,
63 fontStyle
: FontStyle
.ITALIC
,
66 export const defaultFrameStyle
: FrameBox
= {
67 directionInsideLine
: Direction
.LTR
,
68 direction
: Direction
.TTB
,
69 baseLineskip
: ptToPx(15),
70 textStyle
: defaultTextStyle
,
71 x
: A4_IN_PX
.width
* 0.10,
72 y
: A4_IN_PX
.height
* 0.10,
73 width
: A4_IN_PX
.width
* 0.80,
74 height
: A4_IN_PX
.height
* 0.80,
79 * definition for cjk scripts
80 * - Hani : Han Character
86 export const cjkvBlocksInRegex
= ["Hani", "Hang", "Bopo", "Kana", "Hira"];
88 export const cjkvRegexPattern
= new RegExp("((?:" +
89 cjkvBlocksInRegex
.map((x
)=>"\\p{Script_Extensions="+x
+"}").join("|") + ")+)", "gu");
95 * @param pt pt size value
96 * @returns the corresponding px value
98 export function ptToPx(pt
: number) : number{
99 return pt
* 4.0 / 3.0;
109 * convert '\n\n' to newline command ["nl"]
110 * @param arr the input `tkTree`
111 * @param clo the `Clo` object
112 * @returns the input tktree
114 export function twoReturnsToNewline(arr
: tkTree
, clo
: Clo
): tkTree
{
115 var middle
: tkTree
= [];
117 for (let i
= 0; i
< arr
.length
; i
++) {
119 if (!Array.isArray(item
)){
120 middle
= middle
.concat(item
.split(/(\n\n)/g
));
127 var result
: tkTree
= [];
128 for (let j
= 0; j
< middle
.length
; j
++){
129 var item
= middle
[j
];
130 if (!Array.isArray(item
) && item
== "\n\n"){
131 result
.push(["nl"]); // push a newline command to the result `tkTree`
134 result
.push(middle
[j
]);
142 * split CJKV and non-CJKV
144 * @param arr : input tkTree
145 * @returns a splitted tkTree (by CJK and NonCJK)
148 * [`many臺中daylight`] => [`many`, `臺中`, `dahylight`]
151 export function splitCJKV(arr
: tkTree
, clo
: Clo
): tkTree
{
152 var result
: tkTree
= [];
153 for (let i
= 0; i
< arr
.length
; i
++) {
155 if (!Array.isArray(item
)){
156 result
= result
.concat(item
.split(cjkvRegexPattern
));
167 * hyphenation for a clo document
168 * @param arr the array for a `tkTree`
169 * @param clo the Clo object
171 export function hyphenForClo(arr
: tkTree
, clo
: Clo
): tkTree
{
172 let hyphenLanguage
: string = clo
.attrs
["hyphenLanguage"];
173 let res
= hyphenTkTree(arr
, hyphenLanguage
);
179 * convert spaces to Breakpoint
180 * \s+ => ["bp" [\s+] ""]
181 * @param arr the tkTree input text stream
182 * @param clo the Clo object
183 * @returns the converted object
185 export function spacesToBreakpoint(arr
: tkTree
, clo
: Clo
) : tkTree
{
186 let spacePattern
= /^([ \t]+)$
/g
;
187 var result
: tkTree
= [];
188 for (let i
= 0; i
< arr
.length
; i
++){
190 if (!Array.isArray(item
) && item
.match(spacePattern
)){
191 result
.push([ 'bp', item
, "" ]); // push a newline command to the result `tkTree`
202 * remove all the `` (empty string) in the arr
203 * @param arr the tkTree to be filtered
204 * @param clo the Clo file
206 export function filterEmptyString(arr
: tkTree
, clo
: Clo
) : tkTree
{
207 if (Array.isArray(arr
)){
208 arr
.filter((x
)=>{return x
!= ``;});
220 * hyphenate for a tkTree
221 * - hyphenation => ["bp", "", "-"]
222 * @param arr the tkTree array
223 * @param lang ISO 639 code for the language
225 export function hyphenTkTree(arr
: tkTree
, lang
: string) : tkTree
{
226 // import corresponding hyphen language data and function
227 let hyphen
= require("hyphen/"+lang
);
229 let result
:tkTree
[] = [];
230 for (let i
= 0; i
< arr
.length
; i
++) {
231 let element
= arr
[i
];
232 let splitter
= "分"; // a CJKV
233 if (!Array.isArray(element
)){
234 let hyphenatedElement
: string = hyphen
.hyphenateSync(element
, {hyphenChar
:splitter
});
235 let hyphenatedSplitted
: tkTree
= hyphenatedElement
.split(splitter
);
236 var newSplitted
: tkTree
= [];
237 for (var j
=0; j
<hyphenatedSplitted
.length
-1;j
++){
238 newSplitted
.push(hyphenatedSplitted
[j
]);
239 // "bp" for breakpoint
240 newSplitted
.push(["bp", "", "-"]); //insert a breakable point (bp) mark
242 newSplitted
.push(hyphenatedSplitted
[hyphenatedSplitted
.length
-1]);
244 result
= result
.concat(newSplitted
);
247 result
.push(element
);
256 * calculate the text width and Height with a given `TextStyle`
257 * @param preprocessed
258 * @param defaultFontStyle
260 export function calculateTextWidthHeight(preprocessed
: tkTree
, style
: TextStyle
): void {
261 var dom
= new JSDOM(`<!DOCTYPE html><html><head></head>
262 <body><canvas id="canvas"></canvas></body></html>`);
265 let canvas
= dom
.window
.document
.getElementById("canvas");
268 /*if (!(canvas instanceof HTMLElement)){
269 throw new Error('the <canvas="canvas"> in the jsdom\'s DOM is not found.');
273 let context
= (<HTMLCanvasElement
>canvas
).getContext("2d");
274 console
.log(context
);
275 if (context
== null){
276 throw new Error('`canvas.getContext("2d");` can\'t be executed.');
280 context
.font
= `normal normal ${style.size}px ${style.family}`;
281 console
.log(context
.font
);
282 let txt
= `Hello john`;
284 let measured
= context
.measureText(txt
);
285 let width
= measured
.width
;
286 let height
= measured
.actualBoundingBoxAscent
;
287 let depth
= measured
.actualBoundingBoxDescent
;
289 console
.log("width: "+width
);
290 console
.log("height: "+height
);
291 console
.log("depth: "+depth
);
295 console
.log("Exception "+error
);
305 * whole document-representing class
308 /** storing the text string into the main frame */
309 mainStream
: Array<string>;
310 /** array of preprocessor functions to preprocess the `mainStream` */
311 preprocessors
: Array<Function>;
312 /** the attributes for the Clo */
313 attrs
: {[index
: string]:any} ; // a4 size(x,y)
317 this.preprocessors
= [];
318 this.mainStream
= [];
320 "page" : A4_IN_PX
, // default for a4. in px of [x, y]
321 "defaultFrameStyle" : defaultFrameStyle
, // defaultFrameStyle
322 "hyphenLanguage" : 'en' // hyphenated in the language (in ISO 639)
327 // register the precessor functions
328 this.preprocessorRegister(splitCJKV
);
329 this.preprocessorRegister(hyphenForClo
);
330 this.preprocessorRegister(twoReturnsToNewline
);
331 this.preprocessorRegister(spacesToBreakpoint
);
332 this.preprocessorRegister(filterEmptyString
);
335 public setAttr(attr
: string, val
: any):void{
336 Object.assign(this.attrs
, attr
, val
);
339 public getAttr(attr
:string) : any{
340 if (Object.keys(this.attrs
).length
=== 0){
341 return this.attrs
[attr
];
349 * register a function of preprocessor
350 * @param f a function
352 public preprocessorRegister(f
: Function){
353 this.preprocessors
.push(f
);
356 public generatePdf(){
358 var preprocessed
= this.mainStream
;
359 for (var i
= 0; i
<this.preprocessors
.length
; i
++){
360 preprocessed
= this.preprocessors
[i
](preprocessed
, this);
362 // generate the width and height of the stream
364 let defaultFontStyle
: TextStyle
= this.attrs
["defaultFrameStyle"].textStyle
;
365 calculateTextWidthHeight(preprocessed
, defaultFontStyle
);
368 console
.log(preprocessed
);
375 export let a = new Clo();