问题描述
当矢量 marker 的 markerWidth / markerHeight 使用 zoom stops 函数式符号({ stops: [[zoom, value], ...] })时,打开(或 hover 触发打开)挂载在该 marker 上的 InfoWindow 会抛出错误:
Uncaught Error: Position is NaN
marker 本身渲染正常(maptalks 会把 stops 按当前 zoom 解析为具体数值),只有 InfoWindow 的偏移量计算会崩溃。
maptalks 版本
1.12.1(猜测更早的 1.x 版本也存在)
复现步骤
保存为 .html 文件打开,点击按钮(或把鼠标移到红点上)即可触发错误:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<link rel="stylesheet" href="https://unpkg.com/maptalks@1.12.1/dist/maptalks.css"/>
<style>html,body,#map{margin:0;height:100%}#b{position:fixed;top:8px;left:8px;z-index:9}</style>
</head>
<body>
<div id="map"></div>
<button id="b" onclick="openIW()">打开 InfoWindow(复现)</button>
<script src="https://unpkg.com/maptalks@1.12.1/dist/maptalks.js"></script>
<script>
var map = new maptalks.Map('map', { center:[0,0], zoom:6 });
var marker = new maptalks.Marker([0,0], {
symbol: {
markerType: 'ellipse',
markerWidth: { stops: [[12,6],[15,8]] }, // 合法的 zoom 函数式符号
markerHeight: { stops: [[12,6],[15,8]] },
markerFill: '#f00'
}
});
new maptalks.VectorLayer('v',[marker]).addTo(map);
marker.setInfoWindow({ custom:true, content:'<div style="padding:8px">hi</div>', autoPan:false });
marker.on('mouseover', openIW); // hover 同样会复现
function openIW(){ marker.openInfoWindow(marker.getCoordinates()); }
</script>
</body>
</html>
期望行为
InfoWindow 正常在 marker 旁边打开,不报错。
实际行为
Uncaught Error: Position is NaN
抛错的调用链:
InfoWindow.getOffset()
→ painter.getFixedExtent()
→ getVectorMarkerFixedExtent()
→ calVectorMarkerSize() // 返回 [NaN, NaN]
→ getVectorMarkerAnchor(symbol, NaN, NaN)
→ getAlignPoint(Size(NaN, NaN), ...)
→ new Point(NaN, NaN) // 抛出 "Position is NaN"
根因分析
calVectorMarkerSize(src/core/util/marker.ts)直接读取原始 symbol:
const width = getValueOrDefault(symbol['markerWidth'], DEFAULT_MARKER_SYMBOLS.markerWidth);
const height = getValueOrDefault(symbol['markerHeight'], DEFAULT_MARKER_SYMBOLS.markerHeight);
...
const w = Math.round(width + lineWidth + shadow + padding * 2); // 对象 + 数字 = NaN
而 getValueOrDefault 只在值为 undefined 时才回退到默认值:
export function getValueOrDefault<T>(v: T, d: T) { return v === undefined ? d : v; }
{ stops: [...] } 对象不是 undefined,于是被原样返回 → 参与算术得到 NaN → 一路传递到 new Point(NaN, NaN) → 抛错。
修复建议
在 calVectorMarkerSize 中,用 isNumber()(已在 marker.ts 中导入)对 markerWidth / markerHeight / markerLineWidth 做类型判断,非数字时回退到 DEFAULT_MARKER_SYMBOLS。0 仍是合法数字(isNumber(0) === true),所以现有的零值短路分支行为不变。
- const width = getValueOrDefault(symbol['markerWidth'], DEFAULT_MARKER_SYMBOLS.markerWidth);
- const height = getValueOrDefault(symbol['markerHeight'], DEFAULT_MARKER_SYMBOLS.markerHeight);
+ const width = isNumber(symbol['markerWidth']) ? symbol['markerWidth'] : DEFAULT_MARKER_SYMBOLS.markerWidth;
+ const height = isNumber(symbol['markerHeight']) ? symbol['markerHeight'] : DEFAULT_MARKER_SYMBOLS.markerHeight;
if (width === 0 || height === 0) { ... }
- const lineWidth = getValueOrDefault(symbol['markerLineWidth'], DEFAULT_MARKER_SYMBOLS.markerLineWidth),
+ const lineWidth = isNumber(symbol['markerLineWidth']) ? symbol['markerLineWidth'] : DEFAULT_MARKER_SYMBOLS.markerLineWidth,
stops 符号是 maptalks 文档支持的功能,InfoWindow / extent 的计算应当优雅降级,而不是抛出未捕获异常导致用户代码崩溃。
补充
- 只要矢量 marker(
markerType: ellipse/pin/pie/...)用 zoom stops 控制尺寸,且挂了 InfoWindow 并打开,就能复现。
getImageMarkerFixedExtent 里也有类似写法(markerWidth || (img ? img.width : 0)),图片 marker 若用 stops 尺寸可能存在相关问题——本次未深入验证。
问题描述
当矢量 marker 的
markerWidth/markerHeight使用 zoomstops函数式符号({ stops: [[zoom, value], ...] })时,打开(或 hover 触发打开)挂载在该 marker 上的InfoWindow会抛出错误:marker 本身渲染正常(maptalks 会把
stops按当前 zoom 解析为具体数值),只有 InfoWindow 的偏移量计算会崩溃。maptalks 版本
1.12.1(猜测更早的 1.x 版本也存在)复现步骤
保存为
.html文件打开,点击按钮(或把鼠标移到红点上)即可触发错误:期望行为
InfoWindow 正常在 marker 旁边打开,不报错。
实际行为
抛错的调用链:
根因分析
calVectorMarkerSize(src/core/util/marker.ts)直接读取原始 symbol:而
getValueOrDefault只在值为undefined时才回退到默认值:{ stops: [...] }对象不是undefined,于是被原样返回 → 参与算术得到NaN→ 一路传递到new Point(NaN, NaN)→ 抛错。修复建议
在
calVectorMarkerSize中,用isNumber()(已在marker.ts中导入)对markerWidth/markerHeight/markerLineWidth做类型判断,非数字时回退到DEFAULT_MARKER_SYMBOLS。0仍是合法数字(isNumber(0) === true),所以现有的零值短路分支行为不变。stops符号是 maptalks 文档支持的功能,InfoWindow / extent 的计算应当优雅降级,而不是抛出未捕获异常导致用户代码崩溃。补充
markerType: ellipse/pin/pie/...)用 zoomstops控制尺寸,且挂了 InfoWindow 并打开,就能复现。getImageMarkerFixedExtent里也有类似写法(markerWidth || (img ? img.width : 0)),图片 marker 若用stops尺寸可能存在相关问题——本次未深入验证。