首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Swift多叉树绘制

Swift多叉树绘制

作者头像
玖柒的小窝
发布2021-12-07 13:02:05
发布2021-12-07 13:02:05
43100
代码可运行
举报
文章被收录于专栏:各类技术文章~各类技术文章~
运行总次数:0
代码可运行

主要涉及一个遍历层级,以及遍历计算坐标

上码

结点

代码语言:javascript
代码运行次数:0
运行
复制
class NaryTreeNode {
    var parent: NaryTreeNode?
    var title: String?
    var son: [NaryTreeNode]?
    var level: Int = 0 // 层
    var frame: CGRect?
}
复制代码

树配置

代码语言:javascript
代码运行次数:0
运行
复制
struct NaryTreeConfig {
    var lineSpace: CGFloat = 30
    var interspace: CGFloat = 30
    var nodeSize = CGSize(width: 60, height: 60)
}
复制代码

代码语言:javascript
代码运行次数:0
运行
复制
class NaryTree: UIView {

    var config = NaryTreeConfig() {
        didSet {
            setupNodeFrame(node: root)
        }

    }

    var root: NaryTreeNode? {
        didSet {
            setupNodeFrame(node: root)
        }
    }

    override func draw(_ rect: CGRect) {
        super.draw(rect)
        drawNode()
    }
}

private extension NaryTree {
    func drawNode() {
        guard let root = root else { return }
        var stack = [NaryTreeNode]()
        stack.append(root)
        drawCircle(frame: root.frame)
        while !stack.isEmpty {
            let node = stack.removeLast()
            guard let son = node.son else { return }
            for child in son {
                stack.insert(child, at: 0)
                drawCircle(frame: child.frame)
            }
        }
    }

    func drawCircle(frame: CGRect?) {
        guard let context = UIGraphicsGetCurrentContext(),
              let frame = frame
        else {
            return
        }
        UIColor.red.set()
        let path = UIBezierPath(arcCenter: CGPoint(x: frame.midX, y: frame.midY), radius: config.nodeSize.width / 2, startAngle: 0, endAngle: 360, clockwise: true).cgPath
        context.addPath(path)
        context.fillPath()
    }
}


private extension NaryTree {

    func setupNodes() {
        setupNodeFrame(node: root)
        setNeedsDisplay()
    }

    func setupNodeFrame(node: NaryTreeNode?) {
        var minX: CGFloat = -config.nodeSize.width - config.interspace
        guard let node = node else { return }
        levelOrder(node)
        calculateFrame(node: node, minX: &minX)
    }

    func calculateFrame(node: NaryTreeNode, minX: inout CGFloat) {
        guard let son = node.son,
              son.isEmpty == false
        else {
            minX += config.nodeSize.width + config.interspace
            let y = CGFloat(node.level) * config.lineSpace + CGFloat(node.level) * config.nodeSize.height
            node.frame = CGRect(x: minX, y: y, width: config.nodeSize.width, height: config.nodeSize.height)
            return
        }
        son.enumerated().forEach { _, child in
            calculateFrame(node: child, minX: &minX)
        }
        guard let minx = son.first?.frame?.origin.x,
              let maxX = son.last?.frame?.origin.x else { return }
        let x = (minx + maxX) / 2.0
        let y = CGFloat(node.level) * config.lineSpace + CGFloat(node.level) * config.nodeSize.height
        node.frame = CGRect(x: x, y: y, width: config.nodeSize.width, height: config.nodeSize.height)
    }
    /// 层序遍历
    func levelOrder(_ root: NaryTreeNode?) {
        guard let root = root else { return }
        var stack = [NaryTreeNode]()
        stack.append(root)
        while !stack.isEmpty {
            let node = stack.removeLast()
            guard let son = node.son else { return }
            for child in son {
                stack.insert(child, at: 0)
                child.level = node.level + 1
            }
        }
    }
}

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 结点
  • 树配置
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档