Skip to content

Commit e516b04

Browse files
berbaspinXuan
andauthored
[Feature] added ability to rotate ChartLimitLine label (#5085)
* added labelRotationAngle to ChartLimitLine * added limit line label rotation tests * fixed the code style labelLineRotated_Width/Height got the same position * generated test images for apple TV * add snapshots on x64 arch for tvOS and iOS --------- Co-authored-by: Xuan <[email protected]>
1 parent 52be297 commit e516b04

File tree

30 files changed

+120
-58
lines changed

30 files changed

+120
-58
lines changed

Source/Charts/Components/ChartLimitLine.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ open class ChartLimitLine: ComponentBase
4747
@objc open var drawLabelEnabled = true
4848
@objc open var label = ""
4949
@objc open var labelPosition = LabelPosition.rightTop
50+
@objc open var labelRotationAngle = CGFloat(0.0)
5051

5152
public override init()
5253
{

Source/Charts/Renderers/XAxisRenderer.swift

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -449,40 +449,45 @@ open class XAxisRenderer: NSObject, AxisRenderer
449449
// if drawing the limit-value label is enabled
450450
guard limitLine.drawLabelEnabled, !label.isEmpty else { return }
451451

452-
let labelLineHeight = limitLine.valueFont.lineHeight
452+
let labelLineSize = label.size(withAttributes: [.font: limitLine.valueFont])
453+
let labelLineRotatedSize = labelLineSize.rotatedBy(degrees: limitLine.labelRotationAngle)
454+
let labelLineRotatedWidth = labelLineRotatedSize.width
455+
let labelLineRotatedHeight = labelLineRotatedSize.height
453456

454457
let xOffset: CGFloat = limitLine.lineWidth + limitLine.xOffset
458+
let labelRotationAngleRadians = limitLine.labelRotationAngle.DEG2RAD
455459

456-
let align: TextAlignment
457460
let point: CGPoint
461+
let anchor = CGPoint(x: 0.0, y: 0.0)
458462

459-
switch limitLine.labelPosition
460-
{
463+
switch limitLine.labelPosition {
461464
case .rightTop:
462-
align = .left
463-
point = CGPoint(x: position.x + xOffset,
464-
y: viewPortHandler.contentTop + yOffset)
465+
point = CGPoint(
466+
x: position.x + xOffset,
467+
y: viewPortHandler.contentTop + yOffset)
465468

466469
case .rightBottom:
467-
align = .left
468470
point = CGPoint(x: position.x + xOffset,
469-
y: viewPortHandler.contentBottom - labelLineHeight - yOffset)
471+
y: viewPortHandler.contentBottom - labelLineRotatedHeight - yOffset)
470472

471473
case .leftTop:
472-
align = .right
473-
point = CGPoint(x: position.x - xOffset,
474+
point = CGPoint(x: position.x - labelLineRotatedWidth - xOffset,
474475
y: viewPortHandler.contentTop + yOffset)
475476

476477
case .leftBottom:
477-
align = .right
478-
point = CGPoint(x: position.x - xOffset,
479-
y: viewPortHandler.contentBottom - labelLineHeight - yOffset)
478+
point = CGPoint(x: position.x - labelLineRotatedWidth - xOffset,
479+
y: viewPortHandler.contentBottom - labelLineRotatedHeight - yOffset)
480480
}
481481

482+
let attributes: [NSAttributedString.Key : Any] = [
483+
.font: limitLine.valueFont,
484+
.foregroundColor: limitLine.valueTextColor
485+
]
486+
482487
context.drawText(label,
483488
at: point,
484-
align: align,
485-
attributes: [.font: limitLine.valueFont,
486-
.foregroundColor: limitLine.valueTextColor])
489+
anchor: anchor,
490+
angleRadians: labelRotationAngleRadians,
491+
attributes: attributes)
487492
}
488493
}

Source/Charts/Renderers/XAxisRendererHorizontalBarChart.swift

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -249,41 +249,48 @@ open class XAxisRendererHorizontalBarChart: XAxisRenderer
249249
// if drawing the limit-value label is enabled
250250
if l.drawLabelEnabled, !label.isEmpty
251251
{
252-
let labelLineHeight = l.valueFont.lineHeight
253-
252+
253+
let labelLineSize = label.size(withAttributes: [.font: l.valueFont])
254+
let labelLineRotatedSize = labelLineSize.rotatedBy(degrees: l.labelRotationAngle)
255+
let labelLineRotatedWidth = labelLineRotatedSize.width
256+
let labelLineRotatedHeight = labelLineRotatedSize.height
257+
254258
let xOffset = 4.0 + l.xOffset
255-
let yOffset = l.lineWidth + labelLineHeight + l.yOffset
259+
let yOffset = l.lineWidth + labelLineRotatedHeight + l.yOffset
260+
let labelRotationAngleRadians = l.labelRotationAngle.DEG2RAD
256261

257-
let align: TextAlignment
258262
let point: CGPoint
263+
let anchor = CGPoint(x: 0.0, y: 0.0)
259264

260265
switch l.labelPosition
261266
{
262267
case .rightTop:
263-
align = .right
264-
point = CGPoint(x: viewPortHandler.contentRight - xOffset,
268+
point = CGPoint(x: viewPortHandler.contentRight - labelLineRotatedWidth - xOffset,
265269
y: position.y - yOffset)
266270

267271
case .rightBottom:
268-
align = .right
269-
point = CGPoint(x: viewPortHandler.contentRight - xOffset,
270-
y: position.y + yOffset - labelLineHeight)
272+
point = CGPoint(x: viewPortHandler.contentRight - labelLineRotatedWidth - xOffset,
273+
y: position.y - labelLineRotatedHeight + yOffset)
271274

272275
case .leftTop:
273-
align = .left
274276
point = CGPoint(x: viewPortHandler.contentLeft + xOffset,
275277
y: position.y - yOffset)
276278

277279
case .leftBottom:
278-
align = .left
279280
point = CGPoint(x: viewPortHandler.contentLeft + xOffset,
280-
y: position.y + yOffset - labelLineHeight)
281+
y: position.y - labelLineRotatedHeight + yOffset)
281282
}
282283

284+
let attributes: [NSAttributedString.Key : Any] = [
285+
.font: l.valueFont,
286+
.foregroundColor: l.valueTextColor
287+
]
288+
283289
context.drawText(label,
284290
at: point,
285-
align: align,
286-
attributes: [.font: l.valueFont, .foregroundColor: l.valueTextColor])
291+
anchor: anchor,
292+
angleRadians: labelRotationAngleRadians,
293+
attributes: attributes)
287294
}
288295
}
289296
}

Source/Charts/Renderers/YAxisRenderer.swift

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -295,41 +295,47 @@ open class YAxisRenderer: NSObject, AxisRenderer
295295
// if drawing the limit-value label is enabled
296296
guard l.drawLabelEnabled, !label.isEmpty else { continue }
297297

298-
let labelLineHeight = l.valueFont.lineHeight
299-
298+
let labelLineSize = label.size(withAttributes: [.font: l.valueFont])
299+
let labelLineRotatedSize = labelLineSize.rotatedBy(degrees: l.labelRotationAngle)
300+
let labelLineRotatedWidth = labelLineRotatedSize.width
301+
let labelLineRotatedHeight = labelLineRotatedSize.height
302+
300303
let xOffset = 4.0 + l.xOffset
301-
let yOffset = l.lineWidth + labelLineHeight + l.yOffset
304+
let yOffset = l.lineWidth + labelLineRotatedHeight + l.yOffset
305+
let labelRotationAngleRadians = l.labelRotationAngle.DEG2RAD
302306

303-
let align: TextAlignment
304307
let point: CGPoint
308+
let anchor = CGPoint(x: 0.0, y: 0.0)
305309

306310
switch l.labelPosition
307311
{
308312
case .rightTop:
309-
align = .right
310-
point = CGPoint(x: viewPortHandler.contentRight - xOffset,
313+
point = CGPoint(x: viewPortHandler.contentRight - labelLineRotatedWidth - xOffset,
311314
y: position.y - yOffset)
312315

313316
case .rightBottom:
314-
align = .right
315-
point = CGPoint(x: viewPortHandler.contentRight - xOffset,
316-
y: position.y + yOffset - labelLineHeight)
317+
point = CGPoint(x: viewPortHandler.contentRight - labelLineRotatedWidth - xOffset,
318+
y: position.y - labelLineRotatedHeight + yOffset)
317319

318320
case .leftTop:
319-
align = .left
320321
point = CGPoint(x: viewPortHandler.contentLeft + xOffset,
321322
y: position.y - yOffset)
322323

323324
case .leftBottom:
324-
align = .left
325325
point = CGPoint(x: viewPortHandler.contentLeft + xOffset,
326-
y: position.y + yOffset - labelLineHeight)
326+
y: position.y - labelLineRotatedHeight + yOffset)
327327
}
328328

329+
let attributes: [NSAttributedString.Key : Any] = [
330+
.font: l.valueFont,
331+
.foregroundColor: l.valueTextColor
332+
]
333+
329334
context.drawText(label,
330335
at: point,
331-
align: align,
332-
attributes: [.font: l.valueFont, .foregroundColor: l.valueTextColor])
336+
anchor: anchor,
337+
angleRadians: labelRotationAngleRadians,
338+
attributes: attributes)
333339
}
334340
}
335341

Source/Charts/Renderers/YAxisRendererHorizontalBarChart.swift

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -253,41 +253,47 @@ open class YAxisRendererHorizontalBarChart: YAxisRenderer
253253
// if drawing the limit-value label is enabled
254254
if l.drawLabelEnabled, !label.isEmpty
255255
{
256-
let labelLineHeight = l.valueFont.lineHeight
257-
256+
let labelLineSize = label.size(withAttributes: [.font: l.valueFont])
257+
let labelLineRotatedSize = labelLineSize.rotatedBy(degrees: l.labelRotationAngle)
258+
let labelLineRotatedWidth = labelLineRotatedSize.width
259+
let labelLineRotatedHeight = labelLineRotatedSize.height
260+
258261
let xOffset = l.lineWidth + l.xOffset
259262
let yOffset = 2.0 + l.yOffset
263+
let labelRotationAngleRadians = l.labelRotationAngle.DEG2RAD
260264

261-
let align: TextAlignment
262265
let point: CGPoint
266+
let anchor = CGPoint(x: 0.0, y: 0.0)
263267

264268
switch l.labelPosition
265269
{
266270
case .rightTop:
267-
align = .left
268271
point = CGPoint(x: position.x + xOffset,
269272
y: viewPortHandler.contentTop + yOffset)
270273

271274
case .rightBottom:
272-
align = .left
273275
point = CGPoint(x: position.x + xOffset,
274-
y: viewPortHandler.contentBottom - labelLineHeight - yOffset)
276+
y: viewPortHandler.contentBottom - labelLineRotatedHeight - yOffset)
275277

276278
case .leftTop:
277-
align = .right
278-
point = CGPoint(x: position.x - xOffset,
279+
point = CGPoint(x: position.x - labelLineRotatedWidth - xOffset,
279280
y: viewPortHandler.contentTop + yOffset)
280281

281282
case .leftBottom:
282-
align = .right
283-
point = CGPoint(x: position.x - xOffset,
284-
y: viewPortHandler.contentBottom - labelLineHeight - yOffset)
283+
point = CGPoint(x: position.x - labelLineRotatedWidth - xOffset,
284+
y: viewPortHandler.contentBottom - labelLineRotatedHeight - yOffset)
285285
}
286286

287+
let attributes: [NSAttributedString.Key : Any] = [
288+
.font: l.valueFont,
289+
.foregroundColor: l.valueTextColor
290+
]
291+
287292
context.drawText(label,
288293
at: point,
289-
align: align,
290-
attributes: [.font: l.valueFont, .foregroundColor: l.valueTextColor])
294+
anchor: anchor,
295+
angleRadians: labelRotationAngleRadians,
296+
attributes: attributes)
291297
}
292298
}
293299
}

Tests/ChartsTests/LineChartTests.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,41 @@ class LineChartTests: XCTestCase {
6969
dataSet.drawIconsEnabled = true
7070
assertChartSnapshot(matching: chart)
7171
}
72+
73+
func testLimitLineLabelRotatedBy180() {
74+
addLimitLineWithRotatedAngle(labelPosition: .rightBottom, labelRotationAngle: 180)
75+
assertChartSnapshot(matching: chart)
76+
}
77+
78+
func testLimitLineLabelRotatedBy120() {
79+
addLimitLineWithRotatedAngle(labelPosition: .rightTop, labelRotationAngle: 120)
80+
assertChartSnapshot(matching: chart)
81+
}
82+
83+
func testLimitLineLabelRotatedBy90() {
84+
addLimitLineWithRotatedAngle(labelPosition: .leftTop, labelRotationAngle: 90)
85+
assertChartSnapshot(matching: chart)
86+
}
87+
88+
func testLimitLineLabelRotatedBy45() {
89+
addLimitLineWithRotatedAngle(labelPosition: .leftBottom, labelRotationAngle: 45)
90+
assertChartSnapshot(matching: chart)
91+
}
92+
93+
func testLimitLineLabelRotatedBy30() {
94+
addLimitLineWithRotatedAngle(labelPosition: .leftBottom, labelRotationAngle: 30)
95+
assertChartSnapshot(matching: chart)
96+
}
97+
98+
func testLimitLineLabelDefaultRotation() {
99+
addLimitLineWithRotatedAngle(labelPosition: .rightTop, labelRotationAngle: 0)
100+
assertChartSnapshot(matching: chart)
101+
}
102+
103+
private func addLimitLineWithRotatedAngle(labelPosition: ChartLimitLine.LabelPosition, labelRotationAngle: CGFloat) {
104+
let limitline = ChartLimitLine(limit: 50, label: "Limit Line")
105+
limitline.labelPosition = labelPosition
106+
limitline.labelRotationAngle = labelRotationAngle
107+
chart.leftAxis.addLimitLine(limitline)
108+
}
72109
}
116 KB
Loading
119 KB
Loading
117 KB
Loading
120 KB
Loading

0 commit comments

Comments
 (0)