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

圖形編輯器:標尺功能的實現

開發 前端
標尺指的是畫布上邊和左邊的兩個有刻度的尺子,作用讓用戶知道他正在編輯的視口所在位置范圍。

大家好,我是前端西瓜哥。今天我們來實現圖形編輯器的標尺功能。

項目地址:

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

線上體驗:

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

標尺指的是畫布上邊和左邊的兩個有刻度的尺子,作用讓用戶知道他正在編輯的視口所在位置范圍。

我們的需求是:間隔特定的長度,繪制一個刻度,并顯示這個刻度在 X 軸或 Y 軸上的位置。

先看最終實現效果:

圖片

標尺功能演示

可以看到,視口移動后,標尺上的刻度能正確地改變。此外縮放畫布,標尺的步長會發生改變,保持一個比較適合的密度。

實現思路

總體實現思路:

  1. 確定刻度尺的步長(step)。步長是和畫布縮放比(zoom)相關的,zoom 越大,step 就越小;
  2. 計算出需要繪制的所有刻度。分別為從視口從左側到右側,從上邊到下邊的范圍;
  3. 繪制。繪制上也是有考量的,先繪制背景,然后繪制刻度,最后繪制分界線。

步長選擇

步長會根據 zoom 進行設置,目的是讓視口中的標尺能繪制適宜密度的刻度。

假設我們的步長固定為 50,不跟隨 zoom 改變,在 100% 看起來效果不錯:

圖片

但當你縮小時,會變成下面這樣:

圖片

密度過大,導致數字重疊。同樣,放大時則過于稀疏,刻度很難才見到一個,沒能發揮標尺的效用。

步長怎么計算呢?

理論上步長可以是 50,那么 51 好像也行,3 也行。但更建議使用 5 的倍數、2 的倍數、25 的倍數這些作為步長。

因為沒有什么理論參考,所以我還是選擇參考市面上的設計工具的步長變化設計。

比如 figma,zoom 落在 [100%, 200%) 的步長為 50,[200%, 500%) 則是 10 等等。

我的實現為:

const getStepByZoom = (zoom: number) => {
// 可用的步長列表
const steps = [1, 2, 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000];
// 看著 figma 的 step 變化想出的一個奇怪的規律
// 然后找出可選步長列表最近的并大于它的 step 作為最終步長
const step = 50 / zoom;
for (let i = 0, len = steps.length; i < len; i++) {
if (steps[i] >= step) return steps[i];
}
return steps[0];
};

const step = getStepByZoom(zoom);

計算范圍

這里我講解水平(x 軸)方向的情況。垂直方向同理,就不贅敘了。

首先計算出視口最左側和最右側的 x 坐標值。

let startXInScene = viewport.x + startXInViewport / zoom; // 視口坐標轉場景
let endXInScene = viewport.width + startYInViewport / zoom; // 視口坐標轉場景

然后找離它們最近的落在刻度上的值。

對此,我實現了一個 getClosestVal 方法。

/**
* 找出離 value 最近的 segment 的倍數值
*/
const getClosestVal = (value: number, segment: number) => {
const n = Math.floor(value / segment);
const left = segment * n;
const right = segment * (n + 1);
return value - left <= right - value ? left : right;
};

startXInScene = getClosestVal(startXInScene, step);
endXInScene = getClosestVal(endXInScene, step);

得到起點和終點,我們可以開始循環了,從 startXInScene 開始,每次循環加一個 step,直至達到末尾為止。

ctx.textAlign = 'center'; // 文字水平居中對齊

while (startXInScene <= endXInScene) {
ctx.strokeStyle = setting.rulerMarkStroke;
ctx.fillStyle = setting.rulerMarkStroke;
// 場景轉回視口再繪制。刻度線不能直接在場景中繪制,因為縮放變換會導致線的粗細變化
const x = (startXInScene - viewport.x) * zoom;
// 繪制刻度
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(x, y + setting.rulerMarkSize);
ctx.stroke();
ctx.closePath();
// 刻度值則用場景坐標的值
ctx.fillText(String(startXInScene), x, y - 4);
// +step,指針移動
startXInScene += step;
}

垂直方向的標尺同理,只是稍微特殊的是刻度值文字需要多做一個 -90 度的旋轉。

export const rotateInCanvas = (
ctx: CanvasRenderingContext2D,
angle: number,
cx: number,
cy: number
) => {
ctx.translate(cx, cy);
ctx.rotate(angle);
ctx.translate(-cx, -cy);
};

rotateInCanvas(ctx, -HALF_PI, x, y);

繪制順序

繪制順序需要注意一下,先后順序為:

  1. 繪制兩個標尺的背景色;
  2. 繪制刻度值;
  3. 用一個和背景色同色的矩形蓋掉左上角那個方形,那個地方不能有刻度值,不如兩個標尺的刻度會重疊。你也可以在繪制刻度值時,用裁切(ctx.clip)不讓繪制到那個方形區域上;
  4. 繪制兩條分割線;

最后

標尺實現大致如此,并不復雜。

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

2023-04-07 08:02:30

圖形編輯器對齊功能

2023-04-10 08:45:44

圖形編輯器排列移動功能

2023-10-19 10:12:34

圖形編輯器開發縮放圖形

2023-09-26 07:39:21

2023-01-18 08:30:40

圖形編輯器元素

2023-07-31 08:46:07

圖形編輯器圖形自動對齊

2023-08-31 11:32:57

圖形編輯器contain

2023-09-07 08:24:35

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

2023-02-06 16:59:57

Canvas編輯器

2023-10-08 08:11:40

圖形編輯器快捷鍵操作

2023-02-02 14:07:00

圖形編輯器Canvas

2023-09-11 09:02:31

圖形編輯器模塊間的通信

2023-05-09 08:15:32

圖形編輯器撤銷重做功能

2024-01-08 08:30:05

光標圖形編輯器開發游標

2023-02-09 07:02:30

圖形編輯器修改圖形

2023-08-28 08:10:50

Hex圖形編輯器

2023-10-10 16:04:30

圖形編輯器格式轉換

2023-03-03 10:24:51

2022-03-20 18:12:03

Shotcut開源視頻編輯器

2023-06-12 08:22:56

圖形編輯器工具
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美三级电影在线播放 | 亚洲欧美另类在线 | 中文字幕日韩欧美 | 国产欧美在线观看 | 国产视频精品视频 | 成人欧美一区二区三区白人 | 国产精品久久久久久吹潮 | 精品国产乱码久久久久久久久 | 影音先锋中文字幕在线观看 | 久久久片| 中文字幕精品一区 | 四虎影院在线播放 | 永久av| 欧美日韩激情 | 成人黄色av网站 | 九九99靖品 | 一级毛片免费 | 综合在线视频 | 欧美一级黄色片在线观看 | 日韩精品 | 欧美精品一区二区三区在线播放 | 久久久久久国产精品 | 免费在线看a | 91精品国产91久久久 | 亚洲日本中文字幕在线 | 365夜爽爽欧美性午夜免费视频 | 久久99久久99精品免视看婷婷 | 日韩av免费在线观看 | 日韩高清在线观看 | 亚洲一区二区电影网 | 日韩一区二区三区视频 | 国产真实乱对白精彩久久小说 | 欧美网站一区 | 亚洲三级在线 | 精品福利一区二区三区 | 欧美成人猛片aaaaaaa | aaaa日韩| 亚洲欧美日韩精品久久亚洲区 | 成人免费区一区二区三区 | 欧美中文字幕在线观看 | 日韩视频一级 |