html2canvas-pro 2.0.2 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/html2canvas-pro.esm.js +88 -28
- package/dist/html2canvas-pro.esm.js.map +1 -1
- package/dist/html2canvas-pro.js +88 -28
- package/dist/html2canvas-pro.js.map +1 -1
- package/dist/html2canvas-pro.min.js +5 -5
- package/dist/lib/css/index.js +2 -0
- package/dist/lib/css/index.js.map +1 -1
- package/dist/lib/css/layout/text.js +4 -0
- package/dist/lib/css/layout/text.js.map +1 -1
- package/dist/lib/css/property-descriptors/writing-mode.js +29 -0
- package/dist/lib/css/property-descriptors/writing-mode.js.map +1 -0
- package/dist/lib/dom/document-cloner.js +5 -4
- package/dist/lib/dom/document-cloner.js.map +1 -1
- package/dist/lib/dom/text-container.js +5 -0
- package/dist/lib/dom/text-container.js.map +1 -1
- package/dist/lib/render/canvas/__tests__/text-renderer.test.js +92 -0
- package/dist/lib/render/canvas/__tests__/text-renderer.test.js.map +1 -1
- package/dist/lib/render/canvas/canvas-renderer.js +2 -2
- package/dist/lib/render/canvas/canvas-renderer.js.map +1 -1
- package/dist/lib/render/canvas/text-renderer.js +48 -21
- package/dist/lib/render/canvas/text-renderer.js.map +1 -1
- package/dist/types/css/index.d.ts +2 -0
- package/dist/types/css/property-descriptors/writing-mode.d.ts +11 -0
- package/dist/types/render/canvas/text-renderer.d.ts +3 -1
- package/karma.conf.cjs +6 -1
- package/package.json +5 -4
package/dist/html2canvas-pro.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* html2canvas-pro 2.0.
|
|
2
|
+
* html2canvas-pro 2.0.4 <https://yorickshan.github.io/html2canvas-pro/>
|
|
3
3
|
* Copyright (c) 2024-present yorickshan and html2canvas-pro contributors
|
|
4
4
|
* Released under MIT License
|
|
5
5
|
*/
|
|
@@ -4245,6 +4245,30 @@
|
|
|
4245
4245
|
}
|
|
4246
4246
|
};
|
|
4247
4247
|
|
|
4248
|
+
const isVerticalWritingMode = (writingMode) => writingMode !== 0 /* WRITING_MODE.HORIZONTAL_TB */;
|
|
4249
|
+
const isSidewaysWritingMode = (writingMode) => writingMode === 3 /* WRITING_MODE.SIDEWAYS_RL */ || writingMode === 4 /* WRITING_MODE.SIDEWAYS_LR */;
|
|
4250
|
+
const writingMode = {
|
|
4251
|
+
name: 'writing-mode',
|
|
4252
|
+
initialValue: 'horizontal-tb',
|
|
4253
|
+
prefix: false,
|
|
4254
|
+
type: 2 /* PropertyDescriptorParsingType.IDENT_VALUE */,
|
|
4255
|
+
parse: (_context, writingMode) => {
|
|
4256
|
+
switch (writingMode) {
|
|
4257
|
+
case 'vertical-rl':
|
|
4258
|
+
return 1 /* WRITING_MODE.VERTICAL_RL */;
|
|
4259
|
+
case 'vertical-lr':
|
|
4260
|
+
return 2 /* WRITING_MODE.VERTICAL_LR */;
|
|
4261
|
+
case 'sideways-rl':
|
|
4262
|
+
return 3 /* WRITING_MODE.SIDEWAYS_RL */;
|
|
4263
|
+
case 'sideways-lr':
|
|
4264
|
+
return 4 /* WRITING_MODE.SIDEWAYS_LR */;
|
|
4265
|
+
case 'horizontal-tb':
|
|
4266
|
+
default:
|
|
4267
|
+
return 0 /* WRITING_MODE.HORIZONTAL_TB */;
|
|
4268
|
+
}
|
|
4269
|
+
}
|
|
4270
|
+
};
|
|
4271
|
+
|
|
4248
4272
|
const zIndex = {
|
|
4249
4273
|
name: 'z-index',
|
|
4250
4274
|
initialValue: 'auto',
|
|
@@ -4861,6 +4885,7 @@
|
|
|
4861
4885
|
this.webkitTextStrokeWidth = parse(context, webkitTextStrokeWidth, declaration.webkitTextStrokeWidth);
|
|
4862
4886
|
this.webkitLineClamp = parse(context, webkitLineClamp, declaration.webkitLineClamp);
|
|
4863
4887
|
this.wordBreak = parse(context, wordBreak, declaration.wordBreak);
|
|
4888
|
+
this.writingMode = parse(context, writingMode, declaration.writingMode);
|
|
4864
4889
|
this.zIndex = parse(context, zIndex, declaration.zIndex);
|
|
4865
4890
|
this.objectFit = parse(context, objectFit, declaration.objectFit);
|
|
4866
4891
|
this.imageRendering = parse(context, imageRendering, declaration.imageRendering);
|
|
@@ -5796,6 +5821,9 @@
|
|
|
5796
5821
|
return breakWords(value, styles);
|
|
5797
5822
|
};
|
|
5798
5823
|
const breakText = (value, styles) => {
|
|
5824
|
+
if (isVerticalWritingMode(styles.writingMode)) {
|
|
5825
|
+
return segmentGraphemes(value);
|
|
5826
|
+
}
|
|
5799
5827
|
return styles.letterSpacing !== 0 ? segmentGraphemes(value) : segmentWords(value, styles);
|
|
5800
5828
|
};
|
|
5801
5829
|
// https://drafts.csswg.org/css-text/#word-separator
|
|
@@ -5835,6 +5863,11 @@
|
|
|
5835
5863
|
class TextContainer {
|
|
5836
5864
|
constructor(context, node, styles) {
|
|
5837
5865
|
this.text = transform(node.data, styles.textTransform);
|
|
5866
|
+
// Range offsets below are based on transformed text; keep the node in sync
|
|
5867
|
+
// when casing changes string length, for example "ß".toUpperCase() === "SS".
|
|
5868
|
+
if (this.text.length !== node.data.length) {
|
|
5869
|
+
node.data = this.text;
|
|
5870
|
+
}
|
|
5838
5871
|
this.textBounds = parseTextBounds(context, this.text, styles, node);
|
|
5839
5872
|
}
|
|
5840
5873
|
}
|
|
@@ -6592,10 +6625,11 @@
|
|
|
6592
6625
|
return iframe;
|
|
6593
6626
|
});
|
|
6594
6627
|
/**
|
|
6595
|
-
* The
|
|
6596
|
-
*
|
|
6597
|
-
*
|
|
6598
|
-
|
|
6628
|
+
* The base URI used for resolving relative URLs (e.g. background-image) in the clone.
|
|
6629
|
+
* Must come from the source document: the iframe document is about:blank, so
|
|
6630
|
+
* documentClone.baseURI would break getComputedStyle() for relative background URLs.
|
|
6631
|
+
*/
|
|
6632
|
+
const baseUri = ownerDocument.baseURI;
|
|
6599
6633
|
documentClone.open();
|
|
6600
6634
|
const rawHTML = serializeDoctype(document.doctype) + '<html></html>';
|
|
6601
6635
|
try {
|
|
@@ -8722,7 +8756,11 @@
|
|
|
8722
8756
|
* call (fillText or strokeText), allowing fill and stroke paths to share one
|
|
8723
8757
|
* implementation.
|
|
8724
8758
|
*/
|
|
8725
|
-
iterateLettersWithLetterSpacing(text, letterSpacing, baseline, renderFn) {
|
|
8759
|
+
iterateLettersWithLetterSpacing(text, letterSpacing, baseline, writingMode, renderFn) {
|
|
8760
|
+
if (isVerticalWritingMode(writingMode)) {
|
|
8761
|
+
this.iterateVerticalGlyphs(text, letterSpacing, baseline, writingMode, renderFn);
|
|
8762
|
+
return;
|
|
8763
|
+
}
|
|
8726
8764
|
const letters = segmentGraphemes(text.text);
|
|
8727
8765
|
const y = text.bounds.top + baseline;
|
|
8728
8766
|
let left = text.bounds.left;
|
|
@@ -8739,17 +8777,39 @@
|
|
|
8739
8777
|
left += this.ctx.measureText(letter).width + letterSpacing;
|
|
8740
8778
|
}
|
|
8741
8779
|
}
|
|
8780
|
+
iterateVerticalGlyphs(text, letterSpacing, baseline, writingMode, renderFn) {
|
|
8781
|
+
const letters = segmentGraphemes(text.text);
|
|
8782
|
+
let top = text.bounds.top;
|
|
8783
|
+
for (const letter of letters) {
|
|
8784
|
+
if (isSidewaysWritingMode(writingMode) || (!hasCJKCharacters(letter) && letter.trim().length > 0)) {
|
|
8785
|
+
this.ctx.save();
|
|
8786
|
+
this.ctx.translate(text.bounds.left + baseline, top);
|
|
8787
|
+
this.ctx.rotate(writingMode === 4 /* WRITING_MODE.SIDEWAYS_LR */ ? -Math.PI / 2 : Math.PI / 2);
|
|
8788
|
+
renderFn(letter, 0, 0);
|
|
8789
|
+
this.ctx.restore();
|
|
8790
|
+
}
|
|
8791
|
+
else {
|
|
8792
|
+
const savedBaseline = this.ctx.textBaseline;
|
|
8793
|
+
if (hasCJKCharacters(letter)) {
|
|
8794
|
+
this.ctx.textBaseline = 'ideographic';
|
|
8795
|
+
}
|
|
8796
|
+
renderFn(letter, text.bounds.left, top + baseline);
|
|
8797
|
+
this.ctx.textBaseline = savedBaseline;
|
|
8798
|
+
}
|
|
8799
|
+
top += this.ctx.measureText(letter).width + letterSpacing;
|
|
8800
|
+
}
|
|
8801
|
+
}
|
|
8742
8802
|
/**
|
|
8743
8803
|
* Render text with letter-spacing applied (fill pass).
|
|
8744
8804
|
* When letterSpacing is 0 the whole string is drawn in one call; otherwise each
|
|
8745
8805
|
* grapheme is drawn individually so spacing and CJK baseline are applied correctly.
|
|
8746
8806
|
*/
|
|
8747
|
-
renderTextWithLetterSpacing(text, letterSpacing, baseline) {
|
|
8748
|
-
if (letterSpacing === 0) {
|
|
8807
|
+
renderTextWithLetterSpacing(text, letterSpacing, baseline, writingMode = 0 /* WRITING_MODE.HORIZONTAL_TB */) {
|
|
8808
|
+
if (letterSpacing === 0 && !isVerticalWritingMode(writingMode)) {
|
|
8749
8809
|
this.ctx.fillText(text.text, text.bounds.left, text.bounds.top + baseline);
|
|
8750
8810
|
}
|
|
8751
8811
|
else {
|
|
8752
|
-
this.iterateLettersWithLetterSpacing(text, letterSpacing, baseline, (letter, x, y) => {
|
|
8812
|
+
this.iterateLettersWithLetterSpacing(text, letterSpacing, baseline, writingMode, (letter, x, y) => {
|
|
8753
8813
|
this.ctx.fillText(letter, x, y);
|
|
8754
8814
|
});
|
|
8755
8815
|
}
|
|
@@ -8763,7 +8823,7 @@
|
|
|
8763
8823
|
switch (paintOrderLayer) {
|
|
8764
8824
|
case 0 /* PAINT_ORDER_LAYER.FILL */:
|
|
8765
8825
|
this.ctx.fillStyle = asString(styles.color);
|
|
8766
|
-
this.renderTextWithLetterSpacing(textBound, styles.letterSpacing, styles.fontSize.number);
|
|
8826
|
+
this.renderTextWithLetterSpacing(textBound, styles.letterSpacing, styles.fontSize.number, styles.writingMode);
|
|
8767
8827
|
break;
|
|
8768
8828
|
case 1 /* PAINT_ORDER_LAYER.STROKE */:
|
|
8769
8829
|
if (styles.webkitTextStrokeWidth && textBound.text.trim().length) {
|
|
@@ -8771,11 +8831,11 @@
|
|
|
8771
8831
|
this.ctx.lineWidth = styles.webkitTextStrokeWidth;
|
|
8772
8832
|
this.ctx.lineJoin =
|
|
8773
8833
|
typeof window !== 'undefined' && !!window.chrome ? 'miter' : 'round';
|
|
8774
|
-
if (styles.letterSpacing === 0) {
|
|
8834
|
+
if (styles.letterSpacing === 0 && !isVerticalWritingMode(styles.writingMode)) {
|
|
8775
8835
|
this.ctx.strokeText(textBound.text, textBound.bounds.left, textBound.bounds.top + styles.fontSize.number);
|
|
8776
8836
|
}
|
|
8777
8837
|
else {
|
|
8778
|
-
this.iterateLettersWithLetterSpacing(textBound, styles.letterSpacing, styles.fontSize.number, (letter, x, y) => this.ctx.strokeText(letter, x, y));
|
|
8838
|
+
this.iterateLettersWithLetterSpacing(textBound, styles.letterSpacing, styles.fontSize.number, styles.writingMode, (letter, x, y) => this.ctx.strokeText(letter, x, y));
|
|
8779
8839
|
}
|
|
8780
8840
|
this.ctx.strokeStyle = '';
|
|
8781
8841
|
this.ctx.lineWidth = 0;
|
|
@@ -9011,11 +9071,11 @@
|
|
|
9011
9071
|
switch (paintOrderLayer) {
|
|
9012
9072
|
case 0 /* PAINT_ORDER_LAYER.FILL */:
|
|
9013
9073
|
this.ctx.fillStyle = asString(styles.color);
|
|
9014
|
-
if (styles.letterSpacing === 0) {
|
|
9074
|
+
if (styles.letterSpacing === 0 && !isVerticalWritingMode(styles.writingMode)) {
|
|
9015
9075
|
this.ctx.fillText(truncatedText, firstBound.bounds.left, firstBound.bounds.top + styles.fontSize.number);
|
|
9016
9076
|
}
|
|
9017
9077
|
else {
|
|
9018
|
-
this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, (letter, x, y) => this.ctx.fillText(letter, x, y));
|
|
9078
|
+
this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, styles.writingMode, (letter, x, y) => this.ctx.fillText(letter, x, y));
|
|
9019
9079
|
}
|
|
9020
9080
|
break;
|
|
9021
9081
|
case 1 /* PAINT_ORDER_LAYER.STROKE */:
|
|
@@ -9024,11 +9084,11 @@
|
|
|
9024
9084
|
this.ctx.lineWidth = styles.webkitTextStrokeWidth;
|
|
9025
9085
|
this.ctx.lineJoin =
|
|
9026
9086
|
typeof window !== 'undefined' && !!window.chrome ? 'miter' : 'round';
|
|
9027
|
-
if (styles.letterSpacing === 0) {
|
|
9087
|
+
if (styles.letterSpacing === 0 && !isVerticalWritingMode(styles.writingMode)) {
|
|
9028
9088
|
this.ctx.strokeText(truncatedText, firstBound.bounds.left, firstBound.bounds.top + styles.fontSize.number);
|
|
9029
9089
|
}
|
|
9030
9090
|
else {
|
|
9031
|
-
this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, (letter, x, y) => this.ctx.strokeText(letter, x, y));
|
|
9091
|
+
this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, styles.writingMode, (letter, x, y) => this.ctx.strokeText(letter, x, y));
|
|
9032
9092
|
}
|
|
9033
9093
|
this.ctx.strokeStyle = '';
|
|
9034
9094
|
this.ctx.lineWidth = 0;
|
|
@@ -9083,11 +9143,11 @@
|
|
|
9083
9143
|
switch (paintOrderLayer) {
|
|
9084
9144
|
case 0 /* PAINT_ORDER_LAYER.FILL */: {
|
|
9085
9145
|
this.ctx.fillStyle = asString(styles.color);
|
|
9086
|
-
if (styles.letterSpacing === 0) {
|
|
9146
|
+
if (styles.letterSpacing === 0 && !isVerticalWritingMode(styles.writingMode)) {
|
|
9087
9147
|
this.ctx.fillText(truncatedText, firstBound.bounds.left, firstBound.bounds.top + styles.fontSize.number);
|
|
9088
9148
|
}
|
|
9089
9149
|
else {
|
|
9090
|
-
this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, (letter, x, y) => this.ctx.fillText(letter, x, y));
|
|
9150
|
+
this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, styles.writingMode, (letter, x, y) => this.ctx.fillText(letter, x, y));
|
|
9091
9151
|
}
|
|
9092
9152
|
const textShadows = styles.textShadow;
|
|
9093
9153
|
if (textShadows.length && truncatedText.trim().length) {
|
|
@@ -9099,11 +9159,11 @@
|
|
|
9099
9159
|
this.ctx.shadowOffsetX = textShadow.offsetX.number * this.options.scale;
|
|
9100
9160
|
this.ctx.shadowOffsetY = textShadow.offsetY.number * this.options.scale;
|
|
9101
9161
|
this.ctx.shadowBlur = textShadow.blur.number;
|
|
9102
|
-
if (styles.letterSpacing === 0) {
|
|
9162
|
+
if (styles.letterSpacing === 0 && !isVerticalWritingMode(styles.writingMode)) {
|
|
9103
9163
|
this.ctx.fillText(truncatedText, firstBound.bounds.left, firstBound.bounds.top + styles.fontSize.number);
|
|
9104
9164
|
}
|
|
9105
9165
|
else {
|
|
9106
|
-
this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, (letter, x, y) => this.ctx.fillText(letter, x, y));
|
|
9166
|
+
this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, styles.writingMode, (letter, x, y) => this.ctx.fillText(letter, x, y));
|
|
9107
9167
|
}
|
|
9108
9168
|
});
|
|
9109
9169
|
this.ctx.shadowColor = '';
|
|
@@ -9119,11 +9179,11 @@
|
|
|
9119
9179
|
this.ctx.lineWidth = styles.webkitTextStrokeWidth;
|
|
9120
9180
|
this.ctx.lineJoin =
|
|
9121
9181
|
typeof window !== 'undefined' && !!window.chrome ? 'miter' : 'round';
|
|
9122
|
-
if (styles.letterSpacing === 0) {
|
|
9182
|
+
if (styles.letterSpacing === 0 && !isVerticalWritingMode(styles.writingMode)) {
|
|
9123
9183
|
this.ctx.strokeText(truncatedText, firstBound.bounds.left, firstBound.bounds.top + styles.fontSize.number);
|
|
9124
9184
|
}
|
|
9125
9185
|
else {
|
|
9126
|
-
this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, (letter, x, y) => this.ctx.strokeText(letter, x, y));
|
|
9186
|
+
this.iterateLettersWithLetterSpacing(truncatedBounds, styles.letterSpacing, styles.fontSize.number, styles.writingMode, (letter, x, y) => this.ctx.strokeText(letter, x, y));
|
|
9127
9187
|
}
|
|
9128
9188
|
this.ctx.strokeStyle = '';
|
|
9129
9189
|
this.ctx.lineWidth = 0;
|
|
@@ -9140,7 +9200,7 @@
|
|
|
9140
9200
|
switch (paintOrderLayer) {
|
|
9141
9201
|
case 0 /* PAINT_ORDER_LAYER.FILL */: {
|
|
9142
9202
|
this.ctx.fillStyle = asString(styles.color);
|
|
9143
|
-
this.renderTextWithLetterSpacing(text, styles.letterSpacing, styles.fontSize.number);
|
|
9203
|
+
this.renderTextWithLetterSpacing(text, styles.letterSpacing, styles.fontSize.number, styles.writingMode);
|
|
9144
9204
|
const textShadows = styles.textShadow;
|
|
9145
9205
|
if (textShadows.length && text.text.trim().length) {
|
|
9146
9206
|
textShadows
|
|
@@ -9151,7 +9211,7 @@
|
|
|
9151
9211
|
this.ctx.shadowOffsetX = textShadow.offsetX.number * this.options.scale;
|
|
9152
9212
|
this.ctx.shadowOffsetY = textShadow.offsetY.number * this.options.scale;
|
|
9153
9213
|
this.ctx.shadowBlur = textShadow.blur.number;
|
|
9154
|
-
this.renderTextWithLetterSpacing(text, styles.letterSpacing, styles.fontSize.number);
|
|
9214
|
+
this.renderTextWithLetterSpacing(text, styles.letterSpacing, styles.fontSize.number, styles.writingMode);
|
|
9155
9215
|
});
|
|
9156
9216
|
this.ctx.shadowColor = '';
|
|
9157
9217
|
this.ctx.shadowOffsetX = 0;
|
|
@@ -9170,11 +9230,11 @@
|
|
|
9170
9230
|
this.ctx.lineJoin =
|
|
9171
9231
|
typeof window !== 'undefined' && !!window.chrome ? 'miter' : 'round';
|
|
9172
9232
|
const baseline = styles.fontSize.number;
|
|
9173
|
-
if (styles.letterSpacing === 0) {
|
|
9233
|
+
if (styles.letterSpacing === 0 && !isVerticalWritingMode(styles.writingMode)) {
|
|
9174
9234
|
this.ctx.strokeText(text.text, text.bounds.left, text.bounds.top + baseline);
|
|
9175
9235
|
}
|
|
9176
9236
|
else {
|
|
9177
|
-
this.iterateLettersWithLetterSpacing(text, styles.letterSpacing, baseline, (letter, x, y) => this.ctx.strokeText(letter, x, y));
|
|
9237
|
+
this.iterateLettersWithLetterSpacing(text, styles.letterSpacing, baseline, styles.writingMode, (letter, x, y) => this.ctx.strokeText(letter, x, y));
|
|
9178
9238
|
}
|
|
9179
9239
|
this.ctx.strokeStyle = '';
|
|
9180
9240
|
this.ctx.lineWidth = 0;
|
|
@@ -9469,7 +9529,7 @@
|
|
|
9469
9529
|
new Vector(bounds.left, bounds.top + bounds.height)
|
|
9470
9530
|
]);
|
|
9471
9531
|
this.ctx.clip();
|
|
9472
|
-
this.textRenderer.renderTextWithLetterSpacing(new TextBounds(container.value, textBounds), styles.letterSpacing, baseline);
|
|
9532
|
+
this.textRenderer.renderTextWithLetterSpacing(new TextBounds(container.value, textBounds), styles.letterSpacing, baseline, styles.writingMode);
|
|
9473
9533
|
this.ctx.restore();
|
|
9474
9534
|
this.ctx.textBaseline = 'alphabetic';
|
|
9475
9535
|
this.ctx.textAlign = 'left';
|
|
@@ -9496,7 +9556,7 @@
|
|
|
9496
9556
|
this.ctx.textBaseline = 'middle';
|
|
9497
9557
|
this.ctx.textAlign = 'right';
|
|
9498
9558
|
const bounds = new Bounds(container.bounds.left, container.bounds.top + getAbsoluteValue(container.styles.paddingTop, container.bounds.width), container.bounds.width, computeLineHeight(styles.lineHeight, styles.fontSize.number) / 2 + 1);
|
|
9499
|
-
this.textRenderer.renderTextWithLetterSpacing(new TextBounds(paint.listValue, bounds), styles.letterSpacing, computeLineHeight(styles.lineHeight, styles.fontSize.number) / 2 + 2);
|
|
9559
|
+
this.textRenderer.renderTextWithLetterSpacing(new TextBounds(paint.listValue, bounds), styles.letterSpacing, computeLineHeight(styles.lineHeight, styles.fontSize.number) / 2 + 2, styles.writingMode);
|
|
9500
9560
|
this.ctx.textBaseline = 'bottom';
|
|
9501
9561
|
this.ctx.textAlign = 'left';
|
|
9502
9562
|
}
|