动态雷达图跟踪点

时间:2017-03-23 01:14:00

标签: javascript graph data-visualization

我正在制作动态雷达图表,我对代码进行了审核,并遵循了SO成员的建议。

这是我走了多远,但似乎遇到了障碍:

var canv = document.getElementById('canvas');
var canv1 = document.getElementById('canvas1');
var point_xy = document.getElementById('point_xy');
var tipCanvas = document.getElementById("tip");
var tipCtx = tipCanvas.getContext("2d");
var point_xy_cords = [
  []
];
var pentagon_one = 24;
var pentagon_two = 18;
var pentagon_three = 12;
var pentagon_four = 6;
var pentagon_five = 0;
var circles = [];
var contx = canv.getContext('2d');
var contx1 = canv1.getContext('2d');
var offsetX = canv1.offsetLeft;
var offsetY = canv1.offsetTop;
contx.clearRect(0, 0, canv.width, canv.height);

function drawShape(ctx, x, y, points, radius1, radius2, alpha0) {
  //points: number of points (or number of sides for polygons)
  //radius1: "outer" radius of the star
  //radius2: "inner" radius of the star (if equal to radius1, a polygon is drawn)
  //angle0: initial angle (clockwise), by default, stars and polygons are 'pointing' up
  var radius_size = radius1;
  var i, angle, radius;
  if (radius2 !== radius1) {
    points = 2 * points;
  }
  for (var i = 0; i <= 5; i++) {
    var temp = [];
    contx1.beginPath();
    for (var j = 0; j <= 4; j++) {
      angle = j * 2 * Math.PI / points - Math.PI / 2 + alpha0;
      radius = j % 2 === 0 ? radius_size : radius_size;
      temp[j] = [(x + radius_size * Math.cos(angle)), (y + radius_size * Math.sin(angle))];
      ctx.lineTo(temp[j][0], temp[j][1]);
    }
    ctx.closePath();
    style(ctx);
    radius_size = radius_size - 20;
    point_xy_cords.push(temp);
  }
  point_xy.textContent = "[1] = " + point_xy_cords[1] + " y = " + point_xy_cords[1][1];
}

function style(ctx, fill) {
  ctx.strokeStyle = "rgba(0, 109, 0, 1)";
  ctx.lineWidth = 2;
  if (fill) {
    ctx.fillStyle = "rgba(74, 157, 33, 0.6)";
    ctx.fill();
  } else {
    ctx.stroke()
  }

  //contx.fill();
}

var radius = 2;

var Circle = function(x, y, radius) {
  this.left = x - radius;
  this.top = y - radius;
  this.right = x + radius;
  this.bottom = y + radius;
  this.point_clicked = [];
  
  this.clicked = function(){
    points[1][0] = x; //hardcoded part
    points[1][1] = y; //hardcoded part
    contx1.clearRect(0, 0, canv.width, canv.height);
    drawBackgroundPentagons(contx1);
    drawMainPentagon(contx1, points);
    drawPoints();
  }

  this.draw = function(ctx) {
    //Draw all points
    
    ctx.beginPath();
    ctx.arc(x, y, 2, 0, 2 * Math.PI, false);
    ctx.lineWidth = 1;
    ctx.strokeStyle = "rgba(74, 157, 33, 1)";
    ctx.fill();
    ctx.stroke();
  }
  
  this.containsPoint = function(x,y){
  	return (x < this.right && x > this.left && y > this.top && y < this.bottom);
  }
};

//Draw background
function drawBackgroundPentagons(ctx) {
  drawShape(ctx, 120, 120, 5, 100, 100, 0);
}
drawBackgroundPentagons(contx1);

//Draw all the points
function drawPoints(){
  for (var x = 1; x <= 5; x++){
    for (var y = 0; y <= 4; y++){
      var circle = new Circle(point_xy_cords[x][y][0], point_xy_cords[x][y][1], 8);
      circle.draw(contx1);
      circles.push(circle);
    }
  }
}
drawPoints();
function drawMainPentagon(ctx, points) {
  ctx.beginPath();
  ctx.moveTo(points[0][0], points[0][1]);
  for (var x = 1; x <= 4; x++) {
    ctx.lineTo(points[x][0], points[x][1]);
  }
    style(ctx, "fill");
  	ctx.closePath();
}

points = point_xy_cords[1];
drawMainPentagon(contx1, points);

function handleMouseDown(e, message) {

  point_xy.textContent = (message);
}

function getMousePos(canvas, evt) {
  var rect = canvas.getBoundingClientRect();
  return {
    x: evt.clientX - rect.left,
    y: evt.clientY - rect.top
  };
}

canv1.onmousedown = function(e) {
  var pos = getMousePos(canv1, e);
  var clickedX = pos.x;
  var clickedY = pos.y;


  var tooltipText = "nothing";
  
  for (var i = 0; i < circles.length; i++) {
    var circle = circles[i];
    if (circle.containsPoint(clickedX, clickedY)) {
      circle.clicked();
      return;
    }
	}
  tooltip("points[0]", clickedX, clickedY);
};

function tooltip(text, clickedX, clickedY) {
  tipCtx.fillStyle = "black";
  tipCtx.fillRect(0, 0, canvas.width, canvas.height);
  tipCtx.fillStyle = "white";
  tipCtx.fillText(text, 5, 10);
  tipCanvas.style.left = (clickedX + 15) + "px";
  tipCanvas.style.top = (clickedY - 26) + "px";
}

canv1.onmouseover = function(e) {
  return null;

}
canv1.onmouseout = function(e) {
  return null;
}
canv1.onmousemove = function(e) {
  return null;
}
#tip {
  left: -200px;
  top: 100px;
  position: absolute;
  float: left;
  maxWidth: 200px;
  backgroundColor: rgba(0, 0, 0, 0.8);
  border: rgba(45, 65, 45, 1);
  borderRadius: 5px;
  color: #f9f9f9;
  fontSize: 14px;
  padding: 5px;
  textAlign: left;
}
<div id="canvasesdiv" style="position:relative; width:400px; height:300px">
  <canvas id="tip" width=100 height=100 style="z-index: 3;"></canvas>
  <canvas id="canvas" style="z-index: 1;
position:absolute;
left:10px;
top:10px;
" height="300px" width="400">
    This text is displayed if your browser does not support HTML5 Canvas.
  </canvas>
  <canvas id="canvas1" style="z-index: 2;
position:absolute;
left:10px;
top:10px;
" height="300px" width="400">
    This text is displayed if your browser does not support HTML5 Canvas.
  </canvas>

</div>
<div id='point_xy'></div>

如果单击一个点,则假设将突出显示的五边形的点移动到单击的点。它有效,除了我无法弄清楚要添加什么条件以移动突出显示的五边形的正确角落。在上面的代码中,我对其进行了硬编码,因此无论您点击哪一点,它都会在索引0处移动点。

任何方向都会受到赞赏。

1 个答案:

答案 0 :(得分:1)

所以你要做的就是让每个圈子知道它所属的spokeradii。像这样:

var Circle = function(x, y, radius, spoke, value) {
  this.x = x;
  this.y = y;
  this.radius = radius;
  this.spoke = spoke;
  this.value = value;

现在创建它们:

function drawPoints() {
  for (var value = 1; value <= 5; value++){
    for (var spoke = 0; spoke <= 4; spoke++){
      var circle = new Circle(point_xy_cords[value][spoke][0], point_xy_cords[value][spoke][1], 8, spoke, value);
      circle.draw(contx1);
      circles.push(circle);
    }
  }
}

我将变量名称更改为有意义的名称。这里需要注意的是,您可以混合代码来创建圆圈和代码来绘制它们。你不想这样做。在初始化时创建它们一次,并在进行更改时重绘它们(单击)。每次重绘时都不想重新创建圆圈。

最后改变一下:

// Circle
this.clicked = function(){
    points[this.spoke][0] = this.x;
    points[this.spoke][1] = this.y;
    updateCanvas();
}

其他地方:

function updateCanvas() { 
  contx1.clearRect(0, 0, canv.width, canv.height);
  drawBackgroundPentagons(contx1);
  drawMainPentagon(contx1, points);
  drawPoints();
}

如果我可以提出建议,请从最简单的代码开始。从显示圆圈和五边形开始,让它干净利落地工作并构建在它上面。在代码中尝试并保持逻辑分离。在绘图时,有几个地方可以创建对象并初始化数组(如coords),这既不必要,也意味着您反复执行而不是一次。这里还有很多代码是不必要的。