@next2d/text 1.16.0 → 1.17.0

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/TextField.js DELETED
@@ -1,2683 +0,0 @@
1
- import { TextFormat } from "./TextFormat";
2
- import { InteractiveObject, Sprite } from "@next2d/display";
3
- import { FocusEvent, Event as Next2DEvent, MouseEvent as Next2DMouseEvent } from "@next2d/events";
4
- import { Tween } from "@next2d/ui";
5
- import { Rectangle } from "@next2d/geom";
6
- import { $currentPlayer, $DIV, $isSafari, $MOUSE_DOWN, $MOUSE_UP, $MOUSE_WHEEL, $P_TAG, $PREFIX, $rendererWorker, $SCROLL, $textContext, $TOUCH_END, $TOUCH_START, $document, $RegExp } from "@next2d/util";
7
- import { $cacheStore, $doUpdated, $clamp, $getArray, $intToRGBA, $isNaN, $Math, $requestAnimationFrame, $toColorInt, $getMap, $poolFloat32Array6, $boundsMatrix, $multiplicationMatrix, $poolBoundsObject, $multiplicationColor, $Infinity, $Number, $poolArray, $poolFloat32Array8, $generateFontStyle, $devicePixelRatio, $getBoundsObject } from "@next2d/share";
8
- /**
9
- * TextField クラスは、テキストの表示と入力用の表示オブジェクトを作成するために使用されます。
10
- * プロパティインスペクターを使用して、テキストフィールドにインスタンス名を付けることができます。
11
- * また、TextField クラスのメソッドとプロパティを使用して、JavaScript でテキストフィールドを操作できます。
12
- *
13
- * The TextField class is used to create display objects for text display and input.
14
- * You can give a text field an instance name in the Property inspector
15
- * and use the methods and properties of the TextField class to manipulate it with JavaScript.
16
- *
17
- * @class
18
- * @memberOf next2d.text
19
- * @extends InteractiveObject
20
- */
21
- export class TextField extends InteractiveObject {
22
- /**
23
- * @constructor
24
- * @public
25
- */
26
- constructor() {
27
- super();
28
- /**
29
- * @type {boolean}
30
- * @default false
31
- * @private
32
- */
33
- this._$background = false;
34
- /**
35
- * @type {number}
36
- * @default 0xffffff
37
- * @private
38
- */
39
- this._$backgroundColor = 0xffffff;
40
- /**
41
- * @type {boolean}
42
- * @default false
43
- * @private
44
- */
45
- this._$border = false;
46
- /**
47
- * @type {number}
48
- * @default 0x000000
49
- * @private
50
- */
51
- this._$borderColor = 0x000000;
52
- /**
53
- * @type {string}
54
- * @default ""
55
- * @private
56
- */
57
- this._$htmlText = "";
58
- /**
59
- * @type {boolean}
60
- * @default false
61
- * @private
62
- */
63
- this._$multiline = false;
64
- /**
65
- * @type {string}
66
- * @default ""
67
- * @private
68
- */
69
- this._$text = "";
70
- /**
71
- * @type {boolean}
72
- * @default false
73
- * @private
74
- */
75
- this._$wordWrap = false;
76
- /**
77
- * @type {number}
78
- * @default 0
79
- * @private
80
- */
81
- this._$scrollH = 0;
82
- /**
83
- * @type {number}
84
- * @default 1
85
- * @private
86
- */
87
- this._$scrollV = 1;
88
- /**
89
- * @type {number}
90
- * @default null
91
- * @private
92
- */
93
- this._$maxScrollV = null;
94
- /**
95
- * @type {number}
96
- * @default null
97
- * @private
98
- */
99
- this._$maxScrollH = null;
100
- /**
101
- * @type {number}
102
- * @default 0
103
- * @private
104
- */
105
- this._$maxChars = 0;
106
- // TextFormat
107
- const textFormat = new TextFormat();
108
- textFormat._$setDefault();
109
- /**
110
- * @type {TextFormat}
111
- * @private
112
- */
113
- this._$defaultTextFormat = textFormat;
114
- /**
115
- * @type {string}
116
- * @default ""
117
- * @private
118
- */
119
- this._$rawHtmlText = "";
120
- /**
121
- * @type {object}
122
- * @private
123
- */
124
- this._$bounds = {
125
- "xMin": 0,
126
- "xMax": 100,
127
- "yMin": 0,
128
- "yMax": 100
129
- };
130
- /**
131
- * @type {object}
132
- * @private
133
- */
134
- this._$originBounds = {
135
- "xMin": 0,
136
- "xMax": 100,
137
- "yMin": 0,
138
- "yMax": 100
139
- };
140
- /**
141
- * @type {string}
142
- * @default null
143
- * @private
144
- */
145
- this._$restrict = "";
146
- /**
147
- * @type {boolean}
148
- * @default false
149
- * @private
150
- */
151
- this._$isHTML = false;
152
- /**
153
- * @type {boolean}
154
- * @default false
155
- * @private
156
- */
157
- this._$createdTextData = false;
158
- /**
159
- * @type {array}
160
- * @private
161
- */
162
- this._$textData = $getArray();
163
- /**
164
- * @type {number}
165
- * @default null
166
- * @private
167
- */
168
- this._$textHeight = null;
169
- /**
170
- * @type {number}
171
- * @default null
172
- * @private
173
- */
174
- this._$textWidth = null;
175
- /**
176
- * @type {array}
177
- * @private
178
- */
179
- this._$widthTable = $getArray();
180
- /**
181
- * @type {HTMLTextAreaElement}
182
- * @default null
183
- * @private
184
- */
185
- this._$textarea = null;
186
- /**
187
- * @type {string}
188
- * @default TextFieldAutoSize.NONE
189
- * @private
190
- */
191
- this._$autoSize = "none";
192
- /**
193
- * @type {boolean}
194
- * @default false
195
- * @private
196
- */
197
- this._$autoFontSize = false;
198
- /**
199
- * @type {array}
200
- * @default null
201
- * @private
202
- */
203
- this._$heightTable = $getArray();
204
- /**
205
- * @type {array}
206
- * @private
207
- */
208
- this._$textFormatTable = $getArray();
209
- /**
210
- * @type {boolean}
211
- * @default false
212
- * @private
213
- */
214
- this._$textAreaActive = false;
215
- /**
216
- * @type {number}
217
- * @default 0
218
- * @private
219
- */
220
- this._$totalWidth = 0;
221
- /**
222
- * @type {array}
223
- * @private
224
- */
225
- this._$objectTable = $getArray();
226
- /**
227
- * @type {array}
228
- * @private
229
- */
230
- this._$imageData = $getArray();
231
- /**
232
- * @type {boolean}
233
- * @default true
234
- * @private
235
- */
236
- this._$scrollEnabled = true;
237
- /**
238
- * @type {Sprite}
239
- * @default null
240
- * @private
241
- */
242
- this._$scrollSprite = null;
243
- /**
244
- * @type {string}
245
- * @default null
246
- * @private
247
- */
248
- this._$type = "static";
249
- /**
250
- * @type {array}
251
- * @default null
252
- * @private
253
- */
254
- this._$textHeightTable = $getArray();
255
- /**
256
- * @type {boolean}
257
- * @default false
258
- * @private
259
- */
260
- this._$focus = false;
261
- /**
262
- * @type {boolean}
263
- * @default false
264
- * @private
265
- */
266
- this._$isComposing = false;
267
- /**
268
- * @type {number}
269
- * @default 0
270
- * @private
271
- */
272
- this._$thickness = 0;
273
- /**
274
- * @type {number}
275
- * @default 0
276
- * @private
277
- */
278
- this._$thicknessColor = 0;
279
- /**
280
- * @type {string}
281
- * @default TextFormatVerticalAlign.TOP
282
- * @private
283
- */
284
- this._$verticalAlign = "top";
285
- /**
286
- * @type {Map}
287
- * @private
288
- */
289
- this._$heightCache = $getMap();
290
- /**
291
- * @type {array}
292
- * @private
293
- */
294
- this._$cacheKeys = $getArray();
295
- /**
296
- * @type {array}
297
- * @private
298
- */
299
- this._$cacheParams = $getArray(0, 0, 0);
300
- }
301
- /**
302
- * @description 指定されたクラスのストリングを返します。
303
- * Returns the string representation of the specified class.
304
- *
305
- * @return {string}
306
- * @default [class TextField]
307
- * @method
308
- * @static
309
- */
310
- static toString() {
311
- return "[class TextField]";
312
- }
313
- /**
314
- * @description 指定されたクラスの空間名を返します。
315
- * Returns the space name of the specified class.
316
- *
317
- * @return {string}
318
- * @default next2d.text.TextField
319
- * @const
320
- * @static
321
- */
322
- static get namespace() {
323
- return "next2d.text.TextField";
324
- }
325
- /**
326
- * @description 指定されたオブジェクトのストリングを返します。
327
- * Returns the string representation of the specified object.
328
- *
329
- * @return {string}
330
- * @default [object TextField]
331
- * @method
332
- * @public
333
- */
334
- toString() {
335
- return "[object TextField]";
336
- }
337
- /**
338
- * @description 指定されたオブジェクトの空間名を返します。
339
- * Returns the space name of the specified object.
340
- *
341
- * @return {string}
342
- * @default next2d.text.TextField
343
- * @const
344
- * @public
345
- */
346
- get namespace() {
347
- return "next2d.text.TextField";
348
- }
349
- /**
350
- * @description テキストサイズの自動的な拡大 / 縮小および整列を制御します。
351
- * Controls automatic sizing and alignment of text size.
352
- *
353
- * @member {boolean}
354
- * @default false
355
- * @public
356
- */
357
- get autoFontSize() {
358
- return this._$autoFontSize;
359
- }
360
- set autoFontSize(auto_font_size) {
361
- if (auto_font_size !== this._$autoFontSize) {
362
- this._$autoFontSize = auto_font_size;
363
- this._$reload();
364
- }
365
- }
366
- /**
367
- * @description テキストフィールドの自動的な拡大 / 縮小および整列を制御します。
368
- * Controls automatic sizing and alignment of text fields.
369
- *
370
- * @member {string}
371
- * @default TextFieldAutoSize.NONE
372
- * @public
373
- */
374
- get autoSize() {
375
- return this._$autoSize;
376
- }
377
- set autoSize(auto_size) {
378
- if (auto_size !== this._$autoSize) {
379
- this._$autoSize = auto_size;
380
- this._$reload();
381
- }
382
- }
383
- /**
384
- * @description テキストフィールドに背景の塗りつぶしがあるかどうかを指定します。
385
- * Specifies whether the text field has a background fill.
386
- *
387
- * @member {boolean}
388
- * @default false
389
- * @public
390
- */
391
- get background() {
392
- return this._$background;
393
- }
394
- set background(background) {
395
- if (background !== this._$background) {
396
- this._$background = !!background;
397
- this._$reset();
398
- }
399
- }
400
- /**
401
- * @description テキストフィールドの背景の色です。
402
- * The color of the text field background.
403
- *
404
- * @member {number}
405
- * @default 0xffffff
406
- * @public
407
- */
408
- get backgroundColor() {
409
- return this._$backgroundColor;
410
- }
411
- set backgroundColor(background_color) {
412
- background_color = $clamp($toColorInt(background_color), 0, 0xffffff, 0xffffff);
413
- if (background_color !== this._$backgroundColor) {
414
- this._$backgroundColor = background_color;
415
- this._$reset();
416
- }
417
- }
418
- /**
419
- * @description テキストフィールドに境界線があるかどうかを指定します。
420
- * Specifies whether the text field has a border.
421
- *
422
- * @member {boolean}
423
- * @default false
424
- * @public
425
- */
426
- get border() {
427
- return this._$border;
428
- }
429
- set border(border) {
430
- if (border !== this._$border) {
431
- this._$border = !!border;
432
- this._$reset();
433
- }
434
- }
435
- /**
436
- * @description テキストフィールドの境界線の色です。
437
- * The color of the text field border.
438
- *
439
- * @member {number}
440
- * @default 0x000000
441
- * @public
442
- */
443
- get borderColor() {
444
- return this._$borderColor;
445
- }
446
- set borderColor(border_color) {
447
- border_color = $clamp($toColorInt(border_color), 0, 0xffffff, 0);
448
- if (border_color !== this._$borderColor) {
449
- this._$borderColor = border_color;
450
- this._$reset();
451
- }
452
- }
453
- /**
454
- * @description テキストに適用するフォーマットを指定します。
455
- * Specifies the formatting to be applied to the text.
456
- *
457
- * @member {TextFormat}
458
- * @public
459
- */
460
- get defaultTextFormat() {
461
- return this._$defaultTextFormat._$clone();
462
- }
463
- set defaultTextFormat(text_format) {
464
- text_format._$merge(this._$defaultTextFormat);
465
- this._$defaultTextFormat = text_format;
466
- this._$reset();
467
- }
468
- /**
469
- * @description このオブジェクトでマウスまたはその他のユーザー入力メッセージを
470
- *
471
- * @member {boolean}
472
- * @default false
473
- * @public
474
- */
475
- get focus() {
476
- return this._$focus;
477
- }
478
- set focus(focus) {
479
- if (this._$focus === focus) {
480
- return;
481
- }
482
- this._$focus = focus;
483
- if (this._$focus) {
484
- if (this._$type === "input") {
485
- const player = $currentPlayer();
486
- const div = $document
487
- .getElementById(player.contentElementId);
488
- if (!div) {
489
- return;
490
- }
491
- this._$createTextAreaElement(player._$scale);
492
- // setup
493
- const element = this._$textarea;
494
- if (!element) {
495
- return;
496
- }
497
- const matrix = this._$transform.concatenatedMatrix;
498
- const bounds = this._$getBounds(null);
499
- const color = $intToRGBA($toColorInt(this._$defaultTextFormat.color), 100);
500
- element.style.color = `rgb(${color.R},${color.G},${color.B})`;
501
- element.style.left = `${(matrix.tx + bounds.xMin + player.x / player._$scale / $devicePixelRatio) * player._$scale}px`;
502
- element.style.top = `${(matrix.ty + bounds.yMin + player.y / player._$scale / $devicePixelRatio) * player._$scale}px`;
503
- element.style.width = `${$Math.ceil((this.width - 1) * player._$scale)}px`;
504
- element.style.height = `${$Math.ceil((this.height - 1) * player._$scale)}px`;
505
- // set text
506
- element.value = this.text;
507
- div.appendChild(element);
508
- $requestAnimationFrame(() => {
509
- element.focus();
510
- });
511
- this._$doChanged();
512
- $doUpdated();
513
- this._$textAreaActive = true;
514
- // focus in event
515
- if (this.willTrigger(FocusEvent.FOCUS_IN)) {
516
- this.dispatchEvent(new FocusEvent(FocusEvent.FOCUS_IN));
517
- }
518
- }
519
- }
520
- else {
521
- // execute
522
- if (this._$textarea) {
523
- this._$textarea.dispatchEvent(new Event(`${$PREFIX}_blur`));
524
- if (this.willTrigger(FocusEvent.FOCUS_OUT)) {
525
- this.dispatchEvent(new FocusEvent(FocusEvent.FOCUS_OUT));
526
- }
527
- this._$textarea.remove();
528
- }
529
- }
530
- }
531
- /**
532
- * @description テキストフィールドの内容を HTML で表します。
533
- * Contains the HTML representation of the text field contents.
534
- *
535
- * @member {string}
536
- * @default ""
537
- * @public
538
- */
539
- get htmlText() {
540
- return this._$htmlText;
541
- }
542
- set htmlText(html_text) {
543
- if (this._$htmlText !== html_text) {
544
- this._$htmlText = `${html_text}`;
545
- this._$rawHtmlText = "";
546
- this._$text = "";
547
- this._$isHTML = true;
548
- this._$textFormatTable.length = 0;
549
- this._$reload();
550
- }
551
- }
552
- /**
553
- * @description テキストフィールド内の文字数です。
554
- * The int of characters in a text field.
555
- *
556
- * @member {number}
557
- * @readonly
558
- * @public
559
- */
560
- get length() {
561
- return this.text.length;
562
- }
563
- /**
564
- * @description ユーザーが入力するときに、テキストフィールドに入力できる最大の文字数です。
565
- * The maximum number of characters that the text field can contain,
566
- * as entered by a user.
567
- *
568
- * @member {number}
569
- * @default 0
570
- * @public
571
- */
572
- get maxChars() {
573
- return this._$maxChars;
574
- }
575
- set maxChars(max_chars) {
576
- this._$maxChars = max_chars | 0;
577
- }
578
- /**
579
- * TODO
580
- * @description scrollH の最大値です。
581
- * The maximum value of scrollH.
582
- *
583
- * @member {number}
584
- * @readonly
585
- * @public
586
- */
587
- get maxScrollH() {
588
- if (this._$maxScrollH === null) {
589
- this._$maxScrollH = 0;
590
- }
591
- return this._$maxScrollH;
592
- }
593
- /**
594
- * @description scrollV の最大値です。
595
- * The maximum value of scrollV.
596
- *
597
- * @member {number}
598
- * @readonly
599
- * @public
600
- */
601
- get maxScrollV() {
602
- if (this._$maxScrollV === null) {
603
- this._$maxScrollV = 1;
604
- this._$getTextData();
605
- if (!this._$textHeightTable.length) {
606
- return this._$maxScrollV;
607
- }
608
- const length = this._$textHeightTable.length;
609
- const maxHeight = this.height;
610
- if (maxHeight > this.textHeight) {
611
- return this._$maxScrollV;
612
- }
613
- let textHeight = 0;
614
- let idx = 0;
615
- while (length > idx) {
616
- textHeight += this._$textHeightTable[idx++];
617
- if (textHeight > maxHeight) {
618
- break;
619
- }
620
- this._$maxScrollV++;
621
- }
622
- }
623
- return this._$maxScrollV;
624
- }
625
- /**
626
- * @description フィールドが複数行テキストフィールドであるかどうかを示します。
627
- * Indicates whether field is a multiline text field.
628
- *
629
- * @member {boolean}
630
- * @default false
631
- * @public
632
- */
633
- get multiline() {
634
- return this._$multiline;
635
- }
636
- set multiline(multiline) {
637
- if (multiline !== this._$multiline) {
638
- this._$multiline = !!multiline;
639
- this._$reset();
640
- }
641
- }
642
- /**
643
- * @description フィールドが複数行テキストフィールドであるかどうかを示します。
644
- * Indicates whether field is a multiline text field.
645
- *
646
- * @member {number}
647
- * @readonly
648
- * @public
649
- */
650
- get numLines() {
651
- if (!this._$createdTextData) {
652
- this._$getTextData();
653
- }
654
- return this._$objectTable.length;
655
- }
656
- /**
657
- * @description ユーザーがテキストフィールドに入力できる文字のセットを指定します。
658
- * Indicates the set of characters that a user can enter into the text field.
659
- *
660
- * @member {string}
661
- * @default null
662
- * @public
663
- */
664
- get restrict() {
665
- return this._$restrict;
666
- }
667
- set restrict(restrict) {
668
- this._$restrict = `${restrict}`;
669
- }
670
- /**
671
- * @description スクロール機能のON/OFFの制御。
672
- * Control ON/OFF of the scroll function.
673
- *
674
- * @member {boolean}
675
- * @default true
676
- * @public
677
- */
678
- get scrollEnabled() {
679
- return this._$scrollEnabled;
680
- }
681
- set scrollEnabled(scroll_enabled) {
682
- this._$scrollEnabled = scroll_enabled;
683
- }
684
- /**
685
- * TODO
686
- * @description 現在の水平スクロール位置です。
687
- * The current horizontal scrolling position.
688
- *
689
- * @member {number}
690
- * @public
691
- */
692
- get scrollH() {
693
- return this._$scrollH;
694
- }
695
- set scrollH(scroll_h) {
696
- scroll_h = $clamp(scroll_h | 0, 0, this.maxScrollH);
697
- if (this._$scrollH !== scroll_h) {
698
- this._$scrollH = scroll_h;
699
- this._$reset();
700
- if (this.willTrigger(Next2DEvent.SCROLL)) {
701
- this.dispatchEvent(new Next2DEvent(Next2DEvent.SCROLL, true));
702
- }
703
- }
704
- }
705
- /**
706
- * @description テキストフィールドのテキストの垂直位置です。
707
- * The vertical position of text in a text field.
708
- *
709
- * @member {number}
710
- * @public
711
- */
712
- get scrollV() {
713
- return this._$scrollV;
714
- }
715
- set scrollV(scroll_v) {
716
- scroll_v = $clamp(scroll_v | 0, 1, this.maxScrollV);
717
- if (this._$scrollV !== scroll_v) {
718
- this._$scrollV = $Math.max(1, scroll_v);
719
- this._$reset();
720
- if (this._$scrollSprite && this.textHeight > this.height) {
721
- this._$scrollSprite.height = this.height * this.height / this.textHeight - 1;
722
- const parent = this._$parent;
723
- if (parent) {
724
- // view start
725
- this._$scrollSprite.alpha = 1;
726
- // set position
727
- this._$scrollSprite.x = this.x + this.width - this._$scrollSprite.width - 0.5;
728
- this._$scrollSprite.y = this.y + 0.5
729
- + (this.height - 1 - this._$scrollSprite.height)
730
- / (this.maxScrollV - 1)
731
- * (this._$scrollV - 1);
732
- // added sprite
733
- parent.addChildAt(this._$scrollSprite, parent.getChildIndex(this) + 1);
734
- // start animation
735
- if (this._$scrollSprite.hasLocalVariable("job")) {
736
- this._$scrollSprite.getLocalVariable("job").stop();
737
- }
738
- const job = Tween.add(this._$scrollSprite, { "alpha": 1 }, { "alpha": 0 }, 1);
739
- job.addEventListener(Next2DEvent.COMPLETE, (event) => {
740
- const sprite = event.target.target;
741
- sprite.deleteLocalVariable("job");
742
- if (sprite.parent) {
743
- sprite.parent.removeChild(sprite);
744
- }
745
- });
746
- job.start();
747
- this._$scrollSprite.setLocalVariable("job", job);
748
- }
749
- }
750
- if (this.willTrigger(Next2DEvent.SCROLL)) {
751
- this.dispatchEvent(new Next2DEvent(Next2DEvent.SCROLL, true));
752
- }
753
- }
754
- }
755
- /**
756
- * @description テキストフィールド内の現在のテキストであるストリングです。
757
- * A string that is the current text in the text field.
758
- *
759
- * @member {string}
760
- * @default ""
761
- * @public
762
- */
763
- get text() {
764
- if (!this._$isHTML) {
765
- return this._$text;
766
- }
767
- if (this._$rawHtmlText) {
768
- return this._$rawHtmlText;
769
- }
770
- let text = "";
771
- const textData = this._$getTextData();
772
- for (let idx = 1; idx < textData.length; ++idx) {
773
- const object = textData[idx];
774
- switch (object.mode) {
775
- case "text":
776
- text += object.text;
777
- break;
778
- case "break":
779
- text += "\r";
780
- break;
781
- }
782
- }
783
- this._$rawHtmlText = text;
784
- return text;
785
- }
786
- set text(text) {
787
- if (text === null) {
788
- text = "";
789
- }
790
- text = `${text}`;
791
- if (text !== this._$text) {
792
- this._$text = text;
793
- this._$htmlText = "";
794
- this._$isHTML = false;
795
- this._$textFormatTable.length = 0;
796
- this._$reload();
797
- }
798
- }
799
- /**
800
- * @description テキストフィールドのテキストの色です(16 進数形式)。
801
- * The color of the text in a text field, in hexadecimal format.
802
- *
803
- * @member {number}
804
- * @public
805
- */
806
- get textColor() {
807
- return this._$defaultTextFormat.color || 0;
808
- }
809
- set textColor(text_color) {
810
- this._$defaultTextFormat.color = text_color;
811
- this._$reload();
812
- }
813
- /**
814
- * @description テキストの高さです(ピクセル単位)。
815
- * The height of the text in pixels.
816
- *
817
- * @member {number}
818
- * @readonly
819
- * @public
820
- */
821
- get textHeight() {
822
- if (this.text === "") {
823
- return 0;
824
- }
825
- if (this._$textHeight === null) {
826
- // setup
827
- this._$textHeight = 2;
828
- this._$getTextData();
829
- const length = this._$textHeightTable.length;
830
- if (length === 1) {
831
- this._$textHeight += this._$defaultTextFormat.leading || 0;
832
- }
833
- for (let idx = 0; idx < length; ++idx) {
834
- this._$textHeight += this._$textHeightTable[idx];
835
- }
836
- }
837
- return this._$textHeight;
838
- }
839
- /**
840
- * @description テキストの幅です(ピクセル単位)。
841
- * The width of the text in pixels.
842
- *
843
- * @member {number}
844
- * @readonly
845
- * @public
846
- */
847
- get textWidth() {
848
- if (this._$textWidth === null) {
849
- // setup
850
- this._$textWidth = 0;
851
- this._$getTextData();
852
- for (let idx = 0; idx < this._$widthTable.length; ++idx) {
853
- this._$textWidth = $Math.max(this._$textWidth, this._$widthTable[idx]);
854
- }
855
- }
856
- return this._$textWidth;
857
- }
858
- /**
859
- * @description 輪郭のテキスト幅です。0(デフォルト値)で無効にできます。
860
- * The text width of the outline, which can be disabled with 0 (the default value).
861
- *
862
- * @member {number}
863
- * @default 0
864
- * @public
865
- */
866
- get thickness() {
867
- return this._$thickness;
868
- }
869
- set thickness(thickness) {
870
- thickness |= 0;
871
- if (thickness !== this._$thickness) {
872
- this._$thickness = thickness;
873
- this._$reset();
874
- }
875
- }
876
- /**
877
- * @description 輪郭のテキストの色です(16 進数形式)。
878
- * The color of the outline text. (Hexadecimal format)
879
- *
880
- * @member {number}
881
- * @default 0
882
- * @public
883
- */
884
- get thicknessColor() {
885
- return this._$thicknessColor;
886
- }
887
- set thicknessColor(thickness_color) {
888
- thickness_color = $clamp($toColorInt(thickness_color), 0, 0xffffff, 0);
889
- if (thickness_color !== this._$thicknessColor) {
890
- this._$thicknessColor = thickness_color;
891
- this._$reset();
892
- }
893
- }
894
- /**
895
- * @description テキストフィールドのタイプです。
896
- * The type of the text field.
897
- *
898
- * @member {string}
899
- * @default TextFieldType.STATIC
900
- * @public
901
- */
902
- get type() {
903
- return this._$type;
904
- }
905
- set type(type) {
906
- this._$type = type;
907
- if (type === "static") {
908
- this._$textarea = null;
909
- }
910
- }
911
- /**
912
- * @description 縦方向の揃え位置を指定するプロパティです。
913
- * This property specifies the vertical alignment position.
914
- *
915
- * @member {string}
916
- * @default TextFormatVerticalAlign.TOP
917
- * @public
918
- */
919
- get verticalAlign() {
920
- return this._$verticalAlign;
921
- }
922
- set verticalAlign(vertical_align) {
923
- if (vertical_align !== this._$verticalAlign) {
924
- this._$verticalAlign = vertical_align;
925
- this._$reset();
926
- }
927
- }
928
- /**
929
- * @description テキストフィールドのテキストを折り返すかどうかを示すブール値です。
930
- * A Boolean value that indicates whether the text field has word wrap.
931
- *
932
- * @member {boolean}
933
- * @default false
934
- * @public
935
- */
936
- get wordWrap() {
937
- return this._$wordWrap;
938
- }
939
- set wordWrap(word_wrap) {
940
- if (this._$wordWrap !== word_wrap) {
941
- this._$wordWrap = !!word_wrap;
942
- this._$reset();
943
- }
944
- }
945
- /**
946
- * @description 表示オブジェクトの幅を示します(ピクセル単位)。
947
- * Indicates the width of the display object, in pixels.
948
- *
949
- * @member {number}
950
- * @public
951
- */
952
- get width() {
953
- return super.width;
954
- }
955
- set width(width) {
956
- width = +width;
957
- if (!$isNaN(width) && width > -1) {
958
- const bounds = this._$getBounds(null);
959
- const xMin = $Math.abs(bounds.xMin);
960
- this._$originBounds.xMax = width + xMin;
961
- this._$originBounds.xMin = xMin;
962
- this._$bounds.xMax = this._$originBounds.xMax;
963
- this._$bounds.xMin = this._$originBounds.xMin;
964
- super.width = width;
965
- this._$reload();
966
- }
967
- }
968
- /**
969
- * @description 表示オブジェクトの高さを示します(ピクセル単位)。
970
- * Indicates the height of the display object, in pixels.
971
- *
972
- * @member {number}
973
- * @public
974
- */
975
- get height() {
976
- return super.height;
977
- }
978
- set height(height) {
979
- height = +height;
980
- if (!$isNaN(height) && height > -1) {
981
- const bounds = this._$getBounds(null);
982
- const yMin = $Math.abs(bounds.yMin);
983
- this._$originBounds.yMax = height + yMin;
984
- this._$bounds.yMax = this._$originBounds.yMax;
985
- this._$bounds.yMin = this._$originBounds.yMin;
986
- super.height = height;
987
- this._$reload();
988
- }
989
- }
990
- /**
991
- * @description 親 DisplayObjectContainer のローカル座標を基準にした
992
- * DisplayObject インスタンスの x 座標を示します。
993
- * Indicates the x coordinate
994
- * of the DisplayObject instance relative to the local coordinates
995
- * of the parent DisplayObjectContainer.
996
- *
997
- * @member {number}
998
- * @public
999
- */
1000
- get x() {
1001
- const matrix = this._$transform.matrix;
1002
- const bounds = this._$getBounds(null);
1003
- return matrix._$matrix[4] + bounds.xMin;
1004
- }
1005
- set x(x) {
1006
- const bounds = this._$getBounds(null);
1007
- super.x = x - bounds.xMin;
1008
- }
1009
- /**
1010
- * @description 親 DisplayObjectContainer のローカル座標を基準にした
1011
- * DisplayObject インスタンスの y 座標を示します。
1012
- * Indicates the y coordinate
1013
- * of the DisplayObject instance relative to the local coordinates
1014
- * of the parent DisplayObjectContainer.
1015
- *
1016
- * @member {number}
1017
- * @public
1018
- */
1019
- get y() {
1020
- const matrix = this._$transform.matrix;
1021
- const bounds = this._$getBounds(null);
1022
- return matrix._$matrix[5] + bounds.yMin;
1023
- }
1024
- set y(y) {
1025
- const bounds = this._$getBounds(null);
1026
- super.y = y - bounds.yMin;
1027
- }
1028
- /**
1029
- * @description newText パラメーターで指定されたストリングを、
1030
- * テキストフィールドのテキストの最後に付加します。
1031
- * Appends the string specified by the newText parameter
1032
- * to the end of the text of the text field.
1033
- *
1034
- * @param {string} new_text
1035
- * @return void
1036
- * @method
1037
- * @public
1038
- */
1039
- appendText(new_text) {
1040
- const currentText = this.text;
1041
- this.text = currentText + `${new_text}`;
1042
- }
1043
- /**
1044
- * @description beginIndex パラメーターと endIndex パラメーターで指定された範囲の
1045
- * テキストのフォーマット情報を含む TextFormat オブジェクトを返します。
1046
- * Returns a TextFormat object that contains formatting information
1047
- * for the range of text that the beginIndex and endIndex parameters specify.
1048
- *
1049
- * @param {int} [begin_index=-1]
1050
- * @param {int} [end_index=-1]
1051
- * @return {TextFormat}
1052
- * @method
1053
- * @public
1054
- */
1055
- getTextFormat(begin_index = -1, end_index = -1) {
1056
- begin_index |= 0;
1057
- end_index |= 0;
1058
- const data = this._$getTextData();
1059
- const length = end_index > -1 ? end_index : data.length;
1060
- let init = false;
1061
- let textFormat = new TextFormat();
1062
- let idx = begin_index > -1 ? begin_index : 0;
1063
- for (; idx < length; ++idx) {
1064
- if (data[idx].mode === "break") {
1065
- continue;
1066
- }
1067
- const tf = data[idx].textFormat;
1068
- if (!init) {
1069
- init = true;
1070
- textFormat = tf._$clone();
1071
- continue;
1072
- }
1073
- textFormat.align = textFormat.align !== tf.align ? null : tf.align;
1074
- textFormat.blockIndent = textFormat.blockIndent !== tf.blockIndent ? null : tf.blockIndent;
1075
- textFormat.bold = textFormat.bold !== tf.bold ? null : tf.bold;
1076
- textFormat.color = textFormat.color !== tf.color ? null : tf.color;
1077
- textFormat.font = textFormat.font !== tf.font ? null : tf.font;
1078
- textFormat.indent = textFormat.indent !== tf.indent ? null : tf.indent;
1079
- textFormat.italic = textFormat.italic !== tf.italic ? null : tf.italic;
1080
- textFormat.leading = textFormat.leading !== tf.leading ? null : tf.leading;
1081
- textFormat.leftMargin = textFormat.leftMargin !== tf.leftMargin ? null : tf.leftMargin;
1082
- textFormat.letterSpacing = textFormat.letterSpacing !== tf.letterSpacing ? null : tf.letterSpacing;
1083
- textFormat.rightMargin = textFormat.rightMargin !== tf.rightMargin ? null : tf.rightMargin;
1084
- textFormat.size = textFormat.size !== tf.size ? null : tf.size;
1085
- textFormat.underline = textFormat.underline !== tf.underline ? null : tf.underline;
1086
- }
1087
- return textFormat;
1088
- }
1089
- /**
1090
- * @description lineIndex パラメーターで指定された行のテキストを返します。
1091
- * Returns the text of the line specified by the lineIndex parameter.
1092
- *
1093
- * @param {number} line_index
1094
- * @return {string}
1095
- * @public
1096
- */
1097
- getLineText(line_index) {
1098
- if (!this._$text && !this._$htmlText) {
1099
- return "";
1100
- }
1101
- line_index |= 0;
1102
- let lineText = "";
1103
- const textData = this._$getTextData();
1104
- for (let idx = 0; idx < textData.length; idx++) {
1105
- const obj = textData[idx];
1106
- if (obj.yIndex > line_index) {
1107
- break;
1108
- }
1109
- if (obj.yIndex !== line_index) {
1110
- continue;
1111
- }
1112
- if (obj.mode !== "text") {
1113
- continue;
1114
- }
1115
- lineText += obj.text;
1116
- }
1117
- return lineText;
1118
- }
1119
- /**
1120
- * @description beginIndex パラメーターと endIndex パラメーターで指定された文字範囲を、
1121
- * newText パラメーターの内容に置き換えます。
1122
- * Replaces the range of characters that the beginIndex
1123
- * and endIndex parameters specify with the contents of the newText parameter.
1124
- *
1125
- * @param {number} begin_index
1126
- * @param {number} end_index
1127
- * @param {string} new_text
1128
- * @return {void}
1129
- * @method
1130
- * @public
1131
- */
1132
- replaceText(begin_index, end_index, new_text) {
1133
- begin_index |= 0;
1134
- end_index |= 0;
1135
- if (begin_index > -1 && end_index > -1 && end_index >= begin_index) {
1136
- const text = this.text;
1137
- if (begin_index >= text.length) {
1138
- if (end_index >= text.length && end_index >= begin_index) {
1139
- this.text = text + `${new_text}`;
1140
- }
1141
- }
1142
- else {
1143
- this.text = text.slice(0, begin_index)
1144
- + `${new_text}`
1145
- + text.slice(end_index, text.length);
1146
- }
1147
- }
1148
- }
1149
- /**
1150
- * @description format パラメーターで指定したテキストフォーマットを、
1151
- * テキストフィールド内の指定されたテキストに適用します。
1152
- * Applies the text formatting that the format parameter specifies
1153
- * to the specified text in a text field.
1154
- *
1155
- * @param {TextFormat} text_format
1156
- * @param {number} [begin_index=-1]
1157
- * @param {number} [end_index=-1]
1158
- * @return {void}
1159
- * @method
1160
- * @public
1161
- */
1162
- setTextFormat(text_format, begin_index = -1, end_index = -1) {
1163
- // setup
1164
- begin_index |= 0;
1165
- end_index |= 0;
1166
- const textData = this._$getTextData();
1167
- this._$reset();
1168
- switch (true) {
1169
- case begin_index === -1 && end_index === -1:
1170
- for (let idx = 0; idx < textData.length; ++idx) {
1171
- this._$textFormatTable[idx] = text_format._$clone();
1172
- }
1173
- break;
1174
- case begin_index > -1 && end_index === -1:
1175
- {
1176
- let idx = begin_index + 1;
1177
- let obj = textData[idx];
1178
- if (obj.mode === "wrap") {
1179
- obj = textData[++idx];
1180
- }
1181
- this._$textFormatTable[idx] = text_format._$clone();
1182
- }
1183
- break;
1184
- case begin_index > -1 && end_index > -1 && end_index > begin_index:
1185
- {
1186
- let offset = 0;
1187
- for (let idx = begin_index; idx < end_index; ++idx) {
1188
- const obj = textData[idx];
1189
- if (!obj) {
1190
- continue;
1191
- }
1192
- if (obj.mode === "wrap" || obj.mode === "break") {
1193
- ++end_index;
1194
- --offset;
1195
- continue;
1196
- }
1197
- this._$textFormatTable[idx + offset] = text_format._$clone();
1198
- }
1199
- }
1200
- break;
1201
- }
1202
- this._$getTextData();
1203
- this._$resize();
1204
- }
1205
- /**
1206
- * @return {array}
1207
- * @method
1208
- * @private
1209
- */
1210
- _$getTextData() {
1211
- if (!this._$createdTextData) {
1212
- this._$createdTextData = true;
1213
- // reset
1214
- this._$textData.length = 0;
1215
- this._$imageData.length = 0;
1216
- this._$heightTable.length = 0;
1217
- this._$textHeightTable.length = 0;
1218
- this._$objectTable.length = 0;
1219
- this._$widthTable.length = 0;
1220
- this._$heightCache.clear();
1221
- let tfCopyOffset = -1;
1222
- if (this._$isHTML) {
1223
- // html text
1224
- let htmlText = this._$htmlText;
1225
- const index = htmlText.search(/(< .*>|<>)/g);
1226
- if (index > -1) {
1227
- htmlText = htmlText.slice(0, index);
1228
- }
1229
- htmlText = htmlText.replace(/\r\n/g, "\r\r");
1230
- if ($P_TAG.innerHTML !== htmlText) {
1231
- $P_TAG.textContent = "";
1232
- $P_TAG.insertAdjacentHTML("afterbegin", htmlText);
1233
- }
1234
- // setup
1235
- let tf = this._$defaultTextFormat;
1236
- if (this._$textData.length in this._$textFormatTable) {
1237
- const tft = this._$textFormatTable[this._$textData.length]._$clone();
1238
- tft._$merge(tf);
1239
- tf = tft;
1240
- }
1241
- // init
1242
- this._$totalWidth = 0;
1243
- this._$heightTable[0] = 0;
1244
- this._$textHeightTable[0] = this._$getTextHeight(tf);
1245
- this._$widthTable[0] = 0;
1246
- const obj = {
1247
- "mode": "break",
1248
- "x": 0,
1249
- "yIndex": 0,
1250
- "textFormat": tf._$clone()
1251
- };
1252
- this._$objectTable[0] = obj;
1253
- this._$textData[0] = obj;
1254
- this._$parseTag($P_TAG, tf._$clone(), tfCopyOffset);
1255
- }
1256
- else {
1257
- // plain text
1258
- const texts = this._$multiline
1259
- ? this._$text.split("\n")
1260
- : [this._$text.replace("\n", "")];
1261
- for (let idx = 0; idx < texts.length; ++idx) {
1262
- // reset
1263
- this._$totalWidth = 0;
1264
- let tf = this.defaultTextFormat;
1265
- const yIndex = this._$wordWrap || this._$multiline
1266
- ? this._$heightTable.length
1267
- : 0;
1268
- this._$heightTable[yIndex] = 0;
1269
- this._$textHeightTable[yIndex] = this._$getTextHeight(tf);
1270
- this._$widthTable[yIndex] = 0;
1271
- if (yIndex) {
1272
- this._$heightTable[yIndex] = this._$heightTable[yIndex - 1];
1273
- this._$textHeightTable[yIndex] = this._$textHeightTable[yIndex - 1];
1274
- }
1275
- if (this._$textData.length in this._$textFormatTable) {
1276
- const tft = this._$textFormatTable[this._$textData.length]._$clone();
1277
- tft._$merge(tf);
1278
- tf = tft;
1279
- }
1280
- const obj = {
1281
- "mode": "break",
1282
- "x": 0,
1283
- "yIndex": yIndex,
1284
- "textFormat": tf._$clone()
1285
- };
1286
- tf = this.defaultTextFormat;
1287
- this._$objectTable[yIndex] = obj;
1288
- this._$textData[this._$textData.length] = obj;
1289
- // parse text data
1290
- const text = texts[idx];
1291
- if (text) {
1292
- tfCopyOffset = this._$parseText(text, tf, tfCopyOffset);
1293
- }
1294
- }
1295
- }
1296
- // clear
1297
- this._$heightCache.clear();
1298
- }
1299
- return this._$textData;
1300
- }
1301
- /**
1302
- * @param {Element} tag
1303
- * @param {TextFormat} text_format
1304
- * @param {number} tf_copy_offset
1305
- * @return {void}
1306
- * @private
1307
- */
1308
- _$parseTag(tag, text_format, tf_copy_offset) {
1309
- const childNodes = tag.childNodes;
1310
- const length = childNodes.length;
1311
- for (let idx = 0; idx < length; ++idx) {
1312
- let tf = text_format._$clone();
1313
- const node = childNodes[idx];
1314
- if (node.nodeType === 3) {
1315
- tf_copy_offset = this._$parseText(node.nodeValue || "", tf, tf_copy_offset);
1316
- continue;
1317
- }
1318
- switch (node.nodeName) {
1319
- case "P":
1320
- {
1321
- if (node.hasAttribute("align")) {
1322
- const align = node.getAttribute("align");
1323
- if (align === "center" || align === "left" || align === "right") {
1324
- tf.align = align;
1325
- if (this._$textData.length === 1) {
1326
- this._$textData[0].textFormat.align = tf.align;
1327
- }
1328
- }
1329
- }
1330
- this._$parseTag(node, tf, tf_copy_offset);
1331
- if (!this._$multiline) {
1332
- break;
1333
- }
1334
- // reset
1335
- this._$totalWidth = this._$getImageOffsetX();
1336
- const yIndex = this._$heightTable.length;
1337
- this._$heightTable[yIndex] = 0;
1338
- this._$textHeightTable[yIndex] = 0;
1339
- this._$widthTable[yIndex] = 0;
1340
- if (yIndex) {
1341
- this._$heightTable[yIndex] = this._$heightTable[yIndex - 1];
1342
- this._$textHeightTable[yIndex] = this._$textHeightTable[yIndex - 1];
1343
- }
1344
- if (this._$textData.length in this._$textFormatTable) {
1345
- const tft = this._$textFormatTable[this._$textData.length]._$clone();
1346
- tft._$merge(tf);
1347
- tf = tft;
1348
- }
1349
- const obj = {
1350
- "mode": "break",
1351
- "x": 0,
1352
- "yIndex": yIndex,
1353
- "textFormat": tf
1354
- };
1355
- this._$objectTable[yIndex] = obj;
1356
- this._$textData.push(obj);
1357
- }
1358
- break;
1359
- case "B": // bold
1360
- tf.bold = true;
1361
- this._$parseTag(node, tf, tf_copy_offset);
1362
- break;
1363
- case "I": // italic
1364
- tf.italic = true;
1365
- this._$parseTag(node, tf, tf_copy_offset);
1366
- break;
1367
- case "U": // underline
1368
- tf.underline = true;
1369
- this._$parseTag(node, tf, tf_copy_offset);
1370
- break;
1371
- case "FONT": // FONT
1372
- if (node.hasAttribute("face")) {
1373
- tf.font = node.getAttribute("face");
1374
- }
1375
- if (node.hasAttribute("size")) {
1376
- const size = node.getAttribute("size");
1377
- if (size) {
1378
- tf.size = +size;
1379
- }
1380
- }
1381
- if (node.hasAttribute("color")) {
1382
- tf.color = $toColorInt(node.getAttribute("color"));
1383
- }
1384
- if (node.hasAttribute("letterSpacing")) {
1385
- const letterSpacing = node.getAttribute("size");
1386
- if (letterSpacing) {
1387
- tf.letterSpacing = +letterSpacing;
1388
- }
1389
- }
1390
- this._$parseTag(node, tf, tf_copy_offset);
1391
- break;
1392
- case "BR": // br
1393
- {
1394
- if (!this._$multiline) {
1395
- break;
1396
- }
1397
- // add y index
1398
- const yIndex = this._$heightTable.length;
1399
- this._$heightTable[yIndex] = this._$heightTable[yIndex - 1];
1400
- this._$textHeightTable[yIndex] = this._$textHeightTable[yIndex - 1];
1401
- this._$widthTable[yIndex] = 0;
1402
- // reset
1403
- this._$totalWidth = this._$getImageOffsetX();
1404
- // new clone
1405
- tf.indent = 0;
1406
- // set x offset
1407
- const obj = {
1408
- "mode": "break",
1409
- "x": 0,
1410
- "yIndex": yIndex,
1411
- "textFormat": tf
1412
- };
1413
- this._$objectTable[yIndex] = obj;
1414
- this._$textData[this._$textData.length] = obj;
1415
- }
1416
- break;
1417
- case "IMG":
1418
- {
1419
- if (!node.hasAttribute("src")) {
1420
- break;
1421
- }
1422
- const src = node.getAttribute("src");
1423
- if (!src) {
1424
- break;
1425
- }
1426
- let width = 0;
1427
- if (node.hasAttribute("width")) {
1428
- const attribute = node.getAttribute("width");
1429
- if (attribute) {
1430
- width = +attribute;
1431
- }
1432
- }
1433
- let height = 0;
1434
- if (node.hasAttribute("height")) {
1435
- const attribute = node.getAttribute("height");
1436
- if (attribute) {
1437
- height = +attribute;
1438
- }
1439
- }
1440
- let vspace = 8;
1441
- if (node.hasAttribute("vspace")) {
1442
- const attribute = node.getAttribute("vspace");
1443
- if (attribute) {
1444
- vspace = +attribute;
1445
- }
1446
- }
1447
- let hspace = 8;
1448
- if (node.hasAttribute("hspace")) {
1449
- const attribute = node.getAttribute("hspace");
1450
- if (attribute) {
1451
- hspace = +attribute;
1452
- }
1453
- }
1454
- let totalTextHeight = 0;
1455
- for (let idx = 0; idx < this._$textHeightTable.length; idx++) {
1456
- totalTextHeight += this._$textHeightTable[idx];
1457
- }
1458
- const image = new Image();
1459
- const obj = {
1460
- "mode": "image",
1461
- "image": image,
1462
- "src": src,
1463
- "loaded": false,
1464
- "x": 0,
1465
- "y": totalTextHeight,
1466
- "width": width,
1467
- "height": height,
1468
- "hspace": hspace,
1469
- "vspace": vspace,
1470
- "textFormat": tf._$clone()
1471
- };
1472
- image.crossOrigin = "anonymous";
1473
- image.addEventListener("load", () => {
1474
- if (!obj.width) {
1475
- obj.width = image.width;
1476
- }
1477
- if (!obj.height) {
1478
- obj.height = image.height;
1479
- }
1480
- obj.loaded = true;
1481
- this._$reload();
1482
- });
1483
- image.src = src;
1484
- if (this._$imageData.length > 0) {
1485
- const prevImage = this._$imageData[this._$imageData.length - 1];
1486
- const imageBottom = prevImage.y + prevImage.height + prevImage.vspace * 2;
1487
- obj.y = $Math.max(totalTextHeight, imageBottom);
1488
- }
1489
- this._$textData[this._$textData.length] = obj;
1490
- this._$imageData[this._$imageData.length] = obj;
1491
- }
1492
- break;
1493
- default:
1494
- this._$parseTag(node, tf, tf_copy_offset);
1495
- break;
1496
- }
1497
- }
1498
- }
1499
- /**
1500
- * @param {string} text
1501
- * @param {TextFormat} text_format
1502
- * @param {number} tf_copy_offset
1503
- * @returns {number}
1504
- * @method
1505
- * @private
1506
- */
1507
- _$parseText(text, text_format, tf_copy_offset) {
1508
- let yIndex = this._$heightTable.length - 1;
1509
- // new format
1510
- let tf = text_format._$clone();
1511
- const matrix = this._$transform.concatenatedMatrix._$matrix;
1512
- const boundsWidth = (this._$originBounds.xMax - this._$originBounds.xMin)
1513
- * (matrix[0] / matrix[3]);
1514
- $poolFloat32Array6(matrix);
1515
- const maxWidth = boundsWidth - tf._$widthMargin() - 4;
1516
- for (let idx = 0; idx < text.length; ++idx) {
1517
- tf = text_format._$clone();
1518
- if (this._$textData.length + tf_copy_offset in this._$textFormatTable) {
1519
- const tft = this._$textFormatTable[this._$textData.length + tf_copy_offset]._$clone();
1520
- tft._$merge(tf);
1521
- tf = tft;
1522
- }
1523
- // reset object
1524
- const obj = {
1525
- "mode": "text",
1526
- "text": text[idx],
1527
- "x": 0,
1528
- "width": 0,
1529
- "height": 0,
1530
- "yIndex": yIndex,
1531
- "textFormat": tf
1532
- };
1533
- let breakCode = false;
1534
- if (this._$multiline) {
1535
- breakCode = obj.text === "\n" || obj.text === "\r" || obj.text === "\n\r";
1536
- }
1537
- const leading = yIndex ? tf.leading || 0 : 0;
1538
- let width = 0;
1539
- let height = 0;
1540
- let textHeight = 0;
1541
- let wrapObj;
1542
- if (!$textContext) {
1543
- continue;
1544
- }
1545
- $textContext.font = tf._$generateFontStyle();
1546
- width = $textContext.measureText(obj.text || "").width;
1547
- width += tf.letterSpacing || 0;
1548
- height = this._$getTextHeight(tf);
1549
- textHeight = height + leading;
1550
- obj.height = height;
1551
- if (breakCode ||
1552
- this._$wordWrap && this._$totalWidth + width > maxWidth) {
1553
- // add y index
1554
- this._$widthTable[++yIndex] = 0;
1555
- obj.yIndex = yIndex;
1556
- this._$heightTable[yIndex] = this._$heightTable[yIndex - 1];
1557
- this._$textHeightTable[yIndex] = this._$textHeightTable[yIndex - 1];
1558
- // reset
1559
- this._$totalWidth = this._$getImageOffsetX();
1560
- // new clone
1561
- tf = tf._$clone();
1562
- tf.indent = 0;
1563
- // set x offset
1564
- const mode = breakCode ? "break" : "wrap";
1565
- wrapObj = {
1566
- "mode": mode,
1567
- "x": 0,
1568
- "yIndex": yIndex,
1569
- "textFormat": tf
1570
- };
1571
- this._$objectTable[yIndex] = wrapObj;
1572
- if (!breakCode) {
1573
- --tf_copy_offset;
1574
- }
1575
- let text = obj.text || "";
1576
- let chunkLength = 0;
1577
- let isSeparated = true;
1578
- const pattern = /[0-9a-zA-Z?!;:.,?!。、;:〜]/g;
1579
- while (text.match(pattern)) {
1580
- ++chunkLength;
1581
- const prevObj = this._$textData[this._$textData.length - chunkLength];
1582
- if (prevObj.mode !== "text") {
1583
- isSeparated = false;
1584
- break;
1585
- }
1586
- text = prevObj.text || "";
1587
- }
1588
- if (chunkLength > 1 && this._$textData) {
1589
- const text = this._$textData[this._$textData.length - chunkLength + 1].text || "";
1590
- if (text.match(/[0-9a-zA-Z]/g)) {
1591
- --chunkLength;
1592
- }
1593
- }
1594
- if (chunkLength > 0 && isSeparated) {
1595
- const insertIdx = this._$textData.length - chunkLength;
1596
- this._$textData.splice(insertIdx, 0, wrapObj);
1597
- // prev line
1598
- let offset = 1;
1599
- let targetObj = this._$textData[insertIdx - offset];
1600
- this._$widthTable[yIndex - 1] = 0;
1601
- this._$heightTable[yIndex - 1] = 0;
1602
- this._$textHeightTable[yIndex - 1] = 0;
1603
- while (targetObj.mode === "text") {
1604
- height = this._$getTextHeight(targetObj.textFormat);
1605
- textHeight = height + leading;
1606
- this._$widthTable[yIndex - 1] += targetObj.width || 0;
1607
- this._$heightTable[yIndex - 1] = $Math.max(this._$heightTable[yIndex - 1], height);
1608
- this._$textHeightTable[yIndex - 1] = $Math.max(this._$textHeightTable[yIndex - 1], textHeight);
1609
- ++offset;
1610
- targetObj = this._$textData[insertIdx - offset];
1611
- }
1612
- // new line
1613
- offset = 1;
1614
- while (this._$textData.length > insertIdx + offset) {
1615
- targetObj = this._$textData[insertIdx + offset];
1616
- ++offset;
1617
- height = this._$getTextHeight(targetObj.textFormat);
1618
- textHeight = height + leading;
1619
- this._$heightTable[yIndex] = $Math.max(this._$heightTable[yIndex], height);
1620
- this._$textHeightTable[yIndex] = $Math.max(this._$textHeightTable[yIndex], textHeight);
1621
- targetObj.x = this._$totalWidth;
1622
- targetObj.yIndex = yIndex;
1623
- this._$totalWidth += targetObj.width || 0;
1624
- }
1625
- }
1626
- else {
1627
- this._$textData[this._$textData.length] = wrapObj;
1628
- }
1629
- }
1630
- if (!breakCode) {
1631
- // width data
1632
- obj.width = width;
1633
- obj.x = this._$totalWidth;
1634
- this._$totalWidth += width;
1635
- if (this._$widthTable) {
1636
- this._$widthTable[yIndex] = $Math.max(this._$widthTable[yIndex], this._$totalWidth);
1637
- }
1638
- // height data
1639
- this._$heightTable[yIndex] = $Math.max(this._$heightTable[yIndex], height);
1640
- this._$textHeightTable[yIndex] = $Math.max(this._$textHeightTable[yIndex], textHeight);
1641
- this._$textData[this._$textData.length] = obj;
1642
- }
1643
- }
1644
- return tf_copy_offset;
1645
- }
1646
- /**
1647
- * @param {TextFormat} text_format
1648
- * @return {number}
1649
- * @private
1650
- */
1651
- _$getTextHeight(text_format) {
1652
- const size = text_format.size || 0;
1653
- const font = text_format.font || "";
1654
- const weight = text_format.bold ? "bold" : "normal";
1655
- // use cache
1656
- const key = `${size}_${font}_${weight}`;
1657
- if (this._$heightCache.has(key)) {
1658
- return this._$heightCache.get(key) || 0;
1659
- }
1660
- // update dom data
1661
- const style = $DIV.style;
1662
- const fontSize = `${size}px`;
1663
- if (style.fontSize !== fontSize) {
1664
- style.fontSize = fontSize;
1665
- }
1666
- if (style.fontFamily !== font) {
1667
- style.fontFamily = font;
1668
- }
1669
- if (style.fontWeight !== weight) {
1670
- style.fontWeight = weight;
1671
- }
1672
- const height = 10 > size
1673
- ? $DIV.clientHeight * size * 0.1
1674
- : $DIV.clientHeight;
1675
- // cache
1676
- this._$heightCache.set(key, height);
1677
- return height;
1678
- }
1679
- /**
1680
- * @return {number}
1681
- * @private
1682
- */
1683
- _$getImageOffsetX() {
1684
- if (!this._$imageData.length) {
1685
- return 0;
1686
- }
1687
- let totalTextHeight = 0;
1688
- for (let idx = 0; idx < this._$textHeightTable.length; ++idx) {
1689
- totalTextHeight += this._$textHeightTable[idx];
1690
- }
1691
- if (this._$imageData) {
1692
- for (let idx = 0; idx < this._$imageData.length; ++idx) {
1693
- const image = this._$imageData[idx];
1694
- const imageHeight = image.height + image.vspace * 2;
1695
- if (image.y <= totalTextHeight
1696
- && totalTextHeight < image.y + imageHeight) {
1697
- return image.width + image.hspace * 2;
1698
- }
1699
- }
1700
- }
1701
- return 0;
1702
- }
1703
- /**
1704
- * @return {void}
1705
- * @method
1706
- * @private
1707
- */
1708
- _$reset() {
1709
- this._$createdTextData = false;
1710
- this._$textData.length = 0;
1711
- this._$imageData.length = 0;
1712
- this._$heightTable.length = 0;
1713
- this._$textHeightTable.length = 0;
1714
- this._$widthTable.length = 0;
1715
- this._$objectTable.length = 0;
1716
- this._$textHeight = null;
1717
- this._$textWidth = null;
1718
- this._$totalWidth = 0;
1719
- this._$maxScrollH = null;
1720
- this._$maxScrollV = null;
1721
- this._$doChanged();
1722
- $doUpdated();
1723
- // cache clear
1724
- $cacheStore.removeCache(this._$instanceId);
1725
- }
1726
- /**
1727
- * @return {void}
1728
- * @method
1729
- * @private
1730
- */
1731
- _$reload() {
1732
- this._$reset();
1733
- this._$getTextData();
1734
- if (this._$autoSize === "none" && this._$autoFontSize) {
1735
- let fontSize = this._$defaultTextFormat.size || 0;
1736
- const cacheSize = fontSize;
1737
- if (this.width && this.textWidth
1738
- && this.textWidth > this.width) {
1739
- while (this.textWidth > this.width) {
1740
- this._$defaultTextFormat.size = fontSize--;
1741
- if (1 > fontSize) {
1742
- this._$defaultTextFormat.size = 1;
1743
- break;
1744
- }
1745
- this._$reset();
1746
- this._$getTextData();
1747
- }
1748
- }
1749
- if (this.height && this.textHeight
1750
- && this.textHeight > this.height) {
1751
- while (this.textHeight > this.height) {
1752
- this._$defaultTextFormat.size = fontSize--;
1753
- if (1 > fontSize) {
1754
- this._$defaultTextFormat.size = 1;
1755
- break;
1756
- }
1757
- this._$reset();
1758
- this._$getTextData();
1759
- }
1760
- }
1761
- // restore
1762
- this._$defaultTextFormat.size = cacheSize;
1763
- }
1764
- this._$resize();
1765
- }
1766
- /**
1767
- * @return {void}
1768
- * @method
1769
- * @private
1770
- */
1771
- _$resize() {
1772
- // update bounds
1773
- if (this._$autoSize !== "none") {
1774
- const tf = this._$defaultTextFormat;
1775
- const width = this.textWidth + 4 + tf._$widthMargin();
1776
- if (this._$wordWrap) {
1777
- this._$bounds.xMax = this._$originBounds.xMax;
1778
- this._$bounds.xMin = this._$originBounds.xMin;
1779
- }
1780
- else {
1781
- switch (this._$autoSize) {
1782
- case "left":
1783
- this._$bounds.xMax = width + this._$bounds.xMin;
1784
- break;
1785
- case "center":
1786
- this._$bounds.xMax = width + this._$bounds.xMin;
1787
- break;
1788
- case "right":
1789
- this._$bounds.xMax = this._$originBounds.xMax
1790
- - (this._$originBounds.xMax - this._$originBounds.xMin
1791
- - (width - this._$originBounds.xMin));
1792
- break;
1793
- default:
1794
- break;
1795
- }
1796
- }
1797
- // set height
1798
- this._$bounds.yMax = this.textHeight
1799
- + 4 + this._$originBounds.yMin;
1800
- }
1801
- else {
1802
- if (this._$scrollEnabled && !this._$scrollSprite) {
1803
- this._$scrollSprite = new Sprite();
1804
- this._$scrollSprite
1805
- .graphics
1806
- .beginFill("#000", 0.3)
1807
- .drawRoundRect(0, 0, 3, 3, 3);
1808
- this._$scrollSprite.scale9Grid = new Rectangle(1.5, 1.5, 0.1, 0.1);
1809
- }
1810
- }
1811
- }
1812
- /**
1813
- * @param {object} obj
1814
- * @param {number} width
1815
- * @return {number}
1816
- * @private
1817
- */
1818
- _$getAlignOffset(obj, width) {
1819
- // default
1820
- const totalWidth = this._$widthTable[obj.yIndex];
1821
- const textFormat = obj.textFormat;
1822
- let indent = 0;
1823
- indent += textFormat.blockIndent || 0;
1824
- indent += textFormat.leftMargin || 0;
1825
- const rightMargin = textFormat.rightMargin || 0;
1826
- switch (true) {
1827
- // wordWrap case
1828
- case !this._$wordWrap && totalWidth > width:
1829
- return $Math.max(0, indent);
1830
- case textFormat.align === "center": // format CENTER
1831
- case this._$autoSize === "center": // autoSize CENTER
1832
- return $Math.max(0, width / 2 - indent - rightMargin - totalWidth / 2);
1833
- case textFormat.align === "right": // format RIGHT
1834
- case this._$autoSize === "right": // autoSize RIGHT
1835
- return $Math.max(0, width - indent - totalWidth - rightMargin - 2);
1836
- // autoSize LEFT
1837
- // format LEFT
1838
- default:
1839
- return $Math.max(0, indent + 2);
1840
- }
1841
- }
1842
- /**
1843
- * @param {Float32Array} [matrix=null]
1844
- * @returns {object}
1845
- * @method
1846
- * @private
1847
- */
1848
- _$getBounds(matrix = null) {
1849
- if (matrix) {
1850
- let multiMatrix = matrix;
1851
- const rawMatrix = this._$transform._$rawMatrix();
1852
- if (rawMatrix[0] !== 1 || rawMatrix[1] !== 0
1853
- || rawMatrix[2] !== 0 || rawMatrix[3] !== 1
1854
- || rawMatrix[4] !== 0 || rawMatrix[5] !== 0) {
1855
- multiMatrix = $multiplicationMatrix(matrix, rawMatrix);
1856
- }
1857
- return $boundsMatrix(this._$bounds, multiMatrix);
1858
- }
1859
- return $getBoundsObject(this._$bounds.xMin, this._$bounds.xMax, this._$bounds.yMin, this._$bounds.yMax);
1860
- }
1861
- /**
1862
- * @param {object} character
1863
- * @return {void}
1864
- * @method
1865
- * @private
1866
- */
1867
- _$buildCharacter(character) {
1868
- const textFormat = this._$defaultTextFormat;
1869
- textFormat.font = character.font;
1870
- textFormat.size = character.size | 0;
1871
- textFormat.align = character.align;
1872
- textFormat.color = character.color | 0;
1873
- textFormat.leading = character.leading;
1874
- textFormat.letterSpacing = character.letterSpacing;
1875
- textFormat.leftMargin = character.leftMargin;
1876
- textFormat.rightMargin = character.rightMargin;
1877
- switch (character.fontType) {
1878
- case 1:
1879
- textFormat.bold = true;
1880
- break;
1881
- case 2:
1882
- textFormat.italic = true;
1883
- break;
1884
- case 3:
1885
- textFormat.bold = true;
1886
- textFormat.italic = true;
1887
- break;
1888
- }
1889
- // setup
1890
- this._$type = character.inputType;
1891
- this._$multiline = !!character.multiline;
1892
- this._$wordWrap = !!character.wordWrap;
1893
- this._$border = !!character.border;
1894
- this._$scrollEnabled = !!character.scroll;
1895
- this._$thickness = character.thickness | 0;
1896
- this._$thicknessColor = character.thicknessColor | 0;
1897
- // bounds
1898
- this._$bounds.xMin = character.originBounds.xMin;
1899
- this._$bounds.xMax = character.originBounds.xMax;
1900
- this._$bounds.yMin = character.originBounds.yMin;
1901
- this._$bounds.yMax = character.originBounds.yMax;
1902
- this._$originBounds.xMin = character.originBounds.xMin;
1903
- this._$originBounds.xMax = character.originBounds.xMax;
1904
- this._$originBounds.yMin = character.originBounds.yMin;
1905
- this._$originBounds.yMax = character.originBounds.yMax;
1906
- switch (character.autoSize) {
1907
- case 1:
1908
- this.autoSize = character.align;
1909
- break;
1910
- case 2:
1911
- this.autoFontSize = true;
1912
- break;
1913
- }
1914
- this.text = character.text;
1915
- if ($rendererWorker && this._$stage) {
1916
- this._$createWorkerInstance();
1917
- }
1918
- }
1919
- /**
1920
- * @param {object} character
1921
- * @return {void}
1922
- * @method
1923
- * @private
1924
- */
1925
- _$sync(character) {
1926
- this._$buildCharacter(character);
1927
- }
1928
- /**
1929
- * @param {object} tag
1930
- * @param {DisplayObjectContainer} parent
1931
- * @return {object}
1932
- * @method
1933
- * @private
1934
- */
1935
- _$build(tag, parent) {
1936
- const character = this
1937
- ._$baseBuild(tag, parent);
1938
- this._$buildCharacter(character);
1939
- return character;
1940
- }
1941
- /**
1942
- * @param {CanvasToWebGLContext} context
1943
- * @param {Float32Array} matrix
1944
- * @returns {void}
1945
- * @method
1946
- * @private
1947
- */
1948
- _$clip(context, matrix) {
1949
- // size
1950
- const bounds = this._$getBounds();
1951
- const xMax = bounds.xMax;
1952
- const xMin = bounds.xMin;
1953
- const yMax = bounds.yMax;
1954
- const yMin = bounds.yMin;
1955
- $poolBoundsObject(bounds);
1956
- const width = $Math.ceil($Math.abs(xMax - xMin));
1957
- const height = $Math.ceil($Math.abs(yMax - yMin));
1958
- if (!width || !height) {
1959
- return;
1960
- }
1961
- let multiMatrix = matrix;
1962
- const rawMatrix = this._$transform._$rawMatrix();
1963
- if (rawMatrix[0] !== 1 || rawMatrix[1] !== 0
1964
- || rawMatrix[2] !== 0 || rawMatrix[3] !== 1
1965
- || rawMatrix[4] !== 0 || rawMatrix[5] !== 0) {
1966
- multiMatrix = $multiplicationMatrix(matrix, rawMatrix);
1967
- }
1968
- context.reset();
1969
- context.setTransform(matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
1970
- context.beginPath();
1971
- context.moveTo(0, 0);
1972
- context.lineTo(width, 0);
1973
- context.lineTo(width, height);
1974
- context.lineTo(0, height);
1975
- context.lineTo(0, 0);
1976
- context.clip();
1977
- if (multiMatrix !== matrix) {
1978
- $poolFloat32Array6(multiMatrix);
1979
- }
1980
- }
1981
- /**
1982
- * @param {CanvasToWebGLContext} context
1983
- * @param {Float32Array} matrix
1984
- * @param {Float32Array} color_transform
1985
- * @return {void}
1986
- * @method
1987
- * @private
1988
- */
1989
- _$draw(context, matrix, color_transform) {
1990
- if (!this._$visible || this._$textAreaActive) {
1991
- return;
1992
- }
1993
- if (!this._$background && !this._$border && !this.text) {
1994
- return;
1995
- }
1996
- let multiColor = color_transform;
1997
- const rawColor = this._$transform._$rawColorTransform();
1998
- if (rawColor[0] !== 1 || rawColor[1] !== 1
1999
- || rawColor[2] !== 1 || rawColor[3] !== 1
2000
- || rawColor[4] !== 0 || rawColor[5] !== 0
2001
- || rawColor[6] !== 0 || rawColor[7] !== 0) {
2002
- multiColor = $multiplicationColor(color_transform, rawColor);
2003
- }
2004
- const alpha = $clamp(multiColor[3] + multiColor[7] / 255, 0, 1);
2005
- if (!alpha) {
2006
- return;
2007
- }
2008
- let multiMatrix = matrix;
2009
- const rawMatrix = this._$transform._$rawMatrix();
2010
- if (rawMatrix[0] !== 1 || rawMatrix[1] !== 0
2011
- || rawMatrix[2] !== 0 || rawMatrix[3] !== 1
2012
- || rawMatrix[4] !== 0 || rawMatrix[5] !== 0) {
2013
- multiMatrix = $multiplicationMatrix(matrix, rawMatrix);
2014
- }
2015
- const baseBounds = this._$getBounds(null);
2016
- baseBounds.xMin -= this._$thickness;
2017
- baseBounds.xMax += this._$thickness;
2018
- baseBounds.yMin -= this._$thickness;
2019
- baseBounds.yMax += this._$thickness;
2020
- const bounds = $boundsMatrix(baseBounds, multiMatrix);
2021
- const xMax = +bounds.xMax;
2022
- const xMin = +bounds.xMin;
2023
- const yMax = +bounds.yMax;
2024
- const yMin = +bounds.yMin;
2025
- $poolBoundsObject(bounds);
2026
- const width = $Math.ceil($Math.abs(xMax - xMin));
2027
- const height = $Math.ceil($Math.abs(yMax - yMin));
2028
- switch (true) {
2029
- case width === 0:
2030
- case height === 0:
2031
- case width === -$Infinity:
2032
- case height === -$Infinity:
2033
- case width === $Infinity:
2034
- case height === $Infinity:
2035
- return;
2036
- default:
2037
- break;
2038
- }
2039
- let xScale = +$Math.sqrt(multiMatrix[0] * multiMatrix[0]
2040
- + multiMatrix[1] * multiMatrix[1]);
2041
- if (!$Number.isInteger(xScale)) {
2042
- const value = xScale.toString();
2043
- const index = value.indexOf("e");
2044
- if (index !== -1) {
2045
- xScale = +value.slice(0, index);
2046
- }
2047
- xScale = +xScale.toFixed(4);
2048
- }
2049
- let yScale = +$Math.sqrt(multiMatrix[2] * multiMatrix[2]
2050
- + multiMatrix[3] * multiMatrix[3]);
2051
- if (!$Number.isInteger(yScale)) {
2052
- const value = yScale.toString();
2053
- const index = value.indexOf("e");
2054
- if (index !== -1) {
2055
- yScale = +value.slice(0, index);
2056
- }
2057
- yScale = +yScale.toFixed(4);
2058
- }
2059
- const filters = this._$filters || this.filters;
2060
- const canApply = filters !== null
2061
- && filters.length > 0
2062
- && this._$canApply(filters);
2063
- let filterBounds = $getBoundsObject(0, width, 0, height);
2064
- if (canApply && filters) {
2065
- for (let idx = 0; idx < filters.length; ++idx) {
2066
- filterBounds = filters[idx]
2067
- ._$generateFilterRect(filterBounds, xScale, yScale);
2068
- }
2069
- }
2070
- // cache current buffer
2071
- const manager = context.frameBuffer;
2072
- const currentAttachment = manager.currentAttachment;
2073
- if (!currentAttachment
2074
- || xMin - filterBounds.xMin > currentAttachment.width
2075
- || yMin - filterBounds.yMin > currentAttachment.height) {
2076
- $poolBoundsObject(filterBounds);
2077
- return;
2078
- }
2079
- if (0 > xMin + filterBounds.xMax || 0 > yMin + filterBounds.yMax) {
2080
- $poolBoundsObject(filterBounds);
2081
- return;
2082
- }
2083
- $poolBoundsObject(filterBounds);
2084
- // texture is small or renew
2085
- if (this._$isUpdated()) {
2086
- $cacheStore.removeCache(this._$instanceId);
2087
- context.cachePosition = null;
2088
- this._$cacheKeys.length = 0;
2089
- }
2090
- if (!this._$cacheKeys.length
2091
- || this._$cacheParams[0] !== xScale
2092
- || this._$cacheParams[1] !== yScale
2093
- || this._$cacheParams[2] !== color_transform[7]) {
2094
- const keys = $getArray(xScale, yScale);
2095
- this._$cacheKeys = $cacheStore.generateKeys(this._$instanceId, keys);
2096
- $poolArray(keys);
2097
- this._$cacheParams[0] = xScale;
2098
- this._$cacheParams[1] = yScale;
2099
- this._$cacheParams[2] = color_transform[7];
2100
- }
2101
- const blendMode = this._$blendMode || this.blendMode;
2102
- context.cachePosition = $cacheStore.get(this._$cacheKeys);
2103
- if (!context.cachePosition) {
2104
- // resize
2105
- const lineWidth = $Math.min(1, $Math.max(xScale, yScale));
2106
- const width = $Math.ceil($Math.abs(baseBounds.xMax - baseBounds.xMin) * xScale);
2107
- const height = $Math.ceil($Math.abs(baseBounds.yMax - baseBounds.yMin) * yScale);
2108
- // new canvas
2109
- const canvas = $cacheStore.getCanvas();
2110
- canvas.width = width + lineWidth * 2;
2111
- canvas.height = height + lineWidth * 2;
2112
- const ctx = canvas.getContext("2d");
2113
- if (!ctx) {
2114
- throw new Error("the context is null.");
2115
- }
2116
- // border and background
2117
- if (this._$background || this._$border) {
2118
- ctx.beginPath();
2119
- ctx.moveTo(0, 0);
2120
- ctx.lineTo(width, 0);
2121
- ctx.lineTo(width, height);
2122
- ctx.lineTo(0, height);
2123
- ctx.lineTo(0, 0);
2124
- if (this._$background) {
2125
- const rgb = $intToRGBA(this._$backgroundColor);
2126
- const alpha = $Math.max(0, $Math.min(rgb.A * 255 + multiColor[7], 255)) / 255;
2127
- ctx.fillStyle = `rgba(${rgb.R},${rgb.G},${rgb.B},${alpha})`;
2128
- ctx.fill();
2129
- }
2130
- if (this._$border) {
2131
- const rgb = $intToRGBA(this._$borderColor);
2132
- const alpha = $Math.max(0, $Math.min(rgb.A * 255 + multiColor[7], 255)) / 255;
2133
- ctx.lineWidth = lineWidth;
2134
- ctx.strokeStyle = `rgba(${rgb.R},${rgb.G},${rgb.B},${alpha})`;
2135
- ctx.stroke();
2136
- }
2137
- }
2138
- // mask start
2139
- ctx.save();
2140
- ctx.beginPath();
2141
- ctx.moveTo(2, 2);
2142
- ctx.lineTo(width - 2, 2);
2143
- ctx.lineTo(width - 2, height - 2);
2144
- ctx.lineTo(2, height - 2);
2145
- ctx.lineTo(2, 2);
2146
- ctx.clip();
2147
- ctx.beginPath();
2148
- ctx.setTransform(xScale, 0, 0, yScale, 0, 0);
2149
- this._$doDraw(ctx, matrix, multiColor, width / xScale);
2150
- ctx.restore();
2151
- const position = manager
2152
- .createCachePosition(width, height);
2153
- const texture = manager
2154
- .createTextureFromCanvas(ctx.canvas);
2155
- context.drawTextureFromRect(texture, position);
2156
- // set cache
2157
- context.cachePosition = position;
2158
- $cacheStore.set(this._$cacheKeys, position);
2159
- // destroy cache
2160
- $cacheStore.destroy(ctx);
2161
- }
2162
- let drawFilter = false;
2163
- let offsetX = 0;
2164
- let offsetY = 0;
2165
- if (filters && filters.length
2166
- && this._$canApply(filters)) {
2167
- drawFilter = true;
2168
- const position = this._$drawFilter(context, multiMatrix, filters, width, height);
2169
- if (position.offsetX) {
2170
- offsetX = position.offsetX;
2171
- }
2172
- if (position.offsetY) {
2173
- offsetY = position.offsetY;
2174
- }
2175
- // update
2176
- context.cachePosition = position;
2177
- }
2178
- const radianX = $Math.atan2(multiMatrix[1], multiMatrix[0]);
2179
- const radianY = $Math.atan2(-multiMatrix[2], multiMatrix[3]);
2180
- if (!drawFilter && (radianX || radianY)) {
2181
- const tx = baseBounds.xMin * xScale;
2182
- const ty = baseBounds.yMin * yScale;
2183
- const cosX = $Math.cos(radianX);
2184
- const sinX = $Math.sin(radianX);
2185
- const cosY = $Math.cos(radianY);
2186
- const sinY = $Math.sin(radianY);
2187
- context.setTransform(cosX, sinX, -sinY, cosY, tx * cosX - ty * sinY + multiMatrix[4], tx * sinX + ty * cosY + multiMatrix[5]);
2188
- }
2189
- else {
2190
- context.setTransform(1, 0, 0, 1, xMin - offsetX, yMin - offsetY);
2191
- }
2192
- // draw
2193
- if (context.cachePosition) {
2194
- context.globalAlpha = alpha;
2195
- context.imageSmoothingEnabled = true;
2196
- context.globalCompositeOperation = blendMode;
2197
- context.drawInstance(xMin - offsetX, yMin - offsetY, xMax, yMax, color_transform);
2198
- // cache position clear
2199
- context.cachePosition = null;
2200
- }
2201
- // get cache
2202
- $poolBoundsObject(baseBounds);
2203
- // pool
2204
- if (multiMatrix !== matrix) {
2205
- $poolFloat32Array6(multiMatrix);
2206
- }
2207
- if (multiColor !== color_transform) {
2208
- $poolFloat32Array8(multiColor);
2209
- }
2210
- }
2211
- /**
2212
- * @param {CanvasRenderingContext2D} context
2213
- * @param {Float32Array} matrix
2214
- * @param {Float32Array} color_transform
2215
- * @param {number} width
2216
- * @return {void}
2217
- * @method
2218
- * @private
2219
- */
2220
- _$doDraw(context, matrix, color_transform, width) {
2221
- // init
2222
- const textData = this._$getTextData();
2223
- const limitWidth = this.width;
2224
- const limitHeight = this.height;
2225
- // setup
2226
- let xOffset = 0;
2227
- let offsetHeight = 0;
2228
- let currentV = 0;
2229
- let yOffset = 0;
2230
- if (this._$verticalAlign !== "top"
2231
- && this.height > this.textHeight) {
2232
- switch (this._$verticalAlign) {
2233
- case "middle":
2234
- yOffset = (this.height - this.textHeight + 2) / 2;
2235
- break;
2236
- case "bottom":
2237
- yOffset = this.height - this.textHeight + 2;
2238
- break;
2239
- }
2240
- }
2241
- for (let idx = 0; idx < textData.length; ++idx) {
2242
- const obj = textData[idx];
2243
- if (obj.width === 0) {
2244
- continue;
2245
- }
2246
- // check
2247
- const offsetWidth = xOffset + obj.x;
2248
- if (this._$autoSize === "none"
2249
- && (offsetHeight > limitHeight || offsetWidth > limitWidth)) {
2250
- continue;
2251
- }
2252
- const tf = obj.textFormat;
2253
- // color
2254
- const rgb = $intToRGBA(tf.color || 0);
2255
- const alpha = $Math.max(0, $Math.min(rgb.A * 255 + color_transform[7], 255)) / 255;
2256
- context.fillStyle = `rgba(${rgb.R},${rgb.G},${rgb.B},${alpha})`;
2257
- if (this._$thickness) {
2258
- const rgb = $intToRGBA(this._$thicknessColor);
2259
- const alpha = $Math.max(0, $Math.min(rgb.A * 255 + color_transform[7], 255)) / 255;
2260
- context.lineWidth = this._$thickness;
2261
- context.strokeStyle = `rgba(${rgb.R},${rgb.G},${rgb.B},${alpha})`;
2262
- }
2263
- const yIndex = obj.yIndex | 0;
2264
- switch (obj.mode) {
2265
- case "break":
2266
- case "wrap":
2267
- currentV++;
2268
- if (this.scrollV > currentV) {
2269
- continue;
2270
- }
2271
- offsetHeight += this._$textHeightTable[yIndex];
2272
- xOffset = this._$getAlignOffset(this._$objectTable[yIndex], width);
2273
- if (tf.underline) {
2274
- const offset = tf.size ? tf.size / 12 : 0;
2275
- const rgb = $intToRGBA(tf.color || 0);
2276
- const alpha = $Math.max(0, $Math.min(rgb.A * 255 + color_transform[7], 255)) / 255;
2277
- context.lineWidth = $Math.max(1, 1 / $Math.min(matrix[0], matrix[3]));
2278
- context.strokeStyle = `rgba(${rgb.R},${rgb.G},${rgb.B},${alpha})`;
2279
- context.beginPath();
2280
- context.moveTo(xOffset, yOffset + offsetHeight - offset);
2281
- context.lineTo(xOffset + this._$widthTable[yIndex], yOffset + offsetHeight - offset);
2282
- context.stroke();
2283
- }
2284
- break;
2285
- case "text":
2286
- {
2287
- if (this.scrollV > currentV) {
2288
- continue;
2289
- }
2290
- let offsetY = offsetHeight - this._$heightTable[0];
2291
- if (!$isSafari && tf.size) {
2292
- offsetY += $devicePixelRatio * (tf.size / 12);
2293
- }
2294
- context.beginPath();
2295
- context.textBaseline = "top";
2296
- context.font = $generateFontStyle(tf.font || "", tf.size || 0, !!tf.italic, !!tf.bold);
2297
- if (this._$thickness) {
2298
- context.strokeText(obj.text, offsetWidth, yOffset + offsetY);
2299
- }
2300
- context.fillText(obj.text, offsetWidth, yOffset + offsetY);
2301
- }
2302
- break;
2303
- case "image":
2304
- if (!obj.loaded) {
2305
- continue;
2306
- }
2307
- context.beginPath();
2308
- context.drawImage(obj.image, obj.hspace, yOffset + obj.y, obj.width, obj.height);
2309
- break;
2310
- }
2311
- }
2312
- }
2313
- /**
2314
- * @param {CanvasRenderingContext2D} context
2315
- * @param {Float32Array} matrix
2316
- * @param {object} options
2317
- * @return {boolean}
2318
- * @method
2319
- * @private
2320
- */
2321
- _$mouseHit(context, matrix, options) {
2322
- if (!this._$visible) {
2323
- return false;
2324
- }
2325
- return this._$hit(context, matrix, options);
2326
- }
2327
- /**
2328
- * @param {CanvasRenderingContext2D} context
2329
- * @param {Float32Array} matrix
2330
- * @param {object} options
2331
- * @return {boolean}
2332
- * @method
2333
- * @private
2334
- */
2335
- _$hit(context, matrix, options) {
2336
- let multiMatrix = matrix;
2337
- const rawMatrix = this._$transform._$rawMatrix();
2338
- if (rawMatrix[0] !== 1 || rawMatrix[1] !== 0
2339
- || rawMatrix[2] !== 0 || rawMatrix[3] !== 1
2340
- || rawMatrix[4] !== 0 || rawMatrix[5] !== 0) {
2341
- multiMatrix = $multiplicationMatrix(matrix, rawMatrix);
2342
- }
2343
- const baseBounds = this._$getBounds(null);
2344
- const bounds = $boundsMatrix(baseBounds, multiMatrix);
2345
- const xMax = +bounds.xMax;
2346
- const xMin = +bounds.xMin;
2347
- const yMax = +bounds.yMax;
2348
- const yMin = +bounds.yMin;
2349
- $poolBoundsObject(bounds);
2350
- $poolBoundsObject(baseBounds);
2351
- const width = $Math.ceil($Math.abs(xMax - xMin));
2352
- const height = $Math.ceil($Math.abs(yMax - yMin));
2353
- context.setTransform(1, 0, 0, 1, xMin, yMin);
2354
- context.beginPath();
2355
- context.moveTo(0, 0);
2356
- context.lineTo(width, 0);
2357
- context.lineTo(width, height);
2358
- context.lineTo(0, height);
2359
- context.lineTo(0, 0);
2360
- if (multiMatrix !== matrix) {
2361
- $poolFloat32Array6(multiMatrix);
2362
- }
2363
- return context.isPointInPath(options.x, options.y);
2364
- }
2365
- /**
2366
- * @param {number} scale
2367
- * @return {void}
2368
- * @method
2369
- * @private
2370
- */
2371
- _$createTextAreaElement(scale) {
2372
- // new text area
2373
- if (!this._$textarea) {
2374
- this._$textarea = $document.createElement("textarea");
2375
- this._$textarea.value = this.text;
2376
- this._$textarea.id = `${$PREFIX}_TextField_${this._$instanceId}`;
2377
- if (!this._$wordWrap) {
2378
- this._$textarea.wrap = "off";
2379
- }
2380
- const textFormat = this._$defaultTextFormat;
2381
- // setup
2382
- let style = "";
2383
- style += "position: absolute;";
2384
- style += "outline: 0;";
2385
- style += `padding: 2px 2px 2px ${$Math.max(3, textFormat.leftMargin || 0)}px;`;
2386
- style += "margin: 0;";
2387
- style += "appearance: none;";
2388
- style += "resize: none;";
2389
- style += "overflow: hidden;";
2390
- style += `z-index: ${0x7fffffff};`;
2391
- style += "vertical-align: top;";
2392
- this._$textarea.setAttribute("style", style);
2393
- // add blur event
2394
- this._$textarea.addEventListener(`${$PREFIX}_blur`, (event) => {
2395
- // set new text
2396
- const element = event.target;
2397
- let value = element.value;
2398
- if (value && this._$restrict) {
2399
- let pattern = this._$restrict;
2400
- if (pattern[0] !== "[") {
2401
- pattern = "[" + pattern;
2402
- }
2403
- if (pattern[pattern.length - 1] !== "]") {
2404
- pattern += "]";
2405
- }
2406
- const found = value.match(new $RegExp(pattern, "gm"));
2407
- value = found ? found.join("") : "";
2408
- }
2409
- const player = $currentPlayer();
2410
- const div = $document.getElementById(player.contentElementId);
2411
- if (div) {
2412
- const element = $document.getElementById(`${$PREFIX}_TextField_${this._$instanceId}`);
2413
- if (element) {
2414
- element.remove();
2415
- }
2416
- }
2417
- this.text = value;
2418
- this._$focus = false;
2419
- this._$textAreaActive = false;
2420
- this._$doChanged();
2421
- $doUpdated();
2422
- });
2423
- // input event
2424
- this._$textarea.addEventListener("input", (event) => {
2425
- // set new text
2426
- const element = event.target;
2427
- const player = $currentPlayer();
2428
- let value = element.value;
2429
- // SafariではInputEvent.isComposingがundefined
2430
- if (this._$restrict && !this._$isComposing && value) {
2431
- let pattern = this._$restrict;
2432
- if (pattern[0] !== "[") {
2433
- pattern = "[" + pattern;
2434
- }
2435
- if (pattern[pattern.length - 1] !== "]") {
2436
- pattern += "]";
2437
- }
2438
- const found = value.match(new $RegExp(pattern, "gm"));
2439
- value = found ? found.join("") : "";
2440
- }
2441
- if (!this._$isComposing && this.text !== value) {
2442
- // update
2443
- this.text = value;
2444
- element.value = value;
2445
- if (this.willTrigger(Next2DEvent.CHANGE)) {
2446
- this.dispatchEvent(new Next2DEvent(Next2DEvent.CHANGE, true));
2447
- }
2448
- // setup
2449
- // const element = this._$textarea;
2450
- const matrix = this._$transform.concatenatedMatrix;
2451
- const bounds = this._$getBounds(null);
2452
- element.style.left = `${$Math.floor((matrix.tx + bounds.xMin + player.x / player._$scale / $devicePixelRatio) * player._$scale)}px`;
2453
- element.style.top = `${$Math.floor((matrix.ty + bounds.yMin + player.y / player._$scale / $devicePixelRatio) * player._$scale)}px`;
2454
- element.style.width = `${$Math.ceil((this.width - 1) * player._$scale)}px`;
2455
- element.style.height = `${$Math.ceil((this.height - 1) * player._$scale)}px`;
2456
- }
2457
- });
2458
- // IME入力開始時のevent
2459
- this._$textarea.addEventListener("compositionstart", () => {
2460
- this._$isComposing = true;
2461
- });
2462
- // IME入力確定時のevent
2463
- this._$textarea.addEventListener("compositionend", (event) => {
2464
- this._$isComposing = false;
2465
- const element = event.target;
2466
- let value = element.value;
2467
- if (!this._$restrict || !value) {
2468
- return;
2469
- }
2470
- let pattern = this._$restrict;
2471
- if (pattern[0] !== "[") {
2472
- pattern = "[" + pattern;
2473
- }
2474
- if (pattern[pattern.length - 1] !== "]") {
2475
- pattern += "]";
2476
- }
2477
- const found = value.match(new $RegExp(pattern, "gm"));
2478
- value = found ? found.join("") : "";
2479
- // update
2480
- this.text = value;
2481
- element.value = value;
2482
- });
2483
- // add click event
2484
- this._$textarea.addEventListener("click", () => {
2485
- if (this.willTrigger(Next2DMouseEvent.CLICK)) {
2486
- this.dispatchEvent(new Next2DMouseEvent(Next2DMouseEvent.CLICK));
2487
- }
2488
- });
2489
- // add mousewheel event
2490
- this._$textarea.addEventListener($MOUSE_WHEEL, (event) => {
2491
- this.scrollV += event.deltaY;
2492
- });
2493
- // add scroll event
2494
- this._$textarea.addEventListener($SCROLL, (event) => {
2495
- const element = event.target;
2496
- this.scrollV = element.scrollTop
2497
- / (element.scrollHeight - element.clientHeight)
2498
- * this.maxScrollV + 1;
2499
- });
2500
- // down event
2501
- this._$textarea.addEventListener($TOUCH_START, () => {
2502
- const player = $currentPlayer();
2503
- player._$state = "down";
2504
- });
2505
- // up event
2506
- this._$textarea.addEventListener($TOUCH_END, () => {
2507
- const player = $currentPlayer();
2508
- player._$state = "up";
2509
- });
2510
- // down event
2511
- this._$textarea.addEventListener($MOUSE_DOWN, () => {
2512
- const player = $currentPlayer();
2513
- player._$state = "down";
2514
- });
2515
- // up event
2516
- this._$textarea.addEventListener($MOUSE_UP, () => {
2517
- const player = $currentPlayer();
2518
- player._$state = "up";
2519
- });
2520
- }
2521
- // change style
2522
- const tf = this._$defaultTextFormat;
2523
- const fontSize = tf.size
2524
- ? $Math.ceil(tf.size * scale * this._$transform.concatenatedMatrix.d)
2525
- : 0;
2526
- this._$textarea.style.fontSize = `${fontSize}px`;
2527
- this._$textarea.style.fontFamily = tf.font || "Times New Roman";
2528
- this._$textarea.style.lineHeight = `${(fontSize + $Math.max(0, tf.leading || 0)) / fontSize}em`;
2529
- if (this._$autoSize !== "none") {
2530
- this._$textarea.style.textAlign = "center";
2531
- }
2532
- else {
2533
- this._$textarea.style.textAlign = tf.align || "none";
2534
- }
2535
- this._$textarea.addEventListener("keydown", (event) => {
2536
- const element = event.target;
2537
- let value = element.value;
2538
- // SafariではInputEvent.isComposingがundefined
2539
- if (this._$restrict && !this._$isComposing && value) {
2540
- let pattern = this._$restrict;
2541
- if (pattern[0] !== "[") {
2542
- pattern = "[" + pattern;
2543
- }
2544
- if (pattern[pattern.length - 1] !== "]") {
2545
- pattern += "]";
2546
- }
2547
- const found = value.match(new $RegExp(pattern, "gm"));
2548
- value = found ? found.join("") : "";
2549
- }
2550
- // update
2551
- if (!this._$isComposing) {
2552
- this.text = value;
2553
- element.value = value;
2554
- }
2555
- // enter off
2556
- if (event.code === "Enter" && !this._$multiline) {
2557
- return false;
2558
- }
2559
- });
2560
- const style = this._$textarea.style;
2561
- if (this._$border) {
2562
- style.border = `solid 1px #${this.borderColor.toString(16)}`;
2563
- }
2564
- else {
2565
- style.border = "none";
2566
- }
2567
- if (this._$border || this._$background) {
2568
- style.backgroundColor = `#${this.backgroundColor.toString(16)}`;
2569
- }
2570
- else {
2571
- style.backgroundColor = "transparent";
2572
- }
2573
- //reset
2574
- this._$textarea.maxLength = this._$maxChars ? this._$maxChars : 0x7fffffff;
2575
- }
2576
- /**
2577
- * @return {void}
2578
- * @method
2579
- * @private
2580
- */
2581
- _$createWorkerInstance() {
2582
- if (this._$created || !$rendererWorker) {
2583
- return;
2584
- }
2585
- this._$created = true;
2586
- const bounds = this._$getBounds();
2587
- const message = {
2588
- "command": "createTextField",
2589
- "instanceId": this._$instanceId,
2590
- "parentId": this._$parent ? this._$parent._$instanceId : -1,
2591
- "xMin": bounds.xMin,
2592
- "yMin": bounds.yMin,
2593
- "xMax": bounds.xMax,
2594
- "yMax": bounds.yMax,
2595
- "textData": this._$getTextData(),
2596
- "scrollV": this.scrollV,
2597
- "widthTable": this._$widthTable,
2598
- "heightTable": this._$heightTable,
2599
- "textHeightTable": this._$textHeightTable,
2600
- "objectTable": this._$objectTable,
2601
- "limitWidth": this.width,
2602
- "limitHeight": this.height,
2603
- "textHeight": this.textHeight,
2604
- "verticalAlign": this._$verticalAlign,
2605
- "autoSize": this._$autoSize,
2606
- "wordWrap": this._$wordWrap,
2607
- "border": this._$border,
2608
- "background": this._$background,
2609
- "thickness": this._$thickness
2610
- };
2611
- if (this._$border) {
2612
- message.borderColor = this._$borderColor;
2613
- }
2614
- if (this._$background) {
2615
- message.backgroundColor = this._$backgroundColor;
2616
- }
2617
- if (this._$thickness) {
2618
- message.thicknessColor = this._$backgroundColor;
2619
- }
2620
- if (this._$characterId > -1) {
2621
- message.characterId = this._$characterId;
2622
- }
2623
- if (this._$loaderInfo) {
2624
- message.loaderInfoId = this._$loaderInfo._$id;
2625
- }
2626
- if (this._$scale9Grid) {
2627
- message.grid = {
2628
- "x": this._$scale9Grid.x,
2629
- "y": this._$scale9Grid.y,
2630
- "w": this._$scale9Grid.width,
2631
- "h": this._$scale9Grid.height
2632
- };
2633
- }
2634
- $rendererWorker.postMessage(message);
2635
- }
2636
- /**
2637
- * @return {void}
2638
- * @method
2639
- * @private
2640
- */
2641
- _$postProperty() {
2642
- if (!$rendererWorker) {
2643
- return;
2644
- }
2645
- const message = this._$createMessage();
2646
- message.textAreaActive = this._$textAreaActive;
2647
- const bounds = this._$getBounds(null);
2648
- message.xMin = bounds.xMin;
2649
- message.yMin = bounds.yMin;
2650
- message.xMax = bounds.xMax;
2651
- message.yMax = bounds.yMax;
2652
- $poolBoundsObject(bounds);
2653
- if (this._$isUpdated()) {
2654
- message.textData = this._$getTextData();
2655
- message.scrollV = this.scrollV;
2656
- message.widthTable = this._$widthTable;
2657
- message.heightTable = this._$heightTable;
2658
- message.textHeightTable = this._$textHeightTable;
2659
- message.objectTable = this._$objectTable;
2660
- message.limitWidth = this.width;
2661
- message.limitHeight = this.height;
2662
- message.textHeight = this.textHeight;
2663
- message.verticalAlign = this._$verticalAlign;
2664
- message.autoSize = this._$autoSize;
2665
- message.wordWrap = this._$wordWrap;
2666
- message.border = this._$border;
2667
- if (this._$border) {
2668
- message.borderColor = this._$borderColor;
2669
- }
2670
- message.background = this._$background;
2671
- if (this._$background) {
2672
- message.backgroundColor = this._$backgroundColor;
2673
- }
2674
- message.thickness = this._$thickness;
2675
- if (this._$thickness) {
2676
- message.thicknessColor = this._$backgroundColor;
2677
- }
2678
- }
2679
- $rendererWorker.postMessage(message);
2680
- this._$posted = true;
2681
- this._$updated = false;
2682
- }
2683
- }