Macaw icon indicating copy to clipboard operation
Macaw copied to clipboard

Redraw Chart

Open PunkStarStudios opened this issue 5 years ago • 6 comments

Hi. I saw someone has asked about this but the answer wasn't clear. I've subclassed Macaw and drawing the initial chart is fine. But from a view controller I can reset the data within the subclassed Macaw, but somehow I have to tell it to go ahead and recreate the chart from scratch. Update the nodes etc. But I can't find how to do that.

Someone said to go change a node and that will force a redraw, but all the nodes are created within the subclass (using the tutorial at https://www.youtube.com/watch?v=hMyExC9swz8 ).

I can't figure out how to get it to recreate everything from scratch based on data changed after init

PunkStarStudios avatar Dec 02 '19 22:12 PunkStarStudios

Hi David,

Can you attach a sample? I didn't understand why you can't just adjust the properties / nodes you need.

ystrot avatar Dec 04 '19 12:12 ystrot

Hi, I have a similar issue, maybe my code snippet will help. I can't seem to find a way to change the node once I have initialised it since its static. `import UIKit import Macaw

class MacawChartView: MacawView {

 static var dataSet : [GraphData] = [] {
    didSet {
        adjustData()
    }
}
static let maxValue = 100 // max value of the data in the graph
static let maxValueLineHeight = 300 // based on the view
static let lineWidth : Double = 500 // based on the view

static let dataDivisor = Double(maxValue)/Double(maxValueLineHeight)
static var adjustedData: [Double] = []
static var animations : [Animation] = []


required init?(coder aDecoder: NSCoder) {
    super.init(node: MacawChartView.createChart(), coder: aDecoder)
    backgroundColor = .clear
}

private static func adjustData(){
    adjustedData = dataSet.map({ $0.Score / dataDivisor })
}

private func reinit(){
    super.node = MacawChartView.createChart()
}


private static func createChart() -> Group {
    var items = addYaxisItems() + addXaxisItems()
    items.append(createBars())
    return Group(contents: items, place: .identity)
}

private static func addYaxisItems() -> [Node] {
    let maxlines = 10
    let lineInterval = Int(maxValue/maxlines)
    let YaxisHeight : Double = 300
    let lineSpacing : Double = 30
    
    var newNodes : [Node] = []
    
    for i in 1...maxlines{
        let y = YaxisHeight - (Double(i) * lineSpacing)
        
        let valueLine = Line(x1: -5, y1: y, x2: lineWidth, y2: y).stroke(fill: Color.black.with(a: 0.10))
        let valueText = Text(text: "\(i * lineInterval)", align: .max, baseline: .mid, place: .move(dx: -10, dy: y))
        valueText.fill = Color.black
        
        newNodes.append(valueLine)
        newNodes.append(valueText)
    }
    
    let yAxis = Line(x1: 0, y1: 0, x2: 0, y2: YaxisHeight).stroke(fill: Color.black.with(a: 0.25))
    newNodes.append(yAxis)
    
    return newNodes
}

private static func addXaxisItems() -> [Node] {
    let chartBaseY : Double = 300
    var newNodes : [Node] = []
    
    if(adjustedData.count > 0){
        for i in 1...adjustedData.count {
            let x = (Double(i) * 50 )
            let valueText = Text(text: dataSet[i - 1].Concept, align: .max, baseline: .mid,place: .move(dx: x, dy: chartBaseY + 15))
            
            valueText.fill = Color.black
            newNodes.append(valueText)
        }
    }
    
    let xAxis = Line(x1: 0, y1: chartBaseY, x2: lineWidth, y2: chartBaseY).stroke(fill: Color.black.with(a: 0.25))
    newNodes.append(xAxis)
    return newNodes
}

private static func createBars() -> Group {
    let fill =  LinearGradient(degree: 90, from: Color.init(val: 0xff4704), to: Color(val: 0xff4704).with(a: 0.33))
    let items = adjustedData.map { _ in Group() }
    
    animations = items.enumerated().map {(i : Int, item : Group ) in
        item.contentsVar.animation(delay: Double(i) * 0.1) {t in
            let height = adjustedData[i] * t
            let rect = Rect(x: Double(i) * 50 + 25, y: 300 - height , w: 30, h: height)
            return [rect.fill(with: fill)]
        }
    }
    return items.group()
}

static func playAnimations(){
    animations.combine().play()
}

private static func data() -> [GraphData] {

    return []
}

}`

zyrondias avatar Jan 29 '20 12:01 zyrondias

Even I wanted to reinitialize the UI corresponding to the App theme being switched. I don't know which method or approach to redraw the Macaw View.

I tried to invoke createMacawView in my ViewController's "ViewDidAppear" method but no avail.

SensehacK avatar May 13 '20 03:05 SensehacK

The problem also is that Macaw doesn't support theme changes by default - you can help us and send us a PR with this functionality. Actually I have some experience with Texture (Texture has own rendering system based on UIKit as Macaw) and theme changes in iOS 13, actually, I can check the possibility to refactor some Macaw classes.

amarunko avatar May 13 '20 07:05 amarunko

I followed the same tutorial @PunkStarStudios and @zyrondias, did either of you figure out how to update the bar chart with new data once it was already created? Thank you!

svgupta97 avatar Jun 04 '20 14:06 svgupta97

https://stackoverflow.com/questions/63216461/value-changed-but-the-chart-doesnt-swift

SamMatinyan avatar Aug 04 '20 10:08 SamMatinyan