摘要:而關(guān)鍵幀事件,則會(huì)在每一次界面變動(dòng)時(shí)觸發(fā)該事件內(nèi)建了,但仍然會(huì)有比較多的數(shù)目。關(guān)鍵幀事件的定義如下當(dāng)前事件觸發(fā)者的譬如當(dāng)某個(gè)發(fā)生移動(dòng)時(shí)候,其會(huì)觸發(fā)如下的事件僅在與級(jí)別提供了事件的響應(yīng),而在與級(jí)別提供了事件的觸發(fā)。
fc-whiteboard,支持鏡像、錄播、回放的 Web 電子白板
在很多培訓(xùn)、協(xié)作、在線演講的場景下,我們需要有電子白板的功能,能夠方便地在演講者與聽眾之間共享屏幕、繪制等信息。fc-whiteboard https://parg.co/NiK 是 Web 在線白板組件庫,支持實(shí)時(shí)直播(一對(duì)多)與回放兩種模式,其繪制版也能夠獨(dú)立使用。fc-whiteboard 內(nèi)置了 EventHub,只需要像 Mushi-Chat 這樣提供簡單的 WebSocket 服務(wù)端,即可快速構(gòu)建實(shí)時(shí)在線共享電子白板。
Usage | 使用 Whiteboard live mode | 直播模式直播模式的效果如下圖所示:
示例代碼請(qǐng)參考 Code Sandbox,或者直接查看 Demo;
import { EventHub, Whiteboard, MirrorWhiteboard } from "fc-whiteboard"; // 構(gòu)建消息中間件 const eventHub = new EventHub(); eventHub.on("sync", (changeEv: SyncEvent) => { console.log(changeEv); }); const images = [ "https://upload-images.jianshu.io/upload_images/1647496-6bede989c09af527.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240", "http://upload-images.jianshu.io/upload_images/1647496-d281090a702045e5.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240", "http://upload-images.jianshu.io/upload_images/1647496-611a416be07d7ca3.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" ]; // 初始化演講者端 const whiteboard = new Whiteboard( document.getElementById("root") as HTMLDivElement, { sources: images, eventHub, // Enable this option to disable incremental sync, just use full sync onlyEmitSnap: false } ); whiteboard.open(); // 初始化鏡像端,即觀眾端 const mirrorWhiteboard = new MirrorWhiteboard( document.getElementById("root-mirror") as HTMLDivElement, { sources: images, eventHub } ); mirrorWhiteboard.open();WebSocket 集成
WebSocket 天然就是以事件驅(qū)動(dòng)的消息通信,fc-whiteboard 內(nèi)部對(duì)于消息有比較好的封裝,我們建議使用者直接將消息透傳即可:
const wsEventHub = new EventEmitter(); if (isPresenter) { wsEventHub.on("sync", data => { if (data.event === "finish") { // 多帶帶處理結(jié)束事件 if (typeof callback === "function") { callback(); } } const msg = { from: `${currentUser.id}`, type: "room", to: `${chatroom.room_id}`, msg: { type: "cmd", action: "whiteboard/sync", message: JSON.stringify(data) } }; socket.sendMessage(msg); }); } else { socket.onMessage(([data]) => { const { msg: { type, message } } = data; if (type === "whiteboard/sync") { wsEventHub.emit("sync", JSON.parse(message)); } }); }Whiteboard replay mode | 回放模式
fc-whiteboard 還支持回訪模式,即我們可以將某次白板操作錄制下來,可以一次性或者分批將事件傳遞給 ReplayWhiteboard,它就會(huì)按序播放:
import { ReplayWhiteboard } from "fc-whiteboard"; import * as events from "./events.json"; let hasSend = false; const whiteboard = new ReplayWhiteboard(document.getElementById( "root" ) as HTMLDivElement); whiteboard.setContext(events[0].timestamp, async (t1, t2) => { if (!hasSend) { hasSend = true; return events as any; } return []; }); whiteboard.open();
The persistent events are listed as follow:
事件的基本結(jié)構(gòu)如下所示,具體的事件類別我們會(huì)在下文介紹:
[ { "event": "borderSnap", "id": "08e65660-6064-11e9-be21-fb33250b411f", "target": "whiteboard", "border": { "id": "08e65660-6064-11e9-be21-fb33250b411f", "sources": [ "https://upload-images.jianshu.io/upload_images/1647496-6bede989c09af527.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240", "http://upload-images.jianshu.io/upload_images/1647496-d281090a702045e5.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240", "http://upload-images.jianshu.io/upload_images/1647496-611a416be07d7ca3.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" ], "pageIds": [ "08e65661-6064-11e9-be21-fb33250b411f", "08e6a480-6064-11e9-be21-fb33250b411f", "08e6cb91-6064-11e9-be21-fb33250b411f" ], "visiblePageIndex": 0, "pages": [ { "id": "08e65661-6064-11e9-be21-fb33250b411f", "markers": [] }, { "id": "08e6a480-6064-11e9-be21-fb33250b411f", "markers": [] }, { "id": "08e6cb91-6064-11e9-be21-fb33250b411f", "markers": [] } ] }, "timestamp": 1555431837 } ... ]Use drawboard alone | 多帶帶使用 Drawboard
Drawboard 也可以多帶帶使用作為畫板,整體可以被導(dǎo)出為圖片:
import { Drawboard } from "fc-whiteboard/src"; const d = new Drawboard({ imgEle: document.getElementById("root") as HTMLImageElement }); d.open();內(nèi)部設(shè)計(jì)
fc-whiteboard 的內(nèi)部組件級(jí)別,依次是 WhiteBoard, WhitePage, Drawboard 與 Marker,本節(jié)即介紹內(nèi)部設(shè)計(jì)與實(shí)現(xiàn)。
Draw System | 繪制系統(tǒng)繪制能力最初改造自 markerjs,在 Drawboard 中提供了基礎(chǔ)的畫板,即 boardCanvas 與 boardHolder,后續(xù)的所有 Marker 即掛載于 boardCanvas 中,并相對(duì)于其進(jìn)行絕對(duì)定位。當(dāng)我們添加某個(gè) Marker,即執(zhí)行以下步驟:
const marker = markerType.createMarker(this.page); this.markers.push(marker); this.selectMarker(marker); this.boardCanvas.appendChild(marker.visual); // 定位 marker.moveTo(x, y);
目前 fc-whiteboard 中內(nèi)置了 ArrowMarker, CoverMarker, HighlightMarker, LineMarker, TextMarker 等多種 Marker:
export class BaseMarker extends DomEventAware { id: string = uuid(); type: MarkerType = "base"; // 歸屬的 WhitePage page?: WhitePage; // 歸屬的 Drawboard drawboard?: Drawboard; // Marker 的屬性發(fā)生變化后的回調(diào) onChange: onSyncFunc = () => {}; // 其他屬性 // ... public static createMarker = (page?: WhitePage): BaseMarker => { const marker = new BaseMarker(); marker.page = page; marker.init(); return marker; }; // 響應(yīng)事件變化 public reactToManipulation( type: EventType, { dx, dy, pos }: { dx?: number; dy?: number; pos?: PositionType } = {} ) { // ... } /** 響應(yīng)元素視圖狀態(tài)變化 */ public manipulate = (ev: MouseEvent) => { // ... }; public endManipulation() { // ... } public select() { // ... } public deselect() { // ... } /** 生成某個(gè)快照 */ public captureSnap(): MarkerSnap { // ... } /** 應(yīng)用某個(gè)快照 */ public applySnap(snap: MarkerSnap): void { // ... } /** 移除該 Marker */ public destroy() { this.visual.style.display = "none"; } protected resize(x: number, y: number, cb?: Function) { return; } protected resizeByEvent(x: number, y: number, pos?: PositionType) { return; } public move = (dx: number, dy: number) => { // ... }; /** Move to relative position */ public moveTo = (x: number, y: number) => { // ... }; /** Init base marker */ protected init() { // ... } protected addToVisual = (el: SVGElement) => { this.visual.appendChild(el); }; protected addToRenderVisual = (el: SVGElement) => { this.renderVisual.appendChild(el); }; protected onMouseDown = (ev: MouseEvent) => { // ... }; protected onMouseUp = (ev: MouseEvent) => { // ... }; protected onMouseMove = (ev: MouseEvent) => { // ... }; }
這里關(guān)于 Marker 的內(nèi)部實(shí)現(xiàn)可以參考具體的 Marker,另外值得一提的是,想 LinearMarker, 或者 RectangleMarker 中,其需要響應(yīng)對(duì)關(guān)鍵點(diǎn)拖拽引發(fā)的伸縮事件,這里的拖拽點(diǎn)是自定義的 Grip 組件。
Event System | 事件系統(tǒng)事件系統(tǒng),最基礎(chǔ)的理解就是用戶的任何操作都會(huì)觸發(fā)事件,也可以通過外部傳入某個(gè)事件的方式來觸發(fā)白板的界面變化。事件類型分為 Snapshot(snap)與 Key Actions(ka)兩種。
首先是 Snapshot 事件,即快照事件;快照會(huì)記錄完整的狀態(tài),整個(gè)白板可以從快照中快速恢復(fù)。白板級(jí)別的快照如下:
{ id: this.id, sources: this.sources, pageIds: this.pages.map(page => page.id), visiblePageIndex: this.visiblePageIndex, pages: this.pages.map(p => p.captureSnap()) }
如果是 Shallow 模式,則不會(huì)下鉆到具體的頁面的快照。頁面的快照即是 Marker 快照構(gòu)成,每個(gè) Marker 的快照則是樸素對(duì)象:
{ id: this.id, type: this.type, isActive: this.isActive, x: this.x, y: this.y }
一般來說,Whiteboard 會(huì)定期分發(fā)快照,可以通過 snapInterval 來控制間隔。而關(guān)鍵幀事件,則會(huì)在每一次界面變動(dòng)時(shí)觸發(fā);該事件內(nèi)建了 Debounce,但仍然會(huì)有比較多的數(shù)目。因此可以通過 onlyEmitSnap 來控制是否僅使用快照事件來同步。
關(guān)鍵幀事件的定義如下:
export interface SyncEvent { target: TargetType; // 當(dāng)前事件觸發(fā)者的 ID id?: string; parentId?: string; event: EventType; marker?: MarkerData; border?: WhiteboardSnap; timestamp?: number; }
譬如當(dāng)某個(gè) Marker 發(fā)生移動(dòng)時(shí)候,其會(huì)觸發(fā)如下的事件:
this.onChange({ target: "marker", id: this.id, event: "moveMarker", marker: { dx, dy } });
僅在 WhiteBoard 與 WhitePage 級(jí)別提供了事件的響應(yīng),而在 Drawboard 與 Marker 級(jí)別提供了事件的觸發(fā)。
延伸閱讀您可以通過以下任一方式閱讀筆者的系列文章,涵蓋了技術(shù)資料歸納、編程語言與理論、Web 與大前端、服務(wù)端開發(fā)與基礎(chǔ)架構(gòu)、云計(jì)算與大數(shù)據(jù)、數(shù)據(jù)科學(xué)與人工智能、產(chǎn)品設(shè)計(jì)等多個(gè)領(lǐng)域:
在 Gitbook 中在線瀏覽,每個(gè)系列對(duì)應(yīng)各自的 Gitbook 倉庫。
Awesome Lists | Awesome CheatSheets | Awesome Interviews | Awesome RoadMaps | Awesome-CS-Books-Warehouse |
---|
編程語言理論 | Java 實(shí)戰(zhàn) | JavaScript 實(shí)戰(zhàn) | Go 實(shí)戰(zhàn) | Python 實(shí)戰(zhàn) | Rust 實(shí)戰(zhàn) |
---|
軟件工程、數(shù)據(jù)結(jié)構(gòu)與算法、設(shè)計(jì)模式、軟件架構(gòu) | 現(xiàn)代 Web 開發(fā)基礎(chǔ)與工程實(shí)踐 | 大前端混合開發(fā)與數(shù)據(jù)可視化 | 服務(wù)端開發(fā)實(shí)踐與工程架構(gòu) | 分布式基礎(chǔ)架構(gòu) | 數(shù)據(jù)科學(xué),人工智能與深度學(xué)習(xí) | 產(chǎn)品設(shè)計(jì)與用戶體驗(yàn) |
---|
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/105664.html
摘要:支持等主流流媒體格式。控制中心會(huì)給直播服務(wù)器這些信息,直播服務(wù)器調(diào)用自身的直播流,分發(fā)到各個(gè)切片服務(wù)器。自動(dòng)化運(yùn)維故障恢復(fù)這部分主要是監(jiān)控推流,和切片,以及直播源是否正常。 本文整理自【時(shí)速云微信群線上分享】第十一期 首先介紹一下背景,Radio Dream項(xiàng)目是一個(gè)開源項(xiàng)目,前身為五雷轟頂網(wǎng)絡(luò)電臺(tái),這個(gè)項(xiàng)目是我個(gè)人逐漸打磨了將近兩年,最開始是因?yàn)樨垞渚W(wǎng)絡(luò)電臺(tái)停播,我個(gè)人是貓撲電臺(tái)的老...
摘要:超寬帶信號(hào)高速采集記錄回放系統(tǒng)特點(diǎn)超寬帶信號(hào)采集記錄存儲(chǔ)與回放,用于實(shí)驗(yàn)數(shù)據(jù)事后分析及外場環(huán)境重建。超寬帶信號(hào)高速采集記錄存儲(chǔ)回放系統(tǒng)基于高性能及協(xié)議,實(shí)現(xiàn)標(biāo)準(zhǔn)化模塊化可擴(kuò)展可重構(gòu)的超寬帶信號(hào)高速連續(xù)采集記錄回放產(chǎn)生平臺(tái)。 超寬帶高速記錄回放系統(tǒng) 超寬帶信號(hào)高速采集記錄存儲(chǔ)回放系統(tǒng)主要用于對(duì)...
摘要:超寬帶信號(hào)高速采集記錄回放系統(tǒng)特點(diǎn)超寬帶信號(hào)采集記錄存儲(chǔ)與回放,用于實(shí)驗(yàn)數(shù)據(jù)事后分析及外場環(huán)境重建。超寬帶信號(hào)高速采集記錄存儲(chǔ)回放系統(tǒng)基于高性能及協(xié)議,實(shí)現(xiàn)標(biāo)準(zhǔn)化模塊化可擴(kuò)展可重構(gòu)的超寬帶信號(hào)高速連續(xù)采集記錄回放產(chǎn)生平臺(tái)。 超寬帶高速記錄回放系統(tǒng) 超寬帶信號(hào)高速采集記錄存儲(chǔ)回放系統(tǒng)主要用于對(duì)...
摘要:遠(yuǎn)程醫(yī)療這一概念被提出后,已經(jīng)被廣泛應(yīng)用。但是,如何提高視頻傳輸性能,如何確保家庭基層醫(yī)療機(jī)構(gòu)和戶外應(yīng)急的遠(yuǎn)程醫(yī)療快速接入,是當(dāng)前的遠(yuǎn)程醫(yī)療業(yè)務(wù)系統(tǒng)面臨的主要挑戰(zhàn)。 編者按:近日,Gartner最新發(fā)布了一份《Five Key Essentials for the New Generation of Intelligent Video Cloud》白皮書報(bào)告,報(bào)告中針對(duì)各行業(yè)在視頻應(yīng)用...
摘要:本系列的第一篇文章,筆者分享了在瀏覽器端,結(jié)合聲網(wǎng)的實(shí)時(shí)音視頻互動(dòng)能力與的在線白板能力,來實(shí)現(xiàn)一個(gè)簡單但實(shí)用的在線教室。一引入音視頻音視頻方案選擇聲網(wǎng)作為本次的技術(shù)方案,先從下載聲網(wǎng)最新的備用。 作者:maverick、buhe,本文首發(fā)于 RTC 開發(fā)者社區(qū) 隨著技術(shù)和基礎(chǔ)設(shè)施的進(jìn)一步演進(jìn),線下的教育、會(huì)議已有很大比重演進(jìn)為線上的教育和會(huì)議,突破了空間的桎梏。需求的多樣性爆發(fā)增長和...
閱讀 2329·2021-09-30 09:47
閱讀 2949·2019-08-30 11:05
閱讀 2526·2019-08-29 17:20
閱讀 1912·2019-08-29 13:01
閱讀 1721·2019-08-26 13:39
閱讀 1221·2019-08-26 13:26
閱讀 3205·2019-08-23 18:40
閱讀 1810·2019-08-23 17:09