docs(danmuku): [SITE-DANMUKU-01] complete bilingual usage guides

This commit is contained in:
Harvey Zhao committed 2026-09-15 16:45:35 +08:00
1 parent 520727d762
commit ea3174daa2
56 files changed
+5321 -3108

No files matched your search

+15 -4
View File
@@ -10,18 +10,29 @@ not a VitePress page. Keep both URL surfaces compatible.
| --- | --- | --- |
| `docs/index.md`, `docs/start`, `docs/component`, `docs/advanced` | Chinese API documentation | `/document/` |
| `docs/en` | English counterparts | `/document/en/` |
| `docs/plugin/danmuku.md` | Dedicated Chinese Danmuku guide | `/document/plugin/danmuku.html` |
| `docs/plugin/danmuku.md`, `docs/en/plugin/danmuku.md` | Danmuku options, callbacks, commands, heatmap and types in both languages | `/document/plugin/danmuku.html`, `/document/en/plugin/danmuku.html` |
| `docs/.vitepress/config.js` | Navigation, base URL, output path, page head | Repository `docs/document/` |
| `docs/vite.config.ts` | Search plugin configuration | VitePress/Vite integration; real search acceptance remains pending |
| `docs/public/main.js` | Run Code links and first-visit language redirect | Copied into the built site |
| `docs/public/style.css` | Documentation presentation | Copied into the built site |
Edit Markdown and public sources here. Do not edit the generated repository
`docs/document/`. The current inventory contains 27 Markdown pages: 14 Chinese
and 13 English. Danmuku has no English counterpart yet. Other plugins currently
`docs/document/`. The current inventory contains 28 Markdown pages: 14 Chinese
and 14 English. Danmuku has a dedicated guide and navigation in both languages. Other plugins currently
use their package README, architecture notes and linked editor examples;
navigation links alone are not complete API documentation.
Danmuku guides describe the refactor branch and explicitly distinguish unpublished
`/runtime` declarations from current CDN releases. Preserve old Chinese heading
anchors when editing. Rebuild site assets (the English route inventory), the
LLM corpus and VitePress after changing these pages. The generated readiness smoke
excludes plugin pages; `test/browser/document-danmuku.spec.js` extracts and runs
both guides separately with the local distribution and real sample media. These
checks cover readiness and cleanup, not every interaction or complete playback.
The translation CLI
does not select plugin pages; maintain the two Danmuku guides together manually.
SITE-DANMUKU-01 covers this guide; full bilingual package coverage remains SITE-04.
Site-owned browser behavior now lives in `browser/`; its README maps the shared
loader, desktop editor, mobile entry and Run Code/language navigation. `docs/public/main.js` is a
generated input to VitePress. Run root `yarn build:site-assets` after changes, or
@@ -54,7 +65,7 @@ The repository generators have different ownership:
Checked TS modules in `scripts/editor-declarations/` validate all selected
declarations together with current and historical compilers before writing.
Use `yarn check:editor-types` for drift checks; see that module's README.
- `scripts/build-test.js`: extracts Chinese Run Code blocks into `docs/test/test.js`.
- `scripts/build-test.js`: extracts Chinese core Run Code blocks into `docs/test/test.js`; plugin and English pages are excluded.
The TS implementation in `scripts/docs-smoke/` produces deterministic readiness
smoke cases with owned frames, error observation and cleanup. It does not prove
complete playback or plugin behavior. See its maintenance README and SITE-SMOKE-01.
@@ -139,6 +139,7 @@ const config = {
text: 'Plugins',
collapsible: true,
items: [
{ text: 'Danmuku', link: '/en/plugin/danmuku' },
{ text: 'Advertise', link: 'https://artplayer.org/?libs=./uncompiled/artplayer-plugin-ads/index.js&example=ads' },
{ text: 'Iframe Control', link: 'https://artplayer.org/?libs=./uncompiled/artplayer-tool-iframe/index.js&example=iframe' },
{ text: 'HLS Control', link: 'https://artplayer.org/?libs=https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.5.17/hls.min.js%0A./uncompiled/artplayer-plugin-hls-control/index.js&example=hls.control' },
@@ -0,0 +1,319 @@
# Danmuku
[中文说明](../../plugin/danmuku.md)
Display timed comments over the video, with an input panel, display settings and an optional heatmap.
This guide describes the current refactor branch. The `/runtime` entrypoint and refactor fixes have not yet been published to npm; unversioned CDN links still load the published release.
## Demo
[Open the full example](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-danmuku/index.js&example=danmuku).
Run Code examples below use the site's local plugin build and sample media. In your application, use your own container and media URLs.
## Installation
::: code-group
```sh [npm]
npm install artplayer artplayer-plugin-danmuku
```
```sh [yarn]
yarn add artplayer artplayer-plugin-danmuku
```
```sh [pnpm]
pnpm add artplayer artplayer-plugin-danmuku
```
```html [script]
<script src="path/to/artplayer.js"></script>
<script src="path/to/artplayer-plugin-danmuku.js"></script>
```
:::
JavaScript projects can import the default factory from `artplayer-plugin-danmuku`.
Script builds expose `artplayerPluginDanmuku`; pass its result to the player's `plugins` array.
## CDN
::: code-group
```text [jsDelivr]
https://cdn.jsdelivr.net/npm/artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.js
```
```text [unpkg]
https://unpkg.com/artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.js
```
:::
## Comment structure
Only `text` is required. Leading and trailing whitespace is removed; empty comments are ignored.
```js
({
text: 'Hello!',
time: 10, // Seconds; omitted time defaults to currentTime + 0.5
mode: 0, // 0: scrolling, 1: top, 2: bottom; defaults to option.mode
color: '#FFFFFF', // Defaults to option.color
border: false,
style: {}, // CSS properties for this comment
});
```
Explicit `time: 0` is preserved. Negative times are clamped to zero. Other than 0, 1 and 2, comment modes are ignored.
## All options
Pass an option object to the factory. At runtime, `{}` is valid and all fields have defaults.
The historical root declarations still require `danmuku`; existing TypeScript projects can keep providing it. See [TypeScript](#typescript) for accurate declarations.
```js
({
danmuku: [], // Array, XML URL, Promise of an array, or function returning an array/Promise
speed: 5, // Display duration in seconds, clamped to 1–10
margin: [10, '25%'], // Top/bottom spacing: pixels or percentages
opacity: 1, // Clamped to 0–1
color: '#FFFFFF', // Default comment color
mode: 0, // Default comment mode
modes: [0, 1, 2], // Visible modes
fontSize: 25, // Pixels or a percentage of player height
antiOverlap: true,
synchronousPlayback: false, // Follow video playbackRate when enabled
mount: undefined, // Defaults to the center of the player controls
heatmap: false, // Enable at construction: true or a heatmap options object
width: 512, // Below this width, the default input panel moves below the player
points: [], // Stored option; use the points event to draw custom data
filter: () => true, // Synchronous; do not return a Promise
beforeEmit: () => true, // Input-panel submissions only; may return a Promise
beforeVisible: () => true, // Called before display; may return a Promise
visible: true,
emitter: true, // Show the input panel's sending UI
maxLength: 200, // Input length, clamped to 1–1000
lockTime: 5, // Seconds between input-panel submissions, clamped to 1–60
theme: 'dark', // 'dark' or 'light' for an external mount
OPACITY: {},
FONT_SIZE: {},
MARGIN: {},
SPEED: {},
COLOR: [],
});
```
`OPACITY`, `FONT_SIZE`, `MARGIN` and `SPEED` override slider definitions with `min`, `max` and `steps`.
Each step can contain `name`, `value`, `hide` and `show`; margin values are pairs such as `[10, '50%']`.
`COLOR` replaces the palette with an array of CSS color strings; an empty array uses the built-in palette.
## Array, XML and asynchronous input
XML input uses Bilibili's comment format. Fetching a cross-origin XML URL requires that server to allow browser access.
An input function runs without the option object as its receiver. It may return an array directly or asynchronously.
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
</div>
```js
var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
plugins: [
artplayerPluginDanmuku({
danmuku: [{ text: 'Hello from an array', time: 1 }],
// Alternatives:
// danmuku: '/assets/sample/danmuku.xml',
// danmuku: Promise.resolve([{ text: 'From a Promise', time: 1 }]),
// danmuku: async () => [{ text: 'From a function', time: 1 }],
}),
],
});
```
## Lifecycle callbacks
Input-panel submissions run `beforeEmit → filter → beforeVisible → artplayerPluginDanmuku:visible`.
Loaded comments and direct `emit` calls run `filter → beforeVisible → artplayerPluginDanmuku:visible`.
This describes accepted comments; callbacks can reject them, and scheduling still requires playback and an available track.
| Callback | Input | Acceptance |
| --- | --- | --- |
| `beforeEmit` | Input-panel comment | Only strict `true`, or a Promise resolving to `true`, sends it |
| `filter` | Comment with time, mode, color and style filled in | A synchronous truthy result adds it to the queue |
| `beforeVisible` | Queue item | A truthy result, including an awaited result, permits display |
Normal functions receive the current option object as `this` for all three callbacks. Arrow functions retain their lexical `this`.
`emit()` does not call `beforeEmit`: perform application validation before calling it when needed.
`beforeEmit` failures are logged in the console and leave the input available for another attempt.
An asynchronous `beforeVisible` rejection emits `artplayerPluginDanmuku:error` once for that item in the current run; other items continue.
Pause/resume, reset or replacing the callback permits a retry if the item is still eligible by time.
Pausing, seeking, hiding, resetting or destroying cancels unfinished visibility preparation.
## Methods and state
The registered plugin is available synchronously as `art.plugins.artplayerPluginDanmuku`.
| Member | Behavior and return value |
| --- | --- |
| `emit(comment)` | Processes one comment for the queue; returns a Promise |
| `load()` | Reads `option.danmuku` and replaces the queue; returns a Promise |
| `load(input)` | Appends comments from the input; returns a Promise |
| `config(partialOption)` | Synchronously merges configuration |
| `hide()` / `show()` | Synchronously hides or shows the comment layer |
| `reset()` | Clears displayed comments and returns queue items to waiting; does not delete the queue |
| `mount(target)` | Moves the panel to an existing element or selector; returns `undefined` |
| `option` | Live current configuration; use `config()` for validated updates |
| `isHide` | Read-only live visibility state: `true` when hidden |
| `isStop` | Read-only live stopped state; distinct from visibility and not a media-readiness signal |
`emit/load` Promises resolve to the internal Danmuku owner. `config/hide/show/reset` return that same owner synchronously.
The owner is **different from the registered plugin facade**. Keep using the registered facade for subsequent commands.
Awaiting `emit()` means queue processing has finished, not that the comment has appeared.
### Loading and configuration
Changing `config({ danmuku: input })` does not load the new input. Follow it with `load()` to replace the queue.
Input-read failures leave the existing queue intact; failures while filtering individual rows do not guarantee an atomic rollback of the entire batch.
Independent append operations do not cancel one another. A newer replacement cancels an unfinished older replacement.
Destroy cancels pending loads. Cancelled Promises resolve to the owner without a late `loaded` or `error` event.
Fetch and response-text failures emit `artplayerPluginDanmuku:error` and reject the corresponding public `load()` Promise.
Handle rejection with `await`/`try...catch` or `.catch(...)`. Initial automatic loading observes rejection and logs a warning.
Invalid configuration leaves the current option intact. Use `mount(target)` to move the panel; changing `option.mount` through `config()` does not perform a mount.
Enable heatmap when constructing the plugin; `config({ heatmap: true })` does not create it later.
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
</div>
```js
var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
plugins: [artplayerPluginDanmuku({ danmuku: [], emitter: false })],
});
async function updateComments() {
var plugin = art.plugins.artplayerPluginDanmuku;
plugin.config({ danmuku: [{ text: 'Replacement', time: 1 }] });
await plugin.load();
await plugin.load([{ text: 'Appended', time: 2 }]);
await plugin.emit({ text: 'Scheduled from the current time' });
plugin.hide();
console.info('Hidden:', plugin.isHide);
plugin.show();
plugin.reset();
}
updateComments().catch(console.error);
```
## External mount
Create a separate mount element before constructing the plugin. The panel moves into the controls during player fullscreen or web fullscreen and returns to its configured mount on exit.
Use `theme: 'light'` on a light background. The live `mount(target)` method requires a valid target; omitting its argument does not select the default.
Destroy releases the plugin panel; the application owns any container it created.
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
</div>
```js
var $danmu = document.createElement('div');
document.querySelector('.artplayer-app').after($danmu);
var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
fullscreenWeb: true,
plugins: [artplayerPluginDanmuku({
danmuku: [{ text: 'External input panel', time: 1 }],
mount: $danmu,
theme: 'dark',
})],
});
art.on('destroy', () => $danmu.remove());
// Move it later with art.plugins.artplayerPluginDanmuku.mount(otherElement).
```
## Heatmap
Set `heatmap: true` at construction to sample the queue automatically. A live stream does not draw a heatmap.
Dense automatic curves now fit in the bottom quarter of the chart instead of covering the video (issue #958).
Explicit finite `yMin` or `yMax` and custom points retain their coordinate mapping.
An object can set `xMin`, `xMax`, `yMin`, `yMax`, `scale`, `opacity`, `minHeight`, `sampling`, `smoothing` and `flattening`.
Defaults are `xMin: 0`, `xMax: chartWidth`, `yMin: 0`, `yMax: 128`, `scale: 0.25`, `opacity: 0.2`,
`minHeight: floor(chartHeight * 0.05)`, `sampling: max(1, floor(chartWidth / 100))`, `smoothing: 0.2`, `flattening: 0.2`.
Send `art.emit('artplayerPluginDanmuku:points', points)` to draw custom `[x, value]` pairs.
The default x-axis uses chart pixels, not seconds. Set `xMin/xMax` explicitly if supplying another coordinate range.
Rendering mutates the inner point arrays for historical compatibility: copy each pair if reusing the original data.
The stored `points` option does not draw custom data. A resize or successful load redraws the automatic curve, so resend custom data after those events when needed.
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
</div>
```js
var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
plugins: [artplayerPluginDanmuku({
danmuku: [{ text: 'Heatmap example', time: 1 }],
heatmap: true,
})],
});
var points = [[0, 5], [0.25, 12], [0.5, 30], [0.75, 10], [1, 5]];
function drawPoints() {
var width = art.controls.heatmap.offsetWidth;
art.emit('artplayerPluginDanmuku:points', points.map(([ratio, value]) => [ratio * width, value]));
}
art.on('ready', drawPoints);
art.on('resize', drawPoints);
art.on('artplayerPluginDanmuku:loaded', drawPoints);
```
## Events
Subscribe with `art.on(name, callback)` and remove subscriptions with `art.off(name, callback)`.
| Event | Payload / meaning |
| --- | --- |
| `artplayerPluginDanmuku:visible` | Queue item; its `$ref` is the displayed element |
| `artplayerPluginDanmuku:loaded` | Current full queue after a successful load, including appends |
| `artplayerPluginDanmuku:error` | Original error from loading or scheduling; handle public Promise rejections separately |
| `artplayerPluginDanmuku:config` | Current configuration |
| `artplayerPluginDanmuku:start` | No payload; scheduling starts |
| `artplayerPluginDanmuku:stop` | No payload; scheduling stops |
| `artplayerPluginDanmuku:hide` | No payload; layer hidden |
| `artplayerPluginDanmuku:show` | No payload; layer shown |
| `artplayerPluginDanmuku:reset` | No payload; displayed items reset |
| `artplayerPluginDanmuku:destroy` | No payload; plugin destroyed |
| `artplayerPluginDanmuku:points` | Application-sent custom points for the heatmap |
Events are not replayed to later listeners. In particular, an initially empty array can finish loading during construction.
Subscribe before invoking a later `load()` if you need to observe its completion event.
Use `$ref.textContent` when adding text in a `visible` handler.
## TypeScript
The root and `/legacy` entrypoints keep the npm 5.3.0 declaration shapes for compatibility, including historical inaccuracies about return values.
The current branch adds `/runtime` for accurate types while loading the same runtime factory:
```ts
import Artplayer from 'artplayer';
import danmuku from 'artplayer-plugin-danmuku/runtime';
import type { RuntimeOption, Point, EventMap } from 'artplayer-plugin-danmuku/runtime';
const option: RuntimeOption = { danmuku: [], heatmap: true };
const points: Point[] = [[0, 5], [100, 10]];
const onError = (...[error]: EventMap['artplayerPluginDanmuku:error']) => console.error(error);
const art = new Artplayer({ container: '#player', url: '/video.mp4', plugins: [danmuku(option)] });
art.on('artplayerPluginDanmuku:error', onError);
```
The explicit `EventMap` describes payloads; it does not augment the core's historical event declarations automatically.
The factory also exposes the existing `icons` object for customization. Package `README.md` and `ARCHITECTURE.md` describe module ownership, maintenance commands and remaining device/combination validation.
@@ -1,9 +1,15 @@
# 弹幕库
[English guide](../en/plugin/danmuku.md)
本文描述当前重构分支。`/runtime` 类型入口与本轮修复尚未发布到 npm;CDN 默认仍加载已发布版本。
## 演示
👉 [查看完整演示](https://artplayer.org/?libs=./uncompiled/artplayer-plugin-danmuku/index.js&example=danmuku)
下方 Run Code 使用本站构建的插件与样本。接入自己的应用时,请替换容器和媒体 URL。
## 安装
::: code-group
@@ -47,9 +53,9 @@ https://unpkg.com/artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.js
```js
{
text: '', // 弹幕文本
time: 10, // 弹幕时间, 默认为当前播放器时间
time: 10, // 弹幕时间, 单位秒,省略时为当前播放器时间加 0.5 秒;显式 0 保留
mode: 0, // 弹幕模式: 0: 滚动(默认),1: 顶部,2: 底部
color: '#FFFFFF', // 弹幕颜色,默认为白色
color: '#FFFFFF', // 弹幕颜色,默认使用配置 color(初始为白色)
border: false, // 弹幕是否有描边, 默认为 false
style: {}, // 弹幕自定义样式, 默认为空对象
}
@@ -57,7 +63,7 @@ https://unpkg.com/artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.js
## 全部选项
只有`danmuku`是必须的参数,其余都是非必填
工厂需要一个配置对象。运行时可传 `{}`,每个字段都有默认值;旧版根入口类型仍要求 `danmuku`,旧项目继续传入它即可。准确类型见下方 TypeScript 说明。
```js
{
@@ -74,9 +80,9 @@ https://unpkg.com/artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.js
mount: undefined, // 弹幕发射器挂载点, 默认为播放器控制栏中部
heatmap: false, // 是否开启热力图
width: 512, // 当播放器宽度小于此值时,弹幕发射器置于播放器底部
points: [], // 热力图数据
points: [], // 保留的配置字段;绘制自定义数据请发送 points 事件
filter: () => true, // 弹幕载入前的过滤器,只支持返回布尔值
beforeEmit: () => true, // 弹幕发送前的过滤器,支持返回 Promise
beforeEmit: () => true, // 输入框发送前的过滤器,支持返回 Promise
beforeVisible: () => true, // 弹幕显示前的过滤器,支持返回 Promise
visible: true, // 弹幕层是否可见
emitter: true, // 是否开启弹幕发射器
@@ -91,13 +97,19 @@ https://unpkg.com/artplayer-plugin-danmuku/dist/artplayer-plugin-danmuku.js
}
```
`OPACITY`、`FONT_SIZE`、`MARGIN`、`SPEED` 可覆盖滑块的 `min`、`max`、`steps`。
每个 step 可包含 `name`、`value`、`hide`、`show`;MARGIN 的 value 是上下边距数组。
`COLOR` 用 CSS 颜色字符串数组替换调色板,空数组使用内置调色板。
## 生命周期
`filter` 同步执行,不应返回 Promise;`beforeEmit` 可异步,但只有严格返回 `true` 才发送。`beforeVisible` 可以异步。普通函数形式的这三个回调,其 `this` 都是当前配置对象。直接调用 `emit` 不执行 `beforeEmit`,需要业务校验时请在调用前完成。
来自用户输入的弹幕:
`beforeEmit -> filter -> beforeVisible -> artplayerPluginDanmuku:visible`
来自服务器的弹幕:
来自服务器或直接调用 `emit` 的弹幕:
`filter -> beforeVisible -> artplayerPluginDanmuku:visible`
@@ -151,7 +163,7 @@ var art = new Artplayer({
// 弹幕已经出现在播放器里,你可以访问到弹幕的dom元素里
art.on('artplayerPluginDanmuku:visible', danmu => {
danmu.$ref.innerHTML = 'ଘ(੭ˊᵕˋ)੭: ' + danmu.$ref.innerHTML;
danmu.$ref.textContent = 'ଘ(੭ˊᵕˋ)੭: ' + danmu.$ref.textContent;
})
```
@@ -200,6 +212,8 @@ var art = new Artplayer({
## 使用异步返回
也可以直接传入 `Promise<弹幕数组>`,或传入同步返回数组的函数。输入函数没有配置对象作为 `this`。
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
</div>
@@ -211,8 +225,8 @@ var art = new Artplayer({
plugins: [
artplayerPluginDanmuku({
danmuku: function () {
return new Promise((resovle) => {
return resovle([
return new Promise((resolve) => {
return resolve([
{
text: '使用 Promise 异步返回',
time: 1
@@ -298,7 +312,7 @@ var art = new Artplayer({
## `emit`
通过方法 `emit` 发送一条实时弹幕
通过方法 `emit` 向队列添加一条弹幕。它返回 Promise;完成表示入队处理完成,不代表已经显示。请用 `await` 或 `.catch(...)` 处理拒绝。省略时间时安排在当前播放时间之后 0.5 秒,显示仍受播放状态、过滤器和可用轨道影响。
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
@@ -325,7 +339,7 @@ var art = new Artplayer({
text: text,
color: color,
border: true,
});
}).catch(console.error);
},
},
],
@@ -334,7 +348,7 @@ var art = new Artplayer({
## `config`
通过方法 `config` 实时改变弹幕配置
通过方法 `config` 同步合并弹幕配置。更改 `danmuku` 不会自动重新加载,之后调用无参数的 `load()` 才会替换队列;无效配置不会覆盖现有配置。需要移动发射器时调用 `mount(target)`;热力图应在初始化时启用,`config({ heatmap: true })` 不会创建热力图。
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
@@ -372,7 +386,7 @@ var art = new Artplayer({
## `load`
通过 load 方法可以重载弹幕库,或者切换新弹幕库,或者追加新的弹幕库
通过 `load` 重载、切换或追加弹幕库,返回 Promise。无参数 `load()` 在读取配置中的输入成功后替换队列;传入 `load(input)` 则追加。输入读取失败不会清空现有队列,但逐条过滤时发生异常不保证整批回滚。并发追加互不取消,新的替换会取消尚未完成的旧替换。销毁会取消未完成加载;被取消的 Promise 仍正常结束,但不会发出迟到的 loaded/error 事件。
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
@@ -394,7 +408,7 @@ var art = new Artplayer({
html: '重载',
click: function () {
// 重新加载当前弹幕库
art.plugins.artplayerPluginDanmuku.load();
art.plugins.artplayerPluginDanmuku.load().catch(console.error);
},
},
{
@@ -405,7 +419,7 @@ var art = new Artplayer({
art.plugins.artplayerPluginDanmuku.config({
danmuku: '/assets/sample/danmuku-v2.xml',
});
art.plugins.artplayerPluginDanmuku.load();
art.plugins.artplayerPluginDanmuku.load().catch(console.error);
},
},
{
@@ -414,7 +428,7 @@ var art = new Artplayer({
click: function () {
// 追加新的弹幕库,参数类型和option.danmuku相同
const target = '/assets/sample/danmuku.xml'
art.plugins.artplayerPluginDanmuku.load(target);
art.plugins.artplayerPluginDanmuku.load(target).catch(console.error);
},
},
],
@@ -423,7 +437,7 @@ var art = new Artplayer({
## `reset`
用于清空当前显示的弹幕
用于清空当前显示的弹幕并将队列项重置为等待状态。它不删除队列;后续播放仍可按时间显示弹幕。
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
@@ -450,12 +464,15 @@ art.on('resize', () => {
在初始化弹幕插件的时候,是可以指定弹幕发射器的挂载位置的,默认是挂载在控制栏的中部,你也可以把它挂载在播放器以外的地方。
当播放器全屏的时候,发射器会自动回到控制栏的中部。假如你挂载的地方是亮色的话,建议把 `theme` 设置成 `light`,否则会看不清。
退出全屏后会返回配置的挂载点。`mount(target)` 必须传入已存在的元素或选择器,省略参数不会恢复默认位置;它返回 `undefined`。销毁会移除插件面板,应用创建的外部容器由应用清理。
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
</div>
```js
var $danmu = document.querySelector('.artplayer-app');
var $danmu = document.createElement('div');
document.querySelector('.artplayer-app').after($danmu);
var art = new Artplayer({
container: '.artplayer-app',
@@ -463,20 +480,22 @@ var art = new Artplayer({
fullscreenWeb: true,
plugins: [
artplayerPluginDanmuku({
mount: $danmu,
mount: $danmu,
theme: 'dark',
danmuku: '/assets/sample/danmuku.xml',
}),
],
});
art.on('destroy', () => $danmu.remove());
// 也可以手动挂载
// art.plugins.artplayerPluginDanmuku.mount($danmu);
```
## `option`
用于获取当前弹幕配置
用于获取当前弹幕配置,返回实时配置对象。更新配置请调用 `config`,避免直接修改对象而绕过校验和 UI 同步。
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
@@ -500,6 +519,10 @@ art.on('ready', () => {
## 事件
使用 `art.on(name, callback)` 订阅,`art.off(name, callback)` 取消订阅。事件不会向迟到的监听器重放;初始空数组可能在构造期间就完成加载。若需要观察后续加载,先订阅再调用 `load()`。
`loaded` 参数是当前完整队列,包含已追加数据;`error` 也可能来自显示调度。监听错误事件并不能代替处理公开方法的 Promise 拒绝。
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
</div>
@@ -524,7 +547,7 @@ art.on('artplayerPluginDanmuku:loaded', (danmus) => {
});
art.on('artplayerPluginDanmuku:error', (error) => {
console.info('加载错误', error);
console.info('弹幕错误', error);
});
art.on('artplayerPluginDanmuku:config', (option) => {
@@ -555,3 +578,67 @@ art.on('artplayerPluginDanmuku:destroy', () => {
console.info('弹幕销毁');
});
```
## `isStop` 与方法返回值
`art.plugins.artplayerPluginDanmuku.isStop` 是实时只读的停止状态,与 `isHide` 不同,也不表示媒体是否准备就绪。
`emit/load` 返回的 Promise 完成后得到内部 Danmuku 对象;`config/hide/show/reset` 同步返回同一个内部对象。它与注册在 `art.plugins` 上的插件对象不是同一个对象。后续命令继续通过注册的插件调用即可。
`beforeEmit` 抛出或拒绝时会在控制台报告错误,输入框可再次尝试发送。
`beforeVisible` 拒绝时,对该项在当前调度轮报告一次 `artplayerPluginDanmuku:error`,其他项继续处理;暂停后恢复、reset 或更换回调后,仍符合时间条件的项可重试。
暂停、seek、隐藏、reset 和销毁会取消尚未完成的显示准备。
## 热力图
初始化时设置 `heatmap: true`,按队列自动采样;直播不绘制热力图。
本轮修复了密集弹幕曲线过高遮挡视频的问题(issue #958),自动曲线会适配到图表底部四分之一区域。显式设置有限的 `yMin/yMax` 或发送自定义 points 时保留原坐标映射。
`heatmap` 也可传配置对象:`xMin`、`xMax`、`yMin`、`yMax`、`scale`、`opacity`、`minHeight`、`sampling`、`smoothing`、`flattening`。
默认分别为 `0`、图表宽度、`0`、`128`、`0.25`、`0.2`、`floor(图表高度 * 0.05)`、`max(1, floor(图表宽度 / 100))`、`0.2`、`0.2`。
绘制自定义数据使用 `art.emit('artplayerPluginDanmuku:points', points)`,每项为 `[x, value]`。默认 x 是图表像素坐标,不是秒。
渲染会修改内层数组的第二项,保留原数据时请复制每一对坐标。配置中的 `points` 字段仅存储,不会自动绘图。
resize 或成功 load 会恢复自动曲线,需要自定义曲线时可在这些事件后重新发送。
<div className="run-code" data-libs="./uncompiled/artplayer-plugin-danmuku/index.js">
▶ Run Code
</div>
```js
var art = new Artplayer({
container: '.artplayer-app',
url: '/assets/sample/video.mp4',
plugins: [artplayerPluginDanmuku({
danmuku: [{ text: '热力图示例', time: 1 }],
heatmap: true,
})],
});
var points = [[0, 5], [0.25, 12], [0.5, 30], [0.75, 10], [1, 5]];
function drawPoints() {
var width = art.controls.heatmap.offsetWidth;
art.emit('artplayerPluginDanmuku:points', points.map(([ratio, value]) => [ratio * width, value]));
}
art.on('ready', drawPoints);
art.on('resize', drawPoints);
art.on('artplayerPluginDanmuku:loaded', drawPoints);
```
## TypeScript
根入口和 `/legacy` 保留 npm 5.3.0 的历史声明形状,其中部分方法返回值与真实运行时不一致。
当前分支新增 `/runtime` 提供准确类型,加载的仍是同一个运行时工厂;该入口尚未发布,不能从旧 CDN 版本导入。
```ts
import Artplayer from 'artplayer';
import danmuku from 'artplayer-plugin-danmuku/runtime';
import type { RuntimeOption, Point, EventMap } from 'artplayer-plugin-danmuku/runtime';
const option: RuntimeOption = { danmuku: [], heatmap: true };
const points: Point[] = [[0, 5], [100, 10]];
const onError = (...[error]: EventMap['artplayerPluginDanmuku:error']) => console.error(error);
const art = new Artplayer({ container: '#player', url: '/video.mp4', plugins: [danmuku(option)] });
art.on('artplayerPluginDanmuku:error', onError);
```
`EventMap` 显式描述事件参数,不会自动扩展核心历史事件声明。工厂仍暴露 `icons` 对象供自定义图标。
包内 `README.md` 和 `ARCHITECTURE.md` 维护模块职责、验证命令及尚未完成的设备和组合验收。
@@ -50,5 +50,5 @@
}
// <stdin>
installNavigation(window, ["advanced/built-in.html", "advanced/built-in", "advanced/class.html", "advanced/class", "advanced/event.html", "advanced/event", "advanced/global.html", "advanced/global", "advanced/plugin.html", "advanced/plugin", "advanced/property.html", "advanced/property", "component/contextmenu.html", "component/contextmenu", "component/controls.html", "component/controls", "component/layers.html", "component/layers", "component/setting.html", "component/setting", "", "index.html", "start/i18n.html", "start/i18n", "start/option.html", "start/option"]);
installNavigation(window, ["advanced/built-in.html", "advanced/built-in", "advanced/class.html", "advanced/class", "advanced/event.html", "advanced/event", "advanced/global.html", "advanced/global", "advanced/plugin.html", "advanced/plugin", "advanced/property.html", "advanced/property", "component/contextmenu.html", "component/contextmenu", "component/controls.html", "component/controls", "component/layers.html", "component/layers", "component/setting.html", "component/setting", "", "index.html", "plugin/danmuku.html", "plugin/danmuku", "start/i18n.html", "start/i18n", "start/option.html", "start/option"]);
})();