-1

我们需要同时在屏幕上显示 500 万个点(或非常简单的图形对象),并且我们希望与每个点进行交互(例如,更改它们的颜色或拖放它们)。
为了实现这一点,我们通常在最坏的情况下 O(N) 运行一个 for 循环遍历 500 万个项目,以根据鼠标坐标 (x, y) 访问和更改点的状态。由于对象数量巨大,这种方法会导致大量开销(每当用户选择一个点时,我们都必须运行 500 万个 for 循环)。我已经测试过这种方法,但几乎不可能用它制作交互式工具。无论如何,在不运行百万个 for 循环并导致此性能问题的情况下,是否可以快速有效地访问这些点?

4

2 回答 2

2

你已经看过 KineticJS框架了吗?有一个非常令人印象深刻的压力测试,具有您正在寻找的完全相同的拖放功能。如果您使用 KineticJS,您可以使用以下命令访问每个点eventlistener,当然还可以更改其颜色、大小等:

      stage.on('mousedown', function(evt) {
        var circle = evt.targetNode;
      });
于 2013-06-12T11:16:08.273 回答
2

你真的没有提供很多细节

这些问题很快浮现在脑海:

  • 点的大小相同吗?
  • 画布上的点是否均匀分布?
  • 如果一个点被“选中”,是否只有那个点重新着色或移动了?
  • 为什么你通过压倒用户来违反良好的数据可视化规则?:)

考虑到这种缺乏特异性......

...分而治之:

  • 将您的点阵分成多个部分。
  • 将您的点划分到多个重叠的画布上。

将您的点阵分成多个部分

这将允许您在搜索所需的 1 时检查更少的数组元素。

创建一个包含 1980 个元素的容器对象,这些元素代表屏幕上 1980 年的“x”坐标。

var container={};

for(var x=1;x<=1980;x++){
    container[x]=[];
}

每个容器元素都是一个点对象数组,它们的点中心位于该 x 坐标上。

每个点对象都有足够的信息来定位和重绘自己。

x 坐标 == 125 处的点可以这样定义:

{x:125,y:100,r:2,color:"red",canvas:1};

当您想添加一个点时,将一个点对象推送到容器对象的相应“x”元素。

// add a dot with x screen coordinate == 952
container[952].push({x:952,y:100,r:2,color:"red",canvas:1});

可以根据点对象绘制点:

function drawDot(dot,context){
    context.beginPath();
    context.fillStyle=dot.color;
    context.arc(dot.x,dot.y,dot.r,0,PI2,false);
    context.closePath();
    context.fill();
}

当用户选择一个点时,您可以通过拉动用户单击的 X 周围的几个容器元素来快速找到它:

function getDotsNearX(x,radius){

    // pull arrays from "x" plus/minus "radius"
    var dotArrays=[]
    for(var i=x-radius;i<=x+radius;i++){
        dotArrays.push(container[i]);
    }
    return(dotArray);
}

现在您可以处理这些高度针对性的数组中的点,而不是处理所有 500 万个数组元素。

当用户将点移动到新位置时,只需将点对象从其当前容器元素中拉出并将其推入适当的新“x”容器元素中。

将您的点划分到多个重叠的画布上

为了提高绘图性能,您需要将点分布在多个相互重叠的画布上。

dot 元素包含一个 canvas 属性,用于标识将在哪个画布上绘制该点。

于 2013-06-12T19:08:15.017 回答