精品欧美一区二区三区在线观看 _久久久久国色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技術棧公眾號

日本一区免费观看| 国产成人一区二区三区电影| 一起草最新网址| 国产人成网在线播放va免费| 国产ts人妖一区二区| 97精品视频在线| 东京热无码av男人的天堂| 国产精品国产亚洲精品| 亚洲成av人片观看| 亚洲国产精品综合| 日本美女一级视频| 免费观看日韩av| 欧美国产日韩中文字幕在线| www在线观看免费视频| 97久久中文字幕| 精品久久久久久国产| 亚洲欧美成人一区| 三级网站免费观看| 精品无码三级在线观看视频| 97香蕉久久超级碰碰高清版| 国产视频三区四区| 久久影院资源站| 日韩三级视频中文字幕| 中文字幕永久视频| 99久久精品免费看国产小宝寻花| 国产精品狼人久久影院观看方式| 国产一区二区中文字幕免费看| 亚洲天堂2021av| 亚洲影院免费| 欧美激情综合色综合啪啪五月| 欧美一区二区三区粗大| 四虎884aa成人精品最新| 欧美一区二视频| 日韩在线第三页| 极品视频在线| 亚洲午夜免费视频| 日韩 欧美 自拍| 成年人视频免费在线观看| 粉嫩蜜臀av国产精品网站| 国产免费亚洲高清| 日本中文字幕在线观看视频| 一本久道久久久| 久久免费在线观看| 男人的天堂久久久| 天天综合网网欲色| 中文字幕一区二区三区电影| av小说在线观看| 福利片一区二区| 欧美不卡在线视频| 国产乱淫av片| 136福利精品导航| 精品少妇一区二区三区日产乱码 | 少妇视频在线| 亚洲免费资源在线播放| 在线视频欧美一区| 麻豆电影在线播放| 亚洲欧美日韩综合aⅴ视频| 亚洲一区二区三区加勒比| 国产51人人成人人人人爽色哟哟| 久久久高清一区二区三区| 欧美成人综合一区| 美丽的姑娘在线观看免费动漫| 91麻豆成人久久精品二区三区| 久久精品aaaaaa毛片| 天堂资源最新在线| 久久综合色8888| 蜜桃麻豆91| 国产精品一区在线看| 国产女人18毛片水真多成人如厕| 欧美另类高清视频在线| 国产精品秘入口| 中文字幕av一区二区三区免费看| 一区二区三区免费看| 欧美成人xxx| 亚洲欧美一区二区三区国产精品| 女人床在线观看| 波多野结衣中文在线| 天天色图综合网| 日批视频在线免费看| 91看片一区| 欧美日本免费一区二区三区| 午夜xxxxx| 一区二区在线免费播放| 亚洲精品第一页| 欧美特级黄色录像| 国产精品黑丝在线播放 | 裸体丰满少妇做受久久99精品| 欧美日韩国产亚洲沙发| 国产人成亚洲第一网站在线播放| 亚洲欧美日韩精品久久久| a级在线观看| 性欧美大战久久久久久久久| 亚洲精品中文字幕无码蜜桃| 在线日韩三级| 亚洲国产99精品国自产| 一级特黄曰皮片视频| 久久久久国产| 97av在线视频| 91在线视频国产| www.66久久| 伊人久久婷婷色综合98网| 亚洲wwwww| 在线视频亚洲一区| 国产精品99精品无码视亚| 中日韩免视频上线全都免费| 久久精品中文字幕免费mv| 99视频在线看| 久久se精品一区精品二区| 国产一区二区久久久| 91porn在线观看| 婷婷开心激情综合| 欧美国产日韩另类| 欧美日韩一区二区三区在线电影 | 欧美精品九九99久久| 国产极品一区二区| 97国产精品| 日本人成精品视频在线| 亚洲精品一区二区三区区别| 国产嫩草影院久久久久| 黄色一级视频在线播放| 九色精品蝌蚪| 在线观看视频99| 波多野结衣国产| 国产乱理伦片在线观看夜一区| 奇米精品在线| 大桥未久在线视频| 制服.丝袜.亚洲.中文.综合| 国产中年熟女高潮大集合| 欧美日本亚洲韩国国产| 国产在线一区二区三区| 国产精品影院在线| 欧美性色视频在线| 尤物网站在线观看| 欧美全黄视频| 99精品国产高清在线观看| 最新av网站在线观看 | 久久五月天综合| 亚洲不卡在线视频| 99久久精品一区二区| 黄网站色视频免费观看| 国产亚洲字幕| 久久久精品视频在线观看| 欧美在线视频精品| 国产亚洲视频系列| 99re在线视频免费观看| 美女一区2区| 国产69精品久久久久99| 国产超碰人人模人人爽人人添| 国产精品久久久久三级| 污网站免费在线| 精品九九在线| 国产精品网站视频| 日本一二三区视频在线| 免费黄色在线观看| 在线91免费看| 99成人在线观看| 久久99国产精品久久99| 亚洲精品中文字幕在线| 国产精品亚洲成在人线| 日韩中文视频免费在线观看| 一区二区www| 日韩一区有码在线| 九九热视频免费| 狠狠噜噜久久| 国产在线欧美日韩| 黑森林国产精品av| 亚洲色图35p| 中国a一片一级一片| 亚洲欧洲国产日韩| 97人人模人人爽人人澡| 亚洲国内自拍| 欧美中日韩一区二区三区| 成人看片网站| 久久久91精品国产| 亚洲乱码在线观看| 午夜在线电影亚洲一区| 久久久久久久久久久国产精品| 老牛影视一区二区三区| 性刺激综合网| 日韩精品一区二区三区中文| 国内精品小视频| 国产三级在线| 欧美丰满美乳xxx高潮www| 久草视频手机在线观看| 91免费在线看| 日韩一区二区三区不卡视频| 51精产品一区一区三区| 国产在线一区二区三区播放| 日韩欧美另类一区二区| x99av成人免费| 日本高清视频www| 欧美专区日韩专区| 欧美极品视频在线观看| xnxx国产精品| www.桃色.com| 国产欧美欧美| 色乱码一区二区三区熟女| 97se亚洲| 国产精品亚洲аv天堂网| 自由的xxxx在线视频| 亚洲女人天堂网| 精品国自产拍在线观看| 色网站国产精品| 久久久久香蕉视频| 国产精品沙发午睡系列990531| 波多野结衣中文字幕在线播放| 免费精品视频| av在线免费观看国产| 精品国产美女| 国产一区二区三区四区五区在线| 精品福利在线| 欧美一级在线亚洲天堂| 国产一二区在线| 亚洲日本成人女熟在线观看| 精品免费久久久| 欧美亚洲国产一区在线观看网站 | 国产成人精品久久久| av毛片在线免费| 中文字幕日本精品| 日韩在线免费看| 欧美tk丨vk视频| 亚洲一线在线观看| 色老综合老女人久久久| 精品无码黑人又粗又大又长| 国产精品国产精品国产专区不片 | 国产精品国产精品国产专区不蜜| 97精品人妻一区二区三区蜜桃| 久久99精品久久久| 亚洲 中文字幕 日韩 无码| 亚洲激情国产| 中文字幕日韩精品无码内射| 色婷婷色综合| 日韩欧美在线电影| 免费一区二区| 久久精品日产第一区二区三区精品版| 婷婷综合国产| 亚洲一区久久久| 成人动漫视频在线观看| 国产免费亚洲高清| 黑人一区二区三区| 国产精品午夜一区二区欲梦| 国产成人77亚洲精品www| 日韩av片永久免费网站| 性欧美freesex顶级少妇| 欧美精品久久久久久久久| 18videosex性欧美麻豆| 精品国产依人香蕉在线精品| 欧美人xxx| 最新国产成人av网站网址麻豆| 成人h小游戏| 国产一区二区三区精品久久久| 黄色av网站在线| 亚洲天堂色网站| 成人激情电影在线看| 一区二区三区 在线观看视| 国产区高清在线| 这里只有精品丝袜| 麻豆视频在线播放| 欧美大尺度在线观看| 色噜噜狠狠狠综合欧洲色8| 色综合导航网站| 暧暧视频在线免费观看| 欧美一区二区三区图| 校园春色亚洲| 国产玖玖精品视频| 激情五月综合婷婷| 国产高清自拍一区| 欧美sss在线视频| 欧美成人免费在线| 色欧美自拍视频| 中文字幕日韩精品无码内射| 亚洲激情精品| 天天操天天爽天天射| 精品一区二区久久| 国产伦精品一区二区三区妓女下载| 丰满少妇久久久久久久| 国产极品一区二区| 国产女主播一区| 加勒比av在线播放| 欧美色播在线播放| 一级黄色大片免费| 精品久久久久久久久久久久久久久| 手机看片国产1024| 在线看日韩av| 毛片在线导航| 国产精品成人va在线观看| 日韩一级视频| 黄色91av| 久久综合国产| www.射射射| 麻豆精品一区二区av白丝在线| gogo亚洲国模私拍人体| 91美女精品福利| 日本中文在线视频| 欧美日韩免费在线观看| 亚洲最大成人在线视频| 精品国产乱码91久久久久久网站| 欧美美女搞黄| 久久99精品久久久久久琪琪| videos性欧美另类高清| 91网站在线看| 精品国产成人| 水蜜桃色314在线观看| 蜜桃av一区二区三区| 怡红院一区二区| 国产精品美女www爽爽爽| 精品视频在线观看免费| 欧美日韩在线精品一区二区三区激情| 亚洲奶汁xxxx哺乳期| 中文字幕日韩精品有码视频| 波多野结衣在线高清| 91麻豆国产语对白在线观看| 久久99青青| 欧美国产日韩激情| 黄页视频在线91| 李宗瑞91在线正在播放| 亚洲午夜av在线| 国产情侣av在线| 伊人亚洲福利一区二区三区| 久草在线资源站手机版| 91成人在线看| 亚洲激情久久| 亚洲欧美激情网| 久久久久久久久99精品| 国产在线观看免费视频今夜| 欧美日韩日日夜夜| 欧美69xxxxx| 欧美诱惑福利视频| 在线精品国产亚洲| 熟妇熟女乱妇乱女网站| 美腿丝袜在线亚洲一区| 一级黄色性视频| 欧美三级免费观看| 日本中文字幕电影在线观看| 久久久久久国产精品三级玉女聊斋| av国产精品| 最新中文字幕久久| 老司机午夜精品99久久| 亚洲黄色小说视频| 色综合久久久久综合| 亚洲人午夜射精精品日韩| 欧美裸身视频免费观看| 日本亚洲视频| 欧美 亚洲 视频| 国产v日产∨综合v精品视频| 欧美日韩国产精品综合| 日韩一区二区三区视频在线观看| 免费的黄网站在线观看| 国产日韩欧美在线播放| 欧美好骚综合网| 色91精品久久久久久久久| 国产精品美女久久久久久2018| 亚洲精品国产精品国自产网站按摩| 国产一区二区免费| 欧美国产日韩电影| 一区二区视频在线观看| 久久91精品久久久久久秒播| 久草视频手机在线| 91精品福利在线一区二区三区 | 亚洲 日韩 国产第一| 青青草久久爱| 日本新janpanese乱熟| 国产精品无人区| 在线免费看av的网站| xxx成人少妇69| 亚洲精选av| 777精品久无码人妻蜜桃| 久久综合99re88久久爱| 丁香社区五月天| 少妇激情综合网| 久久国产精品美女| 妺妺窝人体色777777| 91亚洲国产成人精品一区二三| 影音先锋在线国产| 伊人久久大香线蕉av一区二区| 九七电影院97理论片久久tvb| 精品一区二区成人免费视频 | 国内精品不卡| 岛国一区二区三区高清视频| 日韩午夜在线| 俄罗斯毛片基地| 日韩欧美一级二级三级| 国产社区精品视频| 亚洲不卡一卡2卡三卡4卡5卡精品| 青青国产91久久久久久| 波多野结衣亚洲一区二区| 日韩成人中文电影| 欧美一级网址| 妞干网在线观看视频| 国产欧美一区二区精品秋霞影院| 国产欧美熟妇另类久久久| 97精品国产97久久久久久免费| 凹凸成人精品亚洲精品密奴| 美女被艹视频网站| 日韩欧美在线第一页| 羞羞视频在线观看不卡| 免费在线一区二区| 国产iv一区二区三区| 亚洲欧美一二三区| 久久久久久久久久国产|