How to create marker in ios-chart - ios-charts

I am looking for marker implementation for line chart. I am using swift 3. all my searches failed, and I need a help.
I went through this steps, but it seems to not working well.
I have two graphs and when I touch on them - there are no action (example bellow).
#IBOutlet weak var modelLineChartView: LineChartView!
#IBOutlet weak var lineChartView: LineChartView!
....
func chartValueSelected(chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
let graphPoint = modelLineChartView.getMarkerPosition(highlight: highlight)
let graphPointt = lineChartView.getMarkerPosition(highlight: highlight)
print(graphPoint.x)
print(graphPointt.x)
}
Please help me, I am stuck.

The reason why the code in the other thread does not work is because the chartValueSelected function is slightly different in swift 3.0 than in older versions. I created a test project and with this code every time you click on a value it is printed out:
import Charts
class ViewController: UIViewController, ChartViewDelegate {
#IBOutlet weak var testLineChartView: LineChartView!
override func viewDidLoad() {
super.viewDidLoad()
testLineChartView.delegate = self
let data = generateLineData()
testLineChartView.data = data
}
func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
print("entry.value \(entry)")
}
func generateLineData() -> LineChartData {
let data: LineChartData = LineChartData()
var entries: [ChartDataEntry] = []
var dataArr: [Int] = []
dataArr.append(10)
dataArr.append(5)
dataArr.append(8)
dataArr.append(12)
dataArr.append(10)
for index in 0..<5 {
entries.append(ChartDataEntry(x: Double(index)+0.5, y: Double(dataArr[index]) ) )
}
let set: LineChartDataSet = LineChartDataSet(values: entries, label: "Label")
set.setCircleColor(UIColor.blue)
set.lineWidth = 1
set.circleRadius = 5
set.drawCircleHoleEnabled = false
set.valueTextColor = UIColor.blue
set.valueFont = UIFont(name: "Verdana", size: 12.0)!
set.drawFilledEnabled = true
set.mode = Charts.LineChartDataSet.Mode.linear
set.axisDependency = Charts.YAxis.AxisDependency.left
data.addDataSet(set)
return data
}
}

Related

Problem using Charts in swift with blinking graph and no chart data available

I'm trying to show a pie chart using cocoapod Charts but I'm basically finding two problems. First of all, when the pie chart is showed for the first time it blinks for a couple of seconds. The chart it's in a tab bar so when I return to it there is no blink.
And secondly it is always showing the text "no chart data available" although the data is show. Please the picture I've attached.
Any suggestion?
import UIKit
import Charts
class PieChartViewController: UIViewController, ChartViewDelegate{
#IBOutlet weak var contenedorView: UIView!
#IBOutlet weak var pieChartView: PieChartView!
var nombres: [String]!
var precios: [Double]!
override func viewDidLoad() {
super.viewDidLoad()
pieChartView.delegate = self
nombres = eventos.devolverNombre()
precios = eventos.devolverPrecios()
//Configuramos el gráfico circular
setChart(dataPoints: nombres, values: precios)
self.pieChartView.noDataText = "Geen"
}
override func viewWillAppear(_ animated: Bool) {
reloadInputViews()
self.pieChartView.noDataText = "Geen"
contenedorView.layer.borderWidth = 2
contenedorView.layer.borderColor = UIColor.white.cgColor
contenedorView.layer.cornerRadius = 10
self.view.aplicarFondoDegradado()
}
func setChart(dataPoints: [String], values: [Double]) {
var dataEntries: [PieChartDataEntry] = []
for i in 0..<dataPoints.count {
let dataEntry = PieChartDataEntry(value: Double(i), label: dataPoints[i], data: dataPoints[i] as AnyObject)
if dataEntry != nil {
dataEntries.append(dataEntry)}
}
let chartDataSet = PieChartDataSet(entries: dataEntries, label: "PRECIOS POR EVENTO")
let chartData = PieChartData(dataSet: chartDataSet)
pieChartView.holeColor = UIColor.black
pieChartView.data = chartData
var colors: [UIColor] = []
for i in 0..<dataPoints.count {
let red = Double(arc4random_uniform(256))
let green = Double(arc4random_uniform(256))
let blue = Double(arc4random_uniform(256))
let color = UIColor(red: CGFloat(red/255), green: CGFloat(green/255), blue: CGFloat(blue/255), alpha: 1)
colors.append(color)
}
pieChartView.noDataText = ""
pieChartView.holeRadiusPercent = 0.6
pieChartView.legend.textColor = UIColor.white
pieChartView.legend.font = UIFont.systemFont(ofSize: 12)
pieChartView.drawEntryLabelsEnabled = false
chartDataSet.colors = colors
}
}

How to get the current Title of a button in Swift?

What am I doing wrong?
I get this error:
let letterString = sender.title(for: .normal)! // Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
when I tried to get the title of a button in swift like below:
import UIKit
class ViewController: UIViewController {
// My IBOutlets
#IBOutlet var treeImageView: UIImageView!
#IBOutlet var correctWordLabel: UILabel!
#IBOutlet var scoreLabel: UILabel!
// My Outlet Collection
#IBOutlet var letterButtons: [UIButton]!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// Begin the round.
newRound()
}
var listOfWords = ["estufa", "nevera", "computadora", "empanada", "chuleta", "camarones", "brincar", "correr", "caminar", "tigre", "jirafa", "mono", "kisseemmee", "Tampa", "Orlando"]
let incorrectMovesAllowed = 7
let totalWins = 0
let totalLosses = 0
// My IBActions
#IBAction func letterButtonPressed(_ sender: UIButton) {
sender.isEnabled = false
let letterString = sender.title(for: .normal)! // Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
let letter = Character(letterString.lowercased())
currentGame.playerGuessed(letter: letter)
updateUI()
}
var currentGame: Game!
func newRound() {
let newWord = listOfWords.removeFirst()
currentGame = Game(word: newWord, incorrectMovesRemaining: incorrectMovesAllowed, guessedLetters: [])
updateUI()
}
func updateUI() {
scoreLabel.text = "Wins: \(totalWins), Losses: \(totalLosses)"
treeImageView.image = UIImage(named: "Tree \(currentGame.incorrectMovesRemaining)")
}
}
// Game.swift file code:
import Foundation
struct Game {
var word: String
var incorrectMovesRemaining: Int
var guessedLetters: [Character]
mutating func playerGuessed(letter: Character) {
guessedLetters.append(letter)
if !word.contains(letter) {
incorrectMovesRemaining -= 1
}
}
}
I'm a newbie. This is my first program. I appreciate if you code the solution.
You can get the title of the UIButton using titleLabel property. Check the below code.
sender.titleLabel?.text
As the above code returns optional, you can use optional chain to safely get the string
if let titleLabel = sender.titleLabel {
let title = titleLabel.text
}
OR
You can also use the currentTitle property as below.
sender.currentTitle
You can use:
sender.titleLabel.text

animationDidStop not executing

I was working on trying to get a background view for a project I'm making and came across a weird instance.
This is how my code is set up.
import Foundation
import UIKit
class MainMenuViewController: UIViewController, CAAnimationDelegate {
#IBOutlet weak var colorView: UIView!
#IBOutlet weak var startLabel: UILabel!
#IBOutlet weak var firstButton: UIButton!
#IBOutlet weak var secondButton: UIButton!
#IBOutlet weak var thirdButton: UIButton!
let gradient = CAGradientLayer()
var gradientSet = [[CGColor]]()
var currentGradient: Int = 0
let gradientOne = gradientColors.lightGrey.cgColor
let gradientTwo = gradientColors.darkGrey.cgColor
let gradientThree = gradientColors.veryDarkGrey.cgColor
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
gradientSet.append([gradientOne, gradientTwo])
gradientSet.append([gradientTwo, gradientThree])
gradientSet.append([gradientThree, gradientOne])
gradient.frame = colorView.bounds
gradient.colors = gradientSet[currentGradient]
gradient.startPoint = CGPoint(x:0, y:0)
gradient.endPoint = CGPoint(x:1, y:1)
gradient.drawsAsynchronously = true
colorView.layer.insertSublayer(gradient, below: thirdButton.layer)
animateGradient()
}
func animateGradient() {
if currentGradient < gradientSet.count - 1 {
currentGradient += 1
} else {
currentGradient = 0
}
let gradientChangeAnimation = CABasicAnimation(keyPath: "colors")
gradientChangeAnimation.duration = 5.0
gradientChangeAnimation.toValue = gradientSet[currentGradient]
gradientChangeAnimation.fillMode = CAMediaTimingFillMode.forwards
gradientChangeAnimation.isRemovedOnCompletion = false
gradient.add(gradientChangeAnimation, forKey: "colorChange")
}
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
if flag == true {
print("animation complete")
gradient.colors = gradientSet[currentGradient]
animateGradient()
}
}
}
The problem I'm having is that when the animation is finished, the 'animationDidStop' never triggers. The first animation runs, but when it's finished it's supposed to run the 'animationDidStop' function and run the 'animateGradient' function on a constant loop. I've looked and looked for solutions online but can't seem to find one. Im running Swift 4 and would really appreciate any help. Thanks!
You left out a line:
gradientChangeAnimation.delegate = self

enable NSButton if NSTextfield is not empty

I am creating a OSX app and would like to enable a button when all textfield are filled. But do not have much experience with osx app as there seem to be some difference from ios.
This is what I have tried.
override func viewDidLoad() {
super.viewDidLoad()
btnCalculate.enabled = false
}
override func controlTextDidChange(obj: NSNotification) {
if panelsWideTextField.stringValue.isEmpty {
btnCalculate.enabled = false
} else {
btnCalculate.enabled = true
}
}
Hope someone has a good tip for me :-)
EDIT:
Complete code.
import Cocoa
//import AppKit
class ViewController: NSViewController, NSTextFieldDelegate {
#IBOutlet weak var panelHightTextField: NSTextField!
#IBOutlet weak var panelWidthTextField: NSTextField!
#IBOutlet weak var panelPitchTextField: NSTextField!
#IBOutlet weak var panelsHighTextField: NSTextField!
#IBOutlet weak var panelsWideTextField: NSTextField!
#IBOutlet weak var resWidthLabel: NSTextField!
#IBOutlet weak var resHightLabel: NSTextField!
#IBOutlet weak var lblScreenWidth: NSTextField!
#IBOutlet weak var lblScreenHight: NSTextField!
#IBOutlet weak var lblScreenArea: NSTextField!
#IBOutlet weak var btnCalculate: NSButton!
#IBOutlet weak var lblAmountPanels: NSTextField!
var panelHight = ""
var panelWidth = ""
var panelPitch = ""
var panelsHigh = ""
var panelsWidth = ""
var resWidth : Float = 0
var resHigh : Float = 0
var screenHight : Float = 0
var screenWidth : Float = 0
var screenArea : Float = 0
var ammountPanels : Float = 0
override func viewDidLoad() {
super.viewDidLoad()
btnCalculate.enabled = false
}
override func controlTextDidChange(obj: NSNotification) {
if panelsWideTextField.stringValue.isEmpty {
btnCalculate.enabled = true
} else {
btnCalculate.enabled = false
}
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
#IBAction func calculateResButton(sender: AnyObject) {
takeUserData()
calculatehight()
calculatewidth()
calculateArea()
calculateAmountPanels()
}
func takeUserData(){
panelHight = panelHightTextField.stringValue
panelWidth = panelWidthTextField.stringValue
panelPitch = panelPitchTextField.stringValue
panelsHigh = panelsHighTextField.stringValue
panelsWidth = panelsWideTextField.stringValue
}
// Calculating resolution and physical hight
func calculatehight(){
let fpanelHight = Float(panelHight)
let fpanelPitch = Float(panelPitch)
let fpanelsHigh = Float(panelsHigh)
resHigh = fpanelHight! * fpanelsHigh! / fpanelPitch!
screenHight = fpanelHight! * fpanelsHigh! / 1_000
printText()
}
// Calculating resolution and physical width
func calculatewidth(){
let fpanelWidth = Float(panelWidth)
let fpanelPitch = Float(panelPitch)
let fpanelsWidth = Float(panelsWidth)
resWidth = fpanelWidth!*fpanelsWidth!/fpanelPitch!
screenWidth = fpanelWidth!*fpanelsWidth! / 1_000
printText()
}
// Calculating sqm of LED screen
func calculateArea(){
let fpanelHight = Float(panelHight)
let fpanelsHigh = Float(panelsHigh)
let fpanelWidth = Float(panelWidth)
let fpanelsWidth = Float(panelsWidth)
screenArea = (fpanelHight! * fpanelsHigh!) * (fpanelWidth! * fpanelsWidth!) / 1_000_000
printText()
}
// Calculating the amount of panels used.
func calculateAmountPanels(){
let fpanelsHigh = Float(panelsHigh)
let fpanelsWidth = Float(panelsWidth)
ammountPanels = (fpanelsWidth! * fpanelsHigh!)
printText()
}
// Outputting text to labels with correct format.
func printText(){
let formatResHigh = String(format: "%0.0f", resHigh)
let formatResWidth = String(format: "%0.0f", resWidth)
let formatScreenHight = String(format: "%0.2f", screenHight)
let formatScreenWidth = String(format: "%0.2f", screenWidth)
let formatScreenArea = String(format: "%0.0f", screenArea)
let formatAmmountPanels = String(format: "%0.0f", ammountPanels)
resHightLabel.stringValue = "\(formatResHigh)px"
resWidthLabel.stringValue = "\(formatResWidth)px"
lblScreenHight.stringValue = "\(formatScreenHight)m"
lblScreenWidth.stringValue = "\(formatScreenWidth)m"
lblScreenArea.stringValue = "\(formatScreenArea) sqm"
lblAmountPanels.stringValue = "\(formatAmmountPanels)"
}
}
I had the same problem but I found simple solution: checkbox can enable and disable NSButton.
import Cocoa
class ViewController: NSViewController {
#IBOutlet weak var btnCalculate: NSButton!
#IBOutlet weak var checkBox: NSButton!
override func viewDidLoad() {
super.viewDidLoad()
btnCalculate.enabled = false
checkBox.state = 0
}
#IBAction func checkAgree(sender: NSButton) {
if btnCalculate.stringValue.characters.count > 0 && checkBox.state == 1 {
btnCalculate.enabled = true
} else {
btnCalculate.enabled = false
}
}
}

Running Pace Calculator in Swift

I'm a complete newbie to Swift. I have created a running pace calculator as experiment in Playground and it works perfectly, but I struggle to figure out how to connect it to a UI.
Things in particular I struggle with currently:
Casting a text string to an Int label
Does the function that does the calculation go in the IBAction?
Playground Code
import UIKit
func PaceCalculator (minutes:Double, seconds:Double, distance:Double) -> Double{
return ((minutes*60) + seconds) / distance
}
var paceInSeconds = PaceCalculator(28, 26, 10.1)
var paceInMinutes = paceInSeconds / 60
var roundedMinutes = Double(floor(paceInMinutes))
var decimalSeconds = paceInMinutes - roundedMinutes
var intPace = Int(floor(roundedMinutes))
var seconds = Int(floor(decimalSeconds * 60))
println("Your average pace is \(intPace):\(seconds)/km")
Incomplete Swift Code
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func calculatePaceButton(sender: UIButton) {
}
#IBOutlet weak var minutesTextField: UITextField!
#IBOutlet weak var distanceTextField: UITextField!
#IBOutlet weak var paceLabel: UILabel!
}
Storyboard
Disclaimer: I have no programming experience either. So be gentle on the jargon and explanation.)
Hope this will work for you :
You didn't added secondsTextField as IBOutlet please check that too.
class ViewController: UIViewController {
#IBOutlet weak var minutesTextField: UITextField!
#IBOutlet weak var distanceTextField: UITextField!
#IBOutlet weak var paceLabel: UILabel!
#IBOutlet weak var secondsTextField: UITextField!
#IBAction func calculatePaceButton(sender: UIButton) {
var paceInSeconds = PaceCalculator((minutesTextField.text as NSString).doubleValue, seconds: (secondsTextField.text as NSString).doubleValue, distance: (distanceTextField.text as NSString).doubleValue)
var paceInMinutes = paceInSeconds / 60.0
var roundedMinutes = Double(floor(paceInMinutes))
var decimalSeconds = paceInMinutes - roundedMinutes
var intPace = Int(floor(roundedMinutes))
var seconds = Int(floor(decimalSeconds * 60))
paceLabel.text = "\(intPace)"
}
func PaceCalculator (minutes:Double, seconds:Double, distance:Double) -> Double{
return ((minutes*60) + seconds) / distance
}
}
Here I would like to share my solution to calculate pace. The calculation is based on inputs of times and locations, which are more generic and useful.
typealias ShortFullTupleStrings = (short: String, full: String)
class PaceCalculator {
private static func relatedTimeString(
for value: TimeInterval)
-> ShortFullTupleStrings?
{
let fm = DateComponentsFormatter()
switch abs(value) {
case 0 ..< 24*3600: // within one day
fm.allowedUnits = [.year, .day, .hour, .minute, .second]
case 24*3600 ..< 24*3600*10: // within 1-10 days
fm.allowedUnits = [.year, .day, .hour, .minute]
case 24*3600*10 ..< 24*3600*365: // within 10-365 days
fm.allowedUnits = [.year, .day, .hour]
default: // within 365-1000 days
fm.allowedUnits = [.year, .day]
}
fm.unitsStyle = .short
let short = fm.string(from: value)
fm.unitsStyle = .full
let full = fm.string(from: value)
if let short = short, let full = full {
return (short, full)
} else {
return nil
}
}
static var isMetric: Bool {
let locale = NSLocale.current
let metricSystem = locale.usesMetricSystem
return metricSystem
}
static func paceFrom( _
dt1: Date, to dt2: Date,
distanceFrom loc1: CLLocation, to loc2: CLLocation) ->
ShortFullTupleStrings?
{
let timeInterval = dt2.timeIntervalSince(dt1)
let dist = loc2.distance(from: loc1)
let pace: ShortFullTupleStrings?
if !dist.isZero {
let paceV: TimeInterval
if isMetric {
paceV = timeInterval / (dist / 1000.0)
} else {
paceV = timeInterval / (dist / 1609.344)
}
pace = relatedTimeString(for: paceV)
} else {
pace = nil
}
return pace
}
}
relatedTimeString is a helper func to get a time string in the format of short form of # yrs, # days, # hrs, # min, # sec, and full form of # years, ..., depending on none zero values. For example, 6 min, 5 sec in short form, or 6 minutes, 5 seconds in full form.
In this way, the func is more generic and supports localization and accessibilities.