// // EndMotionVC.swift // Twear // // Created by yangbin on 2022/1/2. // import UIKit import Charts class EndMotionVC: UIViewController { private lazy var mapView: MAMapView = MAMapView() @IBOutlet weak var distanceLabel: UILabel! @IBOutlet weak var stepChartView: LineChartView! @IBOutlet weak var altitudeChartView: LineChartView! @IBOutlet weak var maxSpeedLabel: UILabel! @IBOutlet weak var minSpeedLabel: UILabel! @IBOutlet weak var timeLabel: UILabel! @IBOutlet weak var calorieLabel: UILabel! @IBOutlet weak var scrollView: UIScrollView! @IBOutlet weak var dateLabel: UILabel! @IBOutlet weak var stepsLabel: UILabel! @IBOutlet weak var stepCadenceLabel: UILabel! @IBOutlet weak var stepStrideLabel: UILabel! @IBOutlet weak var altitudeLabel: UILabel! @IBOutlet weak var altitudeLabel1: UILabel! @IBOutlet weak var minAltitudeLabel: UILabel! @IBOutlet weak var maxAltitudeLabel: UILabel! @IBOutlet weak var totalStepLabel: UILabel! @IBOutlet weak var averageStepLabel: UILabel! @IBOutlet weak var maxStepLabel: UILabel! @IBOutlet weak var averageSpeedLabel: UILabel! @IBOutlet weak var averagePaceLabel: UILabel! @IBOutlet weak var avatarImageView: UIImageView! @IBOutlet weak var motionTypeLabel: UILabel! @IBOutlet weak var mapBackView: UIView! @IBOutlet weak var unitLabel: UILabel! @IBOutlet weak var altiUnitLabel: UILabel! @IBOutlet weak var detailView: UIView! @IBOutlet weak var altitudeView: UIView! @IBOutlet weak var stepView: UIView! @IBOutlet weak var detailBottomLayout: NSLayoutConstraint! @IBOutlet weak var stepBottomLayout: NSLayoutConstraint! @IBOutlet weak var topLayout: NSLayoutConstraint! @IBOutlet weak var detailLabel1: UILabel! @IBOutlet weak var detailLabel2: UILabel! @IBOutlet weak var detailLabel3: UILabel! @IBOutlet weak var detailLabel4: UILabel! @IBOutlet weak var detailLabel5: UILabel! @IBOutlet weak var detailLabel6: UILabel! @IBOutlet weak var detailLabel7: UILabel! @IBOutlet weak var detailLabel8: UILabel! var date: Date! var distance: Float! var length: Int! var calorie: Float! var altitude: Double = 0 var motionType: TrainType = .running var coordinateArray: [CLLocationCoordinate2D] = [] var speedArray: [Float] = [] var stepCadenceArray: [Int] = [] var altitudeArray: [Double] = [] let device = CurDevice var isRecordPresent: Bool = false override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) let polyline = MAPolyline(coordinates: &self.coordinateArray, count: UInt(self.coordinateArray.count)) let padding = UIEdgeInsets(top: 5, left: 5, bottom: 300, right: 5) mapView.setVisibleMapRect(polyline!.boundingMapRect, edgePadding: padding, animated: true) } override func viewDidLoad() { super.viewDidLoad() initMapView() topLayout.constant = SCREEN_HEIGHT-272 timeLabel.toTimeType3(length: length) calorieLabel.text = String(format:"%.2f", calorie) + LocString("千卡") dateLabel.text = date.toString(.custom("yyyy.MM.dd HH:mm")) let step = distanceToStep(distance) stepsLabel.text = "\(step)\(LocString("步"))" stepCadenceLabel.text = "\(Int(step*60/length))\(LocString("步/分钟"))" totalStepLabel.text = "\(step)" maxStepLabel.text = "\(stepCadenceArray.max() ?? 0)" averageStepLabel.text = "\(Int(step*60/length))" detailLabel1.text = LocString("步频(步/分钟)") detailLabel2.text = LocString("总步数") detailLabel3.text = LocString("最大步频") detailLabel4.text = LocString("平均步频") detailLabel5.text = LocString("累计爬升") detailLabel6.text = LocString("最高海拔") detailLabel7.text = LocString("最低海拔") detailLabel8.text = LocString("累计爬山") if device.distanceUnit == 0 { unitLabel.text = LocString("公里") distanceLabel.text = String(format:"%.2f", distance/1000) if let maxSpeed = speedArray.max() { maxSpeedLabel.text = "\(String(format:"%02d", Int(maxSpeed)/60))′\(String(format:"%02d", Int(maxSpeed)%60))″" } if let minSpeed = speedArray.max() { maxSpeedLabel.text = "\(String(format:"%02d", Int(minSpeed)/60))′\(String(format:"%02d", Int(minSpeed)%60))″" } let avgPace = speedArray.average() averagePaceLabel.text = "\(String(format:"%02d", Int(avgPace)/60))′\(String(format:"%02d", Int(avgPace)%60))″/\(LocString("公里"))" averageSpeedLabel.text = "\(String(format:"%.2f", distance/1000/(Float(length)/60)))\(LocString("公里/小时"))" if step > 0 { stepStrideLabel.text = "\(Int(distance)*100/step)\(LocString("厘米"))" } altitudeLabel.text = String(format:"%.2f", altitude) + LocString("米") altitudeLabel1.text = String(format:"%.2f", altitude) minAltitudeLabel.text = String(format:"%.2f", altitudeArray.min() ?? 0) maxAltitudeLabel.text = String(format:"%.2f", altitudeArray.max() ?? 0) altiUnitLabel.text = LocString("海拔(米)") } else { unitLabel.text = LocString("英里") distanceLabel.text = (distance/1000).mileString() if let maxSpeed = speedArray.max() { maxSpeedLabel.text = "\(String(format:"%02d", Int(maxSpeed/0.6213)/60))′\(String(format:"%02d", Int(maxSpeed/0.6213)%60))″" } if let minSpeed = speedArray.max() { maxSpeedLabel.text = "\(String(format:"%02d", Int(minSpeed/0.6213)/60))′\(String(format:"%02d", Int(minSpeed/0.6213)%60))″" } let avgPace = speedArray.average() averagePaceLabel.text = "\(String(format:"%02d", Int(avgPace/0.6213)/60))′\(String(format:"%02d", Int(avgPace/0.6213)%60))″/\(LocString("英里"))" averageSpeedLabel.text = "\(String(format:"%.2f", distance/1000*0.6213/(Float(length)/60)))\(LocString("英里/小时"))" if step > 0 { stepStrideLabel.text = "\(Int(distance*0.3937)*100/step)\(LocString("英寸"))" } altitudeLabel.text = String(format:"%.2f", altitude*3.281) + LocString("英尺") altitudeLabel1.text = String(format:"%.2f", altitude*3.281) minAltitudeLabel.text = String(format:"%.2f", (altitudeArray.min() ?? 0) * 3.281) maxAltitudeLabel.text = String(format:"%.2f", (altitudeArray.max() ?? 0) * 3.281) altiUnitLabel.text = LocString("海拔(英尺)") } if let image = UIImage.getImageFromPath("avatar") { avatarImageView.image = image } else { avatarImageView.image = UIImage(named: UserInfo.gender == 1 ? "avatar_male" : "avatar_female") } var motionTypeText = "户外跑步" switch motionType { case .run_indoor: motionTypeText = "室内跑步" case .walking: motionTypeText = "步行" case .bicycle: motionTypeText = "骑行" case .mountaineering: motionTypeText = "爬山" default: break } motionTypeLabel.text = LocString(motionTypeText) if motionType == .mountaineering { detailBottomLayout.constant = 32.5 stepBottomLayout.constant = 350 altitudeView.isHidden = false } else { detailBottomLayout.constant = 0 stepBottomLayout.constant = 10 altitudeView.isHidden = true } scrollView.delegate = self setupStepChartView() setupAltitudeChartView() // Do any additional setup after loading the view. } func initMapView() { // MAMapView.updatePrivacyShow(.didShow, privacyInfo: .didContain) // MAMapView.updatePrivacyAgree(.didAgree) mapView.showsUserLocation = false // mapView.userTrackingMode = .follow mapView.showsCompass = false mapView.zoomLevel = 16 mapView.mapLanguage = (AppSettings.shared.language == .Chinese) ? 0 : 1 mapView.delegate = self // let tool = MASmoothPathTool() // tool.intensity = 3 // tool.threshHold = 0.3 // tool.noiseThreshhold = 10 // // self.smoothedTracePoints = tool.pathOptimize(self.origTracePoints) let polyline = MAPolyline(coordinates: &self.coordinateArray, count: UInt(self.coordinateArray.count)) mapView.add(polyline) setPointAnnotation() let padding = UIEdgeInsets(top: 5, left: 5, bottom: 25, right: 5) mapView.setVisibleMapRect(polyline!.boundingMapRect, edgePadding: padding, animated: true) mapView.frame = mapBackView.bounds mapBackView.addSubview(mapView) mapBackView.sendSubviewToBack(mapView) } func setPointAnnotation() { if coordinateArray.count > 1 { let startPoint = MAPointAnnotation() startPoint.coordinate = coordinateArray.first! startPoint.title = "起点" mapView.addAnnotation(startPoint) let stopPoint = MAPointAnnotation() stopPoint.coordinate = coordinateArray.last! stopPoint.title = "终点" mapView.addAnnotation(stopPoint) } } @IBAction func back(_ sender: Any) { if !isRecordPresent { presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil) } else { presentingViewController?.dismiss(animated: true, completion: nil) } } @IBAction func share(_ sender: Any) { self.mapView.takeSnapshot(in: view.bounds) { mapImage, status in UIGraphicsBeginImageContextWithOptions(self.detailView.bounds.size, false, UIScreen.main.scale) self.detailView.layer.render(in: UIGraphicsGetCurrentContext()!) let detailImage = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() UIGraphicsBeginImageContextWithOptions(self.stepView.bounds.size, false, UIScreen.main.scale) self.stepView.layer.render(in: UIGraphicsGetCurrentContext()!) let stepImage = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() UIGraphicsBeginImageContextWithOptions(self.altitudeView.bounds.size, false, UIScreen.main.scale) self.altitudeView.layer.render(in: UIGraphicsGetCurrentContext()!) let altitudeImage = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() // union image let imageSize = self.scrollView.contentSize let backImageRect = CGRect(x: 0, y: 0, width: self.scrollView.contentSize.width, height: self.scrollView.contentSize.height) let backImage = UIImage.getImageWithColor(UIColor.rgbColorFromHex(0xF2F2F2), rect: backImageRect) // let imageSize = self.mapView.bounds.size UIGraphicsBeginImageContextWithOptions(imageSize, false, UIScreen.main.scale) backImage.draw(in: backImageRect) mapImage?.draw(in: self.mapView.bounds) detailImage.draw(in: self.detailView.frame) stepImage.draw(in: self.stepView.frame) altitudeImage.draw(in: self.altitudeView.frame) let image = UIGraphicsGetImageFromCurrentImageContext()! UIGraphicsEndImageContext() // self.transitionToDetail(with: image) let shareView = ShareView(image) shareView.show() } } func captureAction() -> UIImage? { // map image // self.mapView.takeSnapshot(in: view.bounds) { image, status in // ret // } return self.mapView.takeSnapshot(in: view.bounds) // takeSnapshot(in: self.mapView.bounds) // // result image // let s = self.view.bounds.size // UIGraphicsBeginImageContextWithOptions(s, false, UIScreen.main.scale) // self.view.layer.render(in: UIGraphicsGetCurrentContext()!) // let resultImage = UIGraphicsGetImageFromCurrentImageContext()! // UIGraphicsEndImageContext() // // union image // let imageSize = self.mapView.bounds.size // UIGraphicsBeginImageContextWithOptions(imageSize, false, UIScreen.main.scale) // mapImage?.draw(in: self.mapView.bounds) // resultImage.draw(in: self.view.frame) // let image = UIGraphicsGetImageFromCurrentImageContext()! // UIGraphicsEndImageContext() // self.transitionToDetail(with: image) } private func distanceToStep(_ distance: Float) -> Int { let user = UserInfo if user.gender == 1 { return Int (distance * 100 / 0.4 / Float(user.height)) } else { return Int (distance * 100 / 0.35 / Float(user.height)) } } private func setupStepChartView() { if stepCadenceArray.count < 2 { return } stepChartView.chartDescription?.enabled = false //图描述 stepChartView.legend.enabled = false //左下角图例 stepChartView.setScaleEnabled(false) //可滑动 stepChartView.rightAxis.enabled = false //不绘制右边轴的信息 let leftAxis = stepChartView.leftAxis leftAxis.labelTextColor = ChartsTextColor leftAxis.labelFont = ChartsTextFont(11) leftAxis.yOffset = -5 leftAxis.xOffset = -1 leftAxis.gridLineDashLengths = [2.0, 2.0] //设置虚线样式的网格线 leftAxis.gridColor = LineColor leftAxis.gridLineWidth = 1 leftAxis.axisLineWidth = 0 leftAxis.drawGridLinesBehindDataEnabled = false leftAxis.labelPosition = .insideChart leftAxis.axisMinimum = 0 //设置左侧Y轴最小值 leftAxis.axisMaximum = max(Double(stepCadenceArray.max() ?? 220) + 20, 140) leftAxis.granularity = 60 let litmitLine = ChartLimitLine(limit: 0, label: "") litmitLine.lineWidth = 1 litmitLine.lineColor = LineColor leftAxis.addLimitLine(litmitLine) leftAxis.drawLimitLinesBehindDataEnabled = false //设置限制线绘制在折线图的后面 let xAxis = stepChartView.xAxis xAxis.granularity = 1 //间隔 xAxis.labelPosition = .bottom xAxis.labelFont = ChartsTextFont(11) xAxis.labelTextColor = ChartsTextColor xAxis.drawGridLinesBehindDataEnabled = false xAxis.axisLineColor = LineColor xAxis.axisLineWidth = 1 xAxis.gridLineDashLengths = [6, 666] xAxis.gridColor = LineColor xAxis.drawAxisLineEnabled = false let XValues = (0.. String in return "\(i)" } xAxis.valueFormatter = IndexAxisValueFormatter(values: XValues) xAxis.labelCount = 5 xAxis.enabled = false xAxis.axisMinimum = -Double(stepCadenceArray.count)/20 xAxis.axisMaximum = Double(stepCadenceArray.count)-1 + Double(stepCadenceArray.count)/20 var dataEntries = [ChartDataEntry]() for (i, cadence) in stepCadenceArray.enumerated() { if cadence > 0 { dataEntries.append(ChartDataEntry(x: Double(i), y: Double(cadence))) } } let dataSet = LineChartDataSet(entries: dataEntries) dataSet.drawCirclesEnabled = false dataSet.drawValuesEnabled = false dataSet.highlightEnabled = false//选中拐点,是否开启高亮效果(显示十字线) dataSet.highlightLineWidth = 1 dataSet.highlightColor = UIColor.rgbColorFromHex(0xD90009)// 十字线颜色 dataSet.drawHorizontalHighlightIndicatorEnabled = false dataSet.mode = .horizontalBezier dataSet.setColor(UIColor.rgbColorFromHex(0xE8AF1C)) dataSet.lineWidth = 1 dataSet.drawFilledEnabled = true //填充绘制 let gradientColors = [UIColor.rgbColorFromHex(0xFFCE12).cgColor, UIColor.rgbColorFromHex(0xFFFEFB).cgColor] let gradient = CGGradient(colorsSpace: nil, colors: gradientColors as CFArray, locations: [1.0, 0.0]) dataSet.fillAlpha = 1 dataSet.fill = Fill(linearGradient: gradient!, angle: 90) stepChartView.data = LineChartData(dataSets: [dataSet]) } private func setupAltitudeChartView() { if altitudeArray.count < 2 { return } altitudeChartView.chartDescription?.enabled = false //图描述 altitudeChartView.legend.enabled = false //左下角图例 altitudeChartView.setScaleEnabled(false) //可滑动 altitudeChartView.rightAxis.enabled = false //不绘制右边轴的信息 let leftAxis = altitudeChartView.leftAxis leftAxis.labelTextColor = ChartsTextColor leftAxis.labelFont = ChartsTextFont(11) leftAxis.yOffset = -5 leftAxis.xOffset = -1 leftAxis.gridLineDashLengths = [2.0, 2.0] //设置虚线样式的网格线 leftAxis.gridColor = LineColor leftAxis.gridLineWidth = 1 leftAxis.axisLineWidth = 0 leftAxis.drawGridLinesBehindDataEnabled = false leftAxis.labelPosition = .insideChart let space = altitude/10 leftAxis.axisMinimum = min((altitudeArray.min() ?? space) - space, 0)//设置左侧Y轴最小值 leftAxis.axisMaximum = max(altitudeArray.max() ?? 100 + space, 100) leftAxis.granularity = 60 let litmitLine = ChartLimitLine(limit: 0, label: "") litmitLine.lineWidth = 1 litmitLine.lineColor = LineColor leftAxis.addLimitLine(litmitLine) leftAxis.drawLimitLinesBehindDataEnabled = false //设置限制线绘制在折线图的后面 let xAxis = altitudeChartView.xAxis xAxis.granularity = 1 //间隔 xAxis.labelPosition = .bottom xAxis.labelFont = ChartsTextFont(11) xAxis.labelTextColor = ChartsTextColor xAxis.drawGridLinesBehindDataEnabled = false xAxis.axisLineColor = LineColor xAxis.axisLineWidth = 1 xAxis.gridLineDashLengths = [6, 666] xAxis.gridColor = LineColor xAxis.drawAxisLineEnabled = false let XValues = (0.. String in return "\(i)" } xAxis.valueFormatter = IndexAxisValueFormatter(values: XValues) xAxis.labelCount = 5 xAxis.enabled = false xAxis.axisMinimum = -Double(altitudeArray.count)/20 xAxis.axisMaximum = Double(altitudeArray.count)-1 + Double(altitudeArray.count)/20 var dataEntries = [ChartDataEntry]() for (i, altitude) in altitudeArray.enumerated() { // if altitude > 0 { dataEntries.append(ChartDataEntry(x: Double(i), y: altitude)) // } } let dataSet = LineChartDataSet(entries: dataEntries) dataSet.drawCirclesEnabled = false dataSet.drawValuesEnabled = false dataSet.highlightEnabled = false//选中拐点,是否开启高亮效果(显示十字线) dataSet.highlightLineWidth = 1 dataSet.highlightColor = UIColor.rgbColorFromHex(0xD90009)// 十字线颜色 dataSet.drawHorizontalHighlightIndicatorEnabled = false dataSet.mode = .horizontalBezier dataSet.setColor(UIColor.rgbColorFromHex(0x08BBB2)) dataSet.lineWidth = 1 dataSet.drawFilledEnabled = true //填充绘制 let gradientColors = [UIColor.rgbColorFromHex(0x12DDE1).cgColor, UIColor.rgbColorFromHex(0xFFFEFB).cgColor] let gradient = CGGradient(colorsSpace: nil, colors: gradientColors as CFArray, locations: [1.0, 0.0]) dataSet.fillAlpha = 1 dataSet.fill = Fill(linearGradient: gradient!, angle: 90) altitudeChartView.data = LineChartData(dataSets: [dataSet]) } deinit { print("deinit\(NSStringFromClass(type(of: self)))!!!!!!!") } } extension EndMotionVC: UIScrollViewDelegate { func scrollViewDidScroll(_ scrollView: UIScrollView) { // print(scr) } } extension EndMotionVC: MAMapViewDelegate { func mapView(_ mapView: MAMapView!, rendererFor overlay: MAOverlay!) -> MAOverlayRenderer! { if let poly = overlay as? MAPolyline { let polylineView = MAPolylineRenderer(polyline: poly) polylineView!.lineWidth = 6 polylineView!.strokeColor = UIColor(red: 4 / 255.0, green: 181 / 255.0, blue: 108 / 255.0, alpha: 1.0) polylineView!.lineJoinType = kMALineJoinRound polylineView!.lineCapType = kMALineCapRound return polylineView } else { return nil } } func mapView(_ mapView: MAMapView!, viewFor annotation: MAAnnotation!) -> MAAnnotationView! { if annotation is MAPointAnnotation { let pointReuseIndetifier = "pointReuseIndetifier" // let customAnnotation = annotation as! CustomPointAnnotation var annotationView: MAAnnotationView? = mapView.dequeueReusableAnnotationView(withIdentifier: pointReuseIndetifier) if annotationView == nil { annotationView = MAAnnotationView(annotation: annotation, reuseIdentifier: pointReuseIndetifier) } if annotation.title == "起点" { annotationView?.image = UIImage(named: "start_point") } if annotation.title == "终点" { annotationView?.image = UIImage(named: "stop_point") } annotationView?.centerOffset = CGPoint(x: 0, y: -7.5); return annotationView } return nil } }