成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

圖形編輯器開發:以光標為中心縮放畫布

開發 前端
場景坐標系 就是圖形所在的二維平面世界所使用的坐標系。單位是像素(px)。坐標系的原點在畫布(canvas 元素)的左上角,x 軸向右,y 軸向下。

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

畫布縮放是圖形設計工具中很重要的基礎能力。

通過它,我們可以像舉著一臺攝影機,在圖形所在的世界到處游逛,透過鏡頭,可以只看自己想看的圖形;可以拉近攝影機,看到圖形的細節;也可以拉遠攝影機,總覽多個圖形之間的關系。

ok,那么我們看看如何實現縮放畫布功能。

文中的動圖演示來自我正在開發的圖形設計工具:

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

線上體驗:

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

場景坐標系和視圖坐標系

場景坐標系 就是圖形所在的二維平面世界所使用的坐標系。單位是像素(px)。坐標系的原點在畫布(canvas 元素)的左上角,x 軸向右,y 軸向下。

圖形會被繪制到這個平面,理論上它的范圍是可以 無限延展 的。(不過實際上我們會給一個上限,但這個值也非常大。無限大的話沒有意義,且浮點數是有取值范圍的)

然而顯示器的寬高是有限的,只能看一個矩形范圍內的內容。

所以我們需要引入一個 “攝影機”:視圖坐標系,只看部分的區域。

其實就是將原來真實的圖形的坐標做一個線性計算轉換。

首先是將特定區域 移動 到視口中,就像攝影機從原點移動我們想要觀察的某個物體上。不過實際上是物體所在的平面做了一個方向的移動。

然后再做一個縮放,就像攝影機拉近或遠離與目標物體距離,效果是物體在鏡頭下變大或變小。

轉換就兩步,移動然后縮放

視圖矩陣轉換

場景坐標系到視圖坐標系的轉換,我們通過 視圖矩陣 相乘來實現。

事實上,任意兩個坐標系下坐標的轉換,都可以通過一個矩陣乘法來實現。

首先是將坐標進行位移,x 方向位移 -viewport.x,y 方向位移 -viewport.y。這里是負數,雖然我們想要移動 “攝影機”這是因為移動的是畫布

<平移矩陣> * 坐標

然后再縮放(縮放值我們會用 zoom 表示):

<縮放矩陣> * 平移后的坐標

所有過程寫在一起,就是:

<縮放矩陣> * <平移矩陣> * 坐標

矩陣乘法符合結合律,所以我們的視圖矩陣為:

<視圖矩陣>
= <縮放矩陣> * <平移矩陣>

矩陣表示為:

計算結果為:

對應的 Canvas 2D 代碼:

ctx.scale(zoom, zoom);
ctx.translate(-viewport.x, -viewport.y);

寫成一個方法:

// 場景坐標轉視圖坐標
function sceneCoordsToViewport(x, y, zoom, scrollX, scrollY) {
  return {
  x: (x - scrollX) * zoom,
  y: (y - scrollY) * zoom
  };
}

至于反過來,場景坐標系轉視圖坐標,計算它的逆矩陣即可:

以光標為中心縮放

首先我們來認清本質,所謂以光標為中心縮放,不變的是什么?

光標所在點在視圖坐標系距離視口左上角的相對位置,保持不變。

我們要做的事是,在 zoom 變化后,調整 viewport.x 和 viewport.y 的值,讓光標在視圖坐標系上相對視口左上角距離不變。

這里得補充一個知識點。就是兩個坐標系中距離的轉換:

  1. 場景轉視圖,距離轉換為 dist * zoom;
  2. 視圖轉場景,距離的轉換是 dist / zoom,因為視口看到的圖形都是縮放(乘以 zoom)后的結果,所以反過來就要除回去。

實現思路是:

  1. 記錄好縮放前,光標所在位置的場景坐標;
  2. 計算 (cx, cy) 在舊縮放比(zoom)的場景坐標。
  3. 計算 cx 在新的縮放比(zoom)下,(cx / zoom, cy / zoom)。
  4. 然后二者相減,即可得到新的適口左上角坐標。

代碼實現為:

/**
 * 以某點為中心,進行畫布縮放
 * @param {number} zoom 新的縮放比
 * @param {number} cx 縮放中心(使用視圖坐標)
 * @param {number} cy
 */
const setZoomAndUpdateViewport = (zoom, cx, cy) => {
  const prevZoom = this.zoom;
  this.zoom = zoom;

  // 計算縮放中點的場景坐標
  const { x: sceneCX, y: sceneCY } = viewportCoordsToScene(
    cx,
    cy,
    prevZoom,
    this.viewport.x,
    this.viewport.y,
  );

  // 核心代碼
  const newViewportX = sceneCX - cx / zoom;
  const newViewportY = sceneCY - cy / zoom;

  this.viewport.x = newViewportX;
  this.viewport.y = newViewportY;

  this.renderScene();
};

以畫布為中心進行縮放

如果縮放時光標不在畫布上,比如通過手動輸入縮放值時,會 以畫布的中心位置進行縮放。

實現同上,只是 cx 和 cy 改成傳入視口(即畫布)的寬高除以 2:(viewport.width / 2, , (viewport.height / 2)。

結尾

要實現畫布縮放,重點是理解場景坐標和視圖坐標之間的關系。

場景坐標轉視圖坐標,首先需要將畫布進行移動,讓場景坐標的原點和視圖坐標的原點對上(場景坐標移動 -viewport.x 和 -viewport.x),然后再進行縮放(乘以 zoom)。

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

2023-10-19 10:12:34

圖形編輯器開發縮放圖形

2024-01-08 08:30:05

光標圖形編輯器開發游標

2024-01-03 08:43:17

圖形編輯器旋轉控制點縮放控制點

2023-08-31 11:32:57

圖形編輯器contain

2023-09-07 08:24:35

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

2023-09-26 07:39:21

2023-09-11 09:02:31

圖形編輯器模塊間的通信

2023-08-28 08:10:50

Hex圖形編輯器

2023-10-10 16:04:30

圖形編輯器格式轉換

2023-10-08 08:11:40

圖形編輯器快捷鍵操作

2023-01-18 08:30:40

圖形編輯器元素

2023-02-01 09:21:59

圖形編輯器標尺

2023-07-31 08:46:07

圖形編輯器圖形自動對齊

2023-02-06 16:59:57

Canvas編輯器

2023-04-07 08:02:30

圖形編輯器對齊功能

2023-06-12 08:22:56

圖形編輯器工具

2023-04-10 08:45:44

圖形編輯器排列移動功能

2023-05-09 08:15:32

圖形編輯器撤銷重做功能

2023-02-09 07:02:30

圖形編輯器修改圖形

2022-12-02 07:24:46

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 在线日韩在线 | 中文一区二区 | 国产成人精品一区二区 | 91福利电影在线观看 | 亭亭五月激情 | 九九久久99 | 国产精品成av人在线视午夜片 | 欧美视频一区二区三区 | 啪啪免费 | 久久9精品 | 午夜播放器在线观看 | 一级毛片在线看 | 欧美日韩一区二区三区在线观看 | 欧美日韩在线一区二区 | 亚洲高清三级 | 狠狠亚洲| 99久久亚洲 | 亚洲 中文 欧美 日韩 在线观看 | 天天插天天狠天天透 | 风间由美一区二区三区在线观看 | 男人的天堂avav | 蜜桃黄网 | 特一级毛片 | 黄色国产在线播放 | 国产欧美精品一区二区 | 亚洲男人天堂av | 成人在线免费视频观看 | 四色成人av永久网址 | 欧美国产视频 | 亚洲欧美一区二区三区视频 | 欧美中文在线 | 日韩在线一区二区 | 欧美日韩精品亚洲 | 欧美精品电影一区 | 精品欧美色视频网站在线观看 | 波多野结衣av中文字幕 | 精品一区二区三区不卡 | 精品久草 | 中文在线视频 | 在线观看中文字幕视频 | 中文字幕视频免费 |