摘要:而關(guān)鍵幀事件,則會在每一次界面變動時觸發(fā)該事件內(nèi)建了,但仍然會有比較多的數(shù)目。關(guān)鍵幀事件的定義如下當前事件觸發(fā)者的譬如當某個發(fā)生移動時候,其會觸發(fā)如下的事件僅在與級別提供了事件的響應,而在與級別提供了事件的觸發(fā)。
fc-whiteboard,支持鏡像、錄播、回放的 Web 電子白板
在很多培訓、協(xié)作、在線演講的場景下,我們需要有電子白板的功能,能夠方便地在演講者與聽眾之間共享屏幕、繪制等信息。fc-whiteboard https://parg.co/NiK 是 Web 在線白板組件庫,支持實時直播(一對多)與回放兩種模式,其繪制版也能夠獨立使用。fc-whiteboard 內(nèi)置了 EventHub,只需要像 Mushi-Chat 這樣提供簡單的 WebSocket 服務(wù)端,即可快速構(gòu)建實時在線共享電子白板。
Usage | 使用 Whiteboard live mode | 直播模式直播模式的效果如下圖所示:
示例代碼請參考 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ū)動的消息通信,fc-whiteboard 內(nèi)部對于消息有比較好的封裝,我們建議使用者直接將消息透傳即可:
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,它就會按序播放:
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)如下所示,具體的事件類別我們會在下文介紹:
[ { "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 也可以多帶帶使用作為畫板,整體可以被導出為圖片:
import { Drawboard } from "fc-whiteboard/src"; const d = new Drawboard({ imgEle: document.getElementById("root") as HTMLImageElement }); d.open();內(nèi)部設(shè)計
fc-whiteboard 的內(nèi)部組件級別,依次是 WhiteBoard, WhitePage, Drawboard 與 Marker,本節(jié)即介紹內(nèi)部設(shè)計與實現(xiàn)。
Draw System | 繪制系統(tǒng)繪制能力最初改造自 markerjs,在 Drawboard 中提供了基礎(chǔ)的畫板,即 boardCanvas 與 boardHolder,后續(xù)的所有 Marker 即掛載于 boardCanvas 中,并相對于其進行絕對定位。當我們添加某個 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; }; // 響應事件變化 public reactToManipulation( type: EventType, { dx, dy, pos }: { dx?: number; dy?: number; pos?: PositionType } = {} ) { // ... } /** 響應元素視圖狀態(tài)變化 */ public manipulate = (ev: MouseEvent) => { // ... }; public endManipulation() { // ... } public select() { // ... } public deselect() { // ... } /** 生成某個快照 */ public captureSnap(): MarkerSnap { // ... } /** 應用某個快照 */ 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)部實現(xiàn)可以參考具體的 Marker,另外值得一提的是,想 LinearMarker, 或者 RectangleMarker 中,其需要響應對關(guān)鍵點拖拽引發(fā)的伸縮事件,這里的拖拽點是自定義的 Grip 組件。
Event System | 事件系統(tǒng)事件系統(tǒng),最基礎(chǔ)的理解就是用戶的任何操作都會觸發(fā)事件,也可以通過外部傳入某個事件的方式來觸發(fā)白板的界面變化。事件類型分為 Snapshot(snap)與 Key Actions(ka)兩種。
首先是 Snapshot 事件,即快照事件;快照會記錄完整的狀態(tài),整個白板可以從快照中快速恢復。白板級別的快照如下:
{ id: this.id, sources: this.sources, pageIds: this.pages.map(page => page.id), visiblePageIndex: this.visiblePageIndex, pages: this.pages.map(p => p.captureSnap()) }
如果是 Shallow 模式,則不會下鉆到具體的頁面的快照。頁面的快照即是 Marker 快照構(gòu)成,每個 Marker 的快照則是樸素對象:
{ id: this.id, type: this.type, isActive: this.isActive, x: this.x, y: this.y }
一般來說,Whiteboard 會定期分發(fā)快照,可以通過 snapInterval 來控制間隔。而關(guān)鍵幀事件,則會在每一次界面變動時觸發(fā);該事件內(nèi)建了 Debounce,但仍然會有比較多的數(shù)目。因此可以通過 onlyEmitSnap 來控制是否僅使用快照事件來同步。
關(guān)鍵幀事件的定義如下:
export interface SyncEvent { target: TargetType; // 當前事件觸發(fā)者的 ID id?: string; parentId?: string; event: EventType; marker?: MarkerData; border?: WhiteboardSnap; timestamp?: number; }
譬如當某個 Marker 發(fā)生移動時候,其會觸發(fā)如下的事件:
this.onChange({ target: "marker", id: this.id, event: "moveMarker", marker: { dx, dy } });
僅在 WhiteBoard 與 WhitePage 級別提供了事件的響應,而在 Drawboard 與 Marker 級別提供了事件的觸發(fā)。
延伸閱讀您可以通過以下任一方式閱讀筆者的系列文章,涵蓋了技術(shù)資料歸納、編程語言與理論、Web 與大前端、服務(wù)端開發(fā)與基礎(chǔ)架構(gòu)、云計算與大數(shù)據(jù)、數(shù)據(jù)科學與人工智能、產(chǎn)品設(shè)計等多個領(lǐng)域:
在 Gitbook 中在線瀏覽,每個系列對應各自的 Gitbook 倉庫。
Awesome Lists | Awesome CheatSheets | Awesome Interviews | Awesome RoadMaps | Awesome-CS-Books-Warehouse |
---|
編程語言理論 | Java 實戰(zhàn) | JavaScript 實戰(zhàn) | Go 實戰(zhàn) | Python 實戰(zhàn) | Rust 實戰(zhàn) |
---|
軟件工程、數(shù)據(jù)結(jié)構(gòu)與算法、設(shè)計模式、軟件架構(gòu) | 現(xiàn)代 Web 開發(fā)基礎(chǔ)與工程實踐 | 大前端混合開發(fā)與數(shù)據(jù)可視化 | 服務(wù)端開發(fā)實踐與工程架構(gòu) | 分布式基礎(chǔ)架構(gòu) | 數(shù)據(jù)科學,人工智能與深度學習 | 產(chǎn)品設(shè)計與用戶體驗 |
---|
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/105664.html
摘要:支持等主流流媒體格式。控制中心會給直播服務(wù)器這些信息,直播服務(wù)器調(diào)用自身的直播流,分發(fā)到各個切片服務(wù)器。自動化運維故障恢復這部分主要是監(jiān)控推流,和切片,以及直播源是否正常。 本文整理自【時速云微信群線上分享】第十一期 首先介紹一下背景,Radio Dream項目是一個開源項目,前身為五雷轟頂網(wǎng)絡(luò)電臺,這個項目是我個人逐漸打磨了將近兩年,最開始是因為貓撲網(wǎng)絡(luò)電臺停播,我個人是貓撲電臺的老...
摘要:超寬帶信號高速采集記錄回放系統(tǒng)特點超寬帶信號采集記錄存儲與回放,用于實驗數(shù)據(jù)事后分析及外場環(huán)境重建。超寬帶信號高速采集記錄存儲回放系統(tǒng)基于高性能及協(xié)議,實現(xiàn)標準化模塊化可擴展可重構(gòu)的超寬帶信號高速連續(xù)采集記錄回放產(chǎn)生平臺。 超寬帶高速記錄回放系統(tǒng) 超寬帶信號高速采集記錄存儲回放系統(tǒng)主要用于對...
摘要:超寬帶信號高速采集記錄回放系統(tǒng)特點超寬帶信號采集記錄存儲與回放,用于實驗數(shù)據(jù)事后分析及外場環(huán)境重建。超寬帶信號高速采集記錄存儲回放系統(tǒng)基于高性能及協(xié)議,實現(xiàn)標準化模塊化可擴展可重構(gòu)的超寬帶信號高速連續(xù)采集記錄回放產(chǎn)生平臺。 超寬帶高速記錄回放系統(tǒng) 超寬帶信號高速采集記錄存儲回放系統(tǒng)主要用于對...
摘要:遠程醫(yī)療這一概念被提出后,已經(jīng)被廣泛應用。但是,如何提高視頻傳輸性能,如何確保家庭基層醫(yī)療機構(gòu)和戶外應急的遠程醫(yī)療快速接入,是當前的遠程醫(yī)療業(yè)務(wù)系統(tǒng)面臨的主要挑戰(zhàn)。 編者按:近日,Gartner最新發(fā)布了一份《Five Key Essentials for the New Generation of Intelligent Video Cloud》白皮書報告,報告中針對各行業(yè)在視頻應用...
摘要:本系列的第一篇文章,筆者分享了在瀏覽器端,結(jié)合聲網(wǎng)的實時音視頻互動能力與的在線白板能力,來實現(xiàn)一個簡單但實用的在線教室。一引入音視頻音視頻方案選擇聲網(wǎng)作為本次的技術(shù)方案,先從下載聲網(wǎng)最新的備用。 作者:maverick、buhe,本文首發(fā)于 RTC 開發(fā)者社區(qū) 隨著技術(shù)和基礎(chǔ)設(shè)施的進一步演進,線下的教育、會議已有很大比重演進為線上的教育和會議,突破了空間的桎梏。需求的多樣性爆發(fā)增長和...
閱讀 2437·2021-09-30 09:47
閱讀 3004·2019-08-30 11:05
閱讀 2595·2019-08-29 17:20
閱讀 1983·2019-08-29 13:01
閱讀 1785·2019-08-26 13:39
閱讀 1370·2019-08-26 13:26
閱讀 3280·2019-08-23 18:40
閱讀 1921·2019-08-23 17:09