一般在做地圖相關的需求是才會用到文字抽稀,我也是在為公司的地圖引擎實現一個功能時才實現了該方法,在這裡將其簡化了,就在普通的Canvas 上進行操作,並沒有引入地圖概念
效果碰撞偵測計算文字在canvas 中所佔據的範圍
// 計算文字所需的寬度var p = { x: 10, y: 10, name: 測試文字};var measure = ctx.measureText(p.name);// 求文字在canvas 畫板中佔據的最大y 座標var maxX = measure.width + px;// 求文字在canvas 畫板中所佔據的最大y 座標// canvas只能計算文字的寬度,不能計算出文字的高度。所以就利用文字的寬度除以文字個數計算個大概var maxY = measure.width / p.name.length + py;var min = { x: px, y: py };var max = { x: maxX, y: maxY };// bounds 為該文字在canvas 中所佔據的範圍。 // 在取點位座標作為最小範圍時,textAlign、textBaseline 依照以下方式設定會比較準確。 // 如設定在不同的位置展示,範圍最大、最小點也需調整// ctx.textAlign = left;// ctx.textBaseline = top;var bounds = new Bounds(min, max);
Bounds 範圍對象
/** * 定義範圍物件*/function Bounds(min, max) { this.min = min; this.max = max;}/** * 判斷範圍是否與另外一個範圍有交集*/Bounds.prototype.intersects = function(bounds) { var min = this.min, max = this.max, min2 = bounds.min, max2 = bounds.max, xIntersects = max2.x >= min.x && min2.x <= max.x, yIntersects = max2.y >= min.y && min2.y <= max.y; return xIntersects && yIntersects;};
偵測
// 每次繪製之前先與已繪製的文字進行範圍交叉檢測// 如發現有交叉,則放棄繪製當前文字,否則繪製並存入已繪製文字列表for (var index in _textBounds) { // 循環所有已繪製的文字範圍,偵測是否和目前文字範圍有交集,如果有交集說明會碰撞,則跳過該文字var pointBounds = _textBounds[index]; if (pointBounds.intersects(bounds)) { return; }}_textBounds.push(bounds);ctx.fillStyle = red;ctx.textAlign = left;ctx.textBaseline = top;ctx.fillText(p.name, px, py);範例、程式碼地址
範例地址:範例
具體可查看完整程式碼:Github 位址
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。