首页 > 解决方案 > 将 svg 路径 d 拆分为对象数组

问题描述

有没有办法将d路径字符串拆分为对象数组?

例如:

const d = `M 0 0 L 0 10 C 0 10 20 30 20 20 Z`
const result = fromPathToArray(d)

// const result = [
//   { type: 'M', x: 0, y: 0 },
//   { type: 'L', x: 0, y: 10 },
//   { type: 'C', x1: 0, y1: 10, x2: 20, y2: 30, x3: 20, y3: 20 },
//   { type: 'Z' },
// ]

这是我的起始代码:

const PATH_COMMANDS = {
  M: ["x", "y"],
  m: ["dx", "dy"],
  H: ["x"],
  h: ["dx"],
  V: ["y"],
  v: ["dy"],
  L: ["x", "y"],
  l: ["dx", "dy"],
  Z: [],
  C: ["x1", "y1", "x2", "y2", "x", "y"],
  c: ["dx1", "dy1", "dx2", "dy2", "dx", "dy"],
  S: ["x2", "y2", "x", "y"],
  s: ["dx2", "dy2", "dx", "dy"],
  Q: ["x1", "y1", "x", "y"],
  q: ["dx1", "dy1", "dx", "dy"],
  T: ["x", "y"],
  t: ["dx", "dy"],
  A: ["rx", "ry", "rotation", "large-arc", "sweep", "x", "y"],
  a: ["rx", "ry", "rotation", "large-arc", "sweep", "dx", "dy"]
};

export function splitPath(path) {
  const items = path.trim().split(/\s*,|\s+/);
  const segments = [];
  
  items.forEach((item, i) => {
    const type = isString(item) ? item : null
    // ...
  })

  return segments
}

老实说我不知道​​该怎么办..

标签: javascriptsvg

解决方案


对于您所描述的情况,这是一个简单的例程。请注意,这种简单的解决方案只有在您知道输入遵循某种模式时才有用。如评论所示,一般情况更复杂。此外,您应该添加完整性检查以处理错误输入。

const PATH_COMMANDS = {
  M: ["x", "y"],
  m: ["dx", "dy"],
  H: ["x"],
  h: ["dx"],
  V: ["y"],
  v: ["dy"],
  L: ["x", "y"],
  l: ["dx", "dy"],
  Z: [],
  C: ["x1", "y1", "x2", "y2", "x", "y"],
  c: ["dx1", "dy1", "dx2", "dy2", "dx", "dy"],
  S: ["x2", "y2", "x", "y"],
  s: ["dx2", "dy2", "dx", "dy"],
  Q: ["x1", "y1", "x", "y"],
  q: ["dx1", "dy1", "dx", "dy"],
  T: ["x", "y"],
  t: ["dx", "dy"],
  A: ["rx", "ry", "rotation", "large-arc", "sweep", "x", "y"],
  a: ["rx", "ry", "rotation", "large-arc", "sweep", "dx", "dy"]
};

function fromPathToArray(path) {
  const items = path.replace(/[\n\r]/g, '').
                replace(/-/g, ' -').
                replace(/(\d*\.)(\d+)(?=\.)/g, '$1$2 ').
                trim().
                split(/\s*,|\s+/);
  const segments = [];
  let currentCommand = '';
  let currentElement = {};
  while (items.length > 0){
    let it = items.shift();
    if (PATH_COMMANDS.hasOwnProperty(it)){
      currentCommand = it;
    }
    else{
      items.unshift(it);
    }
    currentElement = {type: currentCommand};
    PATH_COMMANDS[currentCommand].forEach((prop) => {
      it = items.shift();  // TODO sanity check
      currentElement[prop] = it;
    });
    if (currentCommand === 'M'){
      currentCommand = 'L';
    }
    else if (currentCommand === 'm'){
      currentCommand = 'l';
    }
    segments.push(currentElement);
  }
  return segments
}

const d = `M 0 0 10 10 L 0 10 C 0 10 
20 30 20 20 a 4.12.12 1 0 1 4.13-1 Z`;
const result = fromPathToArray(d);

console.log(result);


推荐阅读