@xpadev-net/niconicomments 0.1.4 → 0.1.8
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/LICENSE +7 -7
- package/README.md +24 -24
- package/dist/bundle.js +364 -197
- package/package.json +31 -33
package/LICENSE
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
Copyright (c) 2021 xpadev https://xpadev.net
|
|
2
|
-
|
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
-
|
|
5
|
-
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
-
|
|
7
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
1
|
+
Copyright (c) 2021 xpadev https://xpadev.net
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
# [niconicomments](https://xpadev.net/niconicomments/)
|
|
2
|
-
[](https://github.com/xpadev-net/niconicomments/blob/master/LICENSE)
|
|
3
|
-
ニコニコ動画の公式プレイヤーに多少の互換性を持つコメント描画ライブラリです
|
|
4
|
-
This is a comment drawing library that is somewhat compatible with the official Nico Nico Douga player.
|
|
5
|
-
Reference: https://xpadev.net/niconicomments/docs/
|
|
6
|
-
Github: https://github.com/xpadev-net/niconicomments
|
|
7
|
-
|
|
8
|
-
## Installation
|
|
9
|
-
```html
|
|
10
|
-
<script src="https://cdn.jsdelivr.net/npm/@xpadev-net/niconicomments@latest/dist/bundle.min.js"></script>
|
|
11
|
-
```
|
|
12
|
-
or
|
|
13
|
-
```
|
|
14
|
-
npm i @xpadev-net/niconicomments
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Examples
|
|
18
|
-
```javascript
|
|
19
|
-
const niconiComments = new NiconiComments(canvas, comments);
|
|
20
|
-
niconiComments.drawCanvas(vpos)
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## Sample
|
|
24
|
-
https://xpadev.net/niconicomments/sample.html
|
|
1
|
+
# [niconicomments](https://xpadev.net/niconicomments/)
|
|
2
|
+
[](https://github.com/xpadev-net/niconicomments/blob/master/LICENSE)
|
|
3
|
+
ニコニコ動画の公式プレイヤーに多少の互換性を持つコメント描画ライブラリです
|
|
4
|
+
This is a comment drawing library that is somewhat compatible with the official Nico Nico Douga player.
|
|
5
|
+
Reference: https://xpadev.net/niconicomments/docs/
|
|
6
|
+
Github: https://github.com/xpadev-net/niconicomments
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
```html
|
|
10
|
+
<script src="https://cdn.jsdelivr.net/npm/@xpadev-net/niconicomments@latest/dist/bundle.min.js"></script>
|
|
11
|
+
```
|
|
12
|
+
or
|
|
13
|
+
```
|
|
14
|
+
npm i @xpadev-net/niconicomments
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Examples
|
|
18
|
+
```javascript
|
|
19
|
+
const niconiComments = new NiconiComments(canvas, comments);
|
|
20
|
+
niconiComments.drawCanvas(vpos)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Sample
|
|
24
|
+
https://xpadev.net/niconicomments/sample.html
|
package/dist/bundle.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
niconicomments.js v0.1.
|
|
2
|
+
niconicomments.js v0.1.8
|
|
3
3
|
(c) 2021 xpadev-net https://xpadevn.et
|
|
4
4
|
Released under the MIT License.
|
|
5
5
|
*/
|
|
@@ -10,42 +10,56 @@
|
|
|
10
10
|
})(this, (function () { 'use strict';
|
|
11
11
|
|
|
12
12
|
class NiconiComments {
|
|
13
|
-
/**
|
|
14
|
-
* NiconiComments Constructor
|
|
15
|
-
* @param {HTMLCanvasElement} canvas - 描画対象のキャンバス
|
|
16
|
-
* @param {[]} data - 描画用のコメント
|
|
17
|
-
* @param {boolean}
|
|
18
|
-
* @param {boolean} formatted - dataが独自フォーマットに変換されているか
|
|
13
|
+
/**
|
|
14
|
+
* NiconiComments Constructor
|
|
15
|
+
* @param {HTMLCanvasElement} canvas - 描画対象のキャンバス
|
|
16
|
+
* @param {[]} data - 描画用のコメント
|
|
17
|
+
* @param {{useLegacy: boolean, formatted: boolean, video: HTMLVideoElement|null}} options - 細かい設定類
|
|
19
18
|
*/
|
|
20
|
-
constructor(canvas, data,
|
|
19
|
+
constructor(canvas, data, options = {
|
|
20
|
+
useLegacy: false,
|
|
21
|
+
formatted: false,
|
|
22
|
+
video: null
|
|
23
|
+
}) {
|
|
21
24
|
this.canvas = canvas;
|
|
22
25
|
this.context = canvas.getContext("2d");
|
|
23
26
|
this.context.strokeStyle = "rgba(0,0,0,0.7)";
|
|
24
27
|
this.context.textAlign = "left";
|
|
25
28
|
this.context.textBaseline = "top";
|
|
26
|
-
this.context.lineWidth =
|
|
29
|
+
this.context.lineWidth = 4;
|
|
27
30
|
|
|
28
|
-
if (useLegacy) {
|
|
31
|
+
if (options.useLegacy) {
|
|
29
32
|
this.commentYOffset = 0.25;
|
|
30
33
|
} else {
|
|
31
|
-
this.commentYOffset = 0.
|
|
34
|
+
this.commentYOffset = 0.2;
|
|
32
35
|
}
|
|
33
36
|
|
|
34
|
-
this.commentYMarginTop =
|
|
37
|
+
this.commentYMarginTop = 0.08;
|
|
35
38
|
this.fontSize = {
|
|
36
39
|
"small": {
|
|
37
|
-
"default":
|
|
38
|
-
"resized":
|
|
40
|
+
"default": 47,
|
|
41
|
+
"resized": 27.5
|
|
39
42
|
},
|
|
40
43
|
"medium": {
|
|
41
|
-
"default":
|
|
42
|
-
"resized":
|
|
44
|
+
"default": 76,
|
|
45
|
+
"resized": 39
|
|
43
46
|
},
|
|
44
47
|
"big": {
|
|
45
|
-
"default":
|
|
46
|
-
"resized":
|
|
48
|
+
"default": 118,
|
|
49
|
+
"resized": 62.5
|
|
47
50
|
}
|
|
48
51
|
};
|
|
52
|
+
this.defaultCommandValue = {
|
|
53
|
+
loc: "naka",
|
|
54
|
+
size: "medium",
|
|
55
|
+
fontSize: this.fontSize.medium.default,
|
|
56
|
+
color: "#ffffff",
|
|
57
|
+
font: 'defont',
|
|
58
|
+
full: false,
|
|
59
|
+
ender: false,
|
|
60
|
+
_live: false,
|
|
61
|
+
invisible: false
|
|
62
|
+
};
|
|
49
63
|
this.doubleResizeMaxWidth = {
|
|
50
64
|
full: {
|
|
51
65
|
legacy: 3020,
|
|
@@ -57,24 +71,26 @@
|
|
|
57
71
|
}
|
|
58
72
|
};
|
|
59
73
|
|
|
60
|
-
if (formatted) {
|
|
74
|
+
if (options.formatted) {
|
|
61
75
|
this.data = data;
|
|
62
76
|
} else {
|
|
63
77
|
this.data = this.parseData(data);
|
|
64
78
|
}
|
|
65
79
|
|
|
80
|
+
this.video = options.video ? options.video : null;
|
|
66
81
|
this.showCollision = false;
|
|
67
82
|
this.showFPS = false;
|
|
68
83
|
this.showCommentCount = false;
|
|
69
84
|
this.timeline = {};
|
|
70
85
|
this.nicoScripts = {
|
|
71
|
-
"reverse": []
|
|
86
|
+
"reverse": [],
|
|
87
|
+
"default": []
|
|
72
88
|
};
|
|
73
89
|
this.collision_right = {};
|
|
74
90
|
this.collision_left = {};
|
|
75
91
|
this.collision_ue = {};
|
|
76
92
|
this.collision_shita = {};
|
|
77
|
-
this.useLegacy = useLegacy;
|
|
93
|
+
this.useLegacy = options.useLegacy;
|
|
78
94
|
this.preRendering();
|
|
79
95
|
this.fpsCount = 0;
|
|
80
96
|
this.fps = 0;
|
|
@@ -83,10 +99,10 @@
|
|
|
83
99
|
this.fpsCount = 0;
|
|
84
100
|
}, 500);
|
|
85
101
|
}
|
|
86
|
-
/**
|
|
87
|
-
* ニコニコが吐き出したデータを処理しやすいように変換する
|
|
88
|
-
* @param {[]} data - ニコニコが吐き出したコメントデータ
|
|
89
|
-
* @returns {*[]} - 独自フォーマットのコメントデータ
|
|
102
|
+
/**
|
|
103
|
+
* ニコニコが吐き出したデータを処理しやすいように変換する
|
|
104
|
+
* @param {[]} data - ニコニコが吐き出したコメントデータ
|
|
105
|
+
* @returns {*[]} - 独自フォーマットのコメントデータ
|
|
90
106
|
*/
|
|
91
107
|
|
|
92
108
|
|
|
@@ -130,8 +146,8 @@
|
|
|
130
146
|
});
|
|
131
147
|
return data_;
|
|
132
148
|
}
|
|
133
|
-
/**
|
|
134
|
-
* 事前に当たり判定を考慮してコメントの描画場所を決定する
|
|
149
|
+
/**
|
|
150
|
+
* 事前に当たり判定を考慮してコメントの描画場所を決定する
|
|
135
151
|
*/
|
|
136
152
|
|
|
137
153
|
|
|
@@ -139,16 +155,17 @@
|
|
|
139
155
|
this.getFont();
|
|
140
156
|
this.getCommentSize();
|
|
141
157
|
this.getCommentPos();
|
|
158
|
+
this.sortComment();
|
|
142
159
|
}
|
|
143
|
-
/**
|
|
144
|
-
* コマンドをもとに各コメントに適用するフォントを決定する
|
|
160
|
+
/**
|
|
161
|
+
* コマンドをもとに各コメントに適用するフォントを決定する
|
|
145
162
|
*/
|
|
146
163
|
|
|
147
164
|
|
|
148
165
|
getFont() {
|
|
149
166
|
for (let i in this.data) {
|
|
150
167
|
let comment = this.data[i];
|
|
151
|
-
let command = this.
|
|
168
|
+
let command = this.parseCommandAndNicoscript(comment);
|
|
152
169
|
this.data[i].loc = command.loc;
|
|
153
170
|
this.data[i].size = command.size;
|
|
154
171
|
this.data[i].fontSize = command.fontSize;
|
|
@@ -157,11 +174,13 @@
|
|
|
157
174
|
this.data[i].full = command.full;
|
|
158
175
|
this.data[i].ender = command.ender;
|
|
159
176
|
this.data[i]._live = command._live;
|
|
177
|
+
this.data[i].long = command.long;
|
|
178
|
+
this.data[i].invisible = command.invisible;
|
|
160
179
|
this.data[i].content = this.data[i].content.replaceAll("\t", " ");
|
|
161
180
|
}
|
|
162
181
|
}
|
|
163
|
-
/**
|
|
164
|
-
* コメントの描画サイズを計算する
|
|
182
|
+
/**
|
|
183
|
+
* コメントの描画サイズを計算する
|
|
165
184
|
*/
|
|
166
185
|
|
|
167
186
|
|
|
@@ -174,6 +193,11 @@
|
|
|
174
193
|
|
|
175
194
|
for (let k in tmpData[i][j]) {
|
|
176
195
|
let comment = tmpData[i][j][k];
|
|
196
|
+
|
|
197
|
+
if (comment.invisible) {
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
|
|
177
201
|
let measure = this.measureText(comment);
|
|
178
202
|
this.data[comment.index].height = measure.height;
|
|
179
203
|
this.data[comment.index].width = measure.width;
|
|
@@ -188,8 +212,8 @@
|
|
|
188
212
|
}
|
|
189
213
|
}
|
|
190
214
|
}
|
|
191
|
-
/**
|
|
192
|
-
* 計算された描画サイズをもとに各コメントの配置位置を決定する
|
|
215
|
+
/**
|
|
216
|
+
* 計算された描画サイズをもとに各コメントの配置位置を決定する
|
|
193
217
|
*/
|
|
194
218
|
|
|
195
219
|
|
|
@@ -199,6 +223,10 @@
|
|
|
199
223
|
for (let i in data) {
|
|
200
224
|
let comment = data[i];
|
|
201
225
|
|
|
226
|
+
if (comment.invisible) {
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
|
|
202
230
|
for (let j = 0; j < 500; j++) {
|
|
203
231
|
if (!this.timeline[comment.vpos + j]) {
|
|
204
232
|
this.timeline[comment.vpos + j] = [];
|
|
@@ -229,73 +257,77 @@
|
|
|
229
257
|
is_change = true,
|
|
230
258
|
count = 0;
|
|
231
259
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
260
|
+
if (1080 < comment.height) {
|
|
261
|
+
posY = (comment.height - 1080) / -2;
|
|
262
|
+
} else {
|
|
263
|
+
while (is_change && count < 10) {
|
|
264
|
+
is_change = false;
|
|
265
|
+
count++;
|
|
266
|
+
|
|
267
|
+
for (let j = 0; j < 500; j++) {
|
|
268
|
+
let vpos = comment.vpos + j;
|
|
269
|
+
let left_pos = 1920 - (1920 + comment.width_max) * j / 500;
|
|
270
|
+
|
|
271
|
+
if (left_pos + comment.width_max >= 1880) {
|
|
272
|
+
for (let k in this.collision_right[vpos]) {
|
|
273
|
+
let l = this.collision_right[vpos][k];
|
|
274
|
+
|
|
275
|
+
if (posY < data[l].posY + data[l].height && posY + comment.height > data[l].posY && data[l].owner === comment.owner) {
|
|
276
|
+
if (data[l].posY + data[l].height > posY) {
|
|
277
|
+
posY = data[l].posY + data[l].height;
|
|
278
|
+
is_change = true;
|
|
279
|
+
}
|
|
239
280
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
281
|
+
if (posY + comment.height > 1080) {
|
|
282
|
+
if (1080 < comment.height) {
|
|
283
|
+
posY = (comment.height - 1080) / -2;
|
|
284
|
+
} else {
|
|
285
|
+
posY = Math.floor(Math.random() * (1080 - comment.height));
|
|
286
|
+
}
|
|
243
287
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
posY = data[l].posY + data[l].height;
|
|
247
|
-
is_change = true;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
if (posY + comment.height > 1080) {
|
|
251
|
-
if (1080 < comment.height) {
|
|
252
|
-
posY = (comment.height - 1080) / -2;
|
|
253
|
-
} else {
|
|
254
|
-
posY = Math.floor(Math.random() * (1080 - comment.height));
|
|
288
|
+
is_break = true;
|
|
289
|
+
break;
|
|
255
290
|
}
|
|
256
|
-
|
|
257
|
-
is_break = true;
|
|
258
|
-
break;
|
|
259
291
|
}
|
|
260
292
|
}
|
|
261
|
-
}
|
|
262
293
|
|
|
263
|
-
|
|
264
|
-
|
|
294
|
+
if (is_break) {
|
|
295
|
+
break;
|
|
296
|
+
}
|
|
265
297
|
}
|
|
266
|
-
}
|
|
267
298
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
299
|
+
if (left_pos <= 40 && is_break === false) {
|
|
300
|
+
for (let k in this.collision_left[vpos]) {
|
|
301
|
+
let l = this.collision_left[vpos][k];
|
|
271
302
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
if (posY + comment.height > 1080) {
|
|
279
|
-
if (1080 < comment.height) {
|
|
280
|
-
posY = 0;
|
|
281
|
-
} else {
|
|
282
|
-
posY = Math.random() * (1080 - comment.height);
|
|
303
|
+
if (posY < data[l].posY + data[l].height && posY + comment.height > data[l].posY && data[l].owner === comment.owner) {
|
|
304
|
+
if (data[l].posY + data[l].height > posY) {
|
|
305
|
+
posY = data[l].posY + data[l].height;
|
|
306
|
+
is_change = true;
|
|
283
307
|
}
|
|
284
308
|
|
|
285
|
-
|
|
286
|
-
|
|
309
|
+
if (posY + comment.height > 1080) {
|
|
310
|
+
if (1080 < comment.height) {
|
|
311
|
+
posY = 0;
|
|
312
|
+
} else {
|
|
313
|
+
posY = Math.random() * (1080 - comment.height);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
is_break = true;
|
|
317
|
+
break;
|
|
318
|
+
}
|
|
287
319
|
}
|
|
288
320
|
}
|
|
321
|
+
|
|
322
|
+
if (is_break) {
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
289
325
|
}
|
|
290
326
|
|
|
291
327
|
if (is_break) {
|
|
292
328
|
break;
|
|
293
329
|
}
|
|
294
330
|
}
|
|
295
|
-
|
|
296
|
-
if (is_break) {
|
|
297
|
-
break;
|
|
298
|
-
}
|
|
299
331
|
}
|
|
300
332
|
}
|
|
301
333
|
|
|
@@ -362,7 +394,7 @@
|
|
|
362
394
|
}
|
|
363
395
|
}
|
|
364
396
|
|
|
365
|
-
for (let j = 0; j <
|
|
397
|
+
for (let j = 0; j < comment.long; j++) {
|
|
366
398
|
let vpos = comment.vpos + j;
|
|
367
399
|
arrayPush(this.timeline, vpos, i);
|
|
368
400
|
|
|
@@ -377,11 +409,28 @@
|
|
|
377
409
|
}
|
|
378
410
|
}
|
|
379
411
|
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
412
|
+
|
|
413
|
+
sortComment() {
|
|
414
|
+
for (let vpos in this.timeline) {
|
|
415
|
+
this.timeline[vpos].sort((a, b) => {
|
|
416
|
+
const A = this.data[a];
|
|
417
|
+
const B = this.data[b];
|
|
418
|
+
|
|
419
|
+
if (!A.owner && B.owner) {
|
|
420
|
+
return -1;
|
|
421
|
+
} else if (A.owner && !B.owner) {
|
|
422
|
+
return 1;
|
|
423
|
+
} else {
|
|
424
|
+
return 0;
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* context.measureTextの複数行対応版
|
|
431
|
+
* 画面外にはみ出すコメントの縮小も行う
|
|
432
|
+
* @param comment - 独自フォーマットのコメントデータ
|
|
433
|
+
* @returns {{resized: boolean, width: number, width_max: number, fontSize: number, width_min: number, height: number}} - 描画サイズとリサイズの情報
|
|
385
434
|
*/
|
|
386
435
|
|
|
387
436
|
|
|
@@ -420,7 +469,7 @@
|
|
|
420
469
|
width = width_arr.reduce((p, c) => p + c, 0) / width_arr.length;
|
|
421
470
|
width_max = Math.max(...width_arr);
|
|
422
471
|
width_min = Math.min(...width_arr);
|
|
423
|
-
height = (comment.fontSize + this.commentYMarginTop) * lines.length;
|
|
472
|
+
height = (comment.fontSize + this.commentYMarginTop * comment.fontSize) * lines.length;
|
|
424
473
|
|
|
425
474
|
if (comment.loc !== "naka" && !comment.tateRisized) {
|
|
426
475
|
if (comment.full && width_max > 1920) {
|
|
@@ -463,10 +512,10 @@
|
|
|
463
512
|
"fontSize": comment.fontSize
|
|
464
513
|
};
|
|
465
514
|
}
|
|
466
|
-
/**
|
|
467
|
-
* コマンドをもとに所定の位置にコメントを表示する
|
|
468
|
-
* @param comment - 独自フォーマットのコメントデータ
|
|
469
|
-
* @param {number} vpos - 動画の現在位置の100倍 ニコニコから吐き出されるコメントの位置情報は主にこれ
|
|
515
|
+
/**
|
|
516
|
+
* コマンドをもとに所定の位置にコメントを表示する
|
|
517
|
+
* @param comment - 独自フォーマットのコメントデータ
|
|
518
|
+
* @param {number} vpos - 動画の現在位置の100倍 ニコニコから吐き出されるコメントの位置情報は主にこれ
|
|
470
519
|
*/
|
|
471
520
|
|
|
472
521
|
|
|
@@ -488,32 +537,16 @@
|
|
|
488
537
|
let lines = comment.content.split("\n"),
|
|
489
538
|
posX = (1920 - comment.width_max) / 2;
|
|
490
539
|
|
|
491
|
-
if (comment.loc === "
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
this.context.fillText(line, posX, posY);
|
|
497
|
-
}
|
|
498
|
-
} else {
|
|
499
|
-
if (comment.loc === "naka") {
|
|
500
|
-
if (reverse) {
|
|
501
|
-
posX = (1920 + comment.width_max) * (vpos - comment.vpos) / 500 - comment.width_max;
|
|
502
|
-
} else {
|
|
503
|
-
posX = 1920 - (1920 + comment.width_max) * (vpos - comment.vpos) / 500;
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
for (let i in lines) {
|
|
508
|
-
let line = lines[i];
|
|
509
|
-
let posY = comment.posY + i * (comment.fontSize + this.commentYMarginTop) + this.commentYOffset * comment.fontSize;
|
|
510
|
-
this.context.strokeText(line, posX, posY);
|
|
511
|
-
this.context.fillText(line, posX, posY);
|
|
540
|
+
if (comment.loc === "naka") {
|
|
541
|
+
if (reverse) {
|
|
542
|
+
posX = (1920 + comment.width_max) * (vpos - comment.vpos) / 500 - comment.width_max;
|
|
543
|
+
} else {
|
|
544
|
+
posX = 1920 - (1920 + comment.width_max) * (vpos - comment.vpos) / 500;
|
|
512
545
|
}
|
|
513
546
|
}
|
|
514
547
|
|
|
515
548
|
if (this.showCollision) {
|
|
516
|
-
this.context.strokeStyle = "rgba(255,255,
|
|
549
|
+
this.context.strokeStyle = "rgba(0,255,255,1)";
|
|
517
550
|
|
|
518
551
|
if (comment.loc === "shita") {
|
|
519
552
|
this.context.strokeRect(posX, 1080 - comment.posY - comment.height, comment.width_max, comment.height);
|
|
@@ -521,60 +554,67 @@
|
|
|
521
554
|
this.context.strokeRect(posX, comment.posY, comment.width_max, comment.height);
|
|
522
555
|
}
|
|
523
556
|
|
|
524
|
-
|
|
557
|
+
if (comment.color === "#000000") {
|
|
558
|
+
this.context.strokeStyle = "rgba(255,255,255,0.7)";
|
|
559
|
+
} else {
|
|
560
|
+
this.context.strokeStyle = "rgba(0,0,0,0.7)";
|
|
561
|
+
}
|
|
525
562
|
}
|
|
526
|
-
}
|
|
527
|
-
/**
|
|
528
|
-
* コメントに含まれるコマンドを解釈する
|
|
529
|
-
* @param comment- 独自フォーマットのコメントデータ
|
|
530
|
-
* @returns {{loc: string, size: string, color: string, fontSize: number, ender: boolean, font: string, full: boolean, _live: boolean}}
|
|
531
|
-
*/
|
|
532
563
|
|
|
564
|
+
for (let i in lines) {
|
|
565
|
+
let line = lines[i],
|
|
566
|
+
posY;
|
|
533
567
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
fontSize = this.fontSize.medium.default,
|
|
539
|
-
color = "#ffffff",
|
|
540
|
-
font = 'defont',
|
|
541
|
-
full = false,
|
|
542
|
-
ender = false,
|
|
543
|
-
reverse = comment.content.match(/@逆 ?(全|コメ|投コメ)?/),
|
|
544
|
-
_live = false;
|
|
545
|
-
|
|
546
|
-
if (reverse) {
|
|
547
|
-
if (!reverse[1]) {
|
|
548
|
-
reverse[1] = "全";
|
|
568
|
+
if (comment.loc === "shita") {
|
|
569
|
+
posY = 1080 - comment.posY + i * (comment.fontSize + this.commentYMarginTop * comment.fontSize) - comment.height + this.commentYOffset * comment.fontSize;
|
|
570
|
+
} else {
|
|
571
|
+
posY = comment.posY + i * (comment.fontSize + this.commentYMarginTop * comment.fontSize) + this.commentYOffset * comment.fontSize;
|
|
549
572
|
}
|
|
550
573
|
|
|
551
|
-
|
|
574
|
+
this.context.strokeText(line, posX, posY);
|
|
575
|
+
this.context.fillText(line, posX, posY);
|
|
552
576
|
|
|
553
|
-
|
|
554
|
-
|
|
577
|
+
if (this.showCollision) {
|
|
578
|
+
this.context.strokeStyle = "rgba(255,255,0,0.5)";
|
|
579
|
+
this.context.strokeRect(posX, posY, comment.width_max, comment.fontSize);
|
|
555
580
|
|
|
556
|
-
if (
|
|
557
|
-
|
|
558
|
-
|
|
581
|
+
if (comment.color === "#000000") {
|
|
582
|
+
this.context.strokeStyle = "rgba(255,255,255,0.7)";
|
|
583
|
+
} else {
|
|
584
|
+
this.context.strokeStyle = "rgba(0,0,0,0.7)";
|
|
559
585
|
}
|
|
560
586
|
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
/**
|
|
590
|
+
* コメントに含まれるコマンドを解釈する
|
|
591
|
+
* @param comment- 独自フォーマットのコメントデータ
|
|
592
|
+
* @returns {{loc: string|null, size: string|null, color: string|null, fontSize: number|null, ender: boolean, font: string|null, full: boolean, _live: boolean, invisible: boolean, long:number|null}}
|
|
593
|
+
*/
|
|
561
594
|
|
|
562
|
-
if (!length) {
|
|
563
|
-
length = 30;
|
|
564
|
-
}
|
|
565
595
|
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
596
|
+
parseCommand(comment) {
|
|
597
|
+
let metadata = comment.mail,
|
|
598
|
+
loc = null,
|
|
599
|
+
size = null,
|
|
600
|
+
fontSize = null,
|
|
601
|
+
color = null,
|
|
602
|
+
font = null,
|
|
603
|
+
full = false,
|
|
604
|
+
ender = false,
|
|
605
|
+
_live = false,
|
|
606
|
+
invisible = false,
|
|
607
|
+
long = null;
|
|
573
608
|
|
|
574
609
|
for (let i in metadata) {
|
|
575
610
|
let command = metadata[i].toLowerCase();
|
|
611
|
+
const match = command.match(/^@([0-9.]+)/);
|
|
612
|
+
|
|
613
|
+
if (match) {
|
|
614
|
+
long = match[1];
|
|
615
|
+
}
|
|
576
616
|
|
|
577
|
-
if (loc ===
|
|
617
|
+
if (loc === null) {
|
|
578
618
|
switch (command) {
|
|
579
619
|
case "ue":
|
|
580
620
|
loc = "ue";
|
|
@@ -586,7 +626,7 @@
|
|
|
586
626
|
}
|
|
587
627
|
}
|
|
588
628
|
|
|
589
|
-
if (size ===
|
|
629
|
+
if (size === null) {
|
|
590
630
|
switch (command) {
|
|
591
631
|
case "big":
|
|
592
632
|
size = "big";
|
|
@@ -600,7 +640,7 @@
|
|
|
600
640
|
}
|
|
601
641
|
}
|
|
602
642
|
|
|
603
|
-
if (color ===
|
|
643
|
+
if (color === null) {
|
|
604
644
|
switch (command) {
|
|
605
645
|
case "white":
|
|
606
646
|
color = "#FFFFFF";
|
|
@@ -700,7 +740,7 @@
|
|
|
700
740
|
}
|
|
701
741
|
}
|
|
702
742
|
|
|
703
|
-
if (font ===
|
|
743
|
+
if (font === null) {
|
|
704
744
|
switch (command) {
|
|
705
745
|
case "gothic":
|
|
706
746
|
font = "gothic";
|
|
@@ -723,6 +763,11 @@
|
|
|
723
763
|
|
|
724
764
|
case "_live":
|
|
725
765
|
_live = true;
|
|
766
|
+
break;
|
|
767
|
+
|
|
768
|
+
case "invisible":
|
|
769
|
+
invisible = true;
|
|
770
|
+
break;
|
|
726
771
|
}
|
|
727
772
|
}
|
|
728
773
|
|
|
@@ -734,12 +779,109 @@
|
|
|
734
779
|
font,
|
|
735
780
|
full,
|
|
736
781
|
ender,
|
|
737
|
-
_live
|
|
782
|
+
_live,
|
|
783
|
+
invisible,
|
|
784
|
+
long
|
|
738
785
|
};
|
|
739
786
|
}
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
787
|
+
|
|
788
|
+
parseCommandAndNicoscript(comment) {
|
|
789
|
+
let data = this.parseCommand(comment),
|
|
790
|
+
nicoscript = comment.content.match(/^@(デフォルト|置換|逆|コメント禁止|シーク禁止|ジャンプ)/);
|
|
791
|
+
|
|
792
|
+
if (nicoscript) {
|
|
793
|
+
switch (nicoscript[1]) {
|
|
794
|
+
case "デフォルト":
|
|
795
|
+
this.nicoScripts.default.push({
|
|
796
|
+
start: comment.vpos,
|
|
797
|
+
long: data.long === null ? null : Math.floor(data.long * 100),
|
|
798
|
+
color: data.color,
|
|
799
|
+
size: data.size,
|
|
800
|
+
font: data.font,
|
|
801
|
+
loc: data.loc
|
|
802
|
+
});
|
|
803
|
+
break;
|
|
804
|
+
|
|
805
|
+
case "逆":
|
|
806
|
+
let reverse = comment.content.match(/^@逆 ?(全|コメ|投コメ)?/);
|
|
807
|
+
|
|
808
|
+
if (!reverse[1]) {
|
|
809
|
+
reverse[1] = "全";
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
if (data.long === null) {
|
|
813
|
+
data.long = 30;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
this.nicoScripts.reverse.push({
|
|
817
|
+
"start": comment.vpos,
|
|
818
|
+
"end": comment.vpos + data.long * 100,
|
|
819
|
+
"target": reverse[1]
|
|
820
|
+
});
|
|
821
|
+
break;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
data.invisible = true;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
let color = "#FFFFFF",
|
|
828
|
+
size = "medium",
|
|
829
|
+
font = "defont",
|
|
830
|
+
loc = "naka";
|
|
831
|
+
|
|
832
|
+
for (let i in this.nicoScripts.default) {
|
|
833
|
+
if (this.nicoScripts.default[i].long !== null && this.nicoScripts.default[i].start + this.nicoScripts.default[i].long < comment.vpos) {
|
|
834
|
+
this.nicoScripts.default = this.nicoScripts.default.splice(Number(i), 1);
|
|
835
|
+
continue;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
if (this.nicoScripts.default[i].loc) {
|
|
839
|
+
loc = this.nicoScripts.default[i].loc;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
if (this.nicoScripts.default[i].color) {
|
|
843
|
+
color = this.nicoScripts.default[i].color;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
if (this.nicoScripts.default[i].size) {
|
|
847
|
+
size = this.nicoScripts.default[i].size;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
if (this.nicoScripts.default[i].font) {
|
|
851
|
+
font = this.nicoScripts.default[i].font;
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
if (!data.loc) {
|
|
856
|
+
data.loc = loc;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
if (!data.color) {
|
|
860
|
+
data.color = color;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
if (!data.size) {
|
|
864
|
+
data.size = size;
|
|
865
|
+
data.fontSize = this.fontSize[data.size].default;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
if (!data.font) {
|
|
869
|
+
data.font = font;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
if (data.loc !== "naka") {
|
|
873
|
+
if (!data.long) {
|
|
874
|
+
data.long = 300;
|
|
875
|
+
} else {
|
|
876
|
+
data.long = Math.floor(data.long * 100);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
return data;
|
|
881
|
+
}
|
|
882
|
+
/**
|
|
883
|
+
* キャンバスを描画する
|
|
884
|
+
* @param vpos - 動画の現在位置の100倍 ニコニコから吐き出されるコメントの位置情報は主にこれ
|
|
743
885
|
*/
|
|
744
886
|
|
|
745
887
|
|
|
@@ -747,25 +889,50 @@
|
|
|
747
889
|
this.fpsCount++;
|
|
748
890
|
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
749
891
|
|
|
750
|
-
|
|
751
|
-
let
|
|
752
|
-
|
|
892
|
+
if (this.video) {
|
|
893
|
+
let offsetX,
|
|
894
|
+
offsetY,
|
|
895
|
+
scale,
|
|
896
|
+
height = this.canvas.height / this.video.videoHeight,
|
|
897
|
+
width = this.canvas.width / this.video.videoWidth;
|
|
753
898
|
|
|
754
|
-
if (
|
|
755
|
-
|
|
756
|
-
this.context.fillStyle = `rgba(${rgb[0]},${rgb[1]},${rgb[2]},0.5)`;
|
|
899
|
+
if (height > width) {
|
|
900
|
+
scale = width;
|
|
757
901
|
} else {
|
|
758
|
-
|
|
902
|
+
scale = height;
|
|
759
903
|
}
|
|
760
904
|
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
905
|
+
offsetX = (this.canvas.width - this.video.videoWidth * scale) * 0.5;
|
|
906
|
+
offsetY = (this.canvas.height - this.video.videoHeight * scale) * 0.5;
|
|
907
|
+
this.context.drawImage(this.video, offsetX, offsetY, this.video.videoWidth * scale, this.video.videoHeight * scale);
|
|
908
|
+
}
|
|
764
909
|
|
|
765
|
-
|
|
910
|
+
if (this.timeline[vpos]) {
|
|
911
|
+
for (let index in this.timeline[vpos]) {
|
|
912
|
+
let comment = this.data[this.timeline[vpos][index]];
|
|
766
913
|
|
|
767
|
-
|
|
768
|
-
|
|
914
|
+
if (comment.invisible) {
|
|
915
|
+
continue;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
this.context.font = parseFont(comment.font, comment.fontSize, this.useLegacy);
|
|
919
|
+
|
|
920
|
+
if (comment._live) {
|
|
921
|
+
let rgb = hex2rgb(comment.color);
|
|
922
|
+
this.context.fillStyle = `rgba(${rgb[0]},${rgb[1]},${rgb[2]},0.5)`;
|
|
923
|
+
} else {
|
|
924
|
+
this.context.fillStyle = comment.color;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
if (comment.color === "#000000") {
|
|
928
|
+
this.context.strokeStyle = "rgba(255,255,255,0.7)";
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
this.drawText(comment, vpos);
|
|
932
|
+
|
|
933
|
+
if (comment.color === "#000000") {
|
|
934
|
+
this.context.strokeStyle = "rgba(0,0,0,0.7)";
|
|
935
|
+
}
|
|
769
936
|
}
|
|
770
937
|
}
|
|
771
938
|
|
|
@@ -783,8 +950,8 @@
|
|
|
783
950
|
this.context.fillText("Count:" + this.timeline[vpos].length, 100, 200);
|
|
784
951
|
}
|
|
785
952
|
}
|
|
786
|
-
/**
|
|
787
|
-
* キャンバスを消去する
|
|
953
|
+
/**
|
|
954
|
+
* キャンバスを消去する
|
|
788
955
|
*/
|
|
789
956
|
|
|
790
957
|
|
|
@@ -793,12 +960,12 @@
|
|
|
793
960
|
}
|
|
794
961
|
|
|
795
962
|
}
|
|
796
|
-
/**
|
|
797
|
-
* 配列を複数のキーでグループ化する
|
|
798
|
-
* @param {{}} array
|
|
799
|
-
* @param {string} key
|
|
800
|
-
* @param {string} key2
|
|
801
|
-
* @returns {{}}
|
|
963
|
+
/**
|
|
964
|
+
* 配列を複数のキーでグループ化する
|
|
965
|
+
* @param {{}} array
|
|
966
|
+
* @param {string} key
|
|
967
|
+
* @param {string} key2
|
|
968
|
+
* @returns {{}}
|
|
802
969
|
*/
|
|
803
970
|
|
|
804
971
|
|
|
@@ -820,12 +987,12 @@
|
|
|
820
987
|
|
|
821
988
|
return data;
|
|
822
989
|
};
|
|
823
|
-
/**
|
|
824
|
-
* フォント名とサイズをもとにcontextで使えるフォントを生成する
|
|
825
|
-
* @param {string} font
|
|
826
|
-
* @param {number} size
|
|
827
|
-
* @param {boolean} useLegacy
|
|
828
|
-
* @returns {string}
|
|
990
|
+
/**
|
|
991
|
+
* フォント名とサイズをもとにcontextで使えるフォントを生成する
|
|
992
|
+
* @param {string} font
|
|
993
|
+
* @param {number} size
|
|
994
|
+
* @param {boolean} useLegacy
|
|
995
|
+
* @returns {string}
|
|
829
996
|
*/
|
|
830
997
|
|
|
831
998
|
|
|
@@ -846,11 +1013,11 @@
|
|
|
846
1013
|
|
|
847
1014
|
}
|
|
848
1015
|
};
|
|
849
|
-
/**
|
|
850
|
-
* phpのarray_push的なあれ
|
|
851
|
-
* @param array
|
|
852
|
-
* @param {string} key
|
|
853
|
-
* @param push
|
|
1016
|
+
/**
|
|
1017
|
+
* phpのarray_push的なあれ
|
|
1018
|
+
* @param array
|
|
1019
|
+
* @param {string} key
|
|
1020
|
+
* @param push
|
|
854
1021
|
*/
|
|
855
1022
|
|
|
856
1023
|
|
|
@@ -865,10 +1032,10 @@
|
|
|
865
1032
|
|
|
866
1033
|
array[key].push(push);
|
|
867
1034
|
};
|
|
868
|
-
/**
|
|
869
|
-
* Hexからrgbに変換する(_live用)
|
|
870
|
-
* @param {string} hex
|
|
871
|
-
* @return {array} RGB
|
|
1035
|
+
/**
|
|
1036
|
+
* Hexからrgbに変換する(_live用)
|
|
1037
|
+
* @param {string} hex
|
|
1038
|
+
* @return {array} RGB
|
|
872
1039
|
*/
|
|
873
1040
|
|
|
874
1041
|
|
package/package.json
CHANGED
|
@@ -1,33 +1,31 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@xpadev-net/niconicomments",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "NiconiComments is a comment drawing library that is somewhat compatible with the official Nico Nico Douga player.",
|
|
5
|
-
"main": "dist/bundle.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"test": "echo \"Error: no test specified\" && exit 1",
|
|
8
|
-
"build": "rollup -c rollup.config.js",
|
|
9
|
-
"prepublishOnly": "rollup -c rollup.config.js"
|
|
10
|
-
},
|
|
11
|
-
"repository": {
|
|
12
|
-
"type": "git",
|
|
13
|
-
"url": "git+https://github.com/xpadev-net/niconicomments.git"
|
|
14
|
-
},
|
|
15
|
-
"keywords": [
|
|
16
|
-
"niconico"
|
|
17
|
-
],
|
|
18
|
-
"author": "xpadev(xpadev.net)",
|
|
19
|
-
"bugs": {
|
|
20
|
-
"url": "https://github.com/xpadev-net/niconicomments/issues"
|
|
21
|
-
},
|
|
22
|
-
"files": [
|
|
23
|
-
"dist/bundle.js"
|
|
24
|
-
],
|
|
25
|
-
"homepage": "https://xpadev.net/niconicomments/docs/",
|
|
26
|
-
"license": "MIT",
|
|
27
|
-
"devDependencies": {
|
|
28
|
-
"rollup": "^2.61.1"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@xpadev-net/niconicomments",
|
|
3
|
+
"version": "0.1.8",
|
|
4
|
+
"description": "NiconiComments is a comment drawing library that is somewhat compatible with the official Nico Nico Douga player.",
|
|
5
|
+
"main": "dist/bundle.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
8
|
+
"build": "rollup -c rollup.config.js",
|
|
9
|
+
"prepublishOnly": "rollup -c rollup.config.js"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/xpadev-net/niconicomments.git"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"niconico"
|
|
17
|
+
],
|
|
18
|
+
"author": "xpadev(xpadev.net)",
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/xpadev-net/niconicomments/issues"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist/bundle.js"
|
|
24
|
+
],
|
|
25
|
+
"homepage": "https://xpadev.net/niconicomments/docs/",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"rollup": "^2.61.1",
|
|
29
|
+
"@rollup/plugin-babel": "^5.3.0"
|
|
30
|
+
}
|
|
31
|
+
}
|