You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AmCharts4折线图可垂直拖拽锚点X轴缩放后不跟随问题

问题根因

为了限制锚点仅支持垂直拖拽,原代码在锚点的positionchanged事件中固定了每个锚点的minX和maxX值。当你通过滚动条缩放X轴时,日期轴会重新计算所有数据点的X轴像素坐标,但之前已经固定的锚点X范围没有同步更新,就会出现锚点和折线位置错位的问题。

修复后的完整实现代码

JS代码

am4core.useTheme(am4themes_animated);

// 创建图表实例
var chart = am4core.create("chartdiv", am4charts.XYChart);

// 添加数据
chart.data = [
  {
    date: new Date(2018, 0, 1),
    value: 450
  },
  {
    date: new Date(2018, 0, 2),
    value: 269
  },
  {
    date: new Date(2018, 0, 3),
    value: 700
  },
  {
    date: new Date(2018, 0, 4),
    value: 490
  },
  {
    date: new Date(2018, 0, 5),
    value: 500
  },
  {
    date: new Date(2018, 0, 6),
    value: 550
  },
  {
    date: new Date(2018, 0, 7),
    value: 420
  }
];

// 创建坐标轴
var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
dateAxis.renderer.grid.template.location = 0;
dateAxis.renderer.minGridDistance = 40;

var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());

// 统一更新所有锚点的X轴限制
function updateAllBulletsXRange() {
  chart.series.each(function(series) {
    series.bullets.each(function(bullet) {
      series.dataItems.each(function(dataItem) {
        if (dataItem.bullets && dataItem.point) {
          let itemBullet = dataItem.bullets.getKey(bullet.uid);
          if (itemBullet) {
            itemBullet.minX = dataItem.point.x;
            itemBullet.maxX = dataItem.point.x;
            itemBullet.minY = 0;
            itemBullet.maxY = chart.seriesContainer.pixelHeight;
          }
        }
      })
    })
  })
}

// 监听X轴范围变化,更新锚点位置
dateAxis.events.on("rangechanged", updateAllBulletsXRange);
// 图表重绘完成后也更新一次锚点位置
chart.events.on("ready", updateAllBulletsXRange);
chart.events.on("datavalidated", updateAllBulletsXRange);

// 创建序列
function createSeries(field, name) {
  var series = chart.series.push(new am4charts.LineSeries());
  series.dataFields.valueY = field;
  series.dataFields.dateX = "date";
  series.name = name;
  series.tooltipText = "{dateX}: [b]{valueY}[/]";
  series.strokeWidth = 2;

  var bullet = series.bullets.push(new am4charts.CircleBullet());
  bullet.circle.stroke = am4core.color("#fff");
  bullet.circle.strokeWidth = 2;

  bullet.draggable = true;
  // 鼠标悬停时显示垂直调整光标
  bullet.cursorOverStyle = am4core.MouseCursorStyle.verticalResize;
  // 拖拽中事件
  bullet.events.on("drag", (event) => {
    handleDrag(event);
  });
  // 拖拽结束事件
  bullet.events.on("dragstop", (event) => {
    handleDragStop(event);
  });
  // 锚点位置变化时更新自身X范围
  bullet.events.on("positionchanged", (event) => {
    let dataItem = event.target.dataItem;
    if (dataItem.bullets && dataItem.point) {
      let itemBullet = dataItem.bullets.getKey(bullet.uid);
      itemBullet.minX = dataItem.point.x;
      itemBullet.maxX = itemBullet.minX;
      itemBullet.minY = 0;
      itemBullet.maxY = chart.seriesContainer.pixelHeight;
    }
  });
}

createSeries("value", "Series #1");

chart.cursor = new am4charts.XYCursor();

chart.scrollbarX = new am4core.Scrollbar();

/* 拖拽事件处理函数 */
function handleDrag(event) {
  let dataItem = event.target.dataItem;
  // 将坐标转换为数值
  let value = valueAxis.yToValue(event.target.pixelY);
  // 设置新数值
  dataItem.valueY = value;
  // 触发展折线 hover 状态
  dataItem.segment.isHover = true;
  // 隐藏提示框避免干扰
  dataItem.segment.hideTooltip(0);
  // 触发锚点 hover 状态,避免鼠标移开后锚点隐藏
  event.target.isHover = true;
}

/* 拖拽结束事件处理函数 */
function handleDragStop(event) {
  handleDrag(event);
  let dataItem = event.target.dataItem;
  dataItem.component.isHover = false; 
  event.target.isHover = false;
}

CSS代码(无修改)

#chartdiv {
  width: 100%;
  height: 500px;
}

HTML代码(无修改)

<script src="//www.amcharts.com/lib/4/core.js"></script>
<script src="//www.amcharts.com/lib/4/charts.js"></script>
<script src="//www.amcharts.com/lib/4/themes/animated.js"></script>
<div id="chartdiv"></div>

内容的提问来源于stack exchange,提问作者Stéphane Laurent

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 07:06:01