Closed Ruchita-Bora closed 4 years ago
Hi,
I have found an example in Swift but finding it difficult doing same in xamarin iOS. Need it for my project.. Any help would be appreciated..
@Ruchita-Bora Please share the Swift version you found so we can help you convert it to the Xamarin version.
func setupLineChart() {
// Set up the chart properties
HourlyLineChart.chartDescription = nil
HourlyLineChart.dragEnabled = true
HourlyLineChart.scaleYEnabled = false
HourlyLineChart.scaleXEnabled = true
HourlyLineChart.pinchZoomEnabled = false
HourlyLineChart.legend.enabled = false
HourlyLineChart.doubleTapToZoomEnabled = false
//HourlyLineChart.zoom(scaleX: 0, scaleY: 0, x: 0, y: 0)
HourlyLineChart.zoom(scaleX: 4, scaleY: 1, x: 0, y: 0)
// Make a frame for drawable space with a portoffset with borders
HourlyLineChart.setViewPortOffsets(left: 0, top: -10, right: 0, bottom: -40)
HourlyLineChart.animate(xAxisDuration: 1, yAxisDuration: 1, easingOption: .easeInBounce)
HourlyLineChart.rightAxis.enabled = false
HourlyLineChart.delegate = self
HourlyLineChart.noDataFont.withSize(17)
// Set up expandable view properties
hourlyExpandableLabel.isHidden = true
hourlyExpandableView.isHidden = true
hourlyExpandableView.backgroundColor = UIColor(red: 99/255, green: 140/255, blue: 189/255, alpha: 1/1)
hourlyExpandableView.layer.cornerRadius = 8
hourlyExpandableHeight.constant = 0
// Set Y-Axis properties
let yAxis = HourlyLineChart.leftAxis
yAxis.enabled = true
yAxis.drawAxisLineEnabled = false
yAxis.drawLabelsEnabled = false
yAxis.drawGridLinesEnabled = false
yAxis.spaceTop = 1
yAxis.spaceBottom = 1.5
// Set Custom XAXis renderers
HourlyLineChart.xAxis.enabled = true
HourlyLineChart.xAxis.drawGridLinesEnabled = false
HourlyLineChart.xAxis.drawLabelsEnabled = true
HourlyLineChart.xAxis.labelPosition = .top
HourlyLineChart.xAxis.labelTextColor = .white
HourlyLineChart.xAxis.granularityEnabled = true
HourlyLineChart.xAxis.granularity = 1
HourlyLineChart.xAxis.avoidFirstLastClippingEnabled = true
HourlyLineChart.xAxis.labelFont = UIFont(name: "HelveticaNeue-Light", size: 12.0)!
dataSet.highlightEnabled = true
dataSet.drawHorizontalHighlightIndicatorEnabled = false
dataSet.highlightColor = UIColor(red: 236/255, green: 239/255, blue: 241/255, alpha: 0.1/1)
dataSet.highlightLineWidth = 50
dataSet.mode = .cubicBezier
dataSet.circleColors = [UIColor(hex: "fafafa")]
dataSet.circleRadius = 4
dataSet.fillColor = UIColor.white
dataSet.drawCircleHoleEnabled = false
dataSet.drawFilledEnabled = false
dataSet.lineWidth = 1.0
dataSet.colors = [UIColor.white]
dataSet.drawValuesEnabled = true
dataSet.valueFont = UIFont(name: "HelveticaNeue-Light", size: 14.0)!
dataSet.axisDependency = .left
}
Here is the code that updates data
func updateHourlyData() {
HourlyLineChart.clear()
lineChartEntries.removeAll()
hourlyTimes.removeAll()
hourlyTemperaturesStr.removeAll()
hourlyPrecip.removeAll()
hourlyIcons.removeAll()
if selectedLocationData?.hourlyFcst?.hourly != nil {
for index in (selectedLocationData?.hourlyFcst?.hourly)! {
hourlyTimes.append(index.time!)
hourlyTemperaturesStr.append((index.temperature?.getValue())!)
hourlyIcons.append(UIImage(named: "\(index.iconCode!)_main")!)
hourlyPrecip.append(index.precip!)
}
}
if selectedLocationData?.hourlyFcst?.hourly != nil && hourlyTimes.count > 0 {
hourlyGraphHeight.constant = 250
// Populate chartDataEntries
for index in hourlyTimes.indices {
let xVal = Double(index).rounded()
var yVal = Double(index)
let yValStr = hourlyTemperaturesStr[index]
if !yValStr.isEmpty {
yVal = Double(yValStr)!
}
lineChartEntries.append(ChartDataEntry(x: xVal, y: yVal, data: selectedLocationData?.hourlyFcst?.hourly![index]))
}
// Set up a dataset for data model
dataSet.values = lineChartEntries
// Setup a valueformatter to get rid of decimals in the graph
let format = NumberFormatter()
format.numberStyle = .none
let formatter = HourTempFormatter(numberFormatter: format)
dataSet.valueFormatter = formatter
// Set the data using the above dataSet for the chart
let data = LineChartData(dataSet: dataSet)
data.setDrawValues(true)
data.setValueTextColor(UIColor(hex: "fafafa"))
HourlyLineChart.data = data
// Custom renederers for icons, precipitation
let customXAxisRenderer = XAxisCustomRenderer(viewPortHandler: HourlyLineChart.viewPortHandler, xAxis: HourlyLineChart.xAxis, transformer: HourlyLineChart.getTransformer(forAxis: YAxis.AxisDependency.left), icons: hourlyIcons, precipitationArray: hourlyPrecip)
HourlyLineChart.xAxisRenderer = customXAxisRenderer
// Custom renderer for time
HourlyLineChart.xAxis.valueFormatter = IndexAxisValueFormatter(values: hourlyTimes)
// Backup renderer for times (CHARTS 3.0.4 -> 3.0.5) ISSUE
//HourlyLineChart.xAxis.valueFormatter = DefaultAxisValueFormatter(block: {(index, _) in
// return self.hourlyTimes[Int(index)]
//})
}
// ELSE BLOCK TO COLLAPSE CHART IF NO DATA
//else {
// hourlyGraphHeight.constant = 0
// }
HourlyLineChart.notifyDataSetChanged()
}
And here is the custom xAxisRenderer:
public class XAxisCustomRenderer: XAxisRenderer {
// Dict to hold the weather icons array
private var icons: [UIImage]
// Dict to hold the preciptation mapping
private var precipitationArray: [String]
// Array to hold the time string
//private var timesArray: [String]
init(viewPortHandler: ViewPortHandler, xAxis: XAxis, transformer: Transformer, icons: [UIImage], precipitationArray: [String]) {
self.icons = icons
self.precipitationArray = precipitationArray
//self.timesArray = times
super.init(viewPortHandler: viewPortHandler, xAxis: xAxis, transformer: transformer)
}
override public func drawLabels(context: CGContext, pos: CGFloat, anchor: CGPoint){
guard
let xAxis = self.axis as? XAxis,
let transformer = self.transformer
else { return }
#if os(OSX)
let paraStyle = NSParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
#else
let paraStyle = NSParagraphStyle.default.mutableCopy() as! NSMutableParagraphStyle
#endif
paraStyle.alignment = .center
let labelAttrs: [NSAttributedStringKey : Any] = [NSAttributedStringKey.font: xAxis.labelFont,
NSAttributedStringKey.foregroundColor: xAxis.labelTextColor,
NSAttributedStringKey.paragraphStyle: paraStyle]
let FDEG2RAD = CGFloat(Double.pi / 180.0)
let labelRotationAngleRadians = xAxis.labelRotationAngle * FDEG2RAD
let centeringEnabled = xAxis.isCenterAxisLabelsEnabled
let valueToPixelMatrix = transformer.valueToPixelMatrix
var position = CGPoint(x: 0.0, y: 0.0)
var labelMaxSize = CGSize()
if xAxis.isWordWrapEnabled
{
labelMaxSize.width = xAxis.wordWrapWidthPercent * valueToPixelMatrix.a
}
let entries = xAxis.entries
for i in stride(from: 0, to: entries.count, by: 1)
{
if centeringEnabled
{
position.x = CGFloat(xAxis.centeredEntries[i])
}
else
{
position.x = CGFloat(entries[i])
}
position.y = 0.0
position = position.applying(valueToPixelMatrix)
if viewPortHandler.isInBoundsX(position.x)
{
let label = xAxis.valueFormatter?.stringForValue(xAxis.entries[i], axis: xAxis) ?? ""
let labelns = label as NSString
if xAxis.isAvoidFirstLastClippingEnabled
{
// avoid clipping of the last
if i == xAxis.entryCount - 1 && xAxis.entryCount > 1
{
let width = labelns.boundingRect(with: labelMaxSize, options: .usesLineFragmentOrigin, attributes: labelAttrs, context: nil).size.width
if width > (viewPortHandler.offsetRight) * 2.0
&& position.x + width > viewPortHandler.chartWidth
{
position.x -= width / 2.0
}
}
else if i == 0
{ // avoid clipping of the first
let width = labelns.boundingRect(with: labelMaxSize, options: .usesLineFragmentOrigin, attributes: labelAttrs, context: nil).size.width
position.x += width / 2.0
}
}
let rawIcon: UIImage = icons[Int(entries[i])].fixedOrientation().imageRotatedByDegrees(degrees: 180)
let icon: CGImage = rawIcon.cgImage!
// Draw the time labels
drawLabel(
context: context,
formattedLabel: label,
x: position.x,
y: pos + 33,
attributes: labelAttrs,
constrainedToSize: labelMaxSize,
anchor: anchor,
angleRadians: labelRotationAngleRadians)
// let time = timesArray[Int(i)]
//drawLabel(context: context, formattedLabel: time, x: position.x + 8, y: viewPortHandler.chartHeight - 2, attributes: labelAttrs, constrainedToSize: labelMaxSize, anchor: anchor, angleRadians: labelRotationAngleRadians)
// Draw the icons
context.draw(icon, in: CGRect(x: position.x - 15, y: viewPortHandler.chartHeight - 47, width: CGFloat(30), height: CGFloat(27)))
// Draw the precipitation value
let precip = precipitationArray[Int(i)]
//if( !(precip.starts(with: "0"))) {
// Draw the precip string
drawLabel(context: context, formattedLabel: precip, x: position.x + 8, y: viewPortHandler.chartHeight - 2, attributes: labelAttrs, constrainedToSize: labelMaxSize, anchor: anchor, angleRadians: labelRotationAngleRadians)
// Draw the precip image
let precipitationIcon: CGImage = (UIImage(named: "rainCloud")?.fixedOrientation().imageRotatedByDegrees(degrees: 180).cgImage)!
context.draw(precipitationIcon, in: CGRect(x: position.x - 19, y: viewPortHandler.chartHeight - 15, width: 15, height: 15))
let axisLine: CGImage = (UIImage(named: "axisLine")?.cgImage)!
// Draw top axis
context.draw(axisLine,in: CGRect(x: -20, y: 0, width: viewPortHandler.chartWidth + 50, height: 50))
//let arrowIconRight: CGImage = (UIImage(named: "arrow")?.fixedOrientation().imageRotatedByDegrees(degrees: 180).alpha(alpha: 0.2)!.cgImage)!
//let arrowIconLeft: CGImage = (UIImage(named: "arrow")?.fixedOrientation().imageRotatedByDegrees(degrees: 0).alpha(alpha: 0.2)!.cgImage)!
//context.draw(arrowIconRight, in: CGRect(x: viewPortHandler.chartWidth - 30 , y: viewPortHandler.chartHeight/2.5, width: 15, height: 15))
//context.draw(arrowIconLeft, in: CGRect(x: 10 , y: viewPortHandler.chartHeight/2.5, width: 15, height: 15))
// Draw bottom axis
context.draw(axisLine,in: CGRect(x: -20 , y: viewPortHandler.chartHeight - 80, width: viewPortHandler.chartWidth + 50, height: 50))
}
}
}
}
I have plotted bar graph using nuget 3.0.4. Using same I am trying to show images on xaxis instead of labels as shown in image below.