国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

fc-whiteboard,支持鏡像、錄播、回放的 Web 電子白板

paulquei / 3215人閱讀

摘要:而關鍵幀事件,則會在每一次界面變動時觸發該事件內建了,但仍然會有比較多的數目。關鍵幀事件的定義如下當前事件觸發者的譬如當某個發生移動時候,其會觸發如下的事件僅在與級別提供了事件的響應,而在與級別提供了事件的觸發。

fc-whiteboard,支持鏡像、錄播、回放的 Web 電子白板

在很多培訓、協作、在線演講的場景下,我們需要有電子白板的功能,能夠方便地在演講者與聽眾之間共享屏幕、繪制等信息。fc-whiteboard https://parg.co/NiK 是 Web 在線白板組件庫,支持實時直播(一對多)與回放兩種模式,其繪制版也能夠獨立使用。fc-whiteboard 內置了 EventHub,只需要像 Mushi-Chat 這樣提供簡單的 WebSocket 服務端,即可快速構建實時在線共享電子白板。

Usage | 使用 Whiteboard live mode | 直播模式

直播模式的效果如下圖所示:

示例代碼請參考 Code Sandbox,或者直接查看 Demo;

import { EventHub, Whiteboard, MirrorWhiteboard } from "fc-whiteboard";

// 構建消息中間件
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 天然就是以事件驅動的消息通信,fc-whiteboard 內部對于消息有比較好的封裝,我們建議使用者直接將消息透傳即可:

const wsEventHub = new EventEmitter();

if (isPresenter) {
  wsEventHub.on("sync", data => {
    if (data.event === "finish") {
      // 多帶帶處理結束事件
      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:

事件的基本結構如下所示,具體的事件類別我們會在下文介紹:

[
  {
    "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();
內部設計

fc-whiteboard 的內部組件級別,依次是 WhiteBoard, WhitePage, Drawboard 與 Marker,本節即介紹內部設計與實現。

Draw System | 繪制系統

繪制能力最初改造自 markerjs,在 Drawboard 中提供了基礎的畫板,即 boardCanvas 與 boardHolder,后續的所有 Marker 即掛載于 boardCanvas 中,并相對于其進行絕對定位。當我們添加某個 Marker,即執行以下步驟:

const marker = markerType.createMarker(this.page);

this.markers.push(marker);
this.selectMarker(marker);
this.boardCanvas.appendChild(marker.visual);

// 定位
marker.moveTo(x, y);

目前 fc-whiteboard 中內置了 ArrowMarker, CoverMarker, HighlightMarker, LineMarker, TextMarker 等多種 Marker:

export class BaseMarker extends DomEventAware {
  id: string = uuid();
  type: MarkerType = "base";
  // 歸屬的 WhitePage
  page?: WhitePage;
  // 歸屬的 Drawboard
  drawboard?: Drawboard;
  // Marker 的屬性發生變化后的回調
  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 } = {}
  ) {
    //  ...
  }

  /** 響應元素視圖狀態變化 */
  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) => {
    // ...
  };
}

這里關于 Marker 的內部實現可以參考具體的 Marker,另外值得一提的是,想 LinearMarker, 或者 RectangleMarker 中,其需要響應對關鍵點拖拽引發的伸縮事件,這里的拖拽點是自定義的 Grip 組件。

Event System | 事件系統

事件系統,最基礎的理解就是用戶的任何操作都會觸發事件,也可以通過外部傳入某個事件的方式來觸發白板的界面變化。事件類型分為 Snapshot(snap)與 Key Actions(ka)兩種。

首先是 Snapshot 事件,即快照事件;快照會記錄完整的狀態,整個白板可以從快照中快速恢復。白板級別的快照如下:

{
  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 快照構成,每個 Marker 的快照則是樸素對象:

{
  id: this.id,
  type: this.type,
  isActive: this.isActive,
  x: this.x,
  y: this.y
}

一般來說,Whiteboard 會定期分發快照,可以通過 snapInterval 來控制間隔。而關鍵幀事件,則會在每一次界面變動時觸發;該事件內建了 Debounce,但仍然會有比較多的數目。因此可以通過 onlyEmitSnap 來控制是否僅使用快照事件來同步。

關鍵幀事件的定義如下:

export interface SyncEvent {
  target: TargetType;

  // 當前事件觸發者的 ID
  id?: string;
  parentId?: string;
  event: EventType;
  marker?: MarkerData;
  border?: WhiteboardSnap;
  timestamp?: number;
}

譬如當某個 Marker 發生移動時候,其會觸發如下的事件:

this.onChange({
  target: "marker",
  id: this.id,
  event: "moveMarker",
  marker: { dx, dy }
});

僅在 WhiteBoard 與 WhitePage 級別提供了事件的響應,而在 Drawboard 與 Marker 級別提供了事件的觸發。

延伸閱讀

您可以通過以下任一方式閱讀筆者的系列文章,涵蓋了技術資料歸納、編程語言與理論、Web 與大前端、服務端開發與基礎架構、云計算與大數據、數據科學與人工智能、產品設計等多個領域:

在 Gitbook 中在線瀏覽,每個系列對應各自的 Gitbook 倉庫。

Awesome Lists Awesome CheatSheets Awesome Interviews Awesome RoadMaps Awesome-CS-Books-Warehouse
編程語言理論 Java 實戰 JavaScript 實戰 Go 實戰 Python 實戰 Rust 實戰
軟件工程、數據結構與算法、設計模式、軟件架構 現代 Web 開發基礎與工程實踐 大前端混合開發與數據可視化 服務端開發實踐與工程架構 分布式基礎架構 數據科學,人工智能與深度學習 產品設計與用戶體驗

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/105664.html

相關文章

  • Radio Dream流媒體直播平臺基于Docker應用

    摘要:支持等主流流媒體格式。控制中心會給直播服務器這些信息,直播服務器調用自身的直播流,分發到各個切片服務器。自動化運維故障恢復這部分主要是監控推流,和切片,以及直播源是否正常。 本文整理自【時速云微信群線上分享】第十一期 首先介紹一下背景,Radio Dream項目是一個開源項目,前身為五雷轟頂網絡電臺,這個項目是我個人逐漸打磨了將近兩年,最開始是因為貓撲網絡電臺停播,我個人是貓撲電臺的老...

    aboutU 評論0 收藏0
  • 全方面了解超寬帶信號高速采集記錄回放系統

    摘要:超寬帶信號高速采集記錄回放系統特點超寬帶信號采集記錄存儲與回放,用于實驗數據事后分析及外場環境重建。超寬帶信號高速采集記錄存儲回放系統基于高性能及協議,實現標準化模塊化可擴展可重構的超寬帶信號高速連續采集記錄回放產生平臺。 超寬帶高速記錄回放系統 超寬帶信號高速采集記錄存儲回放系統主要用于對...

    nanchen2251 評論0 收藏0
  • 全方位了解超寬帶信號高速采集記錄回放系統

    摘要:超寬帶信號高速采集記錄回放系統特點超寬帶信號采集記錄存儲與回放,用于實驗數據事后分析及外場環境重建。超寬帶信號高速采集記錄存儲回放系統基于高性能及協議,實現標準化模塊化可擴展可重構的超寬帶信號高速連續采集記錄回放產生平臺。 超寬帶高速記錄回放系統 超寬帶信號高速采集記錄存儲回放系統主要用于對...

    Jaden 評論0 收藏0
  • 新一代智能視頻云發展現狀分析:五大要素成關鍵

    摘要:遠程醫療這一概念被提出后,已經被廣泛應用。但是,如何提高視頻傳輸性能,如何確保家庭基層醫療機構和戶外應急的遠程醫療快速接入,是當前的遠程醫療業務系統面臨的主要挑戰。 編者按:近日,Gartner最新發布了一份《Five Key Essentials for the New Generation of Intelligent Video Cloud》白皮書報告,報告中針對各行業在視頻應用...

    levy9527 評論0 收藏0
  • 在線教育開發實踐(一):實時視頻與白板教學

    摘要:本系列的第一篇文章,筆者分享了在瀏覽器端,結合聲網的實時音視頻互動能力與的在線白板能力,來實現一個簡單但實用的在線教室。一引入音視頻音視頻方案選擇聲網作為本次的技術方案,先從下載聲網最新的備用。 作者:maverick、buhe,本文首發于 RTC 開發者社區 隨著技術和基礎設施的進一步演進,線下的教育、會議已有很大比重演進為線上的教育和會議,突破了空間的桎梏。需求的多樣性爆發增長和...

    Kahn 評論0 收藏0

發表評論

0條評論

paulquei

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<