簡體   English   中英

僅變換 Path2D 的樣式

[英]Transform only the styling of a Path2D

在 canvas 2D API 中,我們可以首先使用一個上下文的轉換定義一個子路徑,然后僅針對fill()stroke()調用更改該上下文的轉換,這會對樣式產生影響,例如fillStylelineWidth和其他可見屬性,但這將使子路徑保持定義。 當我們想要在保持相同筆畫寬度的同時放大矢量形狀時,這非常方便。

這是一個簡單的示例,其中只有lineWidth受可變縮放變換的影響:

 const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); let zoom = 1; let speed = 0.1; requestAnimationFrame(update); function update() { if( zoom >= 10 || zoom <= 0.1 ) speed *= -1; zoom += speed; draw(); requestAnimationFrame(update); } function draw() { ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.clearRect(0,0,canvas.width,canvas.height); // define the subpath at identity matrix ctx.beginPath(); ctx.moveTo(10 ,80); ctx.quadraticCurveTo(52.5,10,95,80); ctx.quadraticCurveTo(137.5,150,180,80); // stroke zoomed ctx.setTransform(zoom, 0, 0, zoom, 0, 0); ctx.stroke(); }
 <canvas id="canvas"></canvas>

使用Path2D API,我們必須直接在ctx.fill(path)ctx.stroke(path)方法中傳遞這個子ctx.stroke(path)
這意味着我們不能像以前那樣將樣式與子路徑聲明分開:

 const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); let zoom = 1; let speed = 0.1; requestAnimationFrame(update); function update() { if( zoom >= 10 || zoom <= 0.1 ) speed *= -1; zoom += speed; draw(); requestAnimationFrame(update); } function draw() { ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.clearRect(0,0,canvas.width,canvas.height); // define the subpath at identity matrix // (declared in 'draw' just for the example, would be the same anyway outside) const path = new Path2D("M 10 80 Q 52.5 10, 95 80 T 180 80"); // stroke zoomed ctx.setTransform(zoom, 0, 0, zoom, 0, 0); ctx.stroke(path); }
 <canvas id="canvas"></canvas>

在使用這個方便的 Path2D API 時,有沒有辦法做到這一點?

有一種方法通過使以變換Path2D對象DOMMatrix 1Path2D.prototype.addPath方法。

因此,我們實際上可以通過傳遞 Path2d 的轉換副本來實現相同的結果:

const transformPath = (path, matrix) => {
  const copy = new Path2D();
  copy.addPath(path, matrix);
  return copy;
};
// ...
ctx.stroke( transformPath( path, {a: 1/zoom, d: 1/zoom } );

但是,您會注意到我們必須使我們的路徑矩陣相對於樣式矩陣
新的 DOMMatrix API 簡化了矩陣變換2 ,但它使這種方法肯定比beginPath()方法更復雜,很遺憾我們不能對 Path2D 對象本身采取行動,甚至也不能在構造函數上使用這個變換參數,但這是我所知道的唯一方法......

 const transformPath = (path, matrix) => { const copy = new Path2D(); copy.addPath(path, matrix); return copy; }; const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); // define the subpath const path = new Path2D("M 10 80 Q 52.5 10, 95 80 T 180 80"); let zoom = 1; let speed = 0.1; requestAnimationFrame(update); function update() { if( zoom >= 10 || zoom <= 0.1 ) speed *= -1; zoom += speed; draw(); requestAnimationFrame(update); } function draw() { ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.clearRect(0,0,canvas.width,canvas.height); // zoom the stylings ctx.setTransform(zoom, 0, 0, zoom, 0, 0); // create our transformed path const invertMatrix = {a: 1/zoom, d: 1/zoom}; ctx.stroke(transformPath(path, invertMatrix)); }
 <canvas id="canvas"></canvas>

1.實際上它不需要是一個實際的DOMMatrix,任何具有其屬性的對象都可以
2. 我們現在甚至可以在ctx.setTransform(matrix)使用這樣的對象。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM