gpt4 book ai didi

Javascript 在 Canvas 中渲染文本并避免文本冲突

转载 作者:行者123 更新时间:2023-11-30 12:17:17 26 4
gpt4 key购买 nike

我正在开发一种映射软件,可以将文本从数据库渲染到 Canvas 上的特定坐标。目标是渲染的文本不会相互踩踏(不重叠),但仍遵循应显示的坐标。这个想法是,如果呈现的文本重叠,程序可能会选择以一定 Angular 显示它。目前我正在通过以下代码呈现文本:

create_point:function(x,y,stitle){
var canvas = document.getElementById('text-layer');
var context = canvas.getContext('2d');
context.fillText(stitle,x,y); // text and position
context.save();
}

对此有什么想法吗?

提前致谢:-)

最佳答案

有趣的思维谜题!

问题

您已经从数据库中映射了坐标(带有文本标签),有时 2 个或更多坐标靠得太近以至于它们的文本标签相交(导致它们的文本标签不可读)。

一个解决方案

对于要在 map 上绘制的每个新文本标签:

  1. 假设每个新文本标签都绘制在 map 坐标的顶部。测试新标签是否会覆盖任何现有标签。

    • 如果不会发生覆盖,则将其绘制在顶部(这样就完成了此标签)。
    • 如果顶面会导致覆盖,继续第 2 步。
  2. 假设新标签位于 map 坐标的右侧,重复步骤#1。

  3. 假设新标签位于 map 坐标的底部,重复步骤#1。

  4. 假设新标签位于 map 坐标的左侧,重复步骤#1。

如果上述所有 4 个步骤都失败,则无法在不覆盖现有标签的情况下绘制此文本标签。

如果失败,您必须决定以替代方式向用户提供您的文本标签信息。

想到这些选项:

  • 在 map 上绘制一个小标记,用户可以将鼠标悬停在该标记上并查看带有文本标签信息的弹出工具提示。这是处理不适合页面的信息的一种非常常见的方式。

  • 在 map 上绘制一个小标记,将用户引向包含文本标签信息的单独图例。

  • 在 map 上绘制一个带有箭头线的小标记,将用户引导至绘制在 map 上但远离 map 坐标的文本标签。

  • 根本不要包含这个新标签!这个新标签可能不如现有 map 标签重要,因此可能会被省略。您可以按照对用户的重要性对 map 数据库进行排序,从而轻松实现这一目标。

这是说明此解决方案的演示

enter image description here

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }

var fontSize=12;
var fontFace='verdana';
var dotRadius=3;
var legendX=350;
var legendY=0;
var legendYincrement=10;

var labels=[];
var nextId=0;

ctx.textAlign='left';
ctx.textBaseline='top';
ctx.font='10px arial';
ctx.strokeRect(legendX-5,0,cw-legendX+5,ch);
ctx.fillText('Other labels',legendX-3,legendY+2);
legendY+=legendYincrement;
ctx.fillText('(Color Coded)',legendX-3,legendY+2);
legendY+=legendYincrement;

var label=addLabel('Label #0',cw/2,ch/2,fontSize,fontFace,dotRadius);
drawLabel(label);

$("#canvas").mousedown(function(e){handleMouseDown(e);});

//
function addLabel(text,dotX,dotY,fontsize,fontface,dotRadius){
var font=fontsize+'px '+fontface;
ctx.font=font;
var w=ctx.measureText(text).width;
var h=fontsize*1.286;
var label={
id:nextId++,
text:text,
x:dotX-w/2,
y:dotY-dotRadius-h,
w:w,
h:h,
offsetY:0,
font:font,
isColliding:false,
dotRadius:dotRadius,
dotX:dotX,
dotY:dotY,
};
labels.push(label);

// try to position this new label in a non-colliding position
var positions=[
{ x:dotX-w/2, y:dotY-dotRadius-h }, // N
{ x:dotX+dotRadius, y:dotY-h/2 }, // E
{ x:dotX-w/2, y:dotY+dotRadius }, // S
{ x:dotX-dotRadius-w, y:dotY-h/2 }, // W
];
for(var i=0;i<positions.length;i++){
var p=positions[i];
label.x=p.x;
label.y=p.y;
label.isColliding=thisLabelCollides(label);
if(!label.isColliding){ break; }
}

//
return(label);
}

function handleMouseDown(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();

var x=parseInt(e.clientX-offsetX);
var y=parseInt(e.clientY-offsetY);

var label=addLabel('Label #'+nextId,x,y,fontSize,fontFace,dotRadius)

drawLabel(label);
}

//
function drawLabel(label){
ctx.textAlign='left';
ctx.textBaseline='top';
if(label.isColliding){
legendY+=legendYincrement;
ctx.beginPath();
ctx.arc(legendX,legendY,3,0,Math.PI*2);
ctx.fillStyle=randomColor();
ctx.fill();
ctx.font='10px arial';
ctx.fillText(label.text,legendX+5,legendY-5);
}else{
ctx.font=label.font;
ctx.fillStyle='black';
ctx.fillText(label.text,label.x,label.y)
ctx.strokeRect(label.x,label.y,label.w,label.h);
}
ctx.beginPath();
ctx.arc(label.dotX,label.dotY,label.dotRadius,0,Math.PI*2);
ctx.fill();
}

//
function thisLabelCollides(r1){
for(var i=0;i<labels.length;i++){
var r2=labels[i];
if(r1.id==r2.id || r2.isColliding){continue;}
var collides=(!(
r1.x > r2.x+r2.w ||
r1.x+r1.w < r2.x ||
r1.y > r2.y+r2.h ||
r1.y+r1.h < r2.y
));
if(collides){return(true);}
}
return(false);
}

//
function randomColor(){
return('#'+Math.floor(Math.random()*16777215).toString(16));
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Click on the canvas to add more map labels.</h4>
<canvas id="canvas" width=450 height=300></canvas>

关于Javascript 在 Canvas 中渲染文本并避免文本冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32114353/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com