@xpadev-net/niconicomments 0.2.12 → 0.2.13

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.12
2
+ niconicomments.js v0.2.13
3
3
  (c) 2021 xpadev-net https://xpadev.net
4
4
  Released under the MIT License.
5
5
  */
@@ -25,952 +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": 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);
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);
974
974
  };
975
975
 
976
976
  return NiconiComments;