精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

圖形編輯器開發:繪制圖形工具

開發 前端
模板模式的優點是復用和擴展。相同的主體框架邏輯不變,暴露幾個方法讓子類實現,有些是必須實現,有些是可實現可不實現(不實現用默認算法),對我們實現一種通用的繪制圖形工具很有幫助。

大家好,我是前端西瓜哥。

今天來介紹如何實現圖形繪制工具,實現繪制任意的圖形。

編輯器 github 地址:

https://github.com/F-star/suika

線上體驗:

https://blog.fstars.wang/app/suika/

我之前講過如何實現工具類管理類的:

《圖形編輯器:工具管理和切換》

對應的工具類的實現會圍繞用戶的 按下鼠標、拖拽、釋放 這 3 個行為,圖形繪制工具同樣如此。

整體框架:

// 繪制圖形工具類(這里用了抽象類,后面會說為什么)
abstract class DrawGraphTool {
  // 工具被激活
  active() {
    // 通常是設置光標,或是綁定一些事件,比如鍵盤事件
  }
  // 工具失活
  inactive() {
    // 通常是解綁一些事件
  }
  
  // 鼠標按下
  start() { /* TODO */ }
  // 鼠標拖拽
  drag() { /* TODO */ }
  // 鼠標釋放
  end() { /* TODO */ }
}

類似 React / Vue 的生命周期 hook。

模板模式

圖形有很多種,矩形、橢圓、三角形、五角星等等。每個圖形都實現一遍未免有點繁瑣。

西瓜哥我一開始是分別去實現繪制矩形和橢圓的,然后發現有很多相同的邏輯。當又要加一個新的圖形時,又要復制粘貼,然后修改少量的不一樣的地方,這不利于代碼維護。

為解決這個問題,我們要實現一個 繪制圖形基類,將共用邏輯放到里面,不同的部分則交給子類去實現。

這個在設計模式上叫做 模板模式。

所謂模板模式,就是在方法中定義一個  “算法” 骨架,繼承的子類在不改變算法整體結構的情況下,重寫其中某些步驟(有些步驟有默認實現,可不重寫)。

模板模式的具體實現,就是用 抽象類(abstract class) 去實現這個基類。

抽象類是一種不能被實例化的特殊類,繼承的子類才能實例化。

抽象類的方法可以是普通方法,也可以是只定義了方法類型簽名的抽象方法。

子類繼承抽象類時,必須提供抽象類的抽象方法的具體實現。

TypeScript 支持抽象類。下面是一個例子。

// 抽象類
abstract class AbstractClass {
  say() {
    if (this.shoudISaySomething()) {
      console.log('前端西瓜哥')
    }
  }
  // 抽象方法(不能用 private,因為子類要重寫它)
  protected abstract shoudISaySomething(): boolean
}

class A extends AbstractClass {
  shoudISaySomething() {
    // ...假設這里一堆判斷
    return true
  }
}

子類不實現抽象方法的話,TS 編譯會報錯:

如果你用 JavaScript,雖然不能做編譯時的檢驗,但還可以做運行時的檢測。

將需要子類繼承實現的方法,加入拋出錯誤的實現。這樣子類如果沒實現,就會通過原型鏈的方式,執行基類的方法,然后報錯提示給開發者。

class AbstractClass {
  say() {
    if (this.shoudISaySomething()) {
      console.log('前端西瓜哥')
    }
  }
  shoudISaySomething() {
    throw new Error('請實現 shoudISaySomething 方法')
  }
}

class A extends AbstractClass {
  shoudISaySomething() {
    // ...假設這里一堆邏輯
    return true
  }
}

圖形繪制工具的實現

我們回到繪制圖形的業務邏輯。

我們在鼠標按下時確定起始坐標,拖拽時調整終點坐標,鼠標釋放確認終點坐標。

這里產生了一個矩形框,得到 x、y、width、height,通過它們可以確定了一個圖形的位置和大小。

當要加一個新的圖形時,只要它能夠通過 x、y、width、height 這幾個屬性確定繪制效果,那就可以使用這個基類。

如果這個圖形還有其他屬性,我們可以在繪制后通過其他方式(比如控制點或者面板修改值)去修改。

鼠標按下

首先是鼠標按下的邏輯。邏輯很少,主要是記錄起始點。

abstract class DrawGraphTool {
  commandDesc = 'Add Graph'; // 歷史記錄的命令描述
  protected drawingGraph: Graph | null = null; // 被繪制的圖形對象
  
  
  start(e: PointerEvent) {
    // 這里將光標的視口坐標轉成場景坐標
    this.startPoint = this.editor.getSceneCursorXY(e);
    
    // 重置一些狀態
    this.drawingGraph = null;
  }
}

鼠標拖拽

拖拽的時候,會判斷 this.drawingGraph 是否為 null。

如果是,就會創建一個新的圖形對象。如果不是,那就更新  this.drawingGraph 的 x、y、 width、height 屬性。

abstract class DrawGraphTool {
  private lastDragPoint!: IPoint;
  
  drag(e: PointerEvent) {
    // 記錄終點坐標
    this.lastDragPoint = this.editor.getSceneCursorXY(e);
    this.updateRect();
  }
  
  // 更新矩形選框,并對圖形對象進行操作
  private updateRect() {
    const { x, y } = this.lastDragPoint;
    const sceneGraph = this.editor.sceneGraph;
    const { x: startX, y: startY } = this.startPoint;

    const width = x - startX; // 這個可能是負數,還沒做標準化
    const height = y - startY; // 同上

    const rect = {
      x: startX,
      y: startY,
      width,
      height,
    };

    // 按住shift鍵,通過算法把矩形變成方形。
    if (this.editor.hostEventManager.isShiftPressing) {
      this.adjustSizeWhenShiftPressing(rect);
    }

    if (this.drawingGraph) {
      // (1)更新圖形邏輯
      this.updateGraph(rect);
    } else {
      // (2)創建圖形邏輯
      const element = this.createGraph(rect)!;
      sceneGraph.addItems([element]);

      this.drawingGraph = element;
    }
    // 設置選中對象,并渲染
    this.editor.selectedElements.setItems([this.drawingGraph]);
    sceneGraph.render();
  }
}

創建圖形

創建圖形對象的方法是 createGraph(),要返回一個圖形對象,保存到 this.drawingGraph。

這個圖形對象需要子類來提供。所以寫成抽象方法:

protected abstract createGraph(rect: IRect, noMove?: boolean): Graph | null;

我們的矩形繪制工具,實現如下。

export class DrawRectTool extends DrawGraphTool implements ITool {
 // ...
  
  // 這里提供實現創建圖形對象
  protected createGraph(rect: IRect) {
    rect = normalizeRect(rect);
    return new Rect({
      ...rect,
      fill: [cloneDeep(this.editor.setting.get('firstFill'))],
    });
  }
}

這里用 normalizeRect 對 rect 對象做了標準化,原來 width 和 height 可能為負數,標準化就是改變 x、y,并讓 width 和 height 變回正數,變成一個常規的 rect 對象。

這樣我們拿到了圖形對象通用屬性:x、y、width、height,然后這里再補上了一個默認的填充色。

如果要實現繪制直線,就不要提供填充色,而是要補一個默認描邊。

更新圖形

更新圖形通常就是更新一下圖形的 x、y、width、height 屬性,所以基類會提供一個默認實現。

/**
 * 這個是通用邏輯,直接更新 x、y、width、height
 */
protected updateGraph(rect: IRect) {
  // 對矩形標準化
  rect = normalizeRect(rect);

  const drawingShape = this.drawingGraph!;
  drawingShape.x = rect.x;
  drawingShape.y = rect.y;
  drawingShape.width = rect.width;
  drawingShape.height = rect.height;
}

當然有些圖形并不是這樣的邏輯,那子類就需要重寫 updateGraph  方法。

比如繪制直線就比較特殊,它更新的是 width 和 rotation,height 則永遠是 0,需要另寫一個算法去實現轉換。

Shift 模式

這里有個比較特別的效果,就是按住 Shift,會讓 圖形的寬高比保持一比一。

繪制正方形:

繪制圓形:

實現就是找 width 和 height 絕對值大的那一個,然后符號保持不變,兩者的絕對值都變成這個最大值。

protected adjustSizeWhenShiftPressing(rect: IRect) {
  // pressing Shift to draw a square
  const { width, height } = rect;
  
  const size = Math.max(Math.abs(width), Math.abs(height));
  // Math.sign() 方法可能會返回 0,所以要兜底為 1
  rect.height = (Math.sign(height) || 1) * size;
  rect.width = (Math.sign(width) || 1) * size;
}

子類如果比較特殊(沒錯說的就是你,直線工具),可重寫該方法。

順帶一提,還有一種 Alt 模式,會將起始點作為圖形的中心點進行繪制,這個我還沒去實現。

鼠標釋放

鼠標釋放時,主要邏輯是將新的狀態保持到歷史記錄中。

end(e: PointerEvent) {
  if (this.drawingGraph) {
    // 記錄新的狀態
    this.editor.commandManager.pushCommand(
      new AddShapeCommand(this.commandDesc, this.editor, [this.drawingGraph]),
    );
  }
}

結尾

模板模式的優點是復用和擴展。相同的主體框架邏輯不變,暴露幾個方法讓子類實現,有些是必須實現,有些是可實現可不實現(不實現用默認算法),對我們實現一種通用的繪制圖形工具很有幫助。

實現了這個圖形繪制基類后,我們理論上就可以繪制任何圖形了,甚至用戶自定義的圖形,只要這些圖形對象使用 x、y、 width、height。

責任編輯:姜華 來源: 前端西瓜哥
相關推薦

2023-10-19 10:12:34

圖形編輯器開發縮放圖形

2009-10-23 16:43:01

VB.NET繪制圖形

2011-06-30 15:09:37

QT 繪制 圖形

2023-08-31 11:32:57

圖形編輯器contain

2013-12-27 13:00:30

Android開發Android應用Context Men

2023-02-06 16:59:57

Canvas編輯器

2023-09-26 07:39:21

2023-02-02 14:07:00

圖形編輯器Canvas

2024-01-08 08:30:05

光標圖形編輯器開發游標

2023-09-11 09:02:31

圖形編輯器模塊間的通信

2013-12-04 16:07:27

Android游戲引擎libgdx教程

2023-06-12 08:22:56

圖形編輯器工具

2023-07-31 08:46:07

圖形編輯器圖形自動對齊

2023-10-08 08:11:40

圖形編輯器快捷鍵操作

2023-10-10 16:04:30

圖形編輯器格式轉換

2023-08-28 08:10:50

Hex圖形編輯器

2023-02-09 07:02:30

圖形編輯器修改圖形

2023-04-07 08:02:30

圖形編輯器對齊功能

2023-01-18 08:30:40

圖形編輯器元素

2023-02-01 09:21:59

圖形編輯器標尺
點贊
收藏

51CTO技術棧公眾號

免费观看日韩毛片| 99超碰麻豆| 亚洲а∨天堂久久精品2021| 日本成人在线网站| 亚洲精品免费视频| 美国av一区二区三区| 91久久精品无码一区二区| 午夜久久一区| 国产一区二区三区四区福利| 日本女人黄色片| 成人美女大片| 亚洲精品国产高清久久伦理二区| 久久草.com| 国产手机视频在线| 日本中文字幕不卡| 国语自产精品视频在线看一大j8| 影音先锋男人在线| 精品精品国产毛片在线看| 在线观看91视频| 免费一级特黄毛片| www免费在线观看| 久久蜜臀精品av| 99在线影院| 亚洲在线精品视频| 国产精品日韩| 欧美二区乱c黑人| 香蕉久久久久久久| 久久91精品| 亚洲精品美女在线观看| 国产一级片中文字幕| 黄色精品视频| 岛国视频午夜一区免费在线观看| 一本大道东京热无码aⅴ| аⅴ资源新版在线天堂| 91视视频在线观看入口直接观看www | 91精品久久久久久久99蜜桃 | 精品一区二区三区免费| 青草青草久热精品视频在线网站| 免费在线观看国产精品| 99久久精品费精品国产风间由美| 亚洲一区www| 欧美一区二区三区成人精品| 精品国产导航| 精品国产乱码久久久久久久| 色欲无码人妻久久精品| 日韩成人综合网| 欧美午夜片在线观看| 美女福利视频在线| 午夜激情在线播放| 五月婷婷久久丁香| 日韩a∨精品日韩在线观看| 免费在线观看的电影网站| 亚洲欧美日韩在线不卡| 免费成人进口网站| 91极品在线| 亚洲日本一区二区| 福利网在线观看| 中文在线字幕免费观看| 亚洲精品精品亚洲| 欧美中日韩在线| 9999在线视频| 欧美日韩午夜激情| 日本精品一区二区三区四区| 成人福利视频| 欧美日韩美女一区二区| 思思久久精品视频| 欧美片网站免费| 亚洲国产精品久久久| 给我免费观看片在线电影的| 日韩欧美中文字幕电影| 亚洲欧美国产一区二区三区| 蜜桃av乱码一区二区三区| 欧美国产一区二区三区激情无套| 久热精品视频在线观看| 久久久久亚洲av成人片| av不卡在线看| 国产精品wwww| 国产三级漂亮女教师| 成人午夜在线播放| 蜜桃久久精品乱码一区二区| 国产日韩精品在线看| 中文字幕一区二区三区在线播放 | 91免费精品国偷自产在线| 99精品在线看| av在线不卡电影| 日本a级片久久久| 黄页视频在线播放| 亚洲午夜精品17c| 国产91对白刺激露脸在线观看| 超碰超碰人人人人精品| 欧美喷水一区二区| 美女黄色一级视频| 波多野结衣在线观看一区二区三区| 久久精品久久久久| 69精品久久久| 蜜臀a∨国产成人精品| 成人三级在线| 成年人在线观看| 一区二区三区在线影院| 久久久999视频| 色婷婷成人网| 日韩av中文在线| 999精品在线视频| aa亚洲婷婷| 91久久国产精品91久久性色| 亚洲欧美综合在线观看| 亚洲欧美一区二区三区久本道91 | 日韩高清中文字幕一区| 亚洲最大的av网站| 久草在线网址| 一区二区三区视频在线观看| 亚洲国产精品毛片av不卡在线| 色悠久久久久综合先锋影音下载| 亚洲色图综合久久| 国产成人精品av久久| 久久精品av麻豆的观看方式| 久久一区二区精品| 日本大片在线播放| 欧美日韩中文字幕一区二区| 在线免费观看a级片| 1024精品久久久久久久久| 日韩av片免费在线观看| 亚洲xxx在线| 国产精品乱子久久久久| 欧美一级黄色片视频| 91蜜桃臀久久一区二区| 深夜福利91大全| 成人一级免费视频| 91麻豆免费在线观看| 无码熟妇人妻av在线电影| 亚洲色图综合| 日韩中文av在线| 无码人妻精品一区二区| 91丝袜美腿高跟国产极品老师| 今天免费高清在线观看国语| 日本a人精品| 最近免费中文字幕视频2019| 凹凸精品一区二区三区| 久久综合九色综合久久久精品综合| 日本中文字幕在线视频观看| 日韩精品成人| 欧美贵妇videos办公室| 国产模特av私拍大尺度| 中文字幕一区二区视频| 色啦啦av综合| 天天插综合网| 国产日韩在线看| 欧美精品日韩少妇| 在线不卡免费欧美| 手机在线免费看片| 黑人精品欧美一区二区蜜桃| 二级片在线观看| 午夜久久av| 欧美激情视频一区| 免费av网站观看| 精品久久久久久久久国产字幕| 老司机免费视频| 国产视频一区免费看| 久久精品丝袜高跟鞋| 亚洲www.| 日韩有码在线视频| 中文无码av一区二区三区| 国产精品女主播在线观看| 亚洲精品免费一区亚洲精品免费精品一区 | 欧美日韩一区在线| 特黄一区二区三区| 国产综合成人久久大片91| 黄黄视频在线观看| 激情亚洲另类图片区小说区| 欧美一区二区影院| аⅴ资源新版在线天堂| 91精品国产色综合久久久蜜香臀| 亚洲国产精品久| 不卡影院免费观看| 国产无套粉嫩白浆内谢的出处| 久久美女视频| 99国产视频| 日本黄色免费在线| 中文字幕在线亚洲| 丰满人妻熟女aⅴ一区| 精品日本美女福利在线观看| 91视频免费看片| 国产成人在线影院| 99热成人精品热久久66| 国产大片一区| 好吊色欧美一区二区三区四区 | 岛国视频午夜一区免费在线观看| 91激情视频在线观看| 国产麻豆精品在线| 亚洲乱码中文字幕久久孕妇黑人| 日韩精品久久久久久久电影99爱| 99在线观看视频| 色婷婷综合久久久中字幕精品久久| 久久精品视频在线观看| 十八禁一区二区三区| 欧美视频一区二区三区在线观看| 免费无码毛片一区二区app| 91麻豆免费在线观看| 超碰在线免费av| 天堂蜜桃一区二区三区| 久久亚洲a v| 欧美熟乱15p| 精品欧美一区二区久久久伦| 久久99国产精品二区高清软件| 午夜美女久久久久爽久久| av在线1区2区| 亚洲精品国产精品国自产在线 | 久久aⅴ国产欧美74aaa| www.射射射| 婷婷综合在线| 欧美三级网色| 欧美日韩另类图片| 91网免费观看| 国产精品99| 欧美中文字幕在线观看| 美女精品视频| 久久精品久久久久久国产 免费| 久草福利在线| 亚洲激情成人网| 精品人妻一区二区三区换脸明星 | 欧美第一淫aaasss性| eeuss影院www在线播放| 日韩av一卡二卡| 亚洲国产精品18久久久久久| 欧美精品乱码久久久久久按摩| 国产www在线| 亚洲午夜免费电影| 裸体武打性艳史| 国产精品日韩精品欧美在线| 亚洲做受高潮无遮挡| a级精品国产片在线观看| 中文字幕人妻无码系列第三区| 日本不卡在线视频| 欧美日韩在线中文| 免费在线日韩av| 老子影院午夜伦不卡大全| 中文字幕一区二区精品区| 亚洲一区二区三区乱码| 欧美午夜精品一区二区三区电影| 免费成人av网站| 香蕉视频一区二区三区| 狼狼综合久久久久综合网| 红杏成人性视频免费看| 国产精品日韩欧美一区二区| 中文字幕一区二区三区四区久久 | 婷婷成人影院| 久久久com| 亚洲亚洲免费| 青娱乐国产91| 成人精品亚洲| 一本一生久久a久久精品综合蜜| 日韩大片在线| 欧美aaa大片视频一二区| 欧美性淫爽ww久久久久无| 人妻 日韩精品 中文字幕| 欧美日韩国产精品一区| 国产精品免费av一区二区| 天天影视涩香欲综合网 | 天堂a中文在线| 日韩精品高清视频| 蜜桃视频在线观看网站| 在线播放日韩专区| 蜜桃视频在线观看www社区| 色青青草原桃花久久综合| 麻豆网在线观看| 欧美日韩福利电影| 超级白嫩亚洲国产第一| 欧美专区在线播放| 色婷婷综合久久久中字幕精品久久| 国产精品旅馆在线| 久久综合偷偷噜噜噜色| 国产精品视频免费一区二区三区| 日韩激情网站| 五月天色一区| 日韩片欧美片| www.国产在线播放| 丝袜亚洲精品中文字幕一区| 中文字幕亚洲欧洲| 成人免费毛片嘿嘿连载视频| 欧美狂猛xxxxx乱大交3| 中文字幕亚洲精品在线观看| 国产香蕉在线视频| 在线观看一区二区精品视频| 国产精品一区二区免费视频| 亚洲国产精品99久久| caoporn国产精品免费视频| 久久国产精品久久国产精品| 牛牛精品一区二区| 国产欧美精品一区二区三区-老狼 国产欧美精品一区二区三区介绍 国产欧美精品一区二区 | 精品国产sm最大网站免费看| 西西人体44www大胆无码| 丝袜亚洲欧美日韩综合| 嗯~啊~轻一点视频日本在线观看| 国产精品黄视频| 1769国产精品视频| 亚洲高清视频一区二区| 国产精品激情| 538在线视频观看| 成人高清免费观看| 成人性视频免费看| 亚洲福利视频一区二区| 亚洲中文字幕在线观看| 日韩成人在线电影网| 成人免费视屏| 国产精品久久久久久久久| 加勒比视频一区| 无码毛片aaa在线| 老司机精品视频网站| 麻豆短视频在线观看| 国产精品妹子av| 精品国产xxx| 精品日韩在线观看| 嫩草香蕉在线91一二三区| 18性欧美xxxⅹ性满足| 欧美一级片网址| 亚洲国产精品一区在线观看不卡| 国产日韩一区二区三区在线| 国产成人精品一区二区三区在线观看| 99久久国产免费看| 欧美日韩在线观看免费| 欧美日韩在线直播| 免费在线观看一级毛片| 992tv成人免费视频| 中文字幕日韩在线| www.激情网| 狠狠色狠狠色合久久伊人| 欧日韩不卡视频| 在线看不卡av| 九色视频在线观看免费播放| 26uuu另类亚洲欧美日本一| 999在线精品| 91精品国产吴梦梦| 国内一区二区在线| 美女福利视频网| 欧美日韩精品一区二区三区四区| 黄色视屏网站在线免费观看| 日韩暖暖在线视频| 希岛爱理av免费一区二区| 日本十八禁视频无遮挡| 99视频国产精品| 国产一级特黄aaa大片| 精品日韩av一区二区| 女囚岛在线观看| 国产二区一区| 夜久久久久久| 男女黄床上色视频| 欧美午夜电影在线| 日本亚洲一区| 国产91久久婷婷一区二区| 国产探花一区二区| 精品久久久久久久无码| 中文在线资源观看网站视频免费不卡 | 97精品视频在线看| 日韩欧美亚洲另类| 亚洲欧美另类久久久精品2019| 99久久精品免费看国产交换| 欧美大片大片在线播放| 成人高潮a毛片免费观看网站| 国产 日韩 亚洲 欧美| 99久久久无码国产精品| 成人免费毛片视频| 中文字幕在线国产精品| 成人激情久久| bt天堂新版中文在线地址| 99亚偷拍自图区亚洲| 99re这里只有精品在线| 日韩一区二区欧美| 日本精品一区二区三区在线观看视频| 99er在线视频| 26uuu精品一区二区| 亚洲图片小说视频| 欧美国产日韩免费| 校花撩起jk露出白色内裤国产精品| 成人在线激情网| 国产精品久久综合| 亚洲精品97久久中文字幕| 欧美性受xxxx白人性爽| japanese国产精品| 精产国品一二三区| 精品人伦一区二区三区蜜桃网站| 91亚洲欧美| 国产66精品久久久久999小说| 亚洲免费综合| 久草手机视频在线观看| 精品裸体舞一区二区三区| 色老太综合网| 日韩中文在线字幕| www久久精品| 国产一区二区三区视频免费观看| 久久久欧美一区二区| 欧美军人男男激情gay| 无码国产精品一区二区高潮| 色综合一区二区| 先锋成人av| 亚洲高清视频一区| av网站免费线看精品| 国产又黄又大又爽| 欧美在线性视频| 欧美一区在线看| 老头老太做爰xxx视频|