ChartJS -折线图中重叠点的处理

cbjzeqam  于 2023-03-18  发布在  Chart.js
关注(0)|答案(3)|浏览(300)

在我的一个折线图中,我遇到了某些点重叠(即具有完全相同的x,y坐标)的情况。这是预期的行为,但我感兴趣的是找到一种方法来潜在地偏移/抖动任何重叠的点,以便不隐藏任何点。有人遇到过折线图上重叠点的类似情况吗?注意:我不能使用scatter类型,因为我的x轴是类别。
下面是一个小提琴演示重叠(用我的数据集的一个缩小样本):https://jsfiddle.net/quanda412/407dcoL9/19/
在挖掘完文档后,我的第一个直觉是使用ChartJS Plugin Hooks中的一个函数,在该函数中遍历我的数据集以搜索任何重叠的示例,然后更改x或y位置。我在其他地方看到过这被称为“Jitter”,似乎一些图表库支持开箱即用的jitter功能。
无论如何,我的数据集是相当大的,当我迭代它时,例如在beforeDatasetUpdate钩子中,图表不仅会受到巨大的性能影响,而且点也不会按预期调整。
我尝试在beforeDatasetDraw钩子中抖动的代码示例:

  1. beforeDatasetDraw: chart => {
  2. const { datasets } = chart.config.data;
  3. const coordinateMap = []; // holds array of unique coord objects
  4. datasets.forEach(d => {
  5. let elements = d._meta[5].data;
  6. elements.forEach((el, i) => {
  7. let { x, y } = el._model;
  8. const overlap = coordinateMap.find(coord => coord.x === x && coord.y === y);
  9. if (overlap) { // Overlap detected!
  10. // Update coordinate map
  11. x += 1;
  12. y += 1;
  13. // Jitter the x,y positioning - not working!
  14. d._meta[5].data[i]._model.x = x;
  15. d._meta[5].data[i]._model.y = y;
  16. }
  17. coordinateMap.push({ x, y });
  18. });
  19. });
  20. }

这里你可以看到重叠,灰点中的灰点:

jecbmhm3

jecbmhm31#

我能够用这个定制的beforeDatasetDraw插件实现有效的x轴抖动:

  1. beforeDatasetDraw(chart, args) {
  2. if (chart.animating || chart.$deferred.loaded) {
  3. const { index: dataIndex, meta } = args;
  4. const points = meta.data.map(el => ({ x: el._model.x, y: el._model.y }));
  5. const { length: dsLength } = chart.data.datasets;
  6. const adjustedMap = []; // keeps track of adjustments to prevent double offsets
  7. for (let datasetIndex = 0; datasetIndex < dsLength; datasetIndex += 1) {
  8. if (dataIndex !== datasetIndex) {
  9. const datasetMeta = chart.getDatasetMeta(datasetIndex);
  10. datasetMeta.data.forEach(el => {
  11. const overlap = points.find(point => point.x === el._model.x && point.y === el._model.y);
  12. if (overlap) {
  13. const adjusted = adjustedMap.find(item => item.datasetIndex === datasetIndex && item.dataIndex === dataIndex);
  14. if (!adjusted && datasetIndex % 2) { el._model.x += 7; } else { el._model.x -= 7; }
  15. adjustedMap.push({ datasetIndex, dataIndex });
  16. }
  17. });
  18. }
  19. }
  20. }
  21. }

这会产生抖动效果,如下所示:

展开查看全部
vlju58qv

vlju58qv2#

谢谢Quanda.我已经修改了上面的代码来支持IE浏览器.

  1. var jitterEffectPlugin = {
  2. beforeDatasetDraw: function (ctx, args) {
  3. if (ctx.animating) {
  4. var _args = args,
  5. dataIndex = _args.index,
  6. meta = _args.meta;
  7. var points = meta.data.map(function (el) {
  8. return {
  9. x: el._model.x,
  10. y: el._model.y
  11. };
  12. });
  13. var dsLength = ctx.data.datasets.length;
  14. var adjustedMap = []; // keeps track of adjustments to prevent double offsets
  15. for (var datasetIndex = 0; datasetIndex < dsLength; datasetIndex += 1) {
  16. if (dataIndex !== datasetIndex) {
  17. var datasetMeta = ctx.getDatasetMeta(datasetIndex);
  18. datasetMeta.data.forEach(function (el) {
  19. var overlapFilter = points.filter(function (point) {
  20. return point.x === el._model.x && point.y === el._model.y;
  21. });
  22. var overlap = false;
  23. var overObj = JSON.parse(JSON.stringify(overlapFilter));
  24. for (var i = 0; i < overObj.length; i++) {
  25. if(overObj[i]['x'] === el._model.x && overObj[i]['y'] === el._model.y){
  26. overlap = true;
  27. break;
  28. }
  29. }
  30. if (overlap) {
  31. var adjusted = false;
  32. var adjustedFilter = adjustedMap.filter(function (item) {
  33. return item.datasetIndex === datasetIndex && item.dataIndex === dataIndex;
  34. });
  35. var adjObj = JSON.parse(JSON.stringify(adjustedFilter));
  36. for (var i = 0; i < adjObj.length; i++) {
  37. if(adjObj[i]['datasetIndex'] === datasetIndex && adjObj[i]['dataIndex'] === dataIndex){
  38. adjusted = true;
  39. break;
  40. }
  41. }
  42. if (!adjusted && datasetIndex % 2) {
  43. el._model.x += 7;
  44. } else {
  45. el._model.x -= 7;
  46. }
  47. adjustedMap.push({
  48. datasetIndex: datasetIndex,
  49. dataIndex: dataIndex
  50. });
  51. }
  52. });
  53. }
  54. }
  55. }
  56. }
  57. }
  58. Chart.pluginService.register(jitterEffectPlugin);
展开查看全部
ej83mcc0

ej83mcc03#

一定是Chartjs的变化,我不得不修改当前版本的插件。基本上我只是从el._model.x和el.model.y中删除了_model,并添加了id:

  1. var jitterEffectsPlugin = {
  2. id: 'jitterEffects',
  3. beforeDatasetDraw: function (ctx, args) {
  4. var _args = args,
  5. dataIndex = _args.index,
  6. meta = _args.meta;
  7. var points = meta.data.map(function (el) {
  8. return {
  9. x: el.x,
  10. y: el.y
  11. };
  12. });
  13. var dsLength = ctx.data.datasets.length;
  14. var adjustedMap = []; // keeps track of adjustments to prevent double offsets
  15. for (var datasetIndex = 0; datasetIndex < dsLength; datasetIndex += 1) {
  16. if (dataIndex !== datasetIndex) {
  17. var datasetMeta = ctx.getDatasetMeta(datasetIndex);
  18. datasetMeta.data.forEach(function (el) {
  19. var overlapFilter = points.filter(function (point) {
  20. return point.x === el.x && point.y === el.y;
  21. });
  22. var overlap = false;
  23. var overObj = JSON.parse(JSON.stringify(overlapFilter));
  24. for (var i = 0; i < overObj.length; i++) {
  25. if(overObj[i]['x'] === el.x && overObj[i]['y'] === el.y){
  26. overlap = true;
  27. break;
  28. }
  29. }
  30. if (overlap) {
  31. var adjusted = false;
  32. var adjustedFilter = adjustedMap.filter(function (item) {
  33. return item.datasetIndex === datasetIndex && item.dataIndex === dataIndex;
  34. });
  35. var adjObj = JSON.parse(JSON.stringify(adjustedFilter));
  36. for (var i = 0; i < adjObj.length; i++) {
  37. if(adjObj[i]['datasetIndex'] === datasetIndex && adjObj[i]['dataIndex'] === dataIndex){
  38. adjusted = true;
  39. break;
  40. }
  41. }
  42. if (!adjusted && datasetIndex % 2) {
  43. el.x += 7;
  44. } else {
  45. el.x -= 7;
  46. }
  47. adjustedMap.push({
  48. datasetIndex: datasetIndex,
  49. dataIndex: dataIndex
  50. });
  51. }
  52. });
  53. }
  54. }
  55. }
  56. }
展开查看全部

相关问题