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

如何修改Canvas中context.drawImage图片源实现十字标记变色

实现Canvas动态切换十字标记颜色(新标记红,旧标记蓝)

我来帮你解决这个问题!你现在的思路方向是对的,但现有代码里有几个小问题导致效果可能不符合预期——比如每次draw()执行都会创建新的定时器,还有内部定时器引用的i会因为闭包问题指向最新值,导致画错位置。而且Canvas是即时渲染模式,直接在旧标记上覆盖不如维护状态后整体重绘来得可靠。

核心思路调整

  1. 预加载图片:提前加载红色和蓝色十字图片,避免每次绘制重复请求资源
  2. 维护标记状态数组:用数组保存每个标记的坐标和「是否为新标记」的状态,新标记显示红色,2秒后切换为蓝色
  3. 单一主定时器:只创建一个定时器负责添加新标记,避免定时器叠加
  4. 用requestAnimationFrame重绘:持续刷新画布,每次重绘时根据标记状态绘制对应颜色的十字,确保画面清晰一致

修正后的完整代码

<div style="width : 75%;margin : auto;">
  <canvas id="Canvas" width="954" height="267"></canvas>
  <button class="play">Play</button>
  <button class="pause">Pause</button>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
var canvas = document.getElementById('Canvas');
var context = canvas.getContext("2d");

// 预加载所有图片,确保加载完成再使用
var mapSprite = new Image();
var crossRed = new Image();
var crossBlue = new Image();

var imagesLoaded = 0;
var totalImages = 3;
function checkImagesLoaded() {
  imagesLoaded++;
  if (imagesLoaded === totalImages) {
    init(); // 所有图片加载完成后初始化
  }
}

mapSprite.src = "v1.png";
mapSprite.onload = checkImagesLoaded;
crossRed.src = "cross.png";
crossRed.onload = checkImagesLoaded;
crossBlue.src = "cross-blue.png";
crossBlue.onload = checkImagesLoaded;

var array_x = [351,315,353,352,318,485,351,748,568,645,373,350,572,374,650,240,240,320,707,235,402,539,256,410,433,405,353,745,404,320,514,322,692,474,293,418,418,690,237,513,378,478,433,405,285,429,458,622,568,536,564,389,641,534,567,454,575,482,459,539,431,327,464,374,348,520,279,378,509,516,232,744,351,710,481,540,429,642,537,459,513,689,324,463,375,747,431,265,484,591,458,460,485,407,720,483,376,520,691,376,232,413,536,430,653,714,484,715,629,573,263,408,436,300,544,407,432,568,536,462,485,346,610,524];
var array_y = [18,18,181,228,60,232,34,32,26,37,65,62,228,180,91,83,83,81,88,62,35,65,52,155,23,90,94,95,230,232,15,105,37,68,47,186,186,93,14,65,22,10,230,68,18,91,226,22,150,227,89,43,76,92,62,12,187,96,78,33,35,180,151,230,151,154,95,96,31,233,39,77,79,20,30,165,65,51,18,62,96,19,150,33,79,19,35,23,210,20,180,95,184,19,76,64,36,186,73,151,26,192,153,156,24,36,165,97,85,78,77,101,184,22,177,212,210,166,79,210,150,168,45,18];

var isPaused = false;
var markers = []; // 保存所有标记的状态:{x, y, isNew}
var currentIndex = 0;
var addMarkerTimer = null;
var animationId = null;

function init() {
  // 初始化画布样式
  context.font = "15px Georgia";
  context.textAlign = "center";
  
  // 启动添加标记的定时器(每隔5秒添加一个)
  addMarkerTimer = setInterval(function() {
    if (!isPaused && currentIndex < array_x.length) {
      addNewMarker(array_x[currentIndex], array_y[currentIndex]);
      currentIndex++;
    } else if (currentIndex >= array_x.length) {
      clearInterval(addMarkerTimer); // 所有标记添加完成后停止定时器
    }
  }, 5000);
  
  // 启动动画循环
  animate();
}

function addNewMarker(x, y) {
  // 添加新标记,初始状态为红色(isNew: true)
  var marker = {x: x, y: y, isNew: true};
  markers.push(marker);
  
  // 2秒后将该标记改为蓝色
  setTimeout(function() {
    marker.isNew = false;
  }, 2000);
}

function animate() {
  if (!isPaused) {
    draw();
  }
  animationId = requestAnimationFrame(animate);
}

function draw() {
  // 清空画布
  context.fillStyle = "#000";
  context.fillRect(0, 0, canvas.width, canvas.height);
  
  // 绘制背景地图
  context.drawImage(mapSprite, 0, 0, 954, 267);
  
  // 绘制所有标记:根据isNew状态选择红色或蓝色十字
  markers.forEach(function(marker) {
    var cross = marker.isNew ? crossRed : crossBlue;
    context.drawImage(cross, marker.x, marker.y, 10, 10);
  });
}

// 暂停/播放按钮事件
$('.pause').on('click', function(e) {
  e.preventDefault();
  isPaused = true;
});

$('.play').on('click', function(e) {
  e.preventDefault();
  isPaused = false;
});
</script>

关键改动说明

  1. 图片预加载:通过checkImagesLoaded函数确保所有图片加载完成后再初始化,避免绘制时图片未加载导致的空白问题
  2. 标记状态数组:markers数组保存每个标记的坐标和状态,2秒后通过setTimeout修改该标记的isNew属性,重绘时就会自动切换为蓝色
  3. 单一定时器:只创建一个addMarkerTimer负责添加新标记,避免原代码中每次draw()都创建新定时器导致的叠加问题
  4. requestAnimationFrame动画循环:相比直接用定时器重绘,requestAnimationFrame会和浏览器刷新同步,画面更流畅,也更容易控制暂停/播放

这样修改后,就能完美实现你想要的效果:每隔5秒新增一个红色十字,2秒后该十字自动变为蓝色,始终只有最新的十字是红色,吸引用户注意力。

内容的提问来源于stack exchange,提问作者ranell

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:09:07