@xpadev-net/niconicomments 0.2.11 → 0.2.12

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/bundle.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- niconicomments.js v0.2.11
2
+ niconicomments.js v0.2.12
3
3
  (c) 2021 xpadev-net https://xpadev.net
4
4
  Released under the MIT License.
5
5
  */
@@ -25,963 +25,952 @@
25
25
  return _assign.apply(this, arguments);
26
26
  };
27
27
 
28
- var isDebug = false;
29
- var NiconiComments = (function () {
30
- function NiconiComments(canvas, data, options) {
31
- if (options === void 0) { options = {
32
- useLegacy: false,
33
- formatted: false,
34
- video: null,
35
- showCollision: false,
36
- showFPS: false,
37
- showCommentCount: false,
38
- drawAllImageOnLoad: false,
39
- debug: false
40
- }; }
41
- var _this = this;
42
- isDebug = options.debug;
43
- var constructorStart = performance.now();
44
- this.canvas = canvas;
45
- var context = canvas.getContext("2d");
46
- if (!context)
47
- throw new Error("Fail to get CanvasRenderingContext2D");
48
- this.context = context;
49
- this.context.strokeStyle = "rgba(0,0,0,0.7)";
50
- this.context.textAlign = "start";
51
- this.context.textBaseline = "alphabetic";
52
- this.context.lineWidth = 4;
53
- this.commentYPaddingTop = 0.08;
54
- this.commentYMarginBottom = 0.24;
55
- this.fontSize = {
56
- "small": {
57
- "default": 47,
58
- "resized": 26.1
59
- },
60
- "medium": {
61
- "default": 74,
62
- "resized": 38.7
63
- },
64
- "big": {
65
- "default": 111,
66
- "resized": 61
67
- }
68
- };
69
- this.lineHeight = {
70
- "small": {
71
- "default": 1,
72
- "resized": 1
73
- },
74
- "medium": {
75
- "default": 1,
76
- "resized": 1
77
- },
78
- "big": {
79
- "default": 1,
80
- "resized": 1.01
81
- }
82
- };
83
- this.doubleResizeMaxWidth = {
84
- full: {
85
- legacy: 3020,
86
- default: 3220
87
- },
88
- normal: {
89
- legacy: 2540,
90
- default: 2740
91
- }
92
- };
93
- var parsedData = options.formatted ? data : this.parseData(data);
94
- this.video = options.video ? options.video : null;
95
- this.showCollision = options.showCollision;
96
- this.showFPS = options.showFPS;
97
- this.showCommentCount = options.showCommentCount;
98
- this.timeline = {};
99
- this.nicoScripts = { reverse: [], default: [], replace: [], ban: [] };
100
- this.collision_right = {};
101
- this.collision_left = {};
102
- this.collision_ue = {};
103
- this.collision_shita = {};
104
- this.data = [];
105
- this.lastVpos = -1;
106
- this.useLegacy = options.useLegacy;
107
- this.preRendering(parsedData, options.drawAllImageOnLoad);
108
- this.fpsCount = 0;
109
- this.fps = 0;
110
- window.setInterval(function () {
111
- _this.fps = _this.fpsCount * 2;
112
- _this.fpsCount = 0;
113
- }, 500);
114
- logger("constructor complete: ".concat(performance.now() - constructorStart, "ms"));
115
- }
116
- NiconiComments.prototype.parseData = function (data) {
117
- var parseDataStart = performance.now();
118
- var data_ = [];
119
- for (var i = 0; i < data.length; i++) {
120
- for (var key in data[i]) {
121
- var val = data[i];
122
- if (!val)
123
- continue;
124
- var value = val[key];
125
- if (isApiChat(value) && value["deleted"] !== 1) {
126
- var tmpParam = {
127
- "id": value["no"],
128
- "vpos": value["vpos"],
129
- "content": value["content"],
130
- "date": value["date"],
131
- "date_usec": value["date_usec"],
132
- "owner": !value["user_id"],
133
- "premium": value["premium"] === 1,
134
- "mail": []
135
- };
136
- if (value["mail"]) {
137
- tmpParam["mail"] = value["mail"].split(/[\s ]/g);
138
- }
139
- if (value["content"].startsWith("/") && !value["user_id"]) {
140
- tmpParam["mail"].push("invisible");
141
- }
142
- data_.push(tmpParam);
143
- }
144
- }
145
- }
146
- data_.sort(function (a, b) {
147
- if (a.vpos < b.vpos)
148
- return -1;
149
- if (a.vpos > b.vpos)
150
- return 1;
151
- if (a.date < b.date)
152
- return -1;
153
- if (a.date > b.date)
154
- return 1;
155
- if (a.date_usec < b.date_usec)
156
- return -1;
157
- if (a.date_usec > b.date_usec)
158
- return 1;
159
- return 0;
160
- });
161
- logger("parseData complete: ".concat(performance.now() - parseDataStart, "ms"));
162
- return data_;
163
- };
164
- NiconiComments.prototype.preRendering = function (rawData, drawAll) {
165
- var preRenderingStart = performance.now();
166
- var parsedData = this.getCommentPos(this.getCommentSize(this.getFont(rawData)));
167
- this.data = this.sortComment(parsedData);
168
- if (drawAll) {
169
- for (var i in parsedData) {
170
- this.getTextImage(Number(i));
171
- }
172
- }
173
- logger("preRendering complete: ".concat(performance.now() - preRenderingStart, "ms"));
174
- };
175
- NiconiComments.prototype.getFont = function (parsedData) {
176
- var getFontStart = performance.now();
177
- var result = [];
178
- for (var i in parsedData) {
179
- var value = parsedData[i];
180
- if (!value)
181
- continue;
182
- value.content = value.content.replace(/\t/g, "\u2003\u2003");
183
- result[i] = this.parseCommandAndNicoscript(value);
184
- }
185
- logger("getFont complete: ".concat(performance.now() - getFontStart, "ms"));
186
- return result;
187
- };
188
- NiconiComments.prototype.getCommentSize = function (parsedData) {
189
- var getCommentSizeStart = performance.now();
190
- var tmpData = groupBy(parsedData, "font", "fontSize");
191
- var result = [];
192
- for (var i in tmpData) {
193
- for (var j in tmpData[i]) {
194
- this.context.font = parseFont(i, j, this.useLegacy);
195
- for (var k in tmpData[i][j]) {
196
- var comment = tmpData[i][j][k];
197
- if (comment.invisible) {
198
- continue;
199
- }
200
- var measure = this.measureText(comment);
201
- var size = parsedData[comment.index];
202
- size.height = measure.height;
203
- size.width = measure.width;
204
- size.width_max = measure.width_max;
205
- size.width_min = measure.width_min;
206
- size.lineHeight = measure.lineHeight;
207
- if (measure.resized) {
208
- size.fontSize = measure.fontSize;
209
- this.context.font = parseFont(i, j, this.useLegacy);
210
- }
211
- result[comment.index] = size;
212
- }
213
- }
214
- }
215
- logger("getCommentSize complete: ".concat(performance.now() - getCommentSizeStart, "ms"));
216
- return result;
217
- };
218
- NiconiComments.prototype.getCommentPos = function (parsedData) {
219
- var getCommentPosStart = performance.now();
220
- var data = parsedData;
221
- for (var i in data) {
222
- var comment = data[i];
223
- if (!comment || comment.invisible) {
224
- continue;
225
- }
226
- for (var j = 0; j < 500; j++) {
227
- if (!this.timeline[comment.vpos + j]) {
228
- this.timeline[comment.vpos + j] = [];
229
- }
230
- if (!this.collision_right[comment.vpos + j]) {
231
- this.collision_right[comment.vpos + j] = [];
232
- }
233
- if (!this.collision_left[comment.vpos + j]) {
234
- this.collision_left[comment.vpos + j] = [];
235
- }
236
- if (!this.collision_ue[comment.vpos + j]) {
237
- this.collision_ue[comment.vpos + j] = [];
238
- }
239
- if (!this.collision_shita[comment.vpos + j]) {
240
- this.collision_shita[comment.vpos + j] = [];
241
- }
242
- }
243
- if (comment.loc === "naka") {
244
- comment.vpos -= 70;
245
- parsedData[i].vpos -= 70;
246
- var posY = 0, is_break = false, is_change = true, count = 0;
247
- if (1080 < comment.height) {
248
- posY = (comment.height - 1080) / -2;
249
- }
250
- else {
251
- while (is_change && count < 10) {
252
- is_change = false;
253
- count++;
254
- for (var j = 0; j < 500; j++) {
255
- var vpos = comment.vpos + j;
256
- var left_pos = 1920 - ((1920 + comment.width_max) * j / 500);
257
- if (left_pos + comment.width_max >= 1880) {
258
- for (var k in this.collision_right[vpos]) {
259
- var l = this.collision_right[vpos][k];
260
- if ((posY < data[l].posY + data[l].height && posY + comment.height > data[l].posY) && data[l].owner === comment.owner) {
261
- if (data[l].posY + data[l].height > posY) {
262
- posY = data[l].posY + data[l].height;
263
- is_change = true;
264
- }
265
- if (posY + comment.height > 1080) {
266
- if (1080 < comment.height) {
267
- posY = (comment.height - 1080) / -2;
268
- }
269
- else {
270
- posY = Math.floor(Math.random() * (1080 - comment.height));
271
- }
272
- is_break = true;
273
- break;
274
- }
275
- }
276
- }
277
- if (is_break) {
278
- break;
279
- }
280
- }
281
- if (left_pos <= 40 && !is_break) {
282
- for (var k in this.collision_left[vpos]) {
283
- var l = this.collision_left[vpos][k];
284
- if ((posY < data[l].posY + data[l].height && posY + comment.height > data[l].posY) && data[l].owner === comment.owner) {
285
- if (data[l].posY + data[l].height > posY) {
286
- posY = data[l].posY + data[l].height;
287
- is_change = true;
288
- }
289
- if (posY + comment.height > 1080) {
290
- if (1080 < comment.height) {
291
- posY = 0;
292
- }
293
- else {
294
- posY = Math.random() * (1080 - comment.height);
295
- }
296
- is_break = true;
297
- break;
298
- }
299
- }
300
- }
301
- if (is_break) {
302
- break;
303
- }
304
- }
305
- if (is_break) {
306
- break;
307
- }
308
- }
309
- if (is_break) {
310
- break;
311
- }
312
- }
313
- }
314
- for (var j = 0; j < 500; j++) {
315
- var vpos = comment.vpos + j;
316
- var left_pos = 1920 - ((1920 + comment.width_max) * j / 500);
317
- arrayPush(this.timeline, vpos, i);
318
- if (left_pos + comment.width_max >= 1880) {
319
- arrayPush(this.collision_right, vpos, i);
320
- }
321
- if (left_pos <= 40) {
322
- arrayPush(this.collision_left, vpos, i);
323
- }
324
- }
325
- parsedData[i].posY = posY;
326
- }
327
- else {
328
- var posY = 0, is_break = false, is_change = true, count = 0, collision = void 0;
329
- if (comment.loc === "ue") {
330
- collision = this.collision_ue;
331
- }
332
- else if (comment.loc === "shita") {
333
- collision = this.collision_shita;
334
- }
335
- while (is_change && count < 10) {
336
- is_change = false;
337
- count++;
338
- for (var j = 0; j < 300; j++) {
339
- var vpos = comment.vpos + j;
340
- for (var k in collision[vpos]) {
341
- var l = collision[vpos][k];
342
- if ((posY < data[l].posY + data[l].height && posY + comment.height > data[l].posY) && data[l].owner === comment.owner) {
343
- if (data[l].posY + data[l].height > posY) {
344
- posY = data[l].posY + data[l].height;
345
- is_change = true;
346
- }
347
- if (posY + comment.height > 1080) {
348
- if (1000 <= comment.height) {
349
- posY = 0;
350
- }
351
- else {
352
- posY = Math.floor(Math.random() * (1080 - comment.height));
353
- }
354
- is_break = true;
355
- break;
356
- }
357
- }
358
- }
359
- if (is_break) {
360
- break;
361
- }
362
- }
363
- }
364
- for (var j = 0; j < comment.long; j++) {
365
- var vpos = comment.vpos + j;
366
- arrayPush(this.timeline, vpos, i);
367
- if (comment.loc === "ue") {
368
- arrayPush(this.collision_ue, vpos, i);
369
- }
370
- else {
371
- arrayPush(this.collision_shita, vpos, i);
372
- }
373
- }
374
- parsedData[i].posY = posY;
375
- }
376
- }
377
- logger("getCommentPos complete: ".concat(performance.now() - getCommentPosStart, "ms"));
378
- return parsedData;
379
- };
380
- NiconiComments.prototype.sortComment = function (parsedData) {
381
- var sortCommentStart = performance.now();
382
- for (var vpos in this.timeline) {
383
- if (!this.timeline[vpos])
384
- continue;
385
- var owner = [], user = [];
386
- for (var _i = 0, _a = this.timeline[vpos]; _i < _a.length; _i++) {
387
- var i = _a[_i];
388
- if (parsedData[i].owner) {
389
- owner.push(i);
390
- }
391
- else {
392
- user.push(i);
393
- }
394
- }
395
- this.timeline[vpos] = owner.concat(user);
396
- }
397
- logger("parseData complete: ".concat(performance.now() - sortCommentStart, "ms"));
398
- return parsedData;
399
- };
400
- NiconiComments.prototype.measureText = function (comment) {
401
- var width, width_max, width_min, height, width_arr = [], lines = comment.content.split("\n");
402
- if (!comment.lineHeight)
403
- comment.lineHeight = this.lineHeight[comment.size].default;
404
- if (!comment.resized && !comment.ender) {
405
- if (comment.size === "big" && lines.length > 2) {
406
- comment.fontSize = this.fontSize.big.resized;
407
- comment.lineHeight = this.lineHeight.big.resized;
408
- comment.resized = true;
409
- comment.tateresized = true;
410
- this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
411
- }
412
- else if (comment.size === "medium" && lines.length > 4) {
413
- comment.fontSize = this.fontSize.medium.resized;
414
- comment.lineHeight = this.lineHeight.medium.resized;
415
- comment.resized = true;
416
- comment.tateresized = true;
417
- this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
418
- }
419
- else if (comment.size === "small" && lines.length > 6) {
420
- comment.fontSize = this.fontSize.small.resized;
421
- comment.lineHeight = this.lineHeight.small.resized;
422
- comment.resized = true;
423
- comment.tateresized = true;
424
- this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
425
- }
426
- }
427
- for (var i = 0; i < lines.length; i++) {
428
- var measure = this.context.measureText(lines[i]);
429
- width_arr.push(measure.width);
430
- }
431
- width = width_arr.reduce(function (p, c) { return p + c; }, 0) / width_arr.length;
432
- width_max = Math.max.apply(Math, width_arr);
433
- width_min = Math.min.apply(Math, width_arr);
434
- height = (comment.fontSize * comment.lineHeight * (1 + this.commentYPaddingTop) * lines.length) + (this.commentYMarginBottom * comment.fontSize);
435
- if (comment.loc !== "naka" && !comment.tateresized) {
436
- if (comment.full && width_max > 1920) {
437
- comment.fontSize -= 2;
438
- comment.resized = true;
439
- comment.yokoResized = true;
440
- this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
441
- return this.measureText(comment);
442
- }
443
- else if (!comment.full && width_max > 1440) {
444
- comment.fontSize -= 1;
445
- comment.resized = true;
446
- comment.yokoResized = true;
447
- this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
448
- return this.measureText(comment);
449
- }
450
- }
451
- else if (comment.loc !== "naka" && comment.tateresized && (comment.full && width_max > 2120 || !comment.full && width_max > 1440) && !comment.yokoResized) {
452
- comment.fontSize = this.fontSize[comment.size].default;
453
- comment.resized = true;
454
- comment.yokoResized = true;
455
- this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
456
- return this.measureText(comment);
457
- }
458
- else if (comment.loc !== "naka" && comment.tateresized && comment.yokoResized) {
459
- if (comment.full && width_max > this.doubleResizeMaxWidth.full[this.useLegacy ? "legacy" : "default"]) {
460
- comment.fontSize -= 1;
461
- this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
462
- return this.measureText(comment);
463
- }
464
- else if (!comment.full && width_max > this.doubleResizeMaxWidth.normal[this.useLegacy ? "legacy" : "default"]) {
465
- comment.fontSize -= 1;
466
- this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
467
- return this.measureText(comment);
468
- }
469
- }
470
- return {
471
- "width": width,
472
- "width_max": width_max,
473
- "width_min": width_min,
474
- "height": height,
475
- "resized": comment.resized,
476
- "fontSize": comment.fontSize,
477
- "lineHeight": comment.lineHeight
478
- };
479
- };
480
- NiconiComments.prototype.drawText = function (comment, vpos) {
481
- var reverse = false;
482
- for (var i in this.nicoScripts.reverse) {
483
- var range = this.nicoScripts.reverse[i];
484
- if ((range.target === "コメ" && comment.owner) || (range.target === "投コメ" && !comment.owner)) {
485
- break;
486
- }
487
- if (range.start < vpos && vpos < range.end) {
488
- reverse = true;
489
- }
490
- }
491
- for (var i in this.nicoScripts.ban) {
492
- var range = this.nicoScripts.ban[i];
493
- if (range.start < vpos && vpos < range.end) {
494
- return;
495
- }
496
- }
497
- var posX = (1920 - comment.width_max) / 2, posY = comment.posY;
498
- if (comment.loc === "naka") {
499
- if (reverse) {
500
- posX = ((1920 + comment.width_max) * (vpos - comment.vpos) / 500) - comment.width_max;
501
- }
502
- else {
503
- posX = 1920 - ((1920 + comment.width_max) * (vpos - comment.vpos) / 500);
504
- }
505
- }
506
- else if (comment.loc === "shita") {
507
- posY = 1080 - comment.posY - comment.height;
508
- }
509
- if (comment.image && comment.image !== true) {
510
- this.context.drawImage(comment.image, posX, posY);
511
- }
512
- };
513
- NiconiComments.prototype.getTextImage = function (i) {
514
- var _this = this;
515
- var value = this.data[i];
516
- if (!value || value.invisible || value.content.match(/^\s*$/))
517
- return;
518
- var image = document.createElement("canvas");
519
- image.width = value.width_max;
520
- image.height = value.height;
521
- var context = image.getContext("2d");
522
- if (!context)
523
- throw new Error("Fail to get CanvasRenderingContext2D");
524
- context.strokeStyle = "rgba(0,0,0,0.7)";
525
- context.textAlign = "start";
526
- context.textBaseline = "alphabetic";
527
- context.lineWidth = 4;
528
- context.font = parseFont(value.font, value.fontSize, this.useLegacy);
529
- if (value._live) {
530
- var rgb = hex2rgb(value.color);
531
- context.fillStyle = "rgba(".concat(rgb[0], ",").concat(rgb[1], ",").concat(rgb[2], ",0.5)");
532
- }
533
- else {
534
- context.fillStyle = value.color;
535
- }
536
- if (value.color === "#000000") {
537
- context.strokeStyle = "rgba(255,255,255,0.7)";
538
- }
539
- if (this.showCollision) {
540
- context.strokeStyle = "rgba(0,255,255,1)";
541
- context.strokeRect(0, 0, value.width_max, value.height);
542
- if (value.color === "#000000") {
543
- context.strokeStyle = "rgba(255,255,255,0.7)";
544
- }
545
- else {
546
- context.strokeStyle = "rgba(0,0,0,0.7)";
547
- }
548
- }
549
- var lines = value.content.split("\n");
550
- for (var i_1 in lines) {
551
- var line = lines[i_1], posY = void 0;
552
- posY = (Number(i_1) + 1) * (value.fontSize * value.lineHeight) * (1 + this.commentYPaddingTop);
553
- context.strokeText(line, 0, posY);
554
- context.fillText(line, 0, posY);
555
- if (this.showCollision) {
556
- context.strokeStyle = "rgba(255,255,0,0.5)";
557
- context.strokeRect(0, posY, value.width_max, value.fontSize * value.lineHeight * -1);
558
- if (value.color === "#000000") {
559
- context.strokeStyle = "rgba(255,255,255,0.7)";
560
- }
561
- else {
562
- context.strokeStyle = "rgba(0,0,0,0.7)";
563
- }
564
- }
565
- }
566
- this.data[i].image = image;
567
- setTimeout(function () {
568
- if (_this.data[i].image)
569
- delete _this.data[i].image;
570
- }, 5000);
571
- };
572
- NiconiComments.prototype.parseCommand = function (comment) {
573
- var metadata = comment.mail, loc = null, size = null, fontSize = null, color = null, font = null, full = false, ender = false, _live = false, invisible = false, long = null;
574
- for (var i in metadata) {
575
- var command = metadata[i].toLowerCase();
576
- var match = command.match(/^@([0-9.]+)/);
577
- if (match) {
578
- long = match[1];
579
- }
580
- if (loc === null) {
581
- switch (command) {
582
- case "ue":
583
- loc = "ue";
584
- break;
585
- case "shita":
586
- loc = "shita";
587
- break;
588
- }
589
- }
590
- if (size === null) {
591
- switch (command) {
592
- case "big":
593
- size = "big";
594
- fontSize = this.fontSize.big.default;
595
- break;
596
- case "small":
597
- size = "small";
598
- fontSize = this.fontSize.small.default;
599
- break;
600
- }
601
- }
602
- if (color === null) {
603
- switch (command) {
604
- case "white":
605
- color = "#FFFFFF";
606
- break;
607
- case "red":
608
- color = "#FF0000";
609
- break;
610
- case "pink":
611
- color = "#FF8080";
612
- break;
613
- case "orange":
614
- color = "#FFC000";
615
- break;
616
- case "yellow":
617
- color = "#FFFF00";
618
- break;
619
- case "green":
620
- color = "#00FF00";
621
- break;
622
- case "cyan":
623
- color = "#00FFFF";
624
- break;
625
- case "blue":
626
- color = "#0000FF";
627
- break;
628
- case "purple":
629
- color = "#C000FF";
630
- break;
631
- case "black":
632
- color = "#000000";
633
- break;
634
- case "white2":
635
- case "niconicowhite":
636
- color = "#CCCC99";
637
- break;
638
- case "red2":
639
- case "truered":
640
- color = "#CC0033";
641
- break;
642
- case "pink2":
643
- color = "#FF33CC";
644
- break;
645
- case "orange2":
646
- case "passionorange":
647
- color = "#FF6600";
648
- break;
649
- case "yellow2":
650
- case "madyellow":
651
- color = "#999900";
652
- break;
653
- case "green2":
654
- case "elementalgreen":
655
- color = "#00CC66";
656
- break;
657
- case "cyan2":
658
- color = "#00CCCC";
659
- break;
660
- case "blue2":
661
- case "marineblue":
662
- color = "#3399FF";
663
- break;
664
- case "purple2":
665
- case "nobleviolet":
666
- color = "#6633CC";
667
- break;
668
- case "black2":
669
- color = "#666666";
670
- break;
671
- default:
672
- var match_1 = command.match(/#[0-9a-z]{3,6}/);
673
- if (match_1 && comment.premium) {
674
- color = match_1[0].toUpperCase();
675
- }
676
- break;
677
- }
678
- }
679
- if (font === null) {
680
- switch (command) {
681
- case "gothic":
682
- font = "gothic";
683
- break;
684
- case "mincho":
685
- font = "mincho";
686
- break;
687
- }
688
- }
689
- switch (command) {
690
- case "full":
691
- full = true;
692
- break;
693
- case "ender":
694
- ender = true;
695
- break;
696
- case "_live":
697
- _live = true;
698
- break;
699
- case "invisible":
700
- invisible = true;
701
- break;
702
- }
703
- }
704
- return { loc: loc, size: size, fontSize: fontSize, color: color, font: font, full: full, ender: ender, _live: _live, invisible: invisible, long: long };
705
- };
706
- NiconiComments.prototype.parseCommandAndNicoscript = function (comment) {
707
- var data = this.parseCommand(comment), nicoscript = comment.content.match(/^@(デフォルト|置換|逆|コメント禁止|シーク禁止|ジャンプ)/);
708
- if (nicoscript) {
709
- switch (nicoscript[1]) {
710
- case "デフォルト":
711
- this.nicoScripts.default.push({
712
- start: comment.vpos,
713
- long: data.long === null ? null : Math.floor(data.long * 100),
714
- color: data.color,
715
- size: data.size,
716
- font: data.font,
717
- loc: data.loc
718
- });
719
- break;
720
- case "逆":
721
- var reverse = comment.content.match(/^@逆 ?(全|コメ|投コメ)?/);
722
- if (!reverse)
723
- reverse = [];
724
- if (!reverse[1]) {
725
- reverse[1] = "全";
726
- }
727
- if (data.long === null) {
728
- data.long = 30;
729
- }
730
- this.nicoScripts.reverse.push({
731
- start: comment.vpos,
732
- end: comment.vpos + (data.long * 100),
733
- target: reverse[1]
734
- });
735
- break;
736
- case "コメント禁止":
737
- if (data.long === null) {
738
- data.long = 30;
739
- }
740
- this.nicoScripts.reverse.push({
741
- start: comment.vpos,
742
- end: comment.vpos + (data.long * 100),
743
- });
744
- break;
745
- case "置換":
746
- var content = comment.content.split(""), quote = "", last_i = "", string = "", result = [];
747
- for (var _i = 0, _a = content.slice(4); _i < _a.length; _i++) {
748
- var i = _a[_i];
749
- if (i.match(/["'「]/) && quote === "") {
750
- quote = i;
751
- }
752
- else if (i.match(/["']/) && quote === i && last_i !== "\\") {
753
- result.push(replaceAll(string, "\\n", "\n"));
754
- quote = "";
755
- string = "";
756
- }
757
- else if (i.match(/」/) && quote === "「") {
758
- result.push(string);
759
- quote = "";
760
- string = "";
761
- }
762
- else if (quote === "" && i.match(/[\s ]/)) {
763
- if (string) {
764
- result.push(string);
765
- string = "";
766
- }
767
- }
768
- else {
769
- string += i;
770
- }
771
- last_i = i;
772
- }
773
- result.push(string);
774
- this.nicoScripts.replace.push({
775
- start: comment.vpos,
776
- long: data.long === null ? null : Math.floor(data.long * 100),
777
- keyword: result[0],
778
- replace: result[1] || "",
779
- range: result[2] || "単",
780
- target: result[3] || "コメ",
781
- condition: result[4] || "部分一致",
782
- color: data.color,
783
- size: data.size,
784
- font: data.font,
785
- loc: data.loc
786
- });
787
- break;
788
- }
789
- data.invisible = true;
790
- }
791
- var color = "#FFFFFF", size = "medium", font = "defont", loc = "naka";
792
- for (var i in this.nicoScripts.default) {
793
- if (this.nicoScripts.default[i].long !== null && this.nicoScripts.default[i].start + this.nicoScripts.default[i].long < comment.vpos) {
794
- this.nicoScripts.default = this.nicoScripts.default.splice(Number(i), 1);
795
- continue;
796
- }
797
- if (this.nicoScripts.default[i].loc) {
798
- loc = this.nicoScripts.default[i].loc;
799
- }
800
- if (this.nicoScripts.default[i].color) {
801
- color = this.nicoScripts.default[i].color;
802
- }
803
- if (this.nicoScripts.default[i].size) {
804
- size = this.nicoScripts.default[i].size;
805
- }
806
- if (this.nicoScripts.default[i].font) {
807
- font = this.nicoScripts.default[i].font;
808
- }
809
- }
810
- for (var i in this.nicoScripts.replace) {
811
- if (this.nicoScripts.replace[i].long !== null && this.nicoScripts.replace[i].start + this.nicoScripts.replace[i].long < comment.vpos) {
812
- this.nicoScripts.default = this.nicoScripts.default.splice(Number(i), 1);
813
- continue;
814
- }
815
- var item = this.nicoScripts.replace[i];
816
- if ((item.target === "コメ" && comment.owner) || (item.target === "投コメ" && !comment.owner) || (item.target === "含まない" && comment.owner))
817
- continue;
818
- if ((item.condition === "完全一致" && comment.content === item.keyword) || (item.condition === "部分一致" && comment.content.indexOf(item.keyword) !== -1)) {
819
- if (item.range === "単") {
820
- comment.content = replaceAll(comment.content, item.keyword, item.replace);
821
- }
822
- else {
823
- comment.content = item.replace;
824
- }
825
- if (item.loc) {
826
- loc = item.loc;
827
- }
828
- if (item.color) {
829
- color = item.color;
830
- }
831
- if (item.size) {
832
- size = item.size;
833
- }
834
- if (item.font) {
835
- font = item.font;
836
- }
837
- }
838
- }
839
- if (!data.loc) {
840
- data.loc = loc;
841
- }
842
- if (!data.color) {
843
- data.color = color;
844
- }
845
- if (!data.size) {
846
- data.size = size;
847
- data.fontSize = this.fontSize[data.size].default;
848
- }
849
- if (!data.font) {
850
- data.font = font;
851
- }
852
- if (data.loc !== "naka") {
853
- if (!data.long) {
854
- data.long = 300;
855
- }
856
- else {
857
- data.long = Math.floor(data.long * 100);
858
- }
859
- }
860
- return _assign(_assign({}, comment), data);
861
- };
862
- NiconiComments.prototype.drawCanvas = function (vpos) {
863
- var drawCanvasStart = performance.now();
864
- if (this.lastVpos === vpos)
865
- return;
866
- this.lastVpos = vpos;
867
- this.fpsCount++;
868
- this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
869
- if (this.video) {
870
- var offsetX = void 0, offsetY = void 0, scale = void 0, height = this.canvas.height / this.video.videoHeight, width = this.canvas.width / this.video.videoWidth;
871
- if (height > width) {
872
- scale = width;
873
- }
874
- else {
875
- scale = height;
876
- }
877
- offsetX = (this.canvas.width - this.video.videoWidth * scale) * 0.5;
878
- offsetY = (this.canvas.height - this.video.videoHeight * scale) * 0.5;
879
- this.context.drawImage(this.video, offsetX, offsetY, this.video.videoWidth * scale, this.video.videoHeight * scale);
880
- }
881
- if (this.timeline[vpos]) {
882
- for (var i in this.timeline[vpos]) {
883
- var index = this.timeline[vpos][Number(i)];
884
- var comment = this.data[index];
885
- if (!comment || comment.invisible || comment.content.match(/^[\u200B-\u200D\uFEFF\u3164\s]*$/)) {
886
- continue;
887
- }
888
- if (comment.image === undefined) {
889
- this.getTextImage(index);
890
- }
891
- try {
892
- this.drawText(comment, vpos);
893
- }
894
- catch (e) {
895
- comment.image = false;
896
- }
897
- }
898
- }
899
- if (this.showFPS) {
900
- this.context.font = parseFont("defont", 60, this.useLegacy);
901
- this.context.fillStyle = "#00FF00";
902
- this.context.strokeText("FPS:" + this.fps, 100, 100);
903
- this.context.fillText("FPS:" + this.fps, 100, 100);
904
- }
905
- if (this.showCommentCount) {
906
- this.context.font = parseFont("defont", 60, this.useLegacy);
907
- this.context.fillStyle = "#00FF00";
908
- if (this.timeline[vpos]) {
909
- this.context.strokeText("Count:" + this.timeline[vpos].length, 100, 200);
910
- this.context.fillText("Count:" + this.timeline[vpos].length, 100, 200);
911
- }
912
- else {
913
- this.context.strokeText("Count:0", 100, 200);
914
- this.context.fillText("Count:0", 100, 200);
915
- }
916
- }
917
- logger("drawCanvas complete: ".concat(performance.now() - drawCanvasStart, "ms"));
918
- };
919
- NiconiComments.prototype.clear = function () {
920
- this.context.clearRect(0, 0, 1920, 1080);
921
- };
922
- return NiconiComments;
923
- }());
924
- var groupBy = function (array, key, key2) {
925
- var data = {};
926
- for (var i in array) {
927
- if (!data[array[i][key]]) {
928
- data[array[i][key]] = {};
929
- }
930
- if (!data[array[i][key]][array[i][key2]]) {
931
- data[array[i][key]][array[i][key2]] = [];
932
- }
933
- array[i].index = i;
934
- data[array[i][key]][array[i][key2]].push(array[i]);
935
- }
936
- return data;
937
- };
938
- var parseFont = function (font, size, useLegacy) {
939
- switch (font) {
940
- case "gothic":
941
- return "normal 400 ".concat(size, "px \"\u6E38\u30B4\u30B7\u30C3\u30AF\u4F53\", \"\u6E38\u30B4\u30B7\u30C3\u30AF\", \"Yu Gothic\", YuGothic, yugothic, YuGo-Medium");
942
- case "mincho":
943
- return "normal 400 ".concat(size, "px \"\u6E38\u660E\u671D\u4F53\", \"\u6E38\u660E\u671D\", \"Yu Mincho\", YuMincho, yumincho, YuMin-Medium");
944
- default:
945
- if (useLegacy) {
946
- return "normal 600 ".concat(size, "px Arial, \"\uFF2D\uFF33 \uFF30\u30B4\u30B7\u30C3\u30AF\", \"MS PGothic\", MSPGothic, MS-PGothic");
947
- }
948
- else {
949
- return "normal 600 ".concat(size, "px sans-serif, Arial, \"\uFF2D\uFF33 \uFF30\u30B4\u30B7\u30C3\u30AF\", \"MS PGothic\", MSPGothic, MS-PGothic");
950
- }
951
- }
952
- };
953
- var arrayPush = function (array, key, push) {
954
- if (!array) {
955
- array = {};
956
- }
957
- if (!array[key]) {
958
- array[key] = [];
959
- }
960
- array[key].push(push);
961
- };
962
- var hex2rgb = function (hex) {
963
- if (hex.slice(0, 1) === "#")
964
- hex = hex.slice(1);
965
- if (hex.length === 3)
966
- hex = hex.slice(0, 1) + hex.slice(0, 1) + hex.slice(1, 2) + hex.slice(1, 2) + hex.slice(2, 3) + hex.slice(2, 3);
967
- return [hex.slice(0, 2), hex.slice(2, 4), hex.slice(4, 6)].map(function (str) {
968
- return parseInt(str, 16);
969
- });
970
- };
971
- var replaceAll = function (string, target, replace) {
972
- var count = 0;
973
- while (string.indexOf(target) !== -1 && count < 100) {
974
- string = string.replace(target, replace);
975
- count++;
976
- }
977
- return string;
978
- };
979
- var isApiChat = function (item) {
980
- return !!item.chat;
981
- };
982
- var logger = function (msg) {
983
- if (isDebug)
984
- console.debug(msg);
28
+ var isDebug = false;
29
+ var NiconiComments = (function () {
30
+ function NiconiComments(canvas, data, options) {
31
+ if (options === void 0) { options = {
32
+ useLegacy: false,
33
+ formatted: false,
34
+ video: null,
35
+ showCollision: false,
36
+ showFPS: false,
37
+ showCommentCount: false,
38
+ drawAllImageOnLoad: false,
39
+ debug: false
40
+ }; }
41
+ var _this = this;
42
+ isDebug = options.debug;
43
+ var constructorStart = performance.now();
44
+ this.canvas = canvas;
45
+ var context = canvas.getContext("2d");
46
+ if (!context)
47
+ throw new Error("Fail to get CanvasRenderingContext2D");
48
+ this.context = context;
49
+ this.context.strokeStyle = "rgba(0,0,0,0.7)";
50
+ this.context.textAlign = "start";
51
+ this.context.textBaseline = "alphabetic";
52
+ this.context.lineWidth = 4;
53
+ this.commentYPaddingTop = 0.08;
54
+ this.commentYMarginBottom = 0.24;
55
+ this.fontSize = {
56
+ "small": {
57
+ "default": 47,
58
+ "resized": 26.1
59
+ },
60
+ "medium": {
61
+ "default": 74,
62
+ "resized": 38.7
63
+ },
64
+ "big": {
65
+ "default": 110,
66
+ "resized": 61
67
+ }
68
+ };
69
+ this.lineHeight = {
70
+ "small": {
71
+ "default": 1,
72
+ "resized": 1
73
+ },
74
+ "medium": {
75
+ "default": 1,
76
+ "resized": 1
77
+ },
78
+ "big": {
79
+ "default": 1.03,
80
+ "resized": 1.01
81
+ }
82
+ };
83
+ this.doubleResizeMaxWidth = {
84
+ full: {
85
+ legacy: 3020,
86
+ default: 3220
87
+ },
88
+ normal: {
89
+ legacy: 2540,
90
+ default: 2740
91
+ }
92
+ };
93
+ var parsedData = options.formatted ? data : this.parseData(data);
94
+ this.video = options.video ? options.video : null;
95
+ this.showCollision = options.showCollision;
96
+ this.showFPS = options.showFPS;
97
+ this.showCommentCount = options.showCommentCount;
98
+ this.timeline = {};
99
+ this.nicoScripts = { reverse: [], default: [], replace: [], ban: [] };
100
+ this.collision_right = {};
101
+ this.collision_left = {};
102
+ this.collision_ue = {};
103
+ this.collision_shita = {};
104
+ this.data = [];
105
+ this.lastVpos = -1;
106
+ this.useLegacy = options.useLegacy;
107
+ this.preRendering(parsedData, options.drawAllImageOnLoad);
108
+ this.fpsCount = 0;
109
+ this.fps = 0;
110
+ window.setInterval(function () {
111
+ _this.fps = _this.fpsCount * 2;
112
+ _this.fpsCount = 0;
113
+ }, 500);
114
+ logger("constructor complete: ".concat(performance.now() - constructorStart, "ms"));
115
+ }
116
+ NiconiComments.prototype.parseData = function (data) {
117
+ var parseDataStart = performance.now();
118
+ var data_ = [];
119
+ for (var i = 0; i < data.length; i++) {
120
+ for (var key in data[i]) {
121
+ var val = data[i];
122
+ if (!val)
123
+ continue;
124
+ var value = val[key];
125
+ if (isApiChat(value) && value["deleted"] !== 1) {
126
+ var tmpParam = {
127
+ "id": value["no"],
128
+ "vpos": value["vpos"],
129
+ "content": value["content"],
130
+ "date": value["date"],
131
+ "date_usec": value["date_usec"],
132
+ "owner": !value["user_id"],
133
+ "premium": value["premium"] === 1,
134
+ "mail": []
135
+ };
136
+ if (value["mail"]) {
137
+ tmpParam["mail"] = value["mail"].split(/[\s ]/g);
138
+ }
139
+ if (value["content"].startsWith("/") && !value["user_id"]) {
140
+ tmpParam["mail"].push("invisible");
141
+ }
142
+ data_.push(tmpParam);
143
+ }
144
+ }
145
+ }
146
+ data_.sort(function (a, b) {
147
+ if (a.vpos < b.vpos)
148
+ return -1;
149
+ if (a.vpos > b.vpos)
150
+ return 1;
151
+ if (a.date < b.date)
152
+ return -1;
153
+ if (a.date > b.date)
154
+ return 1;
155
+ if (a.date_usec < b.date_usec)
156
+ return -1;
157
+ if (a.date_usec > b.date_usec)
158
+ return 1;
159
+ return 0;
160
+ });
161
+ logger("parseData complete: ".concat(performance.now() - parseDataStart, "ms"));
162
+ return data_;
163
+ };
164
+ NiconiComments.prototype.preRendering = function (rawData, drawAll) {
165
+ var preRenderingStart = performance.now();
166
+ var parsedData = this.getCommentPos(this.getCommentSize(this.getFont(rawData)));
167
+ this.data = this.sortComment(parsedData);
168
+ if (drawAll) {
169
+ for (var i in parsedData) {
170
+ this.getTextImage(Number(i));
171
+ }
172
+ }
173
+ logger("preRendering complete: ".concat(performance.now() - preRenderingStart, "ms"));
174
+ };
175
+ NiconiComments.prototype.getFont = function (parsedData) {
176
+ var getFontStart = performance.now();
177
+ var result = [];
178
+ for (var i in parsedData) {
179
+ var value = parsedData[i];
180
+ if (!value)
181
+ continue;
182
+ value.content = value.content.replace(/\t/g, "\u2003\u2003");
183
+ result[i] = this.parseCommandAndNicoscript(value);
184
+ }
185
+ logger("getFont complete: ".concat(performance.now() - getFontStart, "ms"));
186
+ return result;
187
+ };
188
+ NiconiComments.prototype.getCommentSize = function (parsedData) {
189
+ var getCommentSizeStart = performance.now();
190
+ var tmpData = groupBy(parsedData, "font", "fontSize");
191
+ var result = [];
192
+ for (var i in tmpData) {
193
+ for (var j in tmpData[i]) {
194
+ this.context.font = parseFont(i, j, this.useLegacy);
195
+ for (var k in tmpData[i][j]) {
196
+ var comment = tmpData[i][j][k];
197
+ if (comment.invisible) {
198
+ continue;
199
+ }
200
+ var measure = this.measureText(comment);
201
+ var size = parsedData[comment.index];
202
+ size.height = measure.height;
203
+ size.width = measure.width;
204
+ size.width_max = measure.width_max;
205
+ size.width_min = measure.width_min;
206
+ size.lineHeight = measure.lineHeight;
207
+ if (measure.resized) {
208
+ size.fontSize = measure.fontSize;
209
+ this.context.font = parseFont(i, j, this.useLegacy);
210
+ }
211
+ result[comment.index] = size;
212
+ }
213
+ }
214
+ }
215
+ logger("getCommentSize complete: ".concat(performance.now() - getCommentSizeStart, "ms"));
216
+ return result;
217
+ };
218
+ NiconiComments.prototype.getCommentPos = function (parsedData) {
219
+ var getCommentPosStart = performance.now();
220
+ var data = parsedData;
221
+ for (var i in data) {
222
+ var comment = data[i];
223
+ if (!comment || comment.invisible) {
224
+ continue;
225
+ }
226
+ for (var j = 0; j < 500; j++) {
227
+ if (!this.timeline[comment.vpos + j]) {
228
+ this.timeline[comment.vpos + j] = [];
229
+ }
230
+ if (!this.collision_right[comment.vpos + j]) {
231
+ this.collision_right[comment.vpos + j] = [];
232
+ }
233
+ if (!this.collision_left[comment.vpos + j]) {
234
+ this.collision_left[comment.vpos + j] = [];
235
+ }
236
+ if (!this.collision_ue[comment.vpos + j]) {
237
+ this.collision_ue[comment.vpos + j] = [];
238
+ }
239
+ if (!this.collision_shita[comment.vpos + j]) {
240
+ this.collision_shita[comment.vpos + j] = [];
241
+ }
242
+ }
243
+ if (comment.loc === "naka") {
244
+ comment.vpos -= 70;
245
+ parsedData[i].vpos -= 70;
246
+ var posY = 0, is_break = false, is_change = true, count = 0;
247
+ if (1080 < comment.height) {
248
+ posY = (comment.height - 1080) / -2;
249
+ }
250
+ else {
251
+ while (is_change && count < 10) {
252
+ is_change = false;
253
+ count++;
254
+ for (var j = 0; j < 500; j++) {
255
+ var vpos = comment.vpos + j;
256
+ var left_pos = 1920 - ((1920 + comment.width_max) * j / 500);
257
+ if (left_pos + comment.width_max >= 1880) {
258
+ for (var k in this.collision_right[vpos]) {
259
+ var l = this.collision_right[vpos][k];
260
+ if ((posY < data[l].posY + data[l].height && posY + comment.height > data[l].posY) && data[l].owner === comment.owner) {
261
+ if (data[l].posY + data[l].height > posY) {
262
+ posY = data[l].posY + data[l].height;
263
+ is_change = true;
264
+ }
265
+ if (posY + comment.height > 1080) {
266
+ if (1080 < comment.height) {
267
+ posY = (comment.height - 1080) / -2;
268
+ }
269
+ else {
270
+ posY = Math.floor(Math.random() * (1080 - comment.height));
271
+ }
272
+ is_break = true;
273
+ break;
274
+ }
275
+ }
276
+ }
277
+ if (is_break) {
278
+ break;
279
+ }
280
+ }
281
+ if (left_pos <= 40) {
282
+ for (var k in this.collision_left[vpos]) {
283
+ var l = this.collision_left[vpos][k];
284
+ if ((posY < data[l].posY + data[l].height && posY + comment.height > data[l].posY) && data[l].owner === comment.owner) {
285
+ if (data[l].posY + data[l].height > posY) {
286
+ posY = data[l].posY + data[l].height;
287
+ is_change = true;
288
+ }
289
+ if (posY + comment.height > 1080) {
290
+ if (1080 < comment.height) {
291
+ posY = 0;
292
+ }
293
+ else {
294
+ posY = Math.random() * (1080 - comment.height);
295
+ }
296
+ is_break = true;
297
+ break;
298
+ }
299
+ }
300
+ }
301
+ if (is_break) {
302
+ break;
303
+ }
304
+ }
305
+ }
306
+ if (is_break) {
307
+ break;
308
+ }
309
+ }
310
+ }
311
+ for (var j = 0; j < 500; j++) {
312
+ var vpos = comment.vpos + j;
313
+ var left_pos = 1920 - ((1920 + comment.width_max) * j / 500);
314
+ arrayPush(this.timeline, vpos, i);
315
+ if (left_pos + comment.width_max >= 1880) {
316
+ arrayPush(this.collision_right, vpos, i);
317
+ }
318
+ if (left_pos <= 40) {
319
+ arrayPush(this.collision_left, vpos, i);
320
+ }
321
+ }
322
+ parsedData[i].posY = posY;
323
+ }
324
+ else {
325
+ var posY = 0, is_break = false, is_change = true, count = 0, collision = void 0;
326
+ if (comment.loc === "ue") {
327
+ collision = this.collision_ue;
328
+ }
329
+ else if (comment.loc === "shita") {
330
+ collision = this.collision_shita;
331
+ }
332
+ while (is_change && count < 10) {
333
+ is_change = false;
334
+ count++;
335
+ for (var j = 0; j < 300; j++) {
336
+ var vpos = comment.vpos + j;
337
+ for (var k in collision[vpos]) {
338
+ var l = collision[vpos][k];
339
+ if ((posY < data[l].posY + data[l].height && posY + comment.height > data[l].posY) && data[l].owner === comment.owner) {
340
+ if (data[l].posY + data[l].height > posY) {
341
+ posY = data[l].posY + data[l].height;
342
+ is_change = true;
343
+ }
344
+ if (posY + comment.height > 1080) {
345
+ if (1000 <= comment.height) {
346
+ posY = 0;
347
+ }
348
+ else {
349
+ posY = Math.floor(Math.random() * (1080 - comment.height));
350
+ }
351
+ is_break = true;
352
+ break;
353
+ }
354
+ }
355
+ }
356
+ if (is_break) {
357
+ break;
358
+ }
359
+ }
360
+ }
361
+ for (var j = 0; j < comment.long; j++) {
362
+ var vpos = comment.vpos + j;
363
+ arrayPush(this.timeline, vpos, i);
364
+ if (comment.loc === "ue") {
365
+ arrayPush(this.collision_ue, vpos, i);
366
+ }
367
+ else {
368
+ arrayPush(this.collision_shita, vpos, i);
369
+ }
370
+ }
371
+ parsedData[i].posY = posY;
372
+ }
373
+ }
374
+ logger("getCommentPos complete: ".concat(performance.now() - getCommentPosStart, "ms"));
375
+ return parsedData;
376
+ };
377
+ NiconiComments.prototype.sortComment = function (parsedData) {
378
+ var sortCommentStart = performance.now();
379
+ for (var vpos in this.timeline) {
380
+ if (!this.timeline[vpos])
381
+ continue;
382
+ var owner = [], user = [];
383
+ for (var _i = 0, _a = this.timeline[vpos]; _i < _a.length; _i++) {
384
+ var i = _a[_i];
385
+ if (parsedData[i].owner) {
386
+ owner.push(i);
387
+ }
388
+ else {
389
+ user.push(i);
390
+ }
391
+ }
392
+ this.timeline[vpos] = owner.concat(user);
393
+ }
394
+ logger("parseData complete: ".concat(performance.now() - sortCommentStart, "ms"));
395
+ return parsedData;
396
+ };
397
+ NiconiComments.prototype.measureText = function (comment) {
398
+ var width, width_max, width_min, height, width_arr = [], lines = comment.content.split("\n");
399
+ if (!comment.lineHeight)
400
+ comment.lineHeight = this.lineHeight[comment.size].default;
401
+ if (!comment.resized && !comment.ender) {
402
+ if (comment.size === "big" && lines.length > 2) {
403
+ comment.fontSize = this.fontSize.big.resized;
404
+ comment.lineHeight = this.lineHeight.big.resized;
405
+ comment.resized = true;
406
+ comment.tateresized = true;
407
+ this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
408
+ }
409
+ else if (comment.size === "medium" && lines.length > 4) {
410
+ comment.fontSize = this.fontSize.medium.resized;
411
+ comment.lineHeight = this.lineHeight.medium.resized;
412
+ comment.resized = true;
413
+ comment.tateresized = true;
414
+ this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
415
+ }
416
+ else if (comment.size === "small" && lines.length > 6) {
417
+ comment.fontSize = this.fontSize.small.resized;
418
+ comment.lineHeight = this.lineHeight.small.resized;
419
+ comment.resized = true;
420
+ comment.tateresized = true;
421
+ this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
422
+ }
423
+ }
424
+ for (var i = 0; i < lines.length; i++) {
425
+ var measure = this.context.measureText(lines[i]);
426
+ width_arr.push(measure.width);
427
+ }
428
+ width = width_arr.reduce(function (p, c) { return p + c; }, 0) / width_arr.length;
429
+ width_max = Math.max.apply(Math, width_arr);
430
+ width_min = Math.min.apply(Math, width_arr);
431
+ height = (comment.fontSize * comment.lineHeight * (1 + this.commentYPaddingTop) * lines.length) + (this.commentYMarginBottom * comment.fontSize);
432
+ if (comment.loc !== "naka" && !comment.tateresized) {
433
+ if (comment.full && width_max > 1930) {
434
+ comment.fontSize -= 2;
435
+ comment.resized = true;
436
+ comment.yokoResized = true;
437
+ this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
438
+ return this.measureText(comment);
439
+ }
440
+ else if (!comment.full && width_max > 1440) {
441
+ comment.fontSize -= 1;
442
+ comment.resized = true;
443
+ comment.yokoResized = true;
444
+ this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
445
+ return this.measureText(comment);
446
+ }
447
+ }
448
+ else if (comment.loc !== "naka" && comment.tateresized && (comment.full && width_max > 2120 || !comment.full && width_max > 1440) && !comment.yokoResized) {
449
+ comment.fontSize = this.fontSize[comment.size].default;
450
+ comment.resized = true;
451
+ comment.yokoResized = true;
452
+ this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
453
+ return this.measureText(comment);
454
+ }
455
+ else if (comment.loc !== "naka" && comment.tateresized && comment.yokoResized) {
456
+ if (comment.full && width_max > this.doubleResizeMaxWidth.full[this.useLegacy ? "legacy" : "default"]) {
457
+ comment.fontSize -= 1;
458
+ this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
459
+ return this.measureText(comment);
460
+ }
461
+ else if (!comment.full && width_max > this.doubleResizeMaxWidth.normal[this.useLegacy ? "legacy" : "default"]) {
462
+ comment.fontSize -= 1;
463
+ this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
464
+ return this.measureText(comment);
465
+ }
466
+ }
467
+ return {
468
+ "width": width,
469
+ "width_max": width_max,
470
+ "width_min": width_min,
471
+ "height": height,
472
+ "resized": comment.resized,
473
+ "fontSize": comment.fontSize,
474
+ "lineHeight": comment.lineHeight
475
+ };
476
+ };
477
+ NiconiComments.prototype.drawText = function (comment, vpos) {
478
+ var reverse = false;
479
+ for (var i in this.nicoScripts.reverse) {
480
+ var range = this.nicoScripts.reverse[i];
481
+ if ((range.target === "コメ" && comment.owner) || (range.target === "投コメ" && !comment.owner)) {
482
+ break;
483
+ }
484
+ if (range.start < vpos && vpos < range.end) {
485
+ reverse = true;
486
+ }
487
+ }
488
+ for (var i in this.nicoScripts.ban) {
489
+ var range = this.nicoScripts.ban[i];
490
+ if (range.start < vpos && vpos < range.end) {
491
+ return;
492
+ }
493
+ }
494
+ var posX = (1920 - comment.width_max) / 2, posY = comment.posY;
495
+ if (comment.loc === "naka") {
496
+ if (reverse) {
497
+ posX = ((1920 + comment.width_max) * (vpos - comment.vpos) / 500) - comment.width_max;
498
+ }
499
+ else {
500
+ posX = 1920 - ((1920 + comment.width_max) * (vpos - comment.vpos) / 500);
501
+ }
502
+ }
503
+ else if (comment.loc === "shita") {
504
+ posY = 1080 - comment.posY - comment.height;
505
+ }
506
+ if (comment.image && comment.image !== true) {
507
+ this.context.drawImage(comment.image, posX, posY);
508
+ }
509
+ if (this.showCollision) {
510
+ this.context.strokeStyle = "rgba(0,255,255,1)";
511
+ this.context.strokeRect(posX, posY, comment.width_max, comment.height);
512
+ var lines = comment.content.split("\n");
513
+ for (var i in lines) {
514
+ var linePosY = (Number(i) + 1) * (comment.fontSize * comment.lineHeight) * (1 + this.commentYPaddingTop);
515
+ this.context.strokeStyle = "rgba(255,255,0,0.5)";
516
+ this.context.strokeRect(posX, posY + linePosY, comment.width_max, comment.fontSize * comment.lineHeight * -1);
517
+ }
518
+ }
519
+ };
520
+ NiconiComments.prototype.getTextImage = function (i) {
521
+ var _this = this;
522
+ var value = this.data[i];
523
+ if (!value || value.invisible)
524
+ return;
525
+ var image = document.createElement("canvas");
526
+ image.width = value.width_max;
527
+ image.height = value.height;
528
+ var context = image.getContext("2d");
529
+ if (!context)
530
+ throw new Error("Fail to get CanvasRenderingContext2D");
531
+ context.strokeStyle = "rgba(0,0,0,0.7)";
532
+ context.textAlign = "start";
533
+ context.textBaseline = "alphabetic";
534
+ context.lineWidth = 4;
535
+ context.font = parseFont(value.font, value.fontSize, this.useLegacy);
536
+ if (value._live) {
537
+ var rgb = hex2rgb(value.color);
538
+ context.fillStyle = "rgba(".concat(rgb[0], ",").concat(rgb[1], ",").concat(rgb[2], ",0.5)");
539
+ }
540
+ else {
541
+ context.fillStyle = value.color;
542
+ }
543
+ if (value.color === "#000000") {
544
+ context.strokeStyle = "rgba(255,255,255,0.7)";
545
+ }
546
+ var lines = value.content.split("\n");
547
+ for (var i_1 in lines) {
548
+ var line = lines[i_1], posY = void 0;
549
+ posY = (Number(i_1) + 1) * (value.fontSize * value.lineHeight) * (1 + this.commentYPaddingTop);
550
+ context.strokeText(line, 0, posY);
551
+ context.fillText(line, 0, posY);
552
+ }
553
+ this.data[i].image = image;
554
+ setTimeout(function () {
555
+ if (_this.data[i].image)
556
+ delete _this.data[i].image;
557
+ }, 5000);
558
+ };
559
+ NiconiComments.prototype.parseCommand = function (comment) {
560
+ var metadata = comment.mail, loc = null, size = null, fontSize = null, color = null, font = null, full = false, ender = false, _live = false, invisible = false, long = null;
561
+ for (var i in metadata) {
562
+ var command = metadata[i].toLowerCase();
563
+ var match = command.match(/^@([0-9.]+)/);
564
+ if (match) {
565
+ long = match[1];
566
+ }
567
+ if (loc === null) {
568
+ switch (command) {
569
+ case "ue":
570
+ loc = "ue";
571
+ break;
572
+ case "shita":
573
+ loc = "shita";
574
+ break;
575
+ }
576
+ }
577
+ if (size === null) {
578
+ switch (command) {
579
+ case "big":
580
+ size = "big";
581
+ fontSize = this.fontSize.big.default;
582
+ break;
583
+ case "small":
584
+ size = "small";
585
+ fontSize = this.fontSize.small.default;
586
+ break;
587
+ }
588
+ }
589
+ if (color === null) {
590
+ switch (command) {
591
+ case "white":
592
+ color = "#FFFFFF";
593
+ break;
594
+ case "red":
595
+ color = "#FF0000";
596
+ break;
597
+ case "pink":
598
+ color = "#FF8080";
599
+ break;
600
+ case "orange":
601
+ color = "#FFC000";
602
+ break;
603
+ case "yellow":
604
+ color = "#FFFF00";
605
+ break;
606
+ case "green":
607
+ color = "#00FF00";
608
+ break;
609
+ case "cyan":
610
+ color = "#00FFFF";
611
+ break;
612
+ case "blue":
613
+ color = "#0000FF";
614
+ break;
615
+ case "purple":
616
+ color = "#C000FF";
617
+ break;
618
+ case "black":
619
+ color = "#000000";
620
+ break;
621
+ case "white2":
622
+ case "niconicowhite":
623
+ color = "#CCCC99";
624
+ break;
625
+ case "red2":
626
+ case "truered":
627
+ color = "#CC0033";
628
+ break;
629
+ case "pink2":
630
+ color = "#FF33CC";
631
+ break;
632
+ case "orange2":
633
+ case "passionorange":
634
+ color = "#FF6600";
635
+ break;
636
+ case "yellow2":
637
+ case "madyellow":
638
+ color = "#999900";
639
+ break;
640
+ case "green2":
641
+ case "elementalgreen":
642
+ color = "#00CC66";
643
+ break;
644
+ case "cyan2":
645
+ color = "#00CCCC";
646
+ break;
647
+ case "blue2":
648
+ case "marineblue":
649
+ color = "#3399FF";
650
+ break;
651
+ case "purple2":
652
+ case "nobleviolet":
653
+ color = "#6633CC";
654
+ break;
655
+ case "black2":
656
+ color = "#666666";
657
+ break;
658
+ default:
659
+ var match_1 = command.match(/#[0-9a-z]{3,6}/);
660
+ if (match_1 && comment.premium) {
661
+ color = match_1[0].toUpperCase();
662
+ }
663
+ break;
664
+ }
665
+ }
666
+ if (font === null) {
667
+ switch (command) {
668
+ case "gothic":
669
+ font = "gothic";
670
+ break;
671
+ case "mincho":
672
+ font = "mincho";
673
+ break;
674
+ }
675
+ }
676
+ switch (command) {
677
+ case "full":
678
+ full = true;
679
+ break;
680
+ case "ender":
681
+ ender = true;
682
+ break;
683
+ case "_live":
684
+ _live = true;
685
+ break;
686
+ case "invisible":
687
+ invisible = true;
688
+ break;
689
+ }
690
+ }
691
+ return { loc: loc, size: size, fontSize: fontSize, color: color, font: font, full: full, ender: ender, _live: _live, invisible: invisible, long: long };
692
+ };
693
+ NiconiComments.prototype.parseCommandAndNicoscript = function (comment) {
694
+ var data = this.parseCommand(comment), nicoscript = comment.content.match(/^@(デフォルト|置換|逆|コメント禁止|シーク禁止|ジャンプ)/);
695
+ if (nicoscript) {
696
+ switch (nicoscript[1]) {
697
+ case "デフォルト":
698
+ this.nicoScripts.default.push({
699
+ start: comment.vpos,
700
+ long: data.long === null ? null : Math.floor(data.long * 100),
701
+ color: data.color,
702
+ size: data.size,
703
+ font: data.font,
704
+ loc: data.loc
705
+ });
706
+ break;
707
+ case "逆":
708
+ var reverse = comment.content.match(/^@逆 ?(全|コメ|投コメ)?/);
709
+ if (!reverse)
710
+ reverse = [];
711
+ if (!reverse[1]) {
712
+ reverse[1] = "全";
713
+ }
714
+ if (data.long === null) {
715
+ data.long = 30;
716
+ }
717
+ this.nicoScripts.reverse.push({
718
+ start: comment.vpos,
719
+ end: comment.vpos + (data.long * 100),
720
+ target: reverse[1]
721
+ });
722
+ break;
723
+ case "コメント禁止":
724
+ if (data.long === null) {
725
+ data.long = 30;
726
+ }
727
+ this.nicoScripts.reverse.push({
728
+ start: comment.vpos,
729
+ end: comment.vpos + (data.long * 100),
730
+ });
731
+ break;
732
+ case "置換":
733
+ var content = comment.content.split(""), quote = "", last_i = "", string = "", result = [];
734
+ for (var _i = 0, _a = content.slice(4); _i < _a.length; _i++) {
735
+ var i = _a[_i];
736
+ if (i.match(/["'「]/) && quote === "") {
737
+ quote = i;
738
+ }
739
+ else if (i.match(/["']/) && quote === i && last_i !== "\\") {
740
+ result.push(replaceAll(string, "\\n", "\n"));
741
+ quote = "";
742
+ string = "";
743
+ }
744
+ else if (i.match(/」/) && quote === "「") {
745
+ result.push(string);
746
+ quote = "";
747
+ string = "";
748
+ }
749
+ else if (quote === "" && i.match(/[\s ]/)) {
750
+ if (string) {
751
+ result.push(string);
752
+ string = "";
753
+ }
754
+ }
755
+ else {
756
+ string += i;
757
+ }
758
+ last_i = i;
759
+ }
760
+ result.push(string);
761
+ this.nicoScripts.replace.push({
762
+ start: comment.vpos,
763
+ long: data.long === null ? null : Math.floor(data.long * 100),
764
+ keyword: result[0],
765
+ replace: result[1] || "",
766
+ range: result[2] || "単",
767
+ target: result[3] || "コメ",
768
+ condition: result[4] || "部分一致",
769
+ color: data.color,
770
+ size: data.size,
771
+ font: data.font,
772
+ loc: data.loc
773
+ });
774
+ break;
775
+ }
776
+ data.invisible = true;
777
+ }
778
+ var color = "#FFFFFF", size = "medium", font = "defont", loc = "naka";
779
+ for (var i in this.nicoScripts.default) {
780
+ if (this.nicoScripts.default[i].long !== null && this.nicoScripts.default[i].start + this.nicoScripts.default[i].long < comment.vpos) {
781
+ this.nicoScripts.default = this.nicoScripts.default.splice(Number(i), 1);
782
+ continue;
783
+ }
784
+ if (this.nicoScripts.default[i].loc) {
785
+ loc = this.nicoScripts.default[i].loc;
786
+ }
787
+ if (this.nicoScripts.default[i].color) {
788
+ color = this.nicoScripts.default[i].color;
789
+ }
790
+ if (this.nicoScripts.default[i].size) {
791
+ size = this.nicoScripts.default[i].size;
792
+ }
793
+ if (this.nicoScripts.default[i].font) {
794
+ font = this.nicoScripts.default[i].font;
795
+ }
796
+ }
797
+ for (var i in this.nicoScripts.replace) {
798
+ if (this.nicoScripts.replace[i].long !== null && this.nicoScripts.replace[i].start + this.nicoScripts.replace[i].long < comment.vpos) {
799
+ this.nicoScripts.default = this.nicoScripts.default.splice(Number(i), 1);
800
+ continue;
801
+ }
802
+ var item = this.nicoScripts.replace[i];
803
+ if ((item.target === "コメ" && comment.owner) || (item.target === "投コメ" && !comment.owner) || (item.target === "含まない" && comment.owner))
804
+ continue;
805
+ if ((item.condition === "完全一致" && comment.content === item.keyword) || (item.condition === "部分一致" && comment.content.indexOf(item.keyword) !== -1)) {
806
+ if (item.range === "単") {
807
+ comment.content = replaceAll(comment.content, item.keyword, item.replace);
808
+ }
809
+ else {
810
+ comment.content = item.replace;
811
+ }
812
+ if (item.loc) {
813
+ loc = item.loc;
814
+ }
815
+ if (item.color) {
816
+ color = item.color;
817
+ }
818
+ if (item.size) {
819
+ size = item.size;
820
+ }
821
+ if (item.font) {
822
+ font = item.font;
823
+ }
824
+ }
825
+ }
826
+ if (!data.loc) {
827
+ data.loc = loc;
828
+ }
829
+ if (!data.color) {
830
+ data.color = color;
831
+ }
832
+ if (!data.size) {
833
+ data.size = size;
834
+ data.fontSize = this.fontSize[data.size].default;
835
+ }
836
+ if (!data.font) {
837
+ data.font = font;
838
+ }
839
+ if (data.loc !== "naka") {
840
+ if (!data.long) {
841
+ data.long = 300;
842
+ }
843
+ else {
844
+ data.long = Math.floor(data.long * 100);
845
+ }
846
+ }
847
+ return _assign(_assign({}, comment), data);
848
+ };
849
+ NiconiComments.prototype.drawCanvas = function (vpos) {
850
+ var drawCanvasStart = performance.now();
851
+ if (this.lastVpos === vpos)
852
+ return;
853
+ this.lastVpos = vpos;
854
+ this.fpsCount++;
855
+ this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
856
+ if (this.video) {
857
+ var offsetX = void 0, offsetY = void 0, scale = void 0, height = this.canvas.height / this.video.videoHeight, width = this.canvas.width / this.video.videoWidth;
858
+ if (height > width) {
859
+ scale = width;
860
+ }
861
+ else {
862
+ scale = height;
863
+ }
864
+ offsetX = (this.canvas.width - this.video.videoWidth * scale) * 0.5;
865
+ offsetY = (this.canvas.height - this.video.videoHeight * scale) * 0.5;
866
+ this.context.drawImage(this.video, offsetX, offsetY, this.video.videoWidth * scale, this.video.videoHeight * scale);
867
+ }
868
+ if (this.timeline[vpos]) {
869
+ for (var i in this.timeline[vpos]) {
870
+ var index = this.timeline[vpos][Number(i)];
871
+ var comment = this.data[index];
872
+ if (!comment || comment.invisible) {
873
+ continue;
874
+ }
875
+ if (comment.image === undefined) {
876
+ this.getTextImage(index);
877
+ }
878
+ try {
879
+ this.drawText(comment, vpos);
880
+ }
881
+ catch (e) {
882
+ comment.image = false;
883
+ }
884
+ }
885
+ }
886
+ if (this.showFPS) {
887
+ this.context.font = parseFont("defont", 60, this.useLegacy);
888
+ this.context.fillStyle = "#00FF00";
889
+ this.context.strokeStyle = "rgba(0,0,0,0.7)";
890
+ this.context.strokeText("FPS:" + this.fps, 100, 100);
891
+ this.context.fillText("FPS:" + this.fps, 100, 100);
892
+ }
893
+ if (this.showCommentCount) {
894
+ this.context.font = parseFont("defont", 60, this.useLegacy);
895
+ this.context.fillStyle = "#00FF00";
896
+ this.context.strokeStyle = "rgba(0,0,0,0.7)";
897
+ if (this.timeline[vpos]) {
898
+ this.context.strokeText("Count:" + this.timeline[vpos].length, 100, 200);
899
+ this.context.fillText("Count:" + this.timeline[vpos].length, 100, 200);
900
+ }
901
+ else {
902
+ this.context.strokeText("Count:0", 100, 200);
903
+ this.context.fillText("Count:0", 100, 200);
904
+ }
905
+ }
906
+ logger("drawCanvas complete: ".concat(performance.now() - drawCanvasStart, "ms"));
907
+ };
908
+ NiconiComments.prototype.clear = function () {
909
+ this.context.clearRect(0, 0, 1920, 1080);
910
+ };
911
+ return NiconiComments;
912
+ }());
913
+ var groupBy = function (array, key, key2) {
914
+ var data = {};
915
+ for (var i in array) {
916
+ if (!data[array[i][key]]) {
917
+ data[array[i][key]] = {};
918
+ }
919
+ if (!data[array[i][key]][array[i][key2]]) {
920
+ data[array[i][key]][array[i][key2]] = [];
921
+ }
922
+ array[i].index = i;
923
+ data[array[i][key]][array[i][key2]].push(array[i]);
924
+ }
925
+ return data;
926
+ };
927
+ var parseFont = function (font, size, useLegacy) {
928
+ switch (font) {
929
+ case "gothic":
930
+ return "normal 400 ".concat(size, "px \"\u6E38\u30B4\u30B7\u30C3\u30AF\u4F53\", \"\u6E38\u30B4\u30B7\u30C3\u30AF\", \"Yu Gothic\", YuGothic, yugothic, YuGo-Medium");
931
+ case "mincho":
932
+ return "normal 400 ".concat(size, "px \"\u6E38\u660E\u671D\u4F53\", \"\u6E38\u660E\u671D\", \"Yu Mincho\", YuMincho, yumincho, YuMin-Medium");
933
+ default:
934
+ if (useLegacy) {
935
+ return "normal 600 ".concat(size, "px Arial, \"\uFF2D\uFF33 \uFF30\u30B4\u30B7\u30C3\u30AF\", \"MS PGothic\", MSPGothic, MS-PGothic");
936
+ }
937
+ else {
938
+ return "normal 600 ".concat(size, "px sans-serif, Arial, \"\uFF2D\uFF33 \uFF30\u30B4\u30B7\u30C3\u30AF\", \"MS PGothic\", MSPGothic, MS-PGothic");
939
+ }
940
+ }
941
+ };
942
+ var arrayPush = function (array, key, push) {
943
+ if (!array) {
944
+ array = {};
945
+ }
946
+ if (!array[key]) {
947
+ array[key] = [];
948
+ }
949
+ array[key].push(push);
950
+ };
951
+ var hex2rgb = function (hex) {
952
+ if (hex.slice(0, 1) === "#")
953
+ hex = hex.slice(1);
954
+ if (hex.length === 3)
955
+ hex = hex.slice(0, 1) + hex.slice(0, 1) + hex.slice(1, 2) + hex.slice(1, 2) + hex.slice(2, 3) + hex.slice(2, 3);
956
+ return [hex.slice(0, 2), hex.slice(2, 4), hex.slice(4, 6)].map(function (str) {
957
+ return parseInt(str, 16);
958
+ });
959
+ };
960
+ var replaceAll = function (string, target, replace) {
961
+ var count = 0;
962
+ while (string.indexOf(target) !== -1 && count < 100) {
963
+ string = string.replace(target, replace);
964
+ count++;
965
+ }
966
+ return string;
967
+ };
968
+ var isApiChat = function (item) {
969
+ return !!item.chat;
970
+ };
971
+ var logger = function (msg) {
972
+ if (isDebug)
973
+ console.debug(msg);
985
974
  };
986
975
 
987
976
  return NiconiComments;