<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
專案地址:
線上體驗:
標尺指的是畫布上邊和左邊的兩個有刻度的尺子,作用讓使用者知道他正在編輯的視口所在位置範圍。
我們的需求是:間隔特定的長度,繪製一個刻度,並顯示這個刻度在 X 軸或 Y 軸上的位置。
先看最終實現效果:
標尺功能演示
可以看到,視口移動後,標尺上的刻度能正確地改變。此外縮放畫布,標尺的步長會發生改變,保持一個比較適合的密度。
總體實現思路:
步長會根據 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);
繪製順序需要注意一下,先後順序為:
以上就是JS圖形編輯器實現標尺功能範例詳解的詳細內容,更多關於JS圖形編輯器實現標尺的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45