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

Canvas绘制六边形地图河流线条不显示问题求助

问题:六边形地图河流线条无法绘制,ctx.stroke()无效果

我正在开发一个基于六边形的地图生成器,需要在客户端绘制穿过服务器计算出的河流六边形中心的“河流”线条。相关变量通过Django从服务器注入(已验证可正常获取值):

// The optional populators
const rivers = {{ rivers |safe}};
const cities = {{ cities |safe}};
const roads = {{roads |safe}};

// Constants for our angles and scales, starting with scale 5
const a = Math.PI/3;
var r = 5;

绘制河流的函数如下:

// Function that draws Rivers
function DrawRivers(){
    // For each river in the rivers
    for (var river of rivers) {
        // Set up point tracking
        let x_coord = r + river[0][0] * (r + (r * Math.cos(a)));
        let y_coord = r + river[0][1] * (r + (r*Math.sin(a)));
        if (river[0][0] % 2 == 1) {
            y_off = y_coord;
        } else { // If it's an even number of tiles in the row it'll be the lower part
            y_off = y_coord + r * Math.sin(a);
        }

        ctx.beginPath();
        ctx.lineWidth = r;
        ctx.strokeStyle = "#000000";
        ctx.moveTo(x_coord, Math.round(y_off))
        // For each point in the river
        for (var river_hex of river){
            let x_coord = r + river[0][0] * (r + (r * Math.cos(a)));
            let y_coord = r + river[0][1] * (r + (r*Math.sin(a)));
            if (river[0][0] % 2 == 1) {
                y_off = y_coord;
            } else { // If it's an even number of tiles in the row it'll be the lower part
                y_off = y_coord + r * Math.sin(a);
            }
            ctx.lineTo(x_coord, Math.round(y_off))
        }
        ctx.closePath();
        ctx.stroke();
    }
}

运行代码后线条未绘制,已排查变量均正常,仅ctx.stroke()调用后无实际线条显示,恳请帮忙找出问题所在。


回答
  • 核心错误:循环中重复使用river[0]而非当前river_hex
    你在遍历河流的每个六边形点时,始终用river[0][0]和river[0][1]计算坐标,导致所有lineTo都指向同一个点,线条长度为0,自然看不到绘制效果。

  • 修正后的代码
    修改内层循环中的坐标计算逻辑,替换river[0]为当前迭代的river_hex:

// Function that draws Rivers
function DrawRivers(){
    // For each river in the rivers
    for (var river of rivers) {
        // Set up point tracking - 使用第一个点初始化起点
        let firstHex = river[0];
        let x_coord = r + firstHex[0] * (r + (r * Math.cos(a)));
        let y_coord = r + firstHex[1] * (r + (r*Math.sin(a)));
        let y_off = firstHex[0] % 2 === 1 ? y_coord : y_coord + r * Math.sin(a);

        ctx.beginPath();
        ctx.lineWidth = r;
        ctx.strokeStyle = "#000000";
        ctx.moveTo(x_coord, Math.round(y_off));

        // 遍历河流的后续点(从第二个开始,避免重复绘制起点)
        for (var i = 1; i < river.length; i++) {
            let river_hex = river[i];
            x_coord = r + river_hex[0] * (r + (r * Math.cos(a)));
            y_coord = r + river_hex[1] * (r + (r*Math.sin(a)));
            y_off = river_hex[0] % 2 === 1 ? y_coord : y_coord + r * Math.sin(a);
            ctx.lineTo(x_coord, Math.round(y_off));
        }

        // 不需要closePath(),河流是连续线条而非闭合图形,否则会自动连接首尾
        ctx.stroke();
    }
}
  • 额外优化点
    1. 内层循环从索引1开始,避免重复绘制起点到起点的无效线条
    2. 移除ctx.closePath(),因为河流是开放线条,闭合会强制连接首尾,不符合河流的视觉逻辑
    3. 使用三元运算符简化y_off的判断,代码更简洁
    4. 变量y_off添加let声明,避免全局变量污染

内容的提问来源于stack exchange,提问作者Sans the Medic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 09:05:22