I'm trying to write an extension in which I need to utilize Inkscape's diagram connectors. I can't find an obvious way to do this, so I attempted to hack together an element using the xml of a diagram connector created using the diagram connector tool in Inkscape.
This is the xml of a diagram connector created using the tool in Inkscape which works as expected (i.e. it moves when its linked endpoints are moved)
I'm part of a map-making community for a game, and I am attempting to create metadata from maps that defines the structure of the map. One of the things that I need to be able to do is to define the graph structure of the map - i.e. connections between territory nodes. Diagram connectors seem to be a logical object to handle the connections, since they will move if the territory node is moved.
I want to give the user the ability to define the connection between two nodes using the extension. Ordinarily I could just let the user use the diagram connector tool in Inkscape themselves, but it is very common to have overlapping paths and objects which makes setting the connector endpoints properly a bit fiddly, so I think it would be easier for them if they could just select the two territories and have my extension automatically create the connector for them.
As a note, in the sample XML I gave above is the d attributes were not identical, but I have since tested this with identical values for that attribute with the same lack of success.
The "d" attribute is part of the svg spec for a path.
If you make a simple connection between two rectangles.
Then save and open the .svg in a text editor that detects changes such as Notepad++ or Geany.
Close Inkscape. Then remove the path data so d="M 200 100 30 40" becomes d=""
Save the file and reopen in Inkscape - you will find it makes no difference to what you see. That is because Inkscape uses
inkscape:connection-start="#path03" inkscape:connection-end="#path6389" ( this is part of the Inkscape namespace and not svg spec )
to draw the line, but generates 'd' to make sure it appears in a standard svg when displayed in a non Inkscape program such as a browser.
If you are monitoring the file in your text editor, then save the file again in Inkscape - no changes occur.
However if you move the rectangle then save - the text editor will spot the changes.
Inkscape regenerates the 'd' when the boxes are re positioned.
So how does this help anything ?
Well also group / ungroup does the same thing.
So in theory all you have to do in an extension is specify connector:start and end - then call group and ungroup - and hey presto a connection is made without having to draws the line manually.
# Could not find simplestyle, found this instead in extensions repo def format_style(my_style): """Format an inline style attribute from a dictionary""" return ";".join([att + ":" + str(val) for att, val in my_style.items()])
I'm trying to write an extension in which I need to utilize Inkscape's diagram connectors. I can't find an obvious way to do this, so I attempted to hack together an element using the xml of a diagram connector created using the diagram connector tool in Inkscape.
This is the xml of a diagram connector created using the tool in Inkscape which works as expected (i.e. it moves when its linked endpoints are moved)
This is the xml of the element I created in my extension:
Any assistance would be greatly appreciated!
Can you describe exactly what you want the extension to do ?
1. From the point of the user
2. From your point of view as the coder ?
I'm part of a map-making community for a game, and I am attempting to create metadata from maps that defines the structure of the map. One of the things that I need to be able to do is to define the graph structure of the map - i.e. connections between territory nodes. Diagram connectors seem to be a logical object to handle the connections, since they will move if the territory node is moved.
I want to give the user the ability to define the connection between two nodes using the extension. Ordinarily I could just let the user use the diagram connector tool in Inkscape themselves, but it is very common to have overlapping paths and objects which makes setting the connector endpoints properly a bit fiddly, so I think it would be easier for them if they could just select the two territories and have my extension automatically create the connector for them.
As a note, in the sample XML I gave above is the
d
attributes were not identical, but I have since tested this with identical values for that attribute with the same lack of success.ETA: I neglected to mention I'm using Inkscape 1.1
The "d" attribute is part of the svg spec for a path.
If you make a simple connection between two rectangles.
Then save and open the .svg in a text editor that detects changes such as Notepad++ or Geany.
Close Inkscape. Then remove the path data so d="M 200 100 30 40" becomes d=""
Save the file and reopen in Inkscape - you will find it makes no difference to what you see. That is because Inkscape uses
inkscape:connection-start="#path03" inkscape:connection-end="#path6389" ( this is part of the Inkscape namespace and not svg spec )
to draw the line, but generates 'd' to make sure it appears in a standard svg when displayed in a non Inkscape program such as a browser.
If you are monitoring the file in your text editor, then save the file again in Inkscape - no changes occur.
However if you move the rectangle then save - the text editor will spot the changes.
Inkscape regenerates the 'd' when the boxes are re positioned.
So how does this help anything ?
Well also group / ungroup does the same thing.
So in theory all you have to do in an extension is specify connector:start and end - then call group and ungroup - and hey presto a connection is made without having to draws the line manually.
Maybe :)
In fact it turns out, that when the extension finishes - all paths are recalculated anyway.
I've posted a video - if you want the code - I can upload a sample to gitlab
Thank you for all your help. As it turns out, my error was something extremely stupid. This was my code to create the connector:
It turns out the only thing wrong here was that I was setting the attribute "inkscape:connector_type" rather than "inkscape:connector-type".
Yes, thats more or less what I used:
import inkex
from lxml import etree
# Could not find simplestyle, found this instead in extensions repo
def format_style(my_style):
"""Format an inline style attribute from a dictionary"""
return ";".join([att + ":" + str(val) for att, val in my_style.items()])
def make_connection(self, start_object, end_object, connector_type='polyline', connector_curvature=0):
parent = self.svg.get_current_layer()
style = {'stroke': 'black',
'stroke-width': '0.5',
'fill': 'none',
'stroke-dasharray': '1,1'
}
attribs = {
'style': format_style(style),
'd': ''
}
my_connector = etree.SubElement(parent, inkex.addNS('path', 'svg'), attribs)
my_connector.set('inkscape:connector-type', connector_type)
my_connector.set('inkscape:connector-curvature', str(connector_curvature))
my_connector.set('inkscape:connection-start', f'#{start_object.get_id()}')
my_connector.set('inkscape:connection-end', f'#{end_object.get_id()}')
return my_connector
class MyFirstExtension(inkex.EffectExtension):
def effect(self):
selection_list = self.svg.selected
if len(selection_list) < 2:
return
target_block_index = 1
for current_block_index in range(0, len(selection_list)-1):
make_connection(self, selection_list[current_block_index], selection_list[target_block_index])
target_block_index += 1
if __name__ == '__main__':
MyFirstExtension().run()