JS圖形編輯器場景坐標(biāo)視口坐標(biāo)的相互轉(zhuǎn)換
圖形編輯器坐標(biāo)系
圖形編輯器的坐標(biāo)系有兩種。
一個是場景(scene)坐標(biāo)系,一個是 視口(viewport)坐標(biāo)系。視口就是場景的一個子區(qū)域。
假設(shè)我們的視口的原點(diǎn),離場景原點(diǎn)的坐標(biāo)水平和垂直距離分別為 scrollX 和 scrollY。
先 不考慮縮放,假設(shè)我們在視口坐標(biāo)上的某個地方點(diǎn)擊了一下,這個坐標(biāo)是 (x, y)
。這個坐標(biāo)在場景坐標(biāo)系中,就是:
const?sceneX?=?scrollX?+?x; const?sceneY?=?scrollY?+?y;
挺簡單。
視口坐標(biāo)轉(zhuǎn)換為場景坐標(biāo)
下面我們引入畫布縮放,即畫布可以縮小和放大,對應(yīng)的一個比例值 zoom。
視口中的某個坐標(biāo) (x, y)
在場景坐標(biāo)系,則是 :
function?viewportCoordsToSceneCoords(x,?y,?scrollX,?scrollY,?zoom)?{ ??return?{ ??x:?scrollX?+?x?/?zoom, ??y:?scrollY?+?y?/?zoom ??} }
之所以要用 x 除以 zoom,是因為此時視口中展示的是縮放后的圖形,里面的坐標(biāo)都是縮放后的值。所以需要先轉(zhuǎn)換為 zoom 值為 1 對應(yīng)的真實(shí)值。
場景坐標(biāo)轉(zhuǎn)換為視口坐標(biāo)
然后我們反過來,如何從場景坐標(biāo) (x, y)
轉(zhuǎn)換為視口坐標(biāo)?將前面的公式做等式變換即可:
function?sceneCoordsToViewportCoords(x,?y,?scrollX,?scrollY,?zoom)?{ ??return?{ ??x:?(x?-?scrollX)?*?zoom, ??y:?(y?-?scrollY)?*?zoom ??}; }
我們通常是使用按鍵加滾輪的方式讓畫布以光標(biāo)為中心進(jìn)行縮放,或按按鈕進(jìn)行縮放,
為了讓縮放后的場景還能對上縮放前光標(biāo)的位置,我們需要計算縮放后的 scrollX 和 scrollY,進(jìn)行校準(zhǔn)。
核心思路是 保持縮放前點(diǎn)到視口左上角距離(視口坐標(biāo)系)相同。
function?calScrollVal(cx,?cy,?prevZoom,?zoom,?scrollX,?scrollY)?{ ??//?先計算目標(biāo)點(diǎn)的場景坐標(biāo)(這里?cx?和?cy?是基于視口坐標(biāo)系的) ??const?{?x:?sceneX,?y:?sceneY?}?=?viewportCoordsToSceneCoords(cx,?cy,?prevZoom,?scrollX,?scrollY); ??//?縮放后畫布縮放比變成了?zoom,距離視口左上角的距離變成了?cx?/?zoom ??//?減去這個距離,就是新的 scrollX 了。 ??const?newScrollX?=?sceneX?-?cx?/?zoom; ??const?newScrollY?=?sceneY?-?cy?/?zoom; ??return?{ ????x:?newScrollX, ????y:?newScrollY ??}; }
再說點(diǎn)別的。
可能會有這么一種情況,就是實(shí)際的視口區(qū)域的原點(diǎn)坐標(biāo)有一些偏移,偏移了 offsetX 和 offsetY,見下圖。
我們只需要將前面代碼中的 scrollX 變成 (scrollX + offsetX),scrollY 變成 (scrollY + offsetY),其他不變。
就這些了。
總結(jié)一下,視口坐標(biāo)是場景坐標(biāo)平移并縮放后的結(jié)果,所以視口轉(zhuǎn)場景,需要除以 zoom 再加上偏移值。在圖形編輯器中,會有相當(dāng)多的坐標(biāo)系轉(zhuǎn)換邏輯,這兩個坐標(biāo)系的關(guān)系需要好好消化理解,更多關(guān)于JS場景視口坐標(biāo)轉(zhuǎn)換的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
總結(jié)JavaScript中BigIn函數(shù)常見的屬性
本文基于JavaScript基礎(chǔ),介紹了 BigInt 函數(shù),常見的屬性,通過 BigInt 函數(shù)進(jìn)行數(shù)字運(yùn)算符的比較。布爾運(yùn)算等等,通過按案例的分析進(jìn)行詳細(xì)的講解,需要的朋友可以參考一下2021-10-10javascript進(jìn)階篇深拷貝實(shí)現(xiàn)的四種方式
這篇文章主要為大家介紹了javascript進(jìn)階篇深拷貝實(shí)現(xiàn)的四種方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07Qiankun Sentry 監(jiān)控異常上報無法自動區(qū)分項目解決
這篇文章主要為大家介紹了Qiankun Sentry 監(jiān)控異常上報無法自動區(qū)分項目解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11next.js源碼解析getStaticProps?getStaticPaths使用場景
這篇文章主要為大家介紹了next.js源碼解析getStaticProps?getStaticPaths使用場景,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08