【问题标题】:Responsive Heatmaps响应式热图
【发布时间】:2021-06-17 13:58:00
【问题描述】:

问题

我在编写一些代码时遇到了一个小问题,其中我已经自动化了一个脚本来跟踪用户与 UI 的交互,包括 mousemoveclick 事件。如果我不必担心让它响应,那么我可能会收工并交付我已经完成的工作,但是我的大脑正在寻找一些魔法知识,我正在努力让它变得超级响应.这只是我正在处理的那种事情的快速示例,这不是天才,如果有的话,我主要是 heatmap.js 正在做繁重的工作。目前,我只是在看看我是否可以将其作为概念证明而不是其他任何事情......

代码

所以目前,我正在跟踪 event.pageXevent.pageY 值以存储确切事件发生的位置,我还将 window.innerWidthwindow.innerHeight 值存储到尝试并制定一些功能,让我可以根据其他设备的大小来偏移位置。

例如如果您查看上面的示例图片,这对于静态页面来说是完美的,但如果我说让页面更窄一点,您可以在这里看到它与上面的图片不符:

不管怎样,废话不多说,这里有一些示例代码:

// A lot of other code...

var setupHeatMaps = function (pages, heatMaps) {
  pages.forEach(function (page) {
    page.addEventListener("click", function (event) {
      heatMaps.push({ x: event.pageX, y: event.pageY, value: 10000 });
      onStateChange();  
    });

    // Don't collect ALL mouse movements, that'd be crazy, so collect 
    // every 1/10 mouse movements.
    var counter = 0;

    page.addEventListener("mousemove", function (event) {
      if (counter === 10) {
        heatMaps.push({ x: event.pageX, y: event.pageY, value: 20 });
        onStateChange();
        counter = 0;
      } else {
        counter ++;
      }
    });
  });
};

// A lot of other code... 

// Curried function so that it can be passed around without exposing the state...
var renderHeatMaps = function (heatMaps) {
  return function () {
    var max = heatMaps.length;
    var points = heatMaps;

    var parent = getParentElement();
    var styleObj = window.getComputedStyle(parent);
    var div = document.createElement("div");
    var body = document.querySelector("body");
    var background = document.createElement("div");

    // This element needs to sit in front of the 
    // background element, hence the higher z-index value.
    div.style.position = "absolute";
    div.style.zIndex = 9;
    div.style.left = "0px";
    div.style.top = "-80px";
    div.style.width = "100vw";

    // Even though this element will sit behind the element
    // that's created above, we will still want this element to 
    // sit in front of 99% of the content that's on the page.
    background.style.position = "fixed";
    background.style.top = "0px";
    background.style.left = "0px";
    background.style.height = "100vh";
    background.style.width = "100vw";
    background.style.zIndex = 5;
    background.style.backgroundColor = "rgba(255, 255, 255, 0.35)";
    background.setAttribute("id", "quote-customer-heat-map-background");

    var heightInPx = styleObj.getPropertyValue("height");
    var rawHeight = parseInt(heightInPx.replace("px", ""));
    var newHeight = parseInt((rawHeight + 80));

    div.style.height = newHeight + "px";
    div.setAttribute("id", "quote-customer-heat-map-foreground");
    body.style.paddingBottom = "0px";
    body.appendChild(background);
    body.appendChild(div);

    var heatMap = h337.create({
      container: div,
      radius: 45
    });
    
    heatMap.setData({ max: max, data: points });
  };
};

// A lot of other code...

由于您可以看到在setupHeatMaps 中使用的pages 元素的宽度发生了变化,因此查看此数据的偏移非常严重。老实说,我昨天花了很多时间思考这个问题,但我仍然没有想到任何似乎合理的事情。

或者

我想知道我是否应该以某种方式只是将页面存储为图像,并过度播放热图,这样我就不会真的担心热图反应灵敏。但后来我需要弄清楚其他一些事情......例如对这些数据进行版本控制,因此如果用户在手机上查看页面,它将将该数据与从之前会话中收集的数据分开存储,在该会话中他们在笔记本电脑或台式设备上。

结论

老实说,我不完全确定最好的行动方案是什么,你们中有人遇到过这样的事情吗?你们有没有想到什么天才可以解决这样的问题?

PS我会分享更多代码,但是这个整体解决方案中包含大量的代码,所以我有点无法分享所有内容,我很确定 Stackoverflow 的人会因此而讨厌我! ??? - 您也可以说我是作为 POC 执行此操作的,因为通常我只是将 background 元素和 div 元素的渲染卸载到底层框架,而不是像这样以编程方式进行,保留它请注意,这只是一个POC

【问题讨论】:

  • 一般来说,我希望响应式布局可以改变布局,使其难以传递有意义的热图数据。但是,在您展示的情况下,它可能是可行的。内容大小看起来是固定的。这是否意味着只有边距发生变化?由于您存储了屏幕尺寸,当您偏移左边距的预期变化时会发生什么?或者,我想知道如果您收集相对于底层 HTML 元素的位置测量值并根据显示之前的当前 el 偏移量锚定它是否会更好。
  • @user650881 很遗憾地通知您,everything 都是响应式的,我承认上面的示例可能不是最好的说明页面 &里面的一切都是响应式的,足够公平! ??? - 但是,是的,这一切都是响应式的。至于底层 DOM 元素的偏移量,这是我想到的,但是当我尝试这种方法时,出现了一些问题,尽管我会再试一次,因为为什么不呢? ...
  • 这确实使它更具挑战性。我已经成功地覆盖了相对于响应式页面布局中底层元素位置的内容。 (在我的例子中,我并不关心保持与不同元素相关的叠加层之间的相对位置。)我可以补充的是,我必须跟踪原点的位置,因为绝对和相对定位的元素会改变测量原点。跨度>
  • 跟踪点击了什么,而不是点击发生的位置。然后在此基础上构建热图。
  • 我想我无法解决您的问题,但可能有不同的方法:您可以跟踪页面上的单个元素被输入、向左和用光标单击。这样您就不会获得热图,但您可以在每个可能的响应场景中获得与不同元素的所有交互。

标签: javascript performance heatmap


【解决方案1】:

也许您可以更改设置并记录事件所在的元素,并保存与该元素相关的位置数据,而不是整个页面。 您仍然在页面上记录所有事件,但您保存的是相对于元素而不是整个页面的数据,这会阻止您在查看之后在热图中将数据混合在一起 以各种宽度覆盖您的网站。

假设你有这样的伪代码设置:

@1000px width
[html width 1000px, height 500px
  [div width 800px, height 400px centered
    [button1 width 100px, height 30px centered] 
  ]
]

@500px width
[html width 500px, height 1000px
  [div width 400px, height 800px centered
    [button1 width 80px, height 30px centered]
  ]
]

您的用户总是在某些元素上移动。只需像这样捕获数据,来自 2 个不同屏幕尺寸的用户的示例数据,将光标移向中心的按钮:

user interaction{
  over element: html {dimensions: width 1000px, height 500px}
  user position: {x 900, y 20}
}

user interaction{
  over element: html {dimensions: width 1000px, height 500px}
  user position: {x 850, y 60}
}

user interaction{
  over element: div {width 800px, height 400px}
  user position: {x 700, y 60}
}

user interaction{
  over element: button1 {width 100px, height 30px}
  user position: {x 90, y 10}
}

user interaction{
  over element: html {dimensions: width 500, height 1000px}
  user position: {x 450, y 100}
}

user interaction{
  over element: div {width 400px, height 800px}
  user position: {x 380, y 40}
}

user interaction{
  over element: button1 {width 80px, height 30px} 
  user position: {x 60, y 10}
}

然后,当您查看您的网站时,请在所有元素上绘制热量并计算捕获数据的相对位置。 因此,当您以@500px 宽度查看您的网站时,按钮 1 上的热量将如下所示:

[button 1 width 80px, height 30px
heat 1, x 72px y 10
heat 2, x 60px y 10
]

你对所有其他元素做同样的事情。我不知道这样的数据有多大用处,但它是为了奇怪的魔法对吧?

我个人只是根据您查看热图的屏幕宽度排除数据。这样您就可以使用此设置并获得有用的热图数据。因此,您将根据数据是否以特定的响应宽度捕获数据来排除数据。因此,您至少可以将所有用户数据以高宽度混合在一起,因为您会知道您感兴趣的 Web 元素可能仍然居中且大小相同。

将响应式设计分成 2 或 3 种尺寸、显示器、平板电脑和手机是很常见的。您会惊讶地发现您的设计布局在这 3 种之间保持多么相似。越相似,将不同宽度的数据混合到特定媒体查询范围内就越有用。

只要您使用与稍后绘制数据相同的技术来获取保存数据的宽度和高度,就可以了。即使您忽略边距和边框,例如您的事件仍会在元素处于边距时捕获元素,这样您就可以获得如下数据:用户位置:{x -10, y -1} 并仍然使用它在元素上涂上你的热量。

您还可以为用户提供混合和过滤不同大小的用户数据的选项,只需将其称为实验数据混合或其他名称。例如,如果您混合所有用户数据而不考虑屏幕大小,您可能仍然可以获得一些关于点击次数最多的元素的非常有用的视觉信息。

您可以做的另一件事是对结果进行软混音。如果您的用户数据的宽度和高度与当前元素的尺寸相差太大,例如超过 30%,您可以将其排除。您可以通过让用户设置该百分比的敏感度(羽化)来实现这一动态。这样,您仍然可以查看所有较小元素上的所有用户热度,同时忽略较大且多变元素上不太相关的用户事件。

【讨论】:

  • 对,我明白你的意思,但是因为我很笨,而且我使用百分比和许多不同的方法来定义元素的高度/宽度,所以我想不出这样的方法排序方法会起作用吗? ... 更不用说会出现 大量 的特定样式,因为每个页面都是动态的,一个页面布局可能与另一个页面布局 1000% 不同,试图迎合这种情况是不可能的容易,至少我想不出一个简单的方法? ?
  • 我的评论太长了,所以我在答案的底部为你添加了它。祝你好运!
  • 完全不同的东西,为什么不简单地在 CSS 中设置热图元素的样式呢?只需将其添加到具有特定 ID 或类的页面即可。您也可以将其放在所有内容之上并使用 css: pointer-events: none;让热图背后的元素仍然可用。
  • 嘿,伙计,对不起,我这么晚才回复你,虽然这在很大程度上是一个非常可靠的建议,因为网站的动态性,不要把它当作批评,这可能更多地反映了 Web 应用程序最初是如何编写的,但这个建议有点过于简化了。例如。因为它是 all 响应式的,所以某些元素不会以 'x' 分辨率出现,某些元素位于 完全 不同的位置,等等。同样,这实际上是一个很棒的建议,非常感谢您抽出宝贵的时间!我真的很感激! ❤
  • P.S.就你所说的相似性而言,是的,随着分辨率的变化,这种美丽会剧烈地发生变化,这可能就是我仍在摸不着头脑的原因。
【解决方案2】:

我对这个问题的理解是,该项目运行良好,在正确执行事件、存储信息和显示信息方面,但存在 UX 问题,因为系统正在偏移(我假设及时) .我会使用一个非常类似于压缩的想法。将您的显示器想象成一个像素网格。很明显存在一些精度问题,因为即使我们使用计算机及其组件允许我们使用的最大精度,如果我们取两个相邻像素并想要在两者之间单击,我们很快就会意识到我们的精度系统提供非常有限,这对于无法尊重Hausdorf separation 的数字设备来说是不言而喻的。

既然我们已经通过我们的小思想实验探索了这些限制,我们可以承认存在这样的限制。因此,原则上,降低像素数而不是事件数不会引入更多问题,它会降低空间精度,尽管会降低一定数量(当然,你认为仍然可以接受的数量)。因此,如果您为地图应用了 x * y 分辨率,那么您可以将您的分辨率视为“每 5 个像素和高度计数”。这将在实际像素和虚构像素之间建立映射,这将构成我们压缩的基础,将可点击位置减少 25 倍。

这将使您可以将监视器视为一组区域,区域的数量明显小于实际像素数(在我们的示例中为 25 倍)。这将允许您避免单独存储每个协调/单击,而是始终可以存储 (x, y, n),即事件发生区域的中心和该事件重复的次数。

这样,如果用户点击位于中心为 (x, y) 的区域中的像素 (x', y'),那么只有在该区域没有发生点击时,您才会获得新数据地区呢。否则,如果在那里发生了点击(不一定在完全相同的像素处,而是在该区域中),那么您只需增加 n。因此,您将拥有一组更小的像素事件数数据,而不是一组非常大的原始像素事件数据。

当然,这种方法的缺点是它在一定程度上降低了几何精度,但它应该有助于优化数据处理。

我承认我对 Heatmap.js 不是很有经验,所以我不确定它是否支持我所建议的 API。如果有,那么尝试使用它是有意义的。如果没有优化好,或者不支持这样的功能,那么我会根据实际需要使用canvas或svg来实现热图功能。

【讨论】:

  • 我什至没有花 10 秒钟阅读这个答案,但仅通过查看内容的数量,这本身就值得一票!谢谢,请耐心等待我实际上阅读它! ?
  • @JO3-W3B-D3V 谢谢。由于我建议的优化是有代价的(如果区域中心的宽度和高度每 5 个,那么单击 (3, 3) 将增加对 (5, 5) 的单击次数,或者单击 (198, 107) 会增加 (195, 105)) 的点击次数,您可能需要实际像素而不是区域中心,但即使在这种情况下,这样的想法也可能对未来的访问者有所帮助。
  • 不,谢谢老兄! ? .. 这是唯一的问题,因为我正在处理/修改此功能有 很多 计算昂贵的任务,我对任何可能添加任何额外的计算复杂度......尽快一起! ? - 你可能已经亲身体验过,这通常意味着你的代码远非艺术...... ?
  • @JO3-W3B-D3V 这将降低计算复杂度。使用分组区域计算聚合数据比使用大量单个像素数据要容易得多。因此,计算简化和存储优化是我提出的方法的优势。缺点是它会比在您的解决方案中以像素精度执行此操作更不精确。所以,如果你说你避免这个解决方案是因为你想保持精度水平,那将是一个完全可以理解的立场。
  • @JO3-W3B-D3V 但是,可以降低计算复杂度。直观地说:什么更简单:只跟踪事件发生的区域或跟踪它们的确切位置?计算成本更高的是什么?使用计数器对 1000 个区域进行计算(每个区域的计数器可以达到 10 000,但它仍然只是一个数字,不会增加复杂性)还是使用 100 000 000 个像素化原始信息进行计算?我相当确信区域聚合可以简化您的计算并对其进行优化,但要以精确为代价。
【解决方案3】:

虽然这个解决方案可能不是有史以来最优雅的解决方案,但它至少可以工作,如果有人有任何想法或任何更好的想法,请务必加入!

我的解决方案解释

所以我在想,我可以通过iframe 渲染它,当然这不是最漂亮的解决方案,但至少这意味着不涉及复杂的定位逻辑,它相对轻量级就计算复杂性而言,与我看过的其他一些解决方案相比,它适用于各种屏幕尺寸,它基本上消除了对它进行响应的需要......有点......

当然,这意味着您将在左、右和中间有滚动条,但它很简单,直截了当,这意味着我可以在非常很短的时间,而且很现实地制作一个 MVP ,我希望您的普通初级开发人员可能更容易理解发生了什么?你们有什么感想? ?

我也在尝试从用户的角度来考虑它,实际上在这种应用程序中,我更喜欢真实、原始的准确性,而不是看起来非常漂亮的东西,这让我想成为一名设计师。我什至对这个主题做了一些功课,因为我基本上一直在尝试构建一些会话重放软件,我必须说这是一个非常有趣的项目/功能! ?

使用 some 样式,我已经能够像这样完成 some ... 显然这不是网站/应用程序的直接 sn-p,但这是我的老板创建的一些营销材料,但“笔记本电脑”中的内容,即网络应用程序的实际屏幕截图/片段! ? - 总而言之,我觉得看起来还可以吗? - 您可以看到溢出发生的位置,并且屏幕的右侧有点被切断,但是因为 UI sorta 中的所有其他内容都表现得像他们在那里有一个fixed 位置,我个人认为它似乎工作得非常好。

编辑

我只想感谢所有花费时间的人,无论是添加 cmets 还是提供答案,很高兴看到开发社区如此乐于助人!谢谢大家! ?

博文

所以我在这里写了更多关于这个主题的一点

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-07
    • 2017-05-27
    相关资源
    最近更新 更多