Javascript 在仪表上布置标签的策略

Javascript 在仪表上布置标签的策略,javascript,canvas,drawing,Javascript,Canvas,Drawing,我构建了这个javascript/canvas仪表库,它可以有效地让您创建阈值和目标值,并围绕这些指标呈现仪表 我的问题不是javascript中画布绘制等的具体内容,而是标签放置的策略。当前,我在计算的角度上打印距离弧中心的标签。这似乎是可行的,但是我遇到了一个问题,标签文本可能与另一个标签重叠(如果下限和目标太接近),或者标签与弧本身重叠 一旦我能得到标签的位置下来,我总是可以很容易地画一条线,它需要在仪表上的点本身。(如本例所示) 我一直在考虑在内存中创建一个粗略的guestimate,然

我构建了这个javascript/canvas仪表库,它可以有效地让您创建阈值和目标值,并围绕这些指标呈现仪表

我的问题不是javascript中画布绘制等的具体内容,而是标签放置的策略。当前,我在计算的角度上打印距离弧中心的标签。这似乎是可行的,但是我遇到了一个问题,标签文本可能与另一个标签重叠(如果下限和目标太接近),或者标签与弧本身重叠

一旦我能得到标签的位置下来,我总是可以很容易地画一条线,它需要在仪表上的点本身。(如本例所示)

我一直在考虑在内存中创建一个粗略的guestimate,然后沿圆弧调整值,直到它们不再重叠。(这似乎效率极低)

我希望有人能提供一个指针,填补我高中数学的空白,以及它在这里的应用=)


这里有一个策略来展示你的语言

示例代码和演示:


正文{背景色:象牙;}
#包装器{位置:相对;}
画布{位置:绝对;左:40px;顶部:5px;边框:1px纯红色;}
#金额{位置:绝对;左侧:1px;顶部:5px;页边距底部:15px;宽度:23px;边框:0;颜色:#f6931f;字体重量:粗体;}
#滑块垂直{位置:绝对;左侧:5px;顶部:40px;宽度:15px;高度:225px;边框:0px;颜色:#f6931f;字体重量:粗体;}
$(函数(){
var canvas=document.getElementById(“canvas”);
var ctx=canvas.getContext(“2d”);
var-PI=Math.PI;
var-cx=200;
var-cy=200;
var半径=100;
var min=0;
var max=1000;
var minBound=250;
var maxBound=750;
弧宽=40;
宽度=4;
var值=400;
var tickColor=“黑色”;
$(“#滑块垂直”)。滑块({
方向:“垂直”,
射程:“分钟”,
敏:敏,,
马克斯:马克斯,
值:tickValue,
幻灯片:功能(事件、用户界面){
美元(“#金额”).val(ui.value);
绘制(ui.value);
}
});
$(“金额”).val($(“垂直滑块”).slider(“值”);
绘制(数值);
函数绘制(值){
价值=价值;
tickColor=“绿色”;
如果(tickValuemaxBound){tickColor=“red”;}
//
clearRect(0,0,canvas.width,canvas.height);
drawArc();
抽虱(绞碎的,“灰色”);
抽签(最大绑定,“灰色”);
drawTick(tickValue,tickColor,10);
drawLabel(minBound,“灰色”,20,18);
drawLabel(最大绑定,“灰色”,20,18);
drawLabel(tickValue,tickColor,55,24);
}
函数drawArc(){
ctx.beginPath();
ctx.弧(cx,cy,半径,0,π,真);
ctx.线宽=弧宽;
ctx.strokeStyle=“浅灰色”;
ctx.stroke();
}
函数drawTick(值、颜色、扩展名){
var plus=扩展| | 0;
var角度=PI+tickValue/(最大-最小)*PI;
var x1=cx+(半径弧宽/2)*数学cos(角度);
变量y1=cy+(半径弧宽/2)*数学sin(角度);
var x2=cx+(半径+弧宽/2+加号)*数学cos(角度);
变量y2=cy+(半径+弧宽/2+加号)*数学sin(角度);
ctx.beginPath();
ctx.moveTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.lineWidth=tickWidth;
ctx.strokeStyle=颜色;
ctx.stroke();
}
函数drawLabel(值、颜色、扩展名、字体大小){
var角度=PI+tickValue/(最大-最小)*PI;
var x=cx+(半径+弧宽/2+延伸)*数学cos(角度);
变量y=cy+(半径+弧宽/2+延伸)*数学sin(角度);
ctx.textAlign=“中心”;
ctx.fillStyle=颜色;
ctx.font=fontsize+“px arial”;
ctx.fillText(tickValue,x,y);
}
});   // end$(函数(){});

您必须更改数字的布局。只要250针在灰色针的外侧居中,那么250针在靠近1针或1000针时将始终与1针或1000针重叠。也许将1和1000移动到灰色弧内的白色区域,使它们变小。这就是问题的关键,我可以检测标签的碰撞,并将它们移动一部分,直到它们不再重叠(然后只画线指向仪表上的适当位置),但我认为这非常低效。我希望有人有一些数学技巧,可以帮助我明智地说,哦,0和5标签将重叠,将它们放置在碰撞检查循环以外的其他位置
<!doctype html>
<html lang="en">
<head>
  <style>
      body{ background-color: ivory; }
      #wrapper{ position:relative; }
      canvas{ position:absolute; left:40px; top:5px; border:1px solid red;}
      #amount{ position:absolute; left:1px; top:5px; margin-bottom:15px; width:23px; border:0; color:#f6931f; font-weight:bold; }
      #slider-vertical{ position:absolute; left:5px; top:40px; width:15px; height:225px; border:0px; color:#f6931f; font-weight:bold; }
  </style>
  <link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
  <script src="http://code.jquery.com/jquery-1.9.1.js"></script>
  <script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
  <script>

  $(function() {

      var canvas=document.getElementById("canvas");
      var ctx=canvas.getContext("2d");

      var PI=Math.PI;
      var cx=200;
      var cy=200;
      var radius=100;
      var min=0;
      var max=1000;
      var minBound=250;
      var maxBound=750;
      var arcWidth=40;
      var tickWidth=4;
      var tickValue=400;
      var tickColor="black";

      $( "#slider-vertical" ).slider({
        orientation: "vertical",
        range: "min",
        min: min,
        max: max,
        value:tickValue,
        slide:function( event, ui ) {
          $( "#amount" ).val(ui.value);
          draw(ui.value);
        }
      });

      $( "#amount" ).val( $( "#slider-vertical" ).slider( "value" ) );


      draw(tickValue);

      function draw(value){
          tickValue=value;
          tickColor="green";
          if(tickValue<minBound){tickColor="blue";}
          if(tickValue>maxBound){tickColor="red";}
          //
          ctx.clearRect(0,0,canvas.width,canvas.height);
          drawArc();
          drawTick(minBound,"gray");
          drawTick(maxBound,"gray");
          drawTick(tickValue,tickColor,10);
          drawLabel(minBound,"gray",20,18);
          drawLabel(maxBound,"gray",20,18);
          drawLabel(tickValue,tickColor,55,24);   
      }

      function drawArc(){
          ctx.beginPath();
          ctx.arc(cx,cy,radius,0,PI,true);
          ctx.lineWidth=arcWidth;
          ctx.strokeStyle="lightgray";
          ctx.stroke();
      }

      function drawTick(tickValue,color,extension){
          var plus=extension||0;
          var angle=PI+tickValue/(max-min)*PI;
          var x1=cx+(radius-arcWidth/2)*Math.cos(angle);
          var y1=cy+(radius-arcWidth/2)*Math.sin(angle);
          var x2=cx+(radius+arcWidth/2+plus)*Math.cos(angle);
          var y2=cy+(radius+arcWidth/2+plus)*Math.sin(angle);
          ctx.beginPath();
          ctx.moveTo(x1,y1);
          ctx.lineTo(x2,y2);
          ctx.lineWidth=tickWidth;
          ctx.strokeStyle=color;
          ctx.stroke();
      }

      function drawLabel(tickValue,color,extension,fontsize){
          var angle=PI+tickValue/(max-min)*PI;
          var x=cx+(radius+arcWidth/2+extension)*Math.cos(angle);
          var y=cy+(radius+arcWidth/2+extension)*Math.sin(angle);
          ctx.textAlign="center";
          ctx.fillStyle=color;
          ctx.font=fontsize+"px arial";
          ctx.fillText(tickValue,x,y);
      }

  });   // end $(function(){});

  </script>
</head>
<body>
    <div id="wrapper">
        <input type="text" id="amount" />
        <div id="slider-vertical"></div>
        <canvas id="canvas" width=425 height=300></canvas>
    </div>
</body>
</html>