2016-08-09 2 views
2

Библиотека, которую я использую: charts
У меня есть линейная диаграмма со значениями в определенные дни в году. Я не хочу рисовать каждый день как метку по оси x (может быть диапазон более 300 дней), поэтому я ищу только для рисования месяцев. Прямо сейчас, мои xVals выглядят так: [nil, nil, nil, «07/2016», nil no nil (..)]. К сожалению, ни одна метка не отображается.
Есть ли другой способ достижения желаемого поведения?

Код (значения по оси Х):
Как визуализировать только выбранные метки осей в диаграммах ios

while date.compare(to) != NSComparisonResult.OrderedDescending { // iterate over all days in range 
     let components = currentCalendar.components([.Day, .Month , .Year], fromDate: date) 
     if components.day != 1 { 
      vals.append(nil) 
     } else { // first day of the month 
      vals.append(String(components.month) + "/" + String(components.year)) 
     } 

     let incrementComponents = NSDateComponents() 
     incrementComponents.day = 1 
     date = currentCalendar.dateByAddingComponents(incrementComponents, toDate: date, options: [])! 
} 

И записи:

for point in base!.points { 
     if let index = chartValuesFormatter?.indexFromDate(point.date) { 
      entries.append(ChartDataEntry(value: point.value, xIndex: index)) 
     } 
} 

Обычно это работает, когда я указываю все значения некоторых из них отображаются и записи отображается правильно. Моя единственная проблема - отображать только метки месяца в начале месячных периодов.

+0

просто положить месяц за все значения, Lib будет выбирать approtiate число значение, чтобы показать – Tj3n

+0

Но иногда он будет показывать тот же месяц более чем один раз. Мне нужно показывать метки месяца 1-го числа каждого месяца (или меньше, если слишком много месяцев - это то, что библиотека должна оптимизировать сама по себе). –

+0

Не могли бы вы вставить код о том, как вы создаете данные. – Jassi

ответ

0

Хорошо, поэтому я нашел решение. Это не так просто, как должно (для такой основной проблемы), но очень настраиваемо. LineChartView (via BarLineChartViewBase) имеет свойство xAxisRenderer. Вы можете подкласса ChartXAxisRenderer, который по умолчанию один, и переопределить функцию drawLabels. В моем случае я скопировал исходный код и модифицировал логику вычисления какого-либо ярлыка и где его следует рисовать.

Редактировать: Мой пользовательский рендерер с логикой перекрытия. Наверное, слишком сложный, но он работает до сих пор.

class ChartXAxisDateRenderer: ChartXAxisRenderer { 
internal static let FDEG2RAD = CGFloat(M_PI/180.0) 

/// draws the x-labels on the specified y-position 
override func drawLabels(context context: CGContext, pos: CGFloat, anchor: CGPoint) { 

    guard let xAxis = xAxis else { return } 

    let paraStyle = NSParagraphStyle.defaultParagraphStyle().mutableCopy() as! NSMutableParagraphStyle 
    paraStyle.alignment = .Center 

    let labelAttrs = [NSFontAttributeName: xAxis.labelFont, 
         NSForegroundColorAttributeName: xAxis.labelTextColor, 
         NSParagraphStyleAttributeName: paraStyle] 
    let labelRotationAngleRadians = xAxis.labelRotationAngle * ChartXAxisDateRenderer.FDEG2RAD 

    let valueToPixelMatrix = transformer.valueToPixelMatrix 

    let minLabelsMargin: CGFloat = 4.0 

    var position = CGPoint(x: 0.0, y: 0.0) 

    var labelMaxSize = CGSize() 

    if (xAxis.isWordWrapEnabled) { 
     labelMaxSize.width = xAxis.wordWrapWidthPercent * valueToPixelMatrix.a 
    } 

    var positions = [CGPoint]() 
    var widths = [CGFloat]() 
    var labels = [String]() 
    var originalIndices = [Int]() 

    for i in 0...xAxis.values.count-1 { 
     let label = xAxis.values[i] 
     if (label == nil || label == "") 
     { 
      continue 
     } 

     originalIndices.append(i) 
     labels.append(label!) 

     position.x = CGFloat(i) 
     position.y = 0.0 
     position = CGPointApplyAffineTransform(position, valueToPixelMatrix) 
     positions.append(position) 

     let labelns = label! as NSString 
     let width = labelns.boundingRectWithSize(labelMaxSize, options: .UsesLineFragmentOrigin, attributes: labelAttrs, context: nil).size.width 
     widths.append(width) 
    } 

    let newIndices = findBestPositions(positions, widths: widths, margin: minLabelsMargin) 

    for index in newIndices { 
     let label = labels[index] 
     let position = positions[index] 
     let i = originalIndices[index] 

     if (viewPortHandler.isInBoundsX(position.x)) { 
      drawLabel(context: context, label: label, xIndex: i, x: position.x, y: pos, attributes: labelAttrs, constrainedToSize: labelMaxSize, anchor: anchor, angleRadians: labelRotationAngleRadians) 
     } 
    } 
} 

// Best position indices - minimum "n" without overlapping 
private func findBestPositions(positions: [CGPoint], widths: [CGFloat], margin: CGFloat) -> [Int] { 
    var n = 1 
    var overlap = true 

    // finding "n" 
    while n < widths.count && overlap { 
     overlap = doesOverlap(n, positions: positions, widths: widths, margin: margin) 
     if overlap { 
      n += 1 
     } 
    } 

    var newPositions = [Int]() 
    var i = 0 
    // create result indices 
    while i < positions.count { 
     newPositions.append(i) 
     i += n 
    } 

    return newPositions 
} 

// returns whether drawing only n-th labels will casue overlapping 
private func doesOverlap(n: Int, positions: [CGPoint], widths: [CGFloat], margin: CGFloat) -> Bool { 
    var i = 0 
    var newPositions = [CGPoint]() 
    var newWidths = [CGFloat]() 

    // getting only n-th records 
    while i < positions.count { 
     newPositions.append(positions[i]) 
     newWidths.append(widths[i]) 
     i += n 
    } 

    // overlap with next label checking 
    for j in 0...newPositions.count - 2 { 
     if newPositions[j].x + newWidths[j] + margin > newPositions[j+1].x { 
      return true 
     } 
    } 

    return false 
} 

}

+0

извините за неудобства, но у меня такая же проблема, можете ли вы разместить свой код? Благодаря! – user3745888

+0

@ пользователь3745888 отправлен. Большинство кодов - это перекрытие, но отдых должен быть совершенно ясным. Я предполагаю, что он ошибочен и слишком сложный (он еще не проверен). Не стесняйтесь оставлять комментарий. –