Demand background
Generally speaking, text thinning is used for map related requirements. I also implemented this method when I implemented a function for the company's map engine. Here, I simplified it and operated it on the ordinary Canvas without introducing the concept of map
Effect
collision detection
Calculate the range of text in canvas
// Calculate the width required for text var p = { x: 10, y: 10, name: "Test text" }; var measure = ctx.measureText(p.name); // Find out the maximum y coordinate occupied by text in canvas drawing board var maxX = measure.width + p.x; // Find out the maximum y coordinate occupied by text in canvas drawing board // canvas can only calculate the width of text, not the height of text. So we use the width of the text divided by the number of words to calculate the approximate value var maxY = measure.width / p.name.length + p.y; var min = { x: p.x, y: p.y }; var max = { x: maxX, y: maxY }; // bounds is the range that the text occupies in canvas. // When taking point coordinates as the minimum range, textAlign and textBaseline will be set accurately in the following ways. // If the setting is displayed in different positions, the maximum and minimum range points shall also be adjusted // ctx.textAlign = "left"; // ctx.textBaseline = "top"; var bounds = new Bounds(min, max);
Bounds scope object
/** * Define scope object */ function Bounds(min, max) { this.min = min; this.max = max; } /** * Judge whether the range intersects another range */ 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; };
Testing
// Before each drawing, cross check the range with the drawn text // If a cross is found, the current text will be discarded, otherwise it will be drawn and saved in the drawn text list for (var index in _textBounds) { // Loop through all drawn text ranges to check whether there is an intersection with the current text range. If there is an intersection, the text will be skipped 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, p.x, p.y);
Example, code address
Example address: Example
See the complete code for details: Github address