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

在Svelte中使用Flubber.js渲染GeoJSON图形报错求助

问题:Svelte + Flubber.js 图形变形报错处理

问题背景

我尝试用Svelte和Flubber.js复刻Flubber官方的GeoJSON图形变形示例,不依赖D3,参考了使用tweened实现插值的示例。

现有实现代码

<script>
   import { interpolate } from 'flubber';
  import { feature } from 'topojson';
  import { tweened } from 'svelte/motion';
  import * as eases from 'svelte/easing';
  import wards from '$lib/Wards/shapes/map.topo.json';

  const shape = tweened(undefined, {
    interpolate,
    easing: eases.cubicInOut,
    duration: 400,
  });

  let places = feature(wards, wards.objects.states).features.map(function (d) {
    return d.geometry.coordinates[0];
  });

  // 转换多边形坐标为字符串格式
  places = places.map(function (d) {
    return d.map(function (d) {
      return d.join(',');
    });
  });
  let selected = 0;
  $: $shape = places[selected];
</script>

{#each Object.keys(places) as key}
  <button
     class:selected="{selected === key}"
     on:click="{() => (selected = key)}"
   >
  {key}
  </button>
{/each}

<main>
   <svg viewBox="0 0 960 500">
      <path d="{$shape}"></path>
   </svg>
</main>

控制台报错信息

Error: attribute d: Expected moveto path command ('M' or 'm'), "77.4618079999067…".

Uncaught TypeError: All shapes must be supplied as arrays of [x, y] points or an SVG path string.
示例合法的形状格式:
[[0, 0], [10, 0], [10, 10]]
"M0,0 L10,0 L10,10Z"

错误原因与解决方法

错误原因

  1. Flubber参数格式不符:你把原始的[x,y]坐标数组转成了字符串数组(如["77.46,xxx", "xxx,xxx"]),但Flubber的interpolate函数只接受二维坐标数组或完整SVG路径字符串,这种格式不被识别。
  2. SVG路径指令缺失:SVG的path元素d属性必须以M(移动到起点)开头,用L等指令连接坐标点,结尾可选Z闭合路径。直接传递坐标字符串会缺少这些必要指令,导致路径解析失败。

修正后的代码

<script>
  import { interpolate } from 'flubber';
  import { feature } from 'topojson';
  import { tweened } from 'svelte/motion';
  import * as eases from 'svelte/easing';
  import wards from '$lib/Wards/shapes/map.topo.json';

  // 将坐标数组转换为标准SVG路径字符串
  const coordsToPath = (coords) => {
    if (!coords) return '';
    return `M ${coords[0].join(' ')} ${coords.slice(1).map(p => `L ${p.join(' ')}`).join(' ')} Z`;
  };

  const shape = tweened(undefined, {
    interpolate,
    easing: eases.cubicInOut,
    duration: 400,
  });

  // 保留原始二维坐标数组,不做字符串转换
  let places = feature(wards, wards.objects.states).features.map(d => d.geometry.coordinates[0]);
  
  let selected = 0;
  $: $shape = places[selected];
</script>

{#each Object.keys(places) as key}
  <button
     class:selected="{selected === key}"
     on:click="{() => (selected = key)}"
   >
  {key}
  </button>
{/each}

<main>
   <svg viewBox="0 0 960 500">
      <path d="{coordsToPath($shape)}"></path>
   </svg>
</main>

修改说明

  • 新增coordsToPath工具函数:将Flubber插值输出的坐标数组转换为符合SVG规范的路径字符串,确保包含M起点指令、L连线指令和Z闭合指令。
  • 移除坐标字符串转换代码:保留原始的[x,y]二维数组格式,让Flubber的interpolate函数能正确处理插值逻辑。
  • 动态生成路径:在<path>的d属性中调用coordsToPath,将插值后的坐标数组转为可用的路径指令。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 11:07:06