ivnsch / SwiftCharts

Easy to use and highly customizable charts library for iOS
Apache License 2.0
2.53k stars 410 forks source link

First and last point in Bar charts cropped #362

Open Mohamed3amer opened 6 years ago

Mohamed3amer commented 6 years ago

I am trying to draw Horizontal Bar chart, but the first and last point is cropped although am providing padding (left, top, right, bottom) for the chart.

here is my code:

`let labelSettings = ChartLabelSettings(font: UIFont.systemFont(ofSize: 15.0)) let chartPoints: [ChartPoint] = category.data.enumerated().map { index, item in let x = ChartAxisValueInt(item.value, labelSettings: labelSettings) let y = ChartAxisValueString(item.key, order: index, labelSettings: labelSettings) return ChartPoint(x: x, y: y) }

    let minY = Double(category.data.min { $0.value < $1.value}?.value ?? 0)
    let maxY = Double(category.data.max { $0.value < $1.value}?.value ?? 0)

    let labelsGenerator = ChartAxisLabelsGeneratorFunc {scalar in
        return ChartAxisLabel(text: "\(Int(scalar))", settings: labelSettings)
    }

    let yValues = chartPoints.map{ $0.y }
    let xModel = ChartAxisModel(firstModelValue: minY-1, lastModelValue: maxY+2, axisValuesGenerator: ChartAxisGeneratorMultiplier(5), labelsGenerator: labelsGenerator)
    let yModel = ChartAxisModel(axisValues: yValues, axisTitleLabel: ChartAxisLabel(text: "", settings: labelSettings))

    let chartFrame = chartContainerView.bounds
    var chartSettings = ChartSettings()
    chartSettings.top = 10
    chartSettings.leading = 10
    chartSettings.trailing = 20
    chartSettings.bottom = 2

    let coordsSpace = ChartCoordsSpaceLeftBottomSingleAxis(chartSettings: chartSettings, chartFrame: chartFrame, xModel: xModel, yModel: yModel)
    let (xAxisLayer, yAxisLayer, innerFrame) = (coordsSpace.xAxisLayer, coordsSpace.yAxisLayer, coordsSpace.chartInnerFrame)

    let minBarSpacing: CGFloat = 8.0

    let generator = {(chartPointModel: ChartPointLayerModel, layer: ChartPointsLayer, chart: Chart) -> UIView? in
        let bottomLeft = layer.modelLocToScreenLoc(x: 0, y: 0)
        let barWidth = layer.minYScreenSpace - minBarSpacing
        let barViewSettings = ChartBarViewSettings(animDuration: 0.5)
        let (p1, p2): (CGPoint, CGPoint) = (CGPoint(x: bottomLeft.x, y: chartPointModel.screenLoc.y), CGPoint(x: chartPointModel.screenLoc.x, y: chartPointModel.screenLoc.y))
        return ChartPointViewBar(p1: p1, p2: p2, width: barWidth, bgColor: .aiduSkyBlue(), settings: barViewSettings)
    }

    let chartPointsLayer = ChartPointsViewsLayer(xAxis: xAxisLayer.axis, yAxis: yAxisLayer.axis, chartPoints: chartPoints, viewGenerator: generator)

    let labelsLayer = ChartPointsViewsLayer(xAxis: xAxisLayer.axis, yAxis: yAxisLayer.axis, chartPoints: chartPoints, viewGenerator: {(chartPointModel, layer, chart) -> UIView? in
        let label = HandlingLabel()
        let pos = chartPointModel.chartPoint.x.scalar > 0

        label.text = "\(Int(chartPointModel.chartPoint.x.scalar))"
        label.font = UIFont.systemFont(ofSize: 15.0)
        label.sizeToFit()
        label.center = CGPoint(x: chartPointModel.screenLoc.x+10, y: pos ? innerFrame.origin.y : innerFrame.origin.y + innerFrame.size.height)
        label.alpha = 0

        label.movedToSuperViewHandler = {[weak label] in
                label?.alpha = 1
                label?.center.y = chartPointModel.screenLoc.y
        }
        return label

    }, displayDelay: 0.5, mode: .translate)

    let settings = ChartGuideLinesDottedLayerSettings(linesColor: .black, linesWidth: 0.3)
    let guidelinesLayer = ChartGuideLinesDottedLayer(xAxisLayer: xAxisLayer, yAxisLayer: yAxisLayer, settings: settings)

    let dividersSettings =  ChartDividersLayerSettings(linesColor: .black, linesWidth: 0.4, start: 3, end: 0)
    let dividersLayer = ChartDividersLayer(xAxisLayer: xAxisLayer, yAxisLayer: yAxisLayer, settings: dividersSettings)

    let chart = Chart(
        frame: chartFrame,
        innerFrame: innerFrame,
        settings: chartSettings,
        layers: [
            xAxisLayer,
            yAxisLayer,
            labelsLayer,
            guidelinesLayer,
            dividersLayer,
            chartPointsLayer
        ]
    )

    chartContainerView.addSubview(chart.view)
    self.chart = chart`

here is screenshot from result: screenshot

lsnmarcinr commented 6 years ago

Here is small hack for it, you need to add first and last empty label. Then everything will be good ;) Check the code:

    var labels: [ChartAxisValue] = []
    labels.append(ChartAxisValueString(order: -1))

    for (index, monthLabel) in Enum.MonthsShort.allValues.enumerated() {
        let xValueString = ChartAxisValueString(monthLabel.rawValue, order: index, labelSettings: defaultLabelSettings())
        labels.append(xValueString)
    }

    labels.append(ChartAxisValueString(order: labels.count - 1))`