如何将SVG导入/转换为原生 Draw.io 形状?[关闭]

How to import/convert SVG to native Draw.io shape? [closed]

提问人:nowox 提问时间:10/28/2023 最后编辑:nowox 更新时间:10/29/2023 访问量:79

问:


我们不允许提出有关书籍、工具、软件库等建议的问题。您可以编辑问题,以便用事实和引文来回答。

7天前关闭。

我正在寻找一个图表编辑器,它支持导入复杂的形状,同时保持页面的样式。Draw.io 似乎很有前途,但如果我没记错的话,它主要促进 SVG 导入或原始 XML 输入,而不提供所见即所得的接口。

关于这个问题,StackOverflow 上有各种各样的问题,但似乎都没有解决我的具体问题。例如,这个问题详细介绍了导入 SVG 然后更改其颜色的过程。

为了说明我的观点,我在下面提供了两张截图。左边的屏幕截图描绘了我导入的 SVG,而右边的屏幕截图展示了标准的 Draw.io 形状。如前所述,我只能修改 SVG 的 Fill .cls-1 或 Line .cls-1 等属性。相反,对于标准形状,我可以指定一个不同的样式。

我梦想着一个图表编辑器,它允许导入复杂的形状并保留页面的样式。Draw.io 有潜力,但据我了解,它只支持 SVG 导入或原始 XML 代码,没有所见即所得的编辑器。

关于 SO 的问题很多,但目前没有一个能回答我的问题。演示如何导入 SVG,然后编辑颜色。

例如,在此屏幕截图中,左侧是导入的 SVG,右侧是常规的 Draw.io 形状。您可以看到,对于 SVG,我只能编辑 或 ,但对于第二个形状,我可以关联样式:Fill .cls-1Line .cls-1

enter image description here enter image description here

有没有一种方法可以将 SVG 转换为原生 Draw.io 形状,从而实现样式应用?

我幼稚的方法是翻译 SVG:

<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_2" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" 
     viewBox="0 0 91.5 91.5">
  <defs>
    <style>
      .cls-1 {
        fill: none;
        stroke: #231f20;
        stroke-miterlimit: 10;
      }
    </style>
  </defs>
  <g id="Layer_1-2" data-name="Layer 1">
    <rect class="cls-1" x=".5" y=".5" width="90.5" height="90.5"/>
    <polygon class="cls-1" points="61.09 19.17 30.4 19.17 
    15.06 45.75 30.4 72.32 61.09 72.32 76.44 45.75 61.09 19.17"/>
    <line class="cls-1" x1="30.4" y1="72.32" x2="61.09" y2="19.17"/>
    <line class="cls-1" x1="76.44" y1="45.75" x2="15.86" y2="45.75"/>
    <line class="cls-1" x1="30.4" y1="19.17" x2="61.09" y2="72.32"/>
  </g>
</svg>

进入 Draw.io 形状语言:

<shape aspect="variable" h="90.5" w="90.5" strokewidth="inherit">    
  <background>
    <rect h="90.5" w="90.5" x="0.5" y=".5"/>
  </background>  
  <foreground>
    <fillstroke />
    <path>
      <move x="61.09" y="19.17"/>
      <line x="30.4" y="19.17"/>
      <line x="15.06" y="45.75"/>
      <line x="30.4" y="72.32"/>
      <line x="30.4" y="72.32"/>
      <line x="61.09" y="72.32"/>
      <line x="76.44" y="45.75"/>
      <line x="61.09" y="19.17"/>
    </path>
    <stroke />
    <path>
      <move x="30.4" y="72.32"/>
      <line x="61.09" y="19.17"/>
    </path>
    <stroke />
    <path>
      <move x="76.44" y="45.75"/>
      <line x="15.86" y="45.75"/>
    </path>
    <stroke />
    <path>
      <move x="30.4" y="19.17"/>
      <line x="61.09" y="72.32"/> 
    </path>
    <stroke />
  </foreground>
</shape>
SVG 图表 MXCurce draw.io

评论


答:

0赞 nowox 10/28/2023 #1

为什么不使用 minidom 编写 Python 脚本?

from xml.dom import minidom
file = minidom.parse('specimen.svg')
svg = file.getElementsByTagName('svg')[0]
viewBox = svg.getAttribute('viewBox').split(' ')
width, height = float(viewBox[2]), float(viewBox[3])


def create_constraint(document, parent, x, y, perimeter=1):
    """ Create a constraint """
    constraint = document.createElement('constraint')
    constraint.setAttribute('x', str(x))
    constraint.setAttribute('y', str(y))
    constraint.setAttribute('perimeter', str(perimeter))
    parent.appendChild(constraint)


def create_connections(document, parent, height, width, nx=3, ny=3):
    connections = document.createElement('connections')
    parent.appendChild(connections)

    nx += 1
    ny += 1
    for x in [1/nx*n for n in range(1, nx)]:
        create_constraint(document, connections, 0, x)
        create_constraint(document, connections, 1, x)
        create_constraint(document, connections, x, 0)
        create_constraint(document, connections, x, 1)


def process_rect(document, parent, rect):
    rectangle = document.createElement('rect')
    rectangle.setAttribute('x', rect.getAttribute('x'))
    rectangle.setAttribute('y', rect.getAttribute('y'))
    rectangle.setAttribute('width', rect.getAttribute('width'))
    rectangle.setAttribute('height', rect.getAttribute('height'))
    parent.appendChild(rectangle)
    parent.appendChild(document.createElement('stroke'))


def process_polygon(document, parent, polygon):
    """ Process a polygon """
    points = polygon.getAttribute('points').split(' ')
    points = zip(*(iter(points),) * 2)
    path = document.createElement('path')
    parent.appendChild(path)
    move = document.createElement('move')
    p = next(points)
    move.setAttribute('x', p[0])
    move.setAttribute('y', p[1])
    path.appendChild(move)
    for (x, y) in points:
        line = document.createElement('line')
        line.setAttribute('x', x)
        line.setAttribute('y', y)
        path.appendChild(line)
    parent.appendChild(document.createElement('stroke'))


def process_line(document, parent, line):
    """ Process a line """
    x1 = line.getAttribute('x1')
    y1 = line.getAttribute('y1')
    x2 = line.getAttribute('x2')
    y2 = line.getAttribute('y2')
    path = document.createElement('path')
    parent.appendChild(path)
    move = document.createElement('move')
    move.setAttribute('x', x1)
    move.setAttribute('y', y1)
    path.appendChild(move)
    line = document.createElement('line')
    line.setAttribute('x', x2)
    line.setAttribute('y', y2)
    path.appendChild(line)
    parent.appendChild(document.createElement('stroke'))


def process_group(document, parent, group):
    """ Process a group """
    for child in group.childNodes:
        if child.nodeType != child.ELEMENT_NODE:
            continue

        if child.tagName == 'g':
            process_group(document, parent, child)
        elif child.tagName == 'polygon':
            process_polygon(document, parent, child)
        elif child.tagName == 'line':
            process_line(document, parent, child)
        elif child.tagName == 'rect':
            process_rect(document, parent, child)


document = minidom.Document()
shape = document.createElement('shape')
shape.setAttribute('aspect', 'variable')
shape.setAttribute('h', viewBox[2])
shape.setAttribute('w', viewBox[3])
shape.setAttribute('strokewidth', "inherit")

parent = document.appendChild(shape)

create_connections(document, parent, height, width)

background = document.createElement('background')
rect = document.createElement('rect')
rect.setAttribute('x', viewBox[0])
rect.setAttribute('y', viewBox[1])
rect.setAttribute('w', viewBox[2])
rect.setAttribute('h', viewBox[3])
background.appendChild(rect)
foreground = document.createElement('foreground')
foreground.appendChild(document.createElement('fillstroke'))
shape.appendChild(background)
shape.appendChild(foreground)

process_group(document, foreground, svg)
print(document.toprettyxml())

只是为了好玩

我在SVG中画了这只猫:

enter image description here

<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_2" data-name="Layer 2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 91.5 91.5">
  <defs>
    <style>
      .cls-1 {
        stroke: #231f20;
        stroke-miterlimit: 10;
      }

      .cls-1, .cls-2 {
        fill: none;
      }

      .cls-2, .cls-3 {
        stroke: #000;
        stroke-linecap: round;
        stroke-linejoin: round;
      }

      .cls-3 {
        fill: #231f20;
      }
    </style>
  </defs>
  <g id="Layer_1-2" data-name="Layer 1">
    <rect class="cls-1" x=".5" y=".5" width="90.5" height="90.5"/>
    <path class="cls-2" d="m52.95,78.36c.66.31,1.32.14,1.97,0,1.23-.28,2.47-.57,3.66-.96,1.32-.43,2.52-1.19,3.36-2.26.61-.78.91-1.84,1.17-2.83.28-1.02.74-2,.73-3.12-.01-.88.26-1.76.3-2.65.17-3.33-.22-6.59-1.84-9.56-1.09-1.99-2.43-3.82-4.12-5.38-2.08-1.93-3.84-4.13-5.37-6.51-.49-.76-.36-1.33.41-1.83.66-.43,1.35-.81,1.96-1.3,1.25-1,1.71-2.45,2.04-3.93.4-1.79.32-3.61.22-5.43-.07-1.31-.06-2.63-.15-3.94-.06-.87-.29-1.72-.38-2.58-.04-.42,0-.88.13-1.28.42-1.28.93-2.53,1.33-3.81.27-.86.56-1.76.59-2.65.03-1.13-.08-2.29-.33-3.39-.29-1.28-1.18-1.74-2.42-1.5-2.14.42-4.17,1.13-6.11,2.11-.4.2-.87.37-1.14.69-.77.91-1.68.61-2.6.46-1.54-.25-3.07-.55-4.62-.74-2.48-.3-4.87.26-7.26.8-.84.19-1.57.11-2.33-.45-1.4-1.03-3.03-1.66-4.67-2.17-1.09-.34-2.25-.54-3.39-.68-.9-.11-1.44.32-1.69,1.2-.48,1.75-.61,3.54-.06,5.29.53,1.69,1.18,3.35,1.74,5.03.11.34.2.74.13,1.08-.51,2.45-.51,4.93-.52,7.4,0,1.24.03,2.49.14,3.73.28,3.12,1.8,5.41,4.82,6.42,1.38.46,1.78,1.19,1.64,2.55-.19,1.87-.25,3.75-.36,5.63-.16,2.8-.38,5.6-.22,8.42.1,1.81.07,3.62.15,5.43.11,2.31.27,4.62.4,6.93.07,1.22.1,2.45.22,3.67.06.64.22,1.28.4,1.9.32,1.07,2.39,1.76,3.18,1.55.79-.21,1.19-.9,1.5-1.61.23-.56.45-1.12.7-1.74.82.56.78,1.34.92,2.02.25,1.15.46,1.33,1.57,1.51.57.1,1.09.13,1.63-.08.87-.34,1.32-1.08,1.37-2.04.07-1.52.21-3.03.33-4.55s.22-3.03.34-4.55c.05-.66.11-1.31.17-1.97"/>
    <path class="cls-2" d="m52.88,78.36c.11-.86.34-1.72.32-2.58-.04-1.86.09-3.73-.37-5.57-.27-1.09-.32-2.23-.58-3.32-.18-.73-.49-1.46-.88-2.1-.53-.87-1.62-.99-2.34-.26-.41.41-.78.99-.87,1.55-.26,1.54-.37,3.11-.11,4.68.16,1.01.14,2.04.3,3.05.18,1.12.49,2.22.73,3.33.09.4.03.88.23,1.2.25.39.65.73,1.07.95.63.33,1.27.23,1.82-.25.23-.2.45-.41.68-.61"/>
    <path class="cls-2" d="m63.75,70.69c.84.23,1.66.51,2.51.67,2.45.45,4.31-.33,5.01-2.91.33-1.22.54-2.48.75-3.73.23-1.35.89-2.09,2.11-2.24.92-.11,1.95.62,2.38,1.7.56,1.42.53,2.88.26,4.34-.32,1.75-.88,3.46-1.85,4.94-1.31,1.99-3.06,3.36-5.61,3.66-2.17.25-4.09-.24-5.98-1.14-.46-.22-.86-.53-1.29-.81"/>
    <path class="cls-3" d="m54.38,21.94c.05-.11.06-.26.14-.33.95-.89,1.21-2.05,1.28-3.26.05-.9-.46-1.31-1.27-1-.89.34-1.76.76-2.46,1.47-.29.29-.34.49-.06.76.77.73,1.54,1.45,2.31,2.17"/>
    <path class="cls-3" d="m26.74,21.87c.79-.68,1.59-1.35,2.42-2.06-.7-1.08-1.66-1.61-2.77-1.86-.51-.11-.86.25-.8.8.07.62.22,1.24.41,1.83.17.52.44,1,.67,1.5"/>
    <path class="cls-2" d="m49.22,78.5c-.52.05-1.04.14-1.56.12-.91-.03-1.81-.12-2.72-.19-1.02-.08-2.04-.18-3.06-.27"/>
    <path class="cls-2" d="m36.52,65.87c-.29,2.22-.05,4.44,0,6.65.02,1.29-.04,2.58-.06,3.87"/>
    <path class="cls-2" d="m40.53,33.89c0,.23.03.46,0,.68-.08.45.21.94-.19,1.36-.61.63-1.26,1.18-2.18,1.21-.36.01-.72-.12-1.09-.19"/>
    <path class="cls-2" d="m40.53,35.86c.23.2.46.4.68.61.77.76,1.66.88,2.65.54"/>
    <path class="cls-2" d="m52.82,34.63c-1.02.09-2.04.18-3.06.27-.07,0-.14-.04-.2-.06"/>
    <path class="cls-2" d="m28.37,34.57c.72.02,1.45.04,2.17.07.27.01.54.04.81.07"/>
    <path class="cls-2" d="m31.16,36.94c-.88.25-1.77.5-2.65.75"/>
    <path class="cls-2" d="m49.29,37.21c.86.32,1.72.63,2.58.95"/>
    <path class="cls-2" d="m39.51,33.14c.34.23.67.46,1.06.73.33-.24.65-.49.98-.73"/>
    <circle class="cls-3" cx="33.12" cy="28.1" r="1.76"/>
    <circle class="cls-3" cx="46.15" cy="28.1" r="1.76"/>
  </g>
</svg>

从这个脚本中,我能够生成这个:

enter image description here

如您所见,您可以应用本机 Draw.io 样式...

0赞 Frodo Baggins 10/29/2023 #2

为此目的存在 https://github.com/jgraph/svg2xml

评论

0赞 nowox 10/29/2023
它不适用于我的猫 svg。它不考虑所有多边形。<fill/><stroke/>
0赞 Frodo Baggins 10/29/2023
请在 repo 上提交包含复制详细信息的问题。