Line/Connector Shape

Lines are a sub-category of auto shape that differ in certain properties and behaviors. In particular, they have a start point and end point in addition to extents (left, top, width, height).

Connectors are based on the <p:cxnSp> element and have one of a handful of different preset geometry values, such as line. Freeform connectors, despite the name, are not connectors, and are a custom geometry shape based on the p:sp element.

Connectors can be “connected” to an auto shape such that a connected end point remains connected when the auto shape is moved. This relies on a concept of “connection points” on the auto shape. These connections points are preset features of the auto shape, similar to how adjustment points are pre-defined. Connection points are identified by index.

Connector shapes do not have a text frame and cannot have text that is anchored to the shape.

Design Issues

  • See how PowerPoint interprets the remaining connector types like bentConnector2

Unimplemented Scope

  • Connector.shape_type = MSO_LINE
  • BaseShape.is_connector + ConnectorShape.is_connector (not yet implemented)
  • [ ] see how a connector returns for connector.AutoShapeType in MS API.

PowerPoint behaviors

  • Once connected, moving the target shape moves the connector the same amount, however, the relative position of the connector end-point is not adjusted to align to the connection point; rather, the relative offset is maintained.

    Also, when the connector is selected, the connected point is highlighted in red, even though it is not coincident with the connection point.

  • Arrow heads are not a direct property of a connector, despite perhaps appearing so in the UI. Line endings are a property of the line style of the connector (and other shapes).

MS API

Shapes Object Members

  • AddConnector(Type, BeginX, BeginY, EndX, EndY)

MsoConnectorType Enumeration

msoConnectorCurve 3 Curved connector.
msoConnectorElbow 2 Elbow connector.
msoConnectorStraight 1 Straight line connector.
msoConnectorTypeMixed -2 Return only; indicates combination of states.

Protocols

Properties:

>>> connector.is_connector
True
>>> connector.type
MSO_SHAPE_TYPE.LINE
>>> connector.start_x
914400
>>> connector.end_y
914400
>>> connector.adjustments
<pptx.shapes.shared.Adjustments instance at 0x123456789>

Creation protocol:

>>> line = shapes.add_connector(
...     MSO_CONNECTOR.STRAIGHT, start_x, start_y, end_x, end_y
... )

MS API Protocol

Behaviors

UI display

Connector shapes do not display a bounding box when selected in the UI. Rather their start and end points are highlighted with a small gray circle that can be moved. If there is an adjustment, such as a mid-point, it is indicated in the normal way with a small yellow diamond. These endpoints and adjustment diamond cannot be individually selected.

Naming

What determines the name automatically applied to a line or connector shape? Can it change after shape creation, for example by applying an arrowhead?

Enumerations

MsoConnectorType

http://msdn.microsoft.com/en-us/library/office/ff860918(v=office.15).aspx

Name Value Description
msoConnectorCurve 3 Curved connector.
msoConnectorElbow 2 Elbow connector.
msoConnectorStraight 1 Straight line connector.
msoConnectorTypeMixed -2 Return value only; indicates a combination of the other states.

Specimen XML

Default connector shapes inserted from PowerPoint UI.

Straight line (Connector):

<p:cxnSp>
  <p:nvCxnSpPr>
    <p:cNvPr id="3" name="Straight Connector 2"/>
    <p:cNvCxnSpPr/>
    <p:nvPr/>
  </p:nvCxnSpPr>
  <p:spPr>
    <a:xfrm>
      <a:off x="611560" y="620688"/>
      <a:ext cx="914400" cy="914400"/>
    </a:xfrm>
    <a:prstGeom prst="line">
      <a:avLst/>
    </a:prstGeom>
  </p:spPr>
  <p:style>
    <a:lnRef idx="2">
      <a:schemeClr val="accent1"/>
    </a:lnRef>
    <a:fillRef idx="0">
      <a:schemeClr val="accent1"/>
    </a:fillRef>
    <a:effectRef idx="1">
      <a:schemeClr val="accent1"/>
    </a:effectRef>
    <a:fontRef idx="minor">
      <a:schemeClr val="tx1"/>
    </a:fontRef>
  </p:style>
</p:cxnSp>

Straight arrow Connector:

<p:cxnSp>
  <p:nvCxnSpPr>
    <p:cNvPr id="7" name="Straight Arrow Connector 6"/>
    <p:cNvCxnSpPr/>
    <p:nvPr/>
  </p:nvCxnSpPr>
  <p:spPr>
    <a:xfrm>
      <a:off x="950964" y="1673307"/>
      <a:ext cx="1257921" cy="0"/>
    </a:xfrm>
    <a:prstGeom prst="straightConnector1">
      <a:avLst/>
    </a:prstGeom>
    <a:ln>
      <a:tailEnd type="arrow"/>
    </a:ln>
  </p:spPr>
  <p:style>
    <a:lnRef idx="2">
      <a:schemeClr val="accent1"/>
    </a:lnRef>
    <a:fillRef idx="0">
      <a:schemeClr val="accent1"/>
    </a:fillRef>
    <a:effectRef idx="1">
      <a:schemeClr val="accent1"/>
    </a:effectRef>
    <a:fontRef idx="minor">
      <a:schemeClr val="tx1"/>
    </a:fontRef>
  </p:style>
</p:cxnSp>

Straight segment jointed connector:

<p:cxnSp>
  <p:nvCxnSpPr>
    <p:cNvPr id="9" name="Elbow Connector 8"/>
    <p:cNvCxnSpPr/>
    <p:nvPr/>
  </p:nvCxnSpPr>
  <p:spPr>
    <a:xfrm>
      <a:off x="950964" y="2124739"/>
      <a:ext cx="1257921" cy="415317"/>
    </a:xfrm>
    <a:prstGeom prst="bentConnector3">
      <a:avLst/>
    </a:prstGeom>
  </p:spPr>
  <p:style>
    <a:lnRef idx="2">
      <a:schemeClr val="accent1"/>
    </a:lnRef>
    <a:fillRef idx="0">
      <a:schemeClr val="accent1"/>
    </a:fillRef>
    <a:effectRef idx="1">
      <a:schemeClr val="accent1"/>
    </a:effectRef>
    <a:fontRef idx="minor">
      <a:schemeClr val="tx1"/>
    </a:fontRef>
  </p:style>
</p:cxnSp>

Curved (S-like) connector:

<p:cxnSp>
  <p:nvCxnSpPr>
    <p:cNvPr id="11" name="Curved Connector 10"/>
    <p:cNvCxnSpPr/>
    <p:nvPr/>
  </p:nvCxnSpPr>
  <p:spPr>
    <a:xfrm>
      <a:off x="950964" y="2925277"/>
      <a:ext cx="1257921" cy="619967"/>
    </a:xfrm>
    <a:prstGeom prst="curvedConnector3">
      <a:avLst/>
    </a:prstGeom>
  </p:spPr>
  <p:style>
    <a:lnRef idx="2">
      <a:schemeClr val="accent1"/>
    </a:lnRef>
    <a:fillRef idx="0">
      <a:schemeClr val="accent1"/>
    </a:fillRef>
    <a:effectRef idx="1">
      <a:schemeClr val="accent1"/>
    </a:effectRef>
    <a:fontRef idx="minor">
      <a:schemeClr val="tx1"/>
    </a:fontRef>
  </p:style>
</p:cxnSp>

Freeform connector:

<p:sp>
  <p:nvSpPr>
    <p:cNvPr id="12" name="Freeform 11"/>
    <p:cNvSpPr/>
    <p:nvPr/>
  </p:nvSpPr>
  <p:spPr>
    <a:xfrm>
      <a:off x="981058" y="4086962"/>
      <a:ext cx="1372277" cy="686176"/>
    </a:xfrm>
    <a:custGeom>
      <a:avLst/>
      <a:gdLst>
        <a:gd name="connsiteX0" fmla="*/ 0 w 1372277"/>
        <a:gd name="connsiteY0" fmla="*/ 0 h 686176"/>
        <a:gd name="connsiteX1" fmla="*/ 379182 w 1372277"/>
        <a:gd name="connsiteY1" fmla="*/ 306973 h 686176"/>
        <a:gd name="connsiteX2" fmla="*/ 944945 w 1372277"/>
        <a:gd name="connsiteY2" fmla="*/ 48152 h 686176"/>
      </a:gdLst>
      <a:ahLst/>
      <a:cxnLst>
        <a:cxn ang="0">
          <a:pos x="connsiteX0" y="connsiteY0"/>
        </a:cxn>
        <a:cxn ang="0">
          <a:pos x="connsiteX1" y="connsiteY1"/>
        </a:cxn>
        <a:cxn ang="0">
          <a:pos x="connsiteX2" y="connsiteY2"/>
        </a:cxn>
      </a:cxnLst>
      <a:rect l="l" t="t" r="r" b="b"/>
      <a:pathLst>
        <a:path w="1372277" h="686176">
          <a:moveTo>
            <a:pt x="0" y="0"/>
          </a:moveTo>
          <a:cubicBezTo>
            <a:pt x="110845" y="149474"/>
            <a:pt x="221691" y="298948"/>
            <a:pt x="379182" y="306973"/>
          </a:cubicBezTo>
          <a:cubicBezTo>
            <a:pt x="536673" y="314998"/>
            <a:pt x="811529" y="4012"/>
            <a:pt x="944945" y="48152"/>
          </a:cubicBezTo>
        </a:path>
      </a:pathLst>
    </a:custGeom>
  </p:spPr>
  <p:style>
    <a:lnRef idx="2">
      <a:schemeClr val="accent1"/>
    </a:lnRef>
    <a:fillRef idx="0">
      <a:schemeClr val="accent1"/>
    </a:fillRef>
    <a:effectRef idx="1">
      <a:schemeClr val="accent1"/>
    </a:effectRef>
    <a:fontRef idx="minor">
      <a:schemeClr val="tx1"/>
    </a:fontRef>
  </p:style>
  <p:txBody>
    <a:bodyPr rtlCol="0" anchor="ctr"/>
    <a:lstStyle/>
    <a:p>
      <a:pPr algn="ctr"/>
      <a:endParaRPr lang="en-US"/>
    </a:p>
  </p:txBody>
</p:sp>

Completely free-form line:

<p:sp>
  <p:nvSpPr>
    <p:cNvPr id="13" name="Freeform 12"/>
    <p:cNvSpPr/>
    <p:nvPr/>
  </p:nvSpPr>
  <p:spPr>
    <a:xfrm>
      <a:off x="1005133" y="5483390"/>
      <a:ext cx="1360239" cy="379203"/>
    </a:xfrm>
    <a:custGeom>
      <a:avLst/>
      <a:gdLst>
        <a:gd name="connsiteX0" fmla="*/ 0 w 1360239"/>
        <a:gd name="connsiteY0" fmla="*/ 0 h 379203"/>
        <a:gd name="connsiteX1" fmla="*/ 0 w 1360239"/>
        <a:gd name="connsiteY1" fmla="*/ 0 h 379203"/>
        <a:gd name="connsiteX2" fmla="*/ 96300 w 1360239"/>
        <a:gd name="connsiteY2" fmla="*/ 6020 h 379203"/>
        <a:gd name="connsiteX3" fmla="*/ 138431 w 1360239"/>
        <a:gd name="connsiteY3" fmla="*/ 18058 h 379203"/>
        <a:gd name="connsiteX4" fmla="*/ 222694 w 1360239"/>
        <a:gd name="connsiteY4" fmla="*/ 24077 h 379203"/>
        <a:gd name="connsiteX5" fmla="*/ 511594 w 1360239"/>
        <a:gd name="connsiteY5" fmla="*/ 24077 h 379203"/>
      </a:gdLst>
      <a:ahLst/>
      <a:cxnLst>
        <a:cxn ang="0">
          <a:pos x="connsiteX0" y="connsiteY0"/>
        </a:cxn>
        <a:cxn ang="0">
          <a:pos x="connsiteX1" y="connsiteY1"/>
        </a:cxn>
        <a:cxn ang="0">
          <a:pos x="connsiteX2" y="connsiteY2"/>
        </a:cxn>
        <a:cxn ang="0">
          <a:pos x="connsiteX3" y="connsiteY3"/>
        </a:cxn>
        <a:cxn ang="0">
          <a:pos x="connsiteX4" y="connsiteY4"/>
        </a:cxn>
        <a:cxn ang="0">
          <a:pos x="connsiteX5" y="connsiteY5"/>
        </a:cxn>
      </a:cxnLst>
      <a:rect l="l" t="t" r="r" b="b"/>
      <a:pathLst>
        <a:path w="1360239" h="379203">
          <a:moveTo>
            <a:pt x="0" y="0"/>
          </a:moveTo>
          <a:lnTo>
            <a:pt x="0" y="0"/>
          </a:lnTo>
          <a:cubicBezTo>
            <a:pt x="32100" y="2007"/>
            <a:pt x="64408" y="1860"/>
            <a:pt x="96300" y="6020"/>
          </a:cubicBezTo>
          <a:cubicBezTo>
            <a:pt x="110783" y="7909"/>
            <a:pt x="123972" y="15992"/>
            <a:pt x="138431" y="18058"/>
          </a:cubicBezTo>
          <a:cubicBezTo>
            <a:pt x="166307" y="22040"/>
            <a:pt x="194606" y="22071"/>
            <a:pt x="222694" y="24077"/>
          </a:cubicBezTo>
          <a:cubicBezTo>
            <a:pt x="333136" y="60893"/>
            <a:pt x="138800" y="-1634"/>
            <a:pt x="511594" y="24077"/>
          </a:cubicBezTo>
          <a:lnTo>
            <a:pt x="1360239" y="343089"/>
          </a:lnTo>
        </a:path>
      </a:pathLst>
    </a:custGeom>
  </p:spPr>
  <p:style>
    <a:lnRef idx="2">
      <a:schemeClr val="accent1"/>
    </a:lnRef>
    <a:fillRef idx="0">
      <a:schemeClr val="accent1"/>
    </a:fillRef>
    <a:effectRef idx="1">
      <a:schemeClr val="accent1"/>
    </a:effectRef>
    <a:fontRef idx="minor">
      <a:schemeClr val="tx1"/>
    </a:fontRef>
  </p:style>
  <p:txBody>
    <a:bodyPr rtlCol="0" anchor="ctr"/>
    <a:lstStyle/>
    <a:p>
      <a:pPr algn="ctr"/>
      <a:endParaRPr lang="en-US"/>
    </a:p>
  </p:txBody>
</p:sp>

Analysis

  • The p:style element represents indirection of the connector visual attributes to the theme part.
  • What’s up with the p:style element? Does that have to be there? What happens if we just leave that out? Is the accent1 default universal enough to pop in there without consideration?
  • Seems like the most common lines are connectors
  • Connectors are a distinct shape type. They are very similar to regular <p:sp>-based auto shapes, but lack a text frame.
  • Hypothesis: There are really two types, connectors and free-form.
    • Connectors are based on the <p:cxnSp> element and have a preset geometry (<a:prstGeom> child of <p:spPr>).
    • Free-form lines are based on the <p:sp> element and have a custom geometry (<a:custGeom> child of <p:spPr>).
  • Connectors don’t have a fill. Free-form shapes do. Fill of free-form shapes extends between the line and a line connecting the end points, whether present or not. Since the lines can cross, this produces some possibly surprising fill behaviors; there is no clear concept of inside and outside for such a shape.