将点移动到ChartJS中的点击点(雷达图)

时间:2017-03-07 04:52:34

标签: jquery html chart.js

继续之前的Question

我试图将RadarChart的点移动到点击位置。当前方法工作​​正常,但如果屏幕大小发生变化,x和y也会发生变化,结果变得无用。

我的JSFiddle

在图表中单击,该点将根据指针的x,y值增加或减少。

代码的相关部分:

function getElementPosition(obj) {
    var curleft = 0, curtop = 0;
    if (obj.offsetParent) {
      do {
        curleft += obj.offsetLeft;
        curtop += obj.offsetTop;
      } while (obj = obj.offsetParent);
        return { x: curleft, y: curtop };
    }
    return undefined;
  };

  function getEventLocation(element,event){
    // Relies on the getElementPosition function.
    var pos = getElementPosition(element);

    return {
      x: (event.pageX - pos.x),
      y: (event.pageY - pos.y)
    };
  };

  function pointDistance(point1, point2) {
    return Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2));
  };

  //Get the context of the Radar Chart canvas element we want to select
  var ctx = document.getElementById("radarChart").getContext("2d");

  // Create the Radar Chart
  var myRadarChart = new Chart(ctx).Radar(radarData, radarOptions);

  $("#radarChart").click(function (evt) {
    var eventLocation = getEventLocation(this,evt);
    var activePoints = myRadarChart.getPointsAtEvent(evt);
    var eventLocDistToCenter = pointDistance({x: myRadarChart.scale.xCenter, y: myRadarChart.scale.yCenter}, eventLocation);
    var activePointDistToCenter = pointDistance({x: myRadarChart.scale.xCenter, y: myRadarChart.scale.yCenter}, activePoints[0]);

    //Check click position and set the point accordingly
    if (eventLocDistToCenter > 320){
        while (activePoints[0].value < 5){
            activePoints[0].value++;
        }
        //alert("click location: " + eventLocDistToCenter + " | point location: " + activePointDistToCenter + " | point value: " + activePoints[0].value); // displays variables (for testing)
    }
    else if (eventLocDistToCenter > 248 && eventLocDistToCenter < 320) {
        if (activePoints[0].value < 4){
            while (activePoints[0].value < 4){
                activePoints[0].value++;
            }
        }
        else {
            while (activePoints[0].value > 4){
                activePoints[0].value--;
            }
        }
    }
    else if (eventLocDistToCenter > 176 && eventLocDistToCenter < 248) {
        if (activePoints[0].value < 3){
            while (activePoints[0].value < 3){
                activePoints[0].value++;
            }
        }
        else {
            while (activePoints[0].value > 3){
                activePoints[0].value--;
            }
        }
    }
    else if (eventLocDistToCenter > 104 && eventLocDistToCenter < 176) {
        if (activePoints[0].value < 2){
            while (activePoints[0].value < 2){
                activePoints[0].value++;
            }
        }
        else {
            while (activePoints[0].value > 2){
                activePoints[0].value--;
            }
        }
    }
    else if (eventLocDistToCenter > 32 && eventLocDistToCenter < 104) {
        if (activePoints[0].value < 1){
            while (activePoints[0].value < 1){
                activePoints[0].value++;
            }
        }
        else {
            while (activePoints[0].value > 1){
                activePoints[0].value--;
            }
        }
    }
    else if (eventLocDistToCenter > 0 && eventLocDistToCenter < 32) {

        while (activePoints[0].value > 0){
            activePoints[0].value--;
        }

    }

    myRadarChart.update();

这可以兑换还是应该找到不同的方法?我的第一种方法是只增加/减少一个值(没有任何问题)。这种新方法更加用户友好,但我似乎遇到了障碍。

寻找一些方向。

2 个答案:

答案 0 :(得分:1)

不幸的是,您的方法不是一个可行的解决方案,因为您实际上是对图表中的区域进行硬编码。正如您已经指出的那样,当图表发生变化时(例如尺寸增加/减少,尺寸变化,步长尺寸配置不同,数据集数量不同等),此解决方案将无效。要使此工作在任何大小的图表上,您必须执行一些图表内省,以尝试确定用户点击的图表与比例区域相比的位置。

基于我们可用的chart.js API,我能想到如何做到这一点的唯一方法是将点击事件和中心点之间的距离与每个图表比例间隔之间的距离进行比较。

然而,这不会产生100%准确的结果,并且可能导致点击导致该点的移动方式与您预期的不同。这是因为刻度线是直的而不是弧形,但我们只能通过使用圆周来近似点击区域。这是我的意思的一个例子。

enter image description here

使用我描述的方法,蓝色圆圈表示将导致点移动到第二个区域的点击区域。我确信通过一些棘手的数学和一些蛮力你可以克服这个限制。但在玩了很长一段时间后,这是我能想到的最好的。

这是展示行为的working example。如果您点击任何主要比例线附近它完美地工作。但是,如果你点击比较线之间的中间位置,它就不能很好地工作(再次,因为上面的圆圈示例)。

以下是该示例中的相关代码,用于确定移动点的距离。

$("#radarChart").click(function (evt) {
  var eventLocation = getEventLocation(this,evt); 
  var activePoints = myRadarChart.getPointsAtEvent(evt);
  var eventLocDistToCenter = pointDistance({x: myRadarChart.scale.xCenter, y: myRadarChart.scale.yCenter}, eventLocation);
  var scale = myRadarChart.scale;
  var scaleIntervalDistance = scale.calculateCenterOffset(scale.min + (1 * scale.stepValue));  

  activePoints[0].value = parseInt(eventLocDistToCenter / scaleIntervalDistance);  
  myRadarChart.update();
});

答案 1 :(得分:0)

这是我最接近产生想要的结果,但这是非常错误的,并且对触摸设备非常不友好。

Object.assign

这使用D3JS library

留在这里让其他人改进。