Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/446.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/svg/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何在不检查画布上的每个点的情况下获取SVG路径字符串中包含的所有点?_Javascript_Svg_Canvas_Html5 Canvas - Fatal编程技术网

Javascript 如何在不检查画布上的每个点的情况下获取SVG路径字符串中包含的所有点?

Javascript 如何在不检查画布上的每个点的情况下获取SVG路径字符串中包含的所有点?,javascript,svg,canvas,html5-canvas,Javascript,Svg,Canvas,Html5 Canvas,是否有一种有效的方法可以找到路径中每个点的[x,y]坐标,而无需使用上下文手动检查整个画布上的每个点。isPointInPath() 来自geojson的示例路径 <path d=" M 588, 173, L 588, 176, L 585, 216, L 585, 216, L 584, 223, L 580, 274, L 565, 273, L 565, 273, L 549, 271, L 539, 270, L 535, 269, L 513,

是否有一种有效的方法可以找到路径中每个点的
[x,y]
坐标,而无需使用
上下文手动检查整个画布上的每个点。isPointInPath()

来自geojson的示例路径

<path d="
  M 588, 173,
  L 588, 176,  L 585, 216,  L 585, 216,  L 584, 223,
  L 580, 274,  L 565, 273,  L 565, 273,  L 549, 271,
  L 539, 270,  L 535, 269,  L 513, 267,  L 503, 266,
  L 486, 264,  L 477, 262,  L 468, 261,  L 464, 260,
  L 455, 259,  L 449, 258,  L 451, 249,  L 452, 244,
  L 453, 233,  L 456, 218,  L 456, 215,  L 460, 192,
  L 460, 191,  L 462, 180,  L 463, 174,  L 463, 171,
  L 464, 167,  L 464, 161,  L 465, 158,  L 470, 159,
  L 471, 159,  L 477, 160,  L 477, 160,  L 480, 161,
  L 482, 161,  L 487, 161,  L 499, 163,  L 500, 163,
  L 514, 165,  L 534, 168,  L 535, 168,  L 544, 169,
  L 555, 170,  L 557, 170,  L 565, 171,  L 581, 173,
  Z"  
fill="transparent" stroke-width="1" stroke="black"></path>

例如,我现在正在使用geojson文件执行以下操作:

  const points = [];
  const pointWidth = 2;

  for (let x = 0; x < canvasWidth; x += pointWidth) {
    for (let y = 0; y < canvasHeight; y += pointWidth) {

      for (const feature of countyGeoJson.features) {
        const d = pathGenerator(feature);
        const countyShape = new Path2D(d);

        if (context.isPointInPath(countyShape, x, y)) {
          points.push({ coords: [x, y], data: feature.properties });
          break;
        }
      }
    }
  }
const points=[];
const pointWidth=2;
for(设x=0;x
基本上,我在画布网格中循环每个点(超过一百万个),然后嵌套另一个循环,查看每个特征以确定该点是否在特征的投影路径字符串中。这是非常低效的,我的浏览器无法处理它


有没有办法使用路径字符串本身来生成点?

下面是我们在评论中讨论的完整实现

var图像=`
`;
内部功能(p,vs){
var内=假;
对于(变量i=0,j=vs.length-1;ip[1])!=(yj>p[1])和&(p[0]<(xj-xi)*(p[1]-yi)/(yj-yi)+xi);
如果(相交)内部=!内部;
}
返回内部;
}
函数绘图(){
ctx.drawImage(img,0,0);
常量匹配=image.matchAll(/L(…),(…),/g)
const poly=Array.from(匹配项,m=>[Number(m[1]),Number(m[2]))
设xs=poly.map(p=>p[0]);
设ys=poly.map(p=>p[1]);
让[xmin,xmax]=[Math.min(…xs),Math.max(…xs)];
让[ymin,ymax]=[Math.min(…ys),Math.max(…ys)];
ctx.globalAlpha=0.5
常数点宽度=4

对于(让x=xmin;x我认为您的算法非常好,在big-O复杂性方面,您几乎找不到性能更好的算法。 不过,您可以在代码中做一些改进:

1) 重要的是要知道画布与所有特征相比有多大。如果画布比所有特征都大,那么找到所有特征的边框(一个边框用于所有特征),然后使用该矩形而不是整个画布进行搜索。如果画布稍微大一点,这可能不会有任何改进

2) 您正在最内部的循环中执行一些工作(如调用
路径生成器
),尽管这并不取决于外部循环的变量。如果这项工作很昂贵,最好事先进行预计算

3) 从您的代码中,由于您的
break;
,我可以假设,如果您发现该点属于一个功能,那么它就不属于任何其他功能。如果这是真的,那么如果您能够以智能方式对功能进行排序,以便更快地从循环中中断,那么对这些功能进行排序可能是有益的。而不知道有关这些功能的任何信息对于你的特征,我将在这里做一个简单的假设:如果一个点属于某个特征,那么相邻的点很可能属于同一个特征

根据我的第2)点和第3)点,这是我建议的代码更新:

//预先计算最内层循环外部的形状(上面第2点)
//具有形状的功能(fws):
const fws=countyGeoJson.features.map(feature=>{
特写,
形状:新Path2D(路径生成器(功能))
});
常数点=[];
const pointWidth=2;
for(设x=0;x
要获得填充路径将产生的所有像素坐标,只需填充该路径并获得已绘制的像素即可。

由于我们不希望有太大的画布进行搜索,因此可以首先提取文档中的的BBox,调整画布大小,并从BBox反向转换其坐标。我们只需在将像素映射回坐标时重新添加转换:

const path_elem=document.querySelector('path');
const coords=getPathFillCoords(路径元素);
设str='';
coords.forEach(([x,y],i)=>{
str+=`;
} );
路径元素insertAdjacentHTML(“beforebeagin”,str);
函数getPathFillCoords(elem){
const bbox=path_elem.getBBox();
const def=path_elem.getAttribute('d');
常量路径=新路径2D(def);
const canvas=document.createElement('canvas');
const width=canvas.width=bbox.width;
const height=canvas.height=bbox.height;
const ctx=canvas.getContext('2d');
ctx.translate(-bbox.x,-bbox.y);
ctx.fill(路径);
常量img=ctx.getImageData(0,0,宽度,高度);
常量像素=新的UINT32阵列(img.data.buffer);
常数坐标=像素。减少((arr,px,ind)=>{
如果(px!==0xFF000000){return arr;}//不完全不透明
常数比=ind/宽度;
常数y=数学楼层(比率);
常数x=数学圆((比值-y)*宽度);
常数坐标=[x+bbox.x,y+bbox.y];
arr.push(协调);
返回arr;
}, [] );
返回坐标;
}
body{背景:白色}