根據基準框, 來放大縮小平移
啊,了解了!這樣就更單純了。drawImage 只是你的參考線。
線條的寬度實際上會變成 N * scaleX(對於水平方向的線段)和 N * scaleY(對於垂直方向的線段)。 如果 scaleX 和 scaleY 不同(非均勻縮放),線條看起來會有不同的粗細。 如果 scaleX 和 scaleY 相同(均勻縮放),線條寬度會一致地變為 N * scaleFactor。
<!DOCTYPE html>
<html>
<head>
<title>Dynamic Canvas Shape (No Image)</title>
<style>
body { margin: 20px; }
canvas { border: 1px solid black; }
</style>
</head>
<body>
<canvas id="myCanvas" width="600" height="450"></canvas>
<script>
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
// 繪製原始尺寸和位置 (方便比較)
drawCustomFrame(ctx, 10, 10, 150, 100, "blue", 1.5);
// 根據新的 x, y, w, h 繪製
drawCustomFrame(ctx, 200, 30, 300, 200, "red", 2); // 放大並移動
drawCustomFrame(ctx, 50, 250, 75, 50, "green", 1); // 縮小並移動到另一位置
drawCustomFrame(ctx, 200, 280, 200, 150, "purple", 3); // 不同尺寸和線寬
/**
* 繪製可變形的自訂邊框路徑
* @param {CanvasRenderingContext2D} context - Canvas 的 2D 渲染上下文
* @param {number} targetX - 目標位置的 X 座標 (圖形左上角)
* @param {number} targetY - 目標位置的 Y 座標 (圖形左上角)
* @param {number} targetWidth - 目標寬度
* @param {number} targetHeight - 目標高度
* @param {string} [strokeColor="black"] - 線條顏色
* @param {number} [baseLineWidth=1] - 線條的基礎寬度。注意:實際渲染的線寬會受到縮放影響。
*/
function drawCustomFrame(context, targetX, targetY, targetWidth, targetHeight, strokeColor = "black", baseLineWidth = 1) {
const originalWidth = 150; // 你定義 Bezier 曲線時的原始寬度
const originalHeight = 100; // 你定義 Bezier 曲線時的原始高度
// 計算縮放比例
// 如果 targetWidth 或 targetHeight 為 0,避免除以零,並將比例設為一個極小值或 1
const scaleX = (originalWidth === 0) ? 1 : targetWidth / originalWidth;
const scaleY = (originalHeight === 0) ? 1 : targetHeight / originalHeight;
context.save(); // 儲存當前狀態 (轉換矩陣, 樣式等)
// 1. 平移: 將畫布原點移動到目標位置的左上角
context.translate(targetX, targetY);
// 2. 縮放: 以新的原點為中心進行縮放
context.scale(scaleX, scaleY);
// --- 現在開始使用原始座標繪製路徑 ---
// (0,0) 現在是 targetX, targetY 經過縮放後的位置
// 所有繪圖指令的座標都是相對於這個原始的 150x100 框框
context.beginPath();
context.moveTo(0, 4);
context.bezierCurveTo(50, 20, 56, 20, 59, 11);
context.bezierCurveTo(88, 27, 143, 7, 150, 0);
context.bezierCurveTo(139, 12, 127, 29, 142, 29);
context.bezierCurveTo(136, 52, 138, 62, 145, 68);
context.bezierCurveTo(130, 78, 146, 90, 150, 100);
context.bezierCurveTo(133, 90, 116, 80, 105, 95);
context.bezierCurveTo(70, 83, 36, 84, 0, 100);
context.bezierCurveTo(11, 91, 27, 66, 7, 69);
context.bezierCurveTo(18, 58, 25, 46, 5, 27);
context.bezierCurveTo(19, 29, 23, 25, 0, 4); // 回到起點 (0,4)
context.closePath(); // 明確閉合路徑,對於 stroke 可能不是絕對必要但好習慣
context.strokeStyle = strokeColor;
context.lineWidth = baseLineWidth; // 設定線條寬度,它會被 scaleX, scaleY 影響
context.stroke(); // 描邊繪製路徑
context.restore(); // 恢復到 save() 之前的狀態,移除本次的 translate 和 scale 影響
}
</script>
</body>
</html>
移除了 imageObject 相關的程式碼。 originalWidth 和 originalHeight : 這些值 (150, 100) 是你定義 Bezier 曲線時,這些座標點所參考的原始畫布或區域的尺寸。scaleX 和 scaleY 就是基於這個原始尺寸和新的目標尺寸計算出來的。baseLineWidth 參數 : 我將 lineWidth 參數名改為 baseLineWidth 並在註解中說明,這個寬度會受到 ctx.scale() 的影響。如果你傳入 baseLineWidth = 1,而圖形被放大兩倍 (scaleX=2, scaleY=2),那麼實際線條看起來會有 2px 寬。context.closePath() : 雖然你的最後一個 bezierCurveTo 已經回到了起點 (0,4),但使用 closePath() 是一個好習慣,它會明確地將當前點連接回路徑的起始點,確保圖形是封閉的。對於 stroke() 來說,如果路徑本身已經閉合,效果可能不明顯,但對於 fill() 則很重要。增加了對 originalWidth 或 originalHeight 為 0 的檢查 :避免除以零的錯誤,雖然在你的情況下它們是固定的 150 和 100。
留言
張貼留言