示例#1
0
    def draw(self, node):
        """
        Draw a curved connection between a node and its child nodes.
        """

        E = self._eval_func(node)

        if node.isleaf():
            return

        _ctx.autoclosepath(True)
        _ctx.stroke(node.connectioncolor)
        _ctx.fill(node.connectioncolor)

        children = node.children

        for child in children:
            linewidth = E('nodeLineWidthEnd')

            _ctx.strokewidth(linewidth)

            direction = child.direction()
            opp_direction = opposite_dir(direction)

            x1, y1 = node.connection_point(direction)
            x2, y2 = child.connection_point(opp_direction)

            if direction == Direction.Left:
                x2 -= linewidth / 2
            elif direction == Direction.Right:
                x2 += linewidth / 2

            if len(children) == 1:
                _ctx.line(x1, y1, x2, y2)
            else:
                cx1 = (x2 - x1) * E('nodeCx1Factor')
                cx2 = (x2 - x1) * E('nodeCx2Factor')

                cy1 = (y2 - y1) * E('nodeCy1Factor')
                cy2 = (y2 - y1) * E('nodeCy2Factor')

                p1x = x1 + cx1
                p1y = y1 + cy1
                p2x = x2 - cx2
                p2y = y2 - cy2

                startwidth = E('nodeLineWidthStart') - 1
                sw = startwidth / 2.

                _ctx.beginpath(x1, y1 - sw)
                _ctx.curveto(p1x, p1y, p2x, p2y, x2, y2)
                _ctx.curveto(p2x, p2y, p1x, p1y, x1, y1 + sw)
                _ctx.endpath()
示例#2
0
    def draw(self, node):
        """
        Draw a curved connection between a node and its child nodes.
        """

        E = self._eval_func(node)

        if node.isleaf():
            return

        _ctx.autoclosepath(True)
        _ctx.stroke(node.connectioncolor)
        _ctx.fill(node.connectioncolor)

        children = node.children

        for child in children:
            linewidth = E('nodeLineWidthEnd')

            _ctx.strokewidth(linewidth)

            direction = child.direction()
            opp_direction = opposite_dir(direction)

            x1, y1 = node.connection_point(direction)
            x2, y2 = child.connection_point(opp_direction)

            if direction == Direction.Left:
                x2 -= linewidth / 2
            elif direction == Direction.Right:
                x2 += linewidth / 2

            if len(children) == 1:
                _ctx.line(x1, y1, x2, y2)
            else:
                cx1 = (x2 - x1) * E('nodeCx1Factor')
                cx2 = (x2 - x1) * E('nodeCx2Factor')

                cy1 = (y2 - y1) * E('nodeCy1Factor')
                cy2 = (y2 - y1) * E('nodeCy2Factor')

                p1x = x1 + cx1
                p1y = y1 + cy1
                p2x = x2 - cx2
                p2y = y2 - cy2

                startwidth = E('nodeLineWidthStart') - 1
                sw = startwidth / 2.

                _ctx.beginpath(x1, y1 - sw)
                _ctx.curveto(p1x, p1y, p2x, p2y, x2, y2)
                _ctx.curveto(p2x, p2y, p1x, p1y, x1, y1 + sw)
                _ctx.endpath()
示例#3
0
文件: layout.py 项目: johnnovak/twyg
    def childrenheight(self, node, direction):
        # direction is None for leaf nodes
        if direction == None:
            return 0

        children = self._getchildren(node, direction)
        if not children or node.isleaf():
            return 0

        firstchild = children[0]
        lastchild = children[-1]

        child_dir = opposite_dir(direction)
        child_conn_ytop = firstchild.connection_point(child_dir)[1]
        child_conn_ybottom = lastchild.connection_point(child_dir)[1]

        return child_conn_ybottom - child_conn_ytop
示例#4
0
文件: layout.py 项目: johnnovak/twyg
    def childrenheight(self, node, direction):
        # direction is None for leaf nodes
        if direction == None:
            return 0

        children = self._getchildren(node, direction)
        if not children or node.isleaf():
            return 0

        firstchild = children[0]
        lastchild = children[-1]

        child_dir = opposite_dir(direction)
        child_conn_ytop = firstchild.connection_point(child_dir)[1]
        child_conn_ybottom = lastchild.connection_point(child_dir)[1]

        return child_conn_ybottom - child_conn_ytop
示例#5
0
文件: layout.py 项目: johnnovak/twyg
    def _calc_y(self, node, direction):
        E = self._eval_func(node)

        # Initialise branch bounding box
        node._branch_bboxtop = node.y
        node._branch_bboxbottom = node.y + node.bboxheight

        node_pady = E('nodePadY')

        if node.isleaf():
            # Set the position of a leaf node node a calculate the y
            # position for the next leaf. Because of the way we traverse
            # the tree, all leaf nodes are positioned consecutively on
            # the y axis, separated by the node and branch paddings.
            node.y = self._leaf_y
            self._leaf_y += node.bboxheight + node_pady
            self._branch_pad = False
        else:
            # Depth-first traversal: we are going to calculate the
            # layout starting from the leaf nodes, progressing upwards
            # in the tree, and from top to bottom (from lower to higher
            # y coordinates) in terms of vertical positioning
            children = self._getchildren(node, direction)
            if not children:
                return

            branch_pad_y = E('branchPadY')

            if not self._branch_pad:
                self._leaf_y += branch_pad_y - node_pady
                self._branch_pad = True

            for child in children:
                self._calc_y(child, direction)

            if not self._branch_pad:
                self._leaf_y += branch_pad_y - node_pady
                self._branch_pad = True

            # At this point the whole subtree under 'node' has been
            # positioned correctly. The only remainig thing is to
            # calculate the y position of 'node' (the parent).
            node_dir = direction
            child_dir = opposite_dir(node_dir)

            # Calculate the y coord of the connection point for the
            # children
            firstchild = children[0]
            lastchild = children[-1]

            child_conn_ytop = firstchild.connection_point(child_dir)[1]
            child_conn_ybottom = lastchild.connection_point(child_dir)[1]

            # The actual connection point will be in between 
            child_conn_y = (child_conn_ytop
                           + (child_conn_ybottom - child_conn_ytop)
                           * E('verticalAlignFactor'))

            # Snap parent connection position to children connection
            # positions vertically
            if E('snapParentToChildren'):
                children_conn_y = [c.connection_point(child_dir)[1]
                                   for c in children]

                # Enable snapping to half-positions 50% inbetween two
                # child connections
                if E('snapToHalfPositions'):
                    l = []
                    for i in range(len(children_conn_y) - 1):
                        y1 = children_conn_y[i]
                        y2 = children_conn_y[i + 1]
                        l.append(y1)
                        l.append((y1 + y2) / 2.)

                    l.append(children_conn_y[-1])
                    children_conn_y = l

                # Get closest connection point index
                d = [abs(child_conn_y - y) for y in children_conn_y]
                closest = d.index(min(d))

                child_conn_y = children_conn_y[closest]

            # Calculate the y offset of the parent node in relation to
            # it's connection point
            node_conn_y = node.connection_point(node_dir)[1]
            node_yoffs = node_conn_y - node.y

            # Calculate the top and bottom y coords of the parent
            node_ytop = child_conn_y - node_yoffs
            node_ybottom = child_conn_y + (node.bboxheight - node_yoffs)

            # Set the position of the parent node
            node.y = node_ytop

            # Calculate the top and bottom y coords of the children
            children_ytop = firstchild.y
            children_ybottom = lastchild.y + lastchild.bboxheight

            # If the parent extends above the topmost child node, shift
            # the whole branch downwards by the same amount 
            dy_top = children_ytop - node_ytop

            if dy_top > 0:
                if node.isroot():
                    node.y += dy_top
                    for n in self._getchildren(node, direction):
                        n.shiftbranch(0, dy_top)
                else:
                    node.shiftbranch(0, dy_top)
            else:
                dy_top = 0

            # If the parent extends below the bottommost child node,
            # offset the y start the next leaf node by the same amount
            if node_ybottom > children_ybottom:
                y = node_ybottom + branch_pad_y
                if y > self._leaf_y:
                    self._leaf_y = y

            # Adjust y coordinates if the branch has been shifted
            # downwards
            self._leaf_y += dy_top

            node_ytop += dy_top
            node_ybottom += dy_top
            children_bboxtop = firstchild._branch_bboxtop + dy_top
            children_bboxbottom = lastchild._branch_bboxbottom + dy_top

            # Calculate the bounding box of the branch
            node._branch_bboxtop = min(children_bboxtop, node_ytop)
            node._branch_bboxbottom = max(children_bboxbottom, node_ybottom)
示例#6
0
    def _draw(self, node, direction=None):
        """
        Draw a curved connection between a node and its child nodes.
        """

        E = self._eval_func(node)

        children = node.getchildren(direction)
        if not children:
            return

        linewidth = E('lineWidth')

        _ctx.autoclosepath(True)
        _ctx.stroke(node.connectioncolor)
        _ctx.fill(node.connectioncolor)
        _ctx.strokewidth(linewidth)

        firstchild = children[0]
        lastchild = children[-1]

        direction = firstchild.direction()
        opp_direction = opposite_dir(direction)
        x1, y1 = node.connection_point(direction)
        xfirst, yfirst = firstchild.connection_point(opp_direction)

        # Special case: draw straight line if there's only one child
        if len(children) == 1:
            _ctx.line(x1, y1, xfirst, yfirst)
            return

        # Calculate junction point position
        jx = x1 + (xfirst - x1) * E('junctionXFactor')
        jy = y1

        # Draw line from parent node to junction point
        _ctx.line(x1, y1, jx, jy)

        # Limit first & last corner radius to the available area
        ylast = lastchild.connection_point(opp_direction)[1]
        ysecond = children[1].connection_point(opp_direction)[1]
        ypenultimate = children[-2].connection_point(opp_direction)[1]

        # Starting corner radius
        cornerPad = E('cornerPad')
        r = min(E('cornerRadius'), abs(jx - xfirst) - cornerPad)
        r = max(r, 0)

        # Adjusted first (top) corner radius
        r1 = min(r, abs(yfirst - jy) - cornerPad)
        r1 = max(r1, 0)
        if ysecond < jy:
            r1 = min(r, abs(yfirst - ysecond) - cornerPad)
            r1 = max(r1, 0)

        # Adjusted last (bottom) corner radius
        r2 = min(r, abs(ylast - jy) - cornerPad)
        r2 = max(r2, 0)
        if ypenultimate > jy:
            r2 = min(r, abs(ylast - ypenultimate) - cornerPad)
            r2 = max(r2, 0)

        # Draw main branch as a single path to ensure line continuity
        p1 = Vector2(jx, yfirst + r1)
        p2 = Vector2(jx, ylast - r2)
        segments = [[p1, p2]]

        corner_style = E('cornerStyle')

        for i, child in enumerate(children):
            direction = child.direction()
            opp_direction = opposite_dir(direction)

            x2, y2 = child.connection_point(opp_direction)
            if direction == Direction.Left:
                x2 -= linewidth / 2
            elif direction == Direction.Right:
                x2 += linewidth / 2

            # Draw corners
            if direction == Direction.Left:
                a1 = 90
                da = -90
                dx1 = r1 * 2
                dx2 = r2 * 2
            else:
                a1 = da = 90
                dx1 = dx2 = 0

            x1 = jx
            if child is firstchild:
                x1 += -r1 if direction == Direction.Left else r1

                if (corner_style == 'square' or abs(y2 - jy) < .001):
                    p1 = Vector2(jx, y2)
                    p2 = Vector2(jx, y2 + r1)
                    segments.insert(0, [p1, p2])

                    p1 = Vector2(x1, y2)
                    p2 = Vector2(jx, y2)
                    segments.insert(0, [p1, p2])

                elif corner_style == 'beveled':
                    p1 = Vector2(x1, y2)
                    p2 = Vector2(jx, y2 + r1)
                    segments.insert(0, [p1, p2])

                elif corner_style == 'rounded':
                    arc = arcpath(jx - dx1, y2, r1 * 2, r1 * 2, a1, da)
                    segments = arc + segments

                p1 = Vector2(x2, y2)
                p2 = Vector2(x1, y2)
                segments.insert(0, [p1, p2])

            elif child is lastchild:
                x1 += -r2 if direction == Direction.Left else r2

                if (corner_style == 'square' or abs(y2 - jy) < .001):
                    p1 = Vector2(jx, y2 - r2)
                    p2 = Vector2(jx, y2)
                    segments.append([p1, p2])

                    p1 = Vector2(jx, y2)
                    p2 = Vector2(x1, y2)
                    segments.append([p1, p2])

                elif corner_style == 'beveled':
                    p1 = Vector2(jx, y2 - r2)
                    p2 = Vector2(x1, y2)
                    segments.append([p1, p2])

                elif corner_style == 'rounded':
                    arc = arcpath(jx - dx2, y2 - r2 * 2, r2 * 2, r2 * 2,
                                  a1 + da, da)
                    segments = segments + arc

                p1 = Vector2(x1, y2)
                p2 = Vector2(x2, y2)
                segments.append([p1, p2])

            else:
                _ctx.line(x1, y2, x2, y2)

        # Draw main branch path
        _ctx.nofill()

        path = createpath(_ctx, segments, close=False)
        _ctx.drawpath(path)

        # Draw junction point
        style = E('junctionStyle')
        if style == 'none':
            return

        r = E('junctionRadius')
        r2 = r / 2.

        _ctx.fill(E('junctionFillColor'))
        _ctx.stroke(E('junctionStrokeColor'))
        _ctx.strokewidth(E('junctionStrokeWidth'))

        if style == 'square':
            _ctx.rect(jx - r2, jy - r2, r, r)

        elif style == 'disc':
            _ctx.oval(jx - r2, jy - r2, r, r)

        elif style == 'diamond':
            _ctx.beginpath(jx, jy - r2)
            _ctx.lineto(jx + r2, jy)
            _ctx.lineto(jx, jy + r2)
            _ctx.lineto(jx - r2, jy)
            _ctx.lineto(jx, jy - r2)
            _ctx.endpath()

        # Draw junction sign
        sign = E('junctionSign')
        if sign == 'none':
            return

        _ctx.stroke(E('junctionSignColor'))

        d = E('junctionSignSize') / 2.
        _ctx.strokewidth(E('junctionSignStrokeWidth'))

        if sign in ('minus', 'plus'):
            _ctx.line(jx - d, jy, jx + d, jy)

        if sign == 'plus':
            _ctx.line(jx, jy - d, jx, jy + d)
示例#7
0
文件: layout.py 项目: johnnovak/twyg
    def _calc_y(self, node, direction):
        E = self._eval_func(node)

        # Initialise branch bounding box
        node._branch_bboxtop = node.y
        node._branch_bboxbottom = node.y + node.bboxheight

        node_pady = E('nodePadY')

        if node.isleaf():
            # Set the position of a leaf node node a calculate the y
            # position for the next leaf. Because of the way we traverse
            # the tree, all leaf nodes are positioned consecutively on
            # the y axis, separated by the node and branch paddings.
            node.y = self._leaf_y
            self._leaf_y += node.bboxheight + node_pady
            self._branch_pad = False
        else:
            # Depth-first traversal: we are going to calculate the
            # layout starting from the leaf nodes, progressing upwards
            # in the tree, and from top to bottom (from lower to higher
            # y coordinates) in terms of vertical positioning
            children = self._getchildren(node, direction)
            if not children:
                return

            branch_pad_y = E('branchPadY')

            if not self._branch_pad:
                self._leaf_y += branch_pad_y - node_pady
                self._branch_pad = True

            for child in children:
                self._calc_y(child, direction)

            if not self._branch_pad:
                self._leaf_y += branch_pad_y - node_pady
                self._branch_pad = True

            # At this point the whole subtree under 'node' has been
            # positioned correctly. The only remainig thing is to
            # calculate the y position of 'node' (the parent).
            node_dir = direction
            child_dir = opposite_dir(node_dir)

            # Calculate the y coord of the connection point for the
            # children
            firstchild = children[0]
            lastchild = children[-1]

            child_conn_ytop = firstchild.connection_point(child_dir)[1]
            child_conn_ybottom = lastchild.connection_point(child_dir)[1]

            # The actual connection point will be in between
            child_conn_y = (child_conn_ytop +
                            (child_conn_ybottom - child_conn_ytop) *
                            E('verticalAlignFactor'))

            # Snap parent connection position to children connection
            # positions vertically
            if E('snapParentToChildren'):
                children_conn_y = [
                    c.connection_point(child_dir)[1] for c in children
                ]

                # Enable snapping to half-positions 50% inbetween two
                # child connections
                if E('snapToHalfPositions'):
                    l = []
                    for i in range(len(children_conn_y) - 1):
                        y1 = children_conn_y[i]
                        y2 = children_conn_y[i + 1]
                        l.append(y1)
                        l.append((y1 + y2) / 2.)

                    l.append(children_conn_y[-1])
                    children_conn_y = l

                # Get closest connection point index
                d = [abs(child_conn_y - y) for y in children_conn_y]
                closest = d.index(min(d))

                child_conn_y = children_conn_y[closest]

            # Calculate the y offset of the parent node in relation to
            # it's connection point
            node_conn_y = node.connection_point(node_dir)[1]
            node_yoffs = node_conn_y - node.y

            # Calculate the top and bottom y coords of the parent
            node_ytop = child_conn_y - node_yoffs
            node_ybottom = child_conn_y + (node.bboxheight - node_yoffs)

            # Set the position of the parent node
            node.y = node_ytop

            # Calculate the top and bottom y coords of the children
            children_ytop = firstchild.y
            children_ybottom = lastchild.y + lastchild.bboxheight

            # If the parent extends above the topmost child node, shift
            # the whole branch downwards by the same amount
            dy_top = children_ytop - node_ytop

            if dy_top > 0:
                if node.isroot():
                    node.y += dy_top
                    for n in self._getchildren(node, direction):
                        n.shiftbranch(0, dy_top)
                else:
                    node.shiftbranch(0, dy_top)
            else:
                dy_top = 0

            # If the parent extends below the bottommost child node,
            # offset the y start the next leaf node by the same amount
            if node_ybottom > children_ybottom:
                y = node_ybottom + branch_pad_y
                if y > self._leaf_y:
                    self._leaf_y = y

            # Adjust y coordinates if the branch has been shifted
            # downwards
            self._leaf_y += dy_top

            node_ytop += dy_top
            node_ybottom += dy_top
            children_bboxtop = firstchild._branch_bboxtop + dy_top
            children_bboxbottom = lastchild._branch_bboxbottom + dy_top

            # Calculate the bounding box of the branch
            node._branch_bboxtop = min(children_bboxtop, node_ytop)
            node._branch_bboxbottom = max(children_bboxbottom, node_ybottom)
示例#8
0
    def _draw(self, node, direction=None):
        """
        Draw a curved connection between a node and its child nodes.
        """

        E = self._eval_func(node)

        children = node.getchildren(direction)
        if not children:
            return

        linewidth = E('lineWidth')

        _ctx.autoclosepath(True)
        _ctx.stroke(node.connectioncolor)
        _ctx.fill(node.connectioncolor)
        _ctx.strokewidth(linewidth)

        firstchild = children[0]
        lastchild = children[-1]

        direction = firstchild.direction()
        opp_direction = opposite_dir(direction)
        x1, y1 = node.connection_point(direction)
        xfirst, yfirst = firstchild.connection_point(opp_direction)

        # Special case: draw straight line if there's only one child
        if len(children) == 1:
            _ctx.line(x1, y1, xfirst, yfirst)
            return

        # Calculate junction point position
        jx = x1 + (xfirst - x1) * E('junctionXFactor')
        jy = y1

        # Draw line from parent node to junction point
        _ctx.line(x1, y1, jx, jy)

        # Limit first & last corner radius to the available area
        ylast = lastchild.connection_point(opp_direction)[1]
        ysecond = children[1].connection_point(opp_direction)[1]
        ypenultimate = children[-2].connection_point(opp_direction)[1]

        # Starting corner radius
        cornerPad = E('cornerPad')
        r = min(E('cornerRadius'), abs(jx - xfirst) - cornerPad)
        r = max(r, 0)

        # Adjusted first (top) corner radius
        r1 = min(r, abs(yfirst - jy) - cornerPad)
        r1 = max(r1, 0)
        if ysecond < jy:
            r1 = min(r, abs(yfirst - ysecond) - cornerPad)
            r1 = max(r1, 0)

        # Adjusted last (bottom) corner radius
        r2 = min(r, abs(ylast - jy) - cornerPad)
        r2 = max(r2, 0)
        if ypenultimate > jy:
            r2 = min(r, abs(ylast - ypenultimate) - cornerPad)
            r2 = max(r2, 0)

        # Draw main branch as a single path to ensure line continuity
        p1 = Vector2(jx, yfirst + r1)
        p2 = Vector2(jx, ylast - r2)
        segments = [[p1, p2]]

        corner_style = E('cornerStyle')

        for i, child in enumerate(children):
            direction = child.direction()
            opp_direction = opposite_dir(direction)

            x2, y2 = child.connection_point(opp_direction)
            if direction == Direction.Left:
                x2 -= linewidth / 2
            elif direction == Direction.Right:
                x2 += linewidth / 2

            # Draw corners
            if direction == Direction.Left:
                a1 = 90
                da = -90
                dx1 = r1 * 2
                dx2 = r2 * 2
            else:
                a1 = da = 90
                dx1 = dx2 = 0

            x1 = jx
            if child is firstchild:
                x1 += -r1 if direction == Direction.Left else r1

                if (corner_style == 'square' or abs(y2 - jy) < .001):
                    p1 = Vector2(jx, y2)
                    p2 = Vector2(jx, y2 + r1)
                    segments.insert(0, [p1, p2])

                    p1 = Vector2(x1, y2)
                    p2 = Vector2(jx, y2)
                    segments.insert(0, [p1, p2])

                elif corner_style == 'beveled':
                    p1 = Vector2(x1, y2)
                    p2 = Vector2(jx, y2 + r1)
                    segments.insert(0, [p1, p2])

                elif corner_style == 'rounded':
                    arc = arcpath(jx - dx1, y2, r1 * 2, r1 * 2, a1, da)
                    segments = arc + segments

                p1 = Vector2(x2, y2)
                p2 = Vector2(x1, y2)
                segments.insert(0, [p1, p2])

            elif child is lastchild:
                x1 += -r2 if direction == Direction.Left else r2

                if (corner_style == 'square' or abs(y2 - jy) < .001):
                    p1 = Vector2(jx, y2 - r2)
                    p2 = Vector2(jx, y2)
                    segments.append([p1, p2])

                    p1 = Vector2(jx, y2)
                    p2 = Vector2(x1, y2)
                    segments.append([p1, p2])

                elif corner_style == 'beveled':
                    p1 = Vector2(jx, y2 - r2)
                    p2 = Vector2(x1, y2)
                    segments.append([p1, p2])

                elif corner_style == 'rounded':
                    arc = arcpath(jx - dx2, y2 - r2 * 2, r2 * 2, r2 * 2,
                                  a1 + da, da)
                    segments = segments + arc

                p1 = Vector2(x1, y2)
                p2 = Vector2(x2, y2)
                segments.append([p1, p2])

            else:
                _ctx.line(x1, y2, x2, y2)

        # Draw main branch path
        _ctx.nofill()

        path = createpath(_ctx, segments, close=False)
        _ctx.drawpath(path)

        # Draw junction point
        style = E('junctionStyle')
        if style == 'none':
            return

        r = E('junctionRadius')
        r2 = r / 2.

        _ctx.fill(E('junctionFillColor'))
        _ctx.stroke(E('junctionStrokeColor'))
        _ctx.strokewidth(E('junctionStrokeWidth'))

        if style == 'square':
            _ctx.rect(jx - r2, jy - r2, r, r)

        elif style == 'disc':
            _ctx.oval(jx - r2, jy - r2, r, r)

        elif style == 'diamond':
            _ctx.beginpath(jx, jy - r2)
            _ctx.lineto(jx + r2, jy)
            _ctx.lineto(jx, jy + r2)
            _ctx.lineto(jx - r2, jy)
            _ctx.lineto(jx, jy - r2)
            _ctx.endpath()

        # Draw junction sign
        sign = E('junctionSign')
        if sign == 'none':
            return

        _ctx.stroke(E('junctionSignColor'))

        d = E('junctionSignSize') / 2.
        _ctx.strokewidth(E('junctionSignStrokeWidth'))

        if sign in ('minus', 'plus'):
            _ctx.line(jx - d, jy, jx + d, jy)

        if sign == 'plus':
            _ctx.line(jx, jy - d, jx, jy + d)