重写OpenLayers的proj4.register函数后投影异常及框架冲突问题
我一眼就看出问题出在你重写的register函数里——prototype.js给所有对象添加的额外属性被Object.keys()误当成了投影编码,这就导致后续遍历的时候混入了无效的键,干扰了投影的正常注册流程,最终地图模糊、投影不生效。
问题根源拆解
prototype.js会给Object.prototype添加一些扩展方法(比如each、clone这类),而Object.keys()会返回对象自身的可枚举属性,但如果proj4.defs的原型链上被prototype.js加了可枚举属性,这些属性就会被一起捞出来。你原来的代码直接用Object.keys(proj4.defs)拿到的数组里,除了EPSG:27572,还混进了prototype添加的额外键,遍历这些无效键的时候,要么拿不到合法的投影定义,要么添加错误的转换规则,自然就出问题了。
修复后的重写方案
核心思路是过滤掉proj4.defs中不属于自身的属性,用Object.prototype.hasOwnProperty.call()来判断属性是不是proj4自己定义的投影编码,而不是从原型链继承来的。
修改后的register函数如下:
ol.proj.proj4.register = function(proj4) { // 过滤掉原型链上的属性,只保留proj4.defs自身的投影编码 const projCodes = Object.keys(proj4.defs).filter(key => Object.prototype.hasOwnProperty.call(proj4.defs, key) ); const len = projCodes.length; let i, j; // 注册投影 for (i = 0; i < len; ++i) { const code = projCodes[i]; if (!ol.proj.get(code)) { const def = proj4.defs(code); ol.proj.addProjection(new ol.proj.Projection({ code: code, axisOrientation: def.axis, metersPerUnit: def.to_meter, units: def.units })); } } // 添加坐标转换规则 for (i = 0; i < len; ++i) { const code1 = projCodes[i]; const proj1 = ol.proj.get(code1); for (j = 0; j < len; ++j) { const code2 = projCodes[j]; const proj2 = ol.proj.get(code2); if (!ol.proj.getTransform(code1, code2)) { if (proj4.defs[code1] === proj4.defs[code2]) { ol.proj.addEquivalentProjections([proj1, proj2]); } else { const transform = proj4(code1, code2); ol.proj.addCoordinateTransforms(proj1, proj2, transform.forward, transform.inverse); } } } } }
为什么这样能解决问题?
Object.prototype.hasOwnProperty.call(proj4.defs, key)会严格检查key是不是proj4.defs对象自身拥有的属性,完全忽略原型链上prototype.js添加的那些额外属性,这样projCodes数组里就只有你定义的EPSG:27572这类合法投影编码了,后续的注册和转换规则添加流程就能正常执行。
额外优化建议
你还可以用更现代的遍历方式替代传统的for循环,让代码更简洁,比如用forEach:
ol.proj.proj4.register = function(proj4) { const projCodes = Object.keys(proj4.defs).filter(key => Object.prototype.hasOwnProperty.call(proj4.defs, key) ); // 注册投影 projCodes.forEach(code => { if (!ol.proj.get(code)) { const def = proj4.defs(code); ol.proj.addProjection(new ol.proj.Projection({ code: code, axisOrientation: def.axis, metersPerUnit: def.to_meter, units: def.units })); } }); // 添加坐标转换规则 projCodes.forEach(code1 => { const proj1 = ol.proj.get(code1); projCodes.forEach(code2 => { const proj2 = ol.proj.get(code2); if (!ol.proj.getTransform(code1, code2)) { if (proj4.defs[code1] === proj4.defs[code2]) { ol.proj.addEquivalentProjections([proj1, proj2]); } else { const transform = proj4(code1, code2); ol.proj.addCoordinateTransforms(proj1, proj2, transform.forward, transform.inverse); } } }); }); }
这样修改后,你的EPSG:27572投影应该就能正常注册并作用于地图了,不会再出现模糊的问题。
内容的提问来源于stack exchange,提问作者PopHip

