doughnut chart model added
doughnut chart view added doughnut chart added
This commit is contained in:
parent
99b97fd934
commit
396c22f243
@ -67,6 +67,9 @@
|
|||||||
94C2D9A723872DA90006CF46 /* LabelAttributeColorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C2D9A623872DA90006CF46 /* LabelAttributeColorModel.swift */; };
|
94C2D9A723872DA90006CF46 /* LabelAttributeColorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C2D9A623872DA90006CF46 /* LabelAttributeColorModel.swift */; };
|
||||||
94C2D9A923872E5E0006CF46 /* LabelAttributeImageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C2D9A823872E5E0006CF46 /* LabelAttributeImageModel.swift */; };
|
94C2D9A923872E5E0006CF46 /* LabelAttributeImageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C2D9A823872E5E0006CF46 /* LabelAttributeImageModel.swift */; };
|
||||||
94C2D9AB23872EB50006CF46 /* LabelAttributeActionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C2D9AA23872EB50006CF46 /* LabelAttributeActionModel.swift */; };
|
94C2D9AB23872EB50006CF46 /* LabelAttributeActionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94C2D9AA23872EB50006CF46 /* LabelAttributeActionModel.swift */; };
|
||||||
|
C695A69423C9909000BFB94E /* DoughnutChartModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C695A69323C9909000BFB94E /* DoughnutChartModel.swift */; };
|
||||||
|
C695A69623C990BC00BFB94E /* DoughnutChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = C695A69523C990BC00BFB94E /* DoughnutChart.swift */; };
|
||||||
|
C695A69823C990C200BFB94E /* DoughnutChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C695A69723C990C200BFB94E /* DoughnutChartView.swift */; };
|
||||||
D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */; };
|
D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */; };
|
||||||
D213347723843825008E41B3 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = D213347623843825008E41B3 /* Line.swift */; };
|
D213347723843825008E41B3 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = D213347623843825008E41B3 /* Line.swift */; };
|
||||||
D21EE53C23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21EE53B23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift */; };
|
D21EE53C23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21EE53B23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift */; };
|
||||||
@ -307,6 +310,9 @@
|
|||||||
94C2D9A623872DA90006CF46 /* LabelAttributeColorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelAttributeColorModel.swift; sourceTree = "<group>"; };
|
94C2D9A623872DA90006CF46 /* LabelAttributeColorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelAttributeColorModel.swift; sourceTree = "<group>"; };
|
||||||
94C2D9A823872E5E0006CF46 /* LabelAttributeImageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelAttributeImageModel.swift; sourceTree = "<group>"; };
|
94C2D9A823872E5E0006CF46 /* LabelAttributeImageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelAttributeImageModel.swift; sourceTree = "<group>"; };
|
||||||
94C2D9AA23872EB50006CF46 /* LabelAttributeActionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelAttributeActionModel.swift; sourceTree = "<group>"; };
|
94C2D9AA23872EB50006CF46 /* LabelAttributeActionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelAttributeActionModel.swift; sourceTree = "<group>"; };
|
||||||
|
C695A69323C9909000BFB94E /* DoughnutChartModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DoughnutChartModel.swift; sourceTree = "<group>"; };
|
||||||
|
C695A69523C990BC00BFB94E /* DoughnutChart.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DoughnutChart.swift; sourceTree = "<group>"; };
|
||||||
|
C695A69723C990C200BFB94E /* DoughnutChartView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DoughnutChartView.swift; sourceTree = "<group>"; };
|
||||||
D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = "<group>"; };
|
D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = "<group>"; };
|
||||||
D213347623843825008E41B3 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = "<group>"; };
|
D213347623843825008E41B3 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = "<group>"; };
|
||||||
D21EE53B23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSLayoutConstraintAxis+Extension.swift"; sourceTree = "<group>"; };
|
D21EE53B23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSLayoutConstraintAxis+Extension.swift"; sourceTree = "<group>"; };
|
||||||
@ -530,6 +536,7 @@
|
|||||||
01EB368723609801006832FA /* Molecules */ = {
|
01EB368723609801006832FA /* Molecules */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
C695A69323C9909000BFB94E /* DoughnutChartModel.swift */,
|
||||||
01EB368923609801006832FA /* ListItemModel.swift */,
|
01EB368923609801006832FA /* ListItemModel.swift */,
|
||||||
01EB368A23609801006832FA /* MoleculeStackItemModel.swift */,
|
01EB368A23609801006832FA /* MoleculeStackItemModel.swift */,
|
||||||
01EB368B23609801006832FA /* MoleculeStackModel.swift */,
|
01EB368B23609801006832FA /* MoleculeStackModel.swift */,
|
||||||
@ -542,6 +549,14 @@
|
|||||||
path = Molecules;
|
path = Molecules;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
0A5D59C323AD488600EFD9E9 /* Protocols */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */,
|
||||||
|
);
|
||||||
|
path = Protocols;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
0AA33B322398134B0067DD0F /* Primitive Models */ = {
|
0AA33B322398134B0067DD0F /* Primitive Models */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -580,14 +595,6 @@
|
|||||||
name = "Recovered References";
|
name = "Recovered References";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
0A5D59C323AD488600EFD9E9 /* Protocols */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */,
|
|
||||||
);
|
|
||||||
path = Protocols;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
D213347423842FE3008E41B3 /* Controllers */ = {
|
D213347423842FE3008E41B3 /* Controllers */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -785,6 +792,8 @@
|
|||||||
D2FB151A23A2B65B00C20E10 /* MoleculeContainer.swift */,
|
D2FB151A23A2B65B00C20E10 /* MoleculeContainer.swift */,
|
||||||
017BEB47236230DB0024EF95 /* MoleculeViewProtocol.swift */,
|
017BEB47236230DB0024EF95 /* MoleculeViewProtocol.swift */,
|
||||||
017BEB49236235BA0024EF95 /* ModelMoleculeViewProtocol.swift */,
|
017BEB49236235BA0024EF95 /* ModelMoleculeViewProtocol.swift */,
|
||||||
|
C695A69523C990BC00BFB94E /* DoughnutChart.swift */,
|
||||||
|
C695A69723C990C200BFB94E /* DoughnutChartView.swift */,
|
||||||
);
|
);
|
||||||
path = Molecules;
|
path = Molecules;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1296,6 +1305,7 @@
|
|||||||
D2A5145F2211DDC100345BFB /* MoleculeStackView.swift in Sources */,
|
D2A5145F2211DDC100345BFB /* MoleculeStackView.swift in Sources */,
|
||||||
D29DF27621E79E81003B2FB9 /* MVMCoreUILoggingHandler.m in Sources */,
|
D29DF27621E79E81003B2FB9 /* MVMCoreUILoggingHandler.m in Sources */,
|
||||||
D29DF24D21E6A177003B2FB9 /* MFTextField.m in Sources */,
|
D29DF24D21E6A177003B2FB9 /* MFTextField.m in Sources */,
|
||||||
|
C695A69623C990BC00BFB94E /* DoughnutChart.swift in Sources */,
|
||||||
94C2D9AB23872EB50006CF46 /* LabelAttributeActionModel.swift in Sources */,
|
94C2D9AB23872EB50006CF46 /* LabelAttributeActionModel.swift in Sources */,
|
||||||
017BEB4023620A230024EF95 /* TextFieldModel.swift in Sources */,
|
017BEB4023620A230024EF95 /* TextFieldModel.swift in Sources */,
|
||||||
D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */,
|
D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */,
|
||||||
@ -1396,6 +1406,7 @@
|
|||||||
D2B18B922361E65A00A9AEDC /* CoreUIObject.swift in Sources */,
|
D2B18B922361E65A00A9AEDC /* CoreUIObject.swift in Sources */,
|
||||||
D29DF2BE21E7BEA4003B2FB9 /* TopTabbar.m in Sources */,
|
D29DF2BE21E7BEA4003B2FB9 /* TopTabbar.m in Sources */,
|
||||||
D2A514632213643100345BFB /* MoleculeStackCenteredTemplate.swift in Sources */,
|
D2A514632213643100345BFB /* MoleculeStackCenteredTemplate.swift in Sources */,
|
||||||
|
C695A69423C9909000BFB94E /* DoughnutChartModel.swift in Sources */,
|
||||||
D29DF32421ED0DA2003B2FB9 /* TextButtonView.m in Sources */,
|
D29DF32421ED0DA2003B2FB9 /* TextButtonView.m in Sources */,
|
||||||
D29DF29E21E7AE3B003B2FB9 /* MFStyler.m in Sources */,
|
D29DF29E21E7AE3B003B2FB9 /* MFStyler.m in Sources */,
|
||||||
D2A514592211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.m in Sources */,
|
D2A514592211C53C00345BFB /* MVMCoreUIMoleculeMappingObject.m in Sources */,
|
||||||
@ -1404,6 +1415,7 @@
|
|||||||
0105618D224BBE7700E1557D /* FormValidator.swift in Sources */,
|
0105618D224BBE7700E1557D /* FormValidator.swift in Sources */,
|
||||||
01509D912327ECE600EF99AA /* CornerLabels.swift in Sources */,
|
01509D912327ECE600EF99AA /* CornerLabels.swift in Sources */,
|
||||||
D22D1F1B220341F60077CEC0 /* MVMCoreUICheckBox.m in Sources */,
|
D22D1F1B220341F60077CEC0 /* MVMCoreUICheckBox.m in Sources */,
|
||||||
|
C695A69823C990C200BFB94E /* DoughnutChartView.swift in Sources */,
|
||||||
D29DF2CB21E7BFCC003B2FB9 /* MFSizeThreshold.m in Sources */,
|
D29DF2CB21E7BFCC003B2FB9 /* MFSizeThreshold.m in Sources */,
|
||||||
946EE1BA237B66D80036751F /* ModelHelper.swift in Sources */,
|
946EE1BA237B66D80036751F /* ModelHelper.swift in Sources */,
|
||||||
01509D932327ECFB00EF99AA /* ProgressBar.swift in Sources */,
|
01509D932327ECFB00EF99AA /* ProgressBar.swift in Sources */,
|
||||||
|
|||||||
85
MVMCoreUI/Models/Molecules/DoughnutChartModel.swift
Normal file
85
MVMCoreUI/Models/Molecules/DoughnutChartModel.swift
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
//
|
||||||
|
// DoughnutChartModel.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Murugan, Vimal on 10/01/20.
|
||||||
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
@objcMembers public class DoughnutChartModel: MoleculeProtocol {
|
||||||
|
|
||||||
|
public var backgroundColor: String?
|
||||||
|
public static var identifier: String = "doughnutChart"
|
||||||
|
public var title: LabelModel?
|
||||||
|
public var subtitle: LabelModel?
|
||||||
|
public var sections: [ChartItemModel]
|
||||||
|
public var lineWidth: CGFloat = 30.0
|
||||||
|
public var lineGap: CGFloat = 0.05 //For 3px gap
|
||||||
|
public var spaceRequired = true
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case list
|
||||||
|
case title
|
||||||
|
case subtitle
|
||||||
|
case sections
|
||||||
|
}
|
||||||
|
|
||||||
|
required public init(from decoder: Decoder) throws {
|
||||||
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
self.title = try typeContainer.decodeMoleculeIfPresent(codingKey: .title) as? LabelModel
|
||||||
|
self.subtitle = try typeContainer.decodeMoleculeIfPresent(codingKey: .subtitle) as? LabelModel
|
||||||
|
//self.sections = try typeContainer.decodeMolecules(codingKey: .sections) as! [ChartItemModel]
|
||||||
|
|
||||||
|
//TODO: Hasve to check with scott
|
||||||
|
self.sections = []
|
||||||
|
guard var container = try? typeContainer.nestedUnkeyedContainer(forKey: .sections) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var sections = [ChartItemModel]()
|
||||||
|
while !container.isAtEnd {
|
||||||
|
if let element = try container
|
||||||
|
.decodeIfPresent(ChartItemModel.self) {
|
||||||
|
sections.append(element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.sections = sections
|
||||||
|
}
|
||||||
|
|
||||||
|
public func encode(to encoder: Encoder) throws {
|
||||||
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
|
try container.encodeModelIfPresent(title, forKey: .title)
|
||||||
|
try container.encodeModelIfPresent(subtitle, forKey: .subtitle)
|
||||||
|
try container.encodeModels(sections as [Model], forKey: .sections)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@objcMembers public class ChartItemModel: MoleculeProtocol {
|
||||||
|
public var backgroundColor: String?
|
||||||
|
public var label: LabelModel
|
||||||
|
public var percent: CGFloat
|
||||||
|
public var color: String
|
||||||
|
public static var identifier: String = "chartItem"
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case label
|
||||||
|
case percent
|
||||||
|
case color
|
||||||
|
}
|
||||||
|
|
||||||
|
required public init(from decoder: Decoder) throws {
|
||||||
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
self.label = try typeContainer.decodeMolecule(codingKey: .label) as! LabelModel
|
||||||
|
self.percent = try typeContainer.decode(CGFloat.self, forKey: .percent)
|
||||||
|
self.color = try typeContainer.decode(String.self, forKey: .color)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func encode(to encoder: Encoder) throws {
|
||||||
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
|
try container.encodeModel(label, forKey: .label)
|
||||||
|
try container.encode(percent, forKey: .percent)
|
||||||
|
try container.encode(color, forKey: .color)
|
||||||
|
}
|
||||||
|
}
|
||||||
179
MVMCoreUI/Molecules/DoughnutChart.swift
Normal file
179
MVMCoreUI/Molecules/DoughnutChart.swift
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
//
|
||||||
|
// DoughnutChart.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Murugan, Vimal on 07/01/20.
|
||||||
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
open class DoughnutChart: View, MVMCoreUIViewConstrainingProtocol {
|
||||||
|
|
||||||
|
var containerView = MVMCoreUICommonViewsUtility.commonView()
|
||||||
|
var containerLayer = CALayer()
|
||||||
|
var titleLabel = Label.commonLabelH3(true)
|
||||||
|
var subTitleLabel = Label.commonLabelB2(true)
|
||||||
|
var doughnutChartModel: DoughnutChartModel? {
|
||||||
|
get { return model as? DoughnutChartModel }
|
||||||
|
}
|
||||||
|
var labelContainer = ViewConstrainingView.empty()
|
||||||
|
var heightConstraint: NSLayoutConstraint?
|
||||||
|
|
||||||
|
private var sizeObject = MFStyler.sizeObjectGeneric(forCurrentDevice: 150)!
|
||||||
|
//private var lineSizeObject = MFStyler.sizeObjectGeneric(forCurrentDevice: 30)!
|
||||||
|
|
||||||
|
var height: CGFloat = 150 {
|
||||||
|
didSet {
|
||||||
|
if height != oldValue {
|
||||||
|
sizeObject = MFStyler.sizeObjectGeneric(forCurrentDevice: height)!
|
||||||
|
updateContainer()
|
||||||
|
drawGraph()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func updateView(_ size: CGFloat) {
|
||||||
|
super.updateView(size)
|
||||||
|
titleLabel.updateView(size)
|
||||||
|
subTitleLabel.updateView(size)
|
||||||
|
updateContainer()
|
||||||
|
drawGraph()
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func reset() {
|
||||||
|
super.reset()
|
||||||
|
titleLabel.reset()
|
||||||
|
subTitleLabel.reset()
|
||||||
|
clearLayers()
|
||||||
|
}
|
||||||
|
|
||||||
|
public func setAsMolecule() {
|
||||||
|
titleLabel.setAsMolecule()
|
||||||
|
subTitleLabel.setAsMolecule()
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func setupView() {
|
||||||
|
super.setupView()
|
||||||
|
guard containerView.superview == nil else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
addSubview(containerView)
|
||||||
|
addSubview(labelContainer)
|
||||||
|
|
||||||
|
labelContainer.addSubview(titleLabel)
|
||||||
|
labelContainer.addSubview(subTitleLabel)
|
||||||
|
titleLabel.textAlignment = .center
|
||||||
|
subTitleLabel.textAlignment = .center
|
||||||
|
|
||||||
|
//Make label font size to adjust width if label content is high
|
||||||
|
titleLabel.numberOfLines = 1
|
||||||
|
titleLabel.adjustsFontSizeToFitWidth = true
|
||||||
|
|
||||||
|
containerView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
|
||||||
|
containerView.topAnchor.constraint(equalTo: topAnchor).isActive = true
|
||||||
|
bottomAnchor.constraint(equalTo: containerView.bottomAnchor).isActive = true
|
||||||
|
trailingAnchor.constraint(equalTo: containerView.trailingAnchor).isActive = true
|
||||||
|
containerView.layer.addSublayer(containerLayer)
|
||||||
|
heightConstraint = containerView.heightAnchor.constraint(equalToConstant:
|
||||||
|
sizeObject.getValueBasedOnApplicationWidth())
|
||||||
|
heightConstraint?.isActive = true
|
||||||
|
containerView.widthAnchor.constraint(equalTo: containerView.heightAnchor).isActive = true
|
||||||
|
|
||||||
|
labelContainer.leftPin = labelContainer.leftAnchor.constraint(greaterThanOrEqualTo: containerView.leftAnchor, constant: lineWidth())
|
||||||
|
labelContainer.leftPin?.isActive = true
|
||||||
|
labelContainer.topPin = labelContainer.topAnchor.constraint(greaterThanOrEqualTo: containerView.topAnchor, constant: lineWidth())
|
||||||
|
labelContainer.topPin?.isActive = true
|
||||||
|
labelContainer.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true
|
||||||
|
labelContainer.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
|
||||||
|
|
||||||
|
NSLayoutConstraint.constraintPinSubview(titleLabel, pinTop: true, pinBottom: false, pinLeft: true, pinRight: true)
|
||||||
|
NSLayoutConstraint.constraintPinSubview(subTitleLabel, pinTop: false, pinBottom: true, pinLeft: true, pinRight: true)
|
||||||
|
_ = NSLayoutConstraint(pinFirstView: titleLabel, toSecondView: subTitleLabel, withConstant: 0, directionVertical: true)
|
||||||
|
//Rotate view for initial draw
|
||||||
|
containerLayer.transform = CATransform3DMakeRotation(1 * .pi, 0.0, 0.0, 1.0)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) {
|
||||||
|
super.setWithModel(model, delegateObject, additionalData)
|
||||||
|
clearLayers()
|
||||||
|
guard let doughnutChartModel = model as? DoughnutChartModel else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
titleLabel.setWithModel(doughnutChartModel.title, delegateObject, additionalData)
|
||||||
|
subTitleLabel.setWithModel(doughnutChartModel.subtitle, delegateObject, additionalData)
|
||||||
|
titleLabel.textAlignment = .center
|
||||||
|
subTitleLabel.textAlignment = .center
|
||||||
|
//lineSizeObject = MFStyler.sizeObjectGeneric(forCurrentDevice: doughnutChartModel.lineWidth)!
|
||||||
|
updateLabelContainer()
|
||||||
|
drawGraph()
|
||||||
|
}
|
||||||
|
|
||||||
|
func drawGraph() {
|
||||||
|
clearLayers()
|
||||||
|
let widthHeight = sizeObject.getValueBasedOnApplicationWidth()
|
||||||
|
containerLayer.frame = CGRect(x: 0, y: 0,
|
||||||
|
width: widthHeight,
|
||||||
|
height: widthHeight)
|
||||||
|
if let doughnutChart = doughnutChartModel {
|
||||||
|
var prevPercent: CGFloat = 0.0
|
||||||
|
//If Single item in array. We don't need gap
|
||||||
|
doughnutChartModel?.lineGap = (doughnutChart.sections.count == 1) ? 0.0 : doughnutChart.lineGap
|
||||||
|
for model in doughnutChart.sections {
|
||||||
|
prevPercent += drawBar(model, prevPercent, doughnutChart.spaceRequired, doughnutChart.lineGap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func drawBar(_ chartModel: ChartItemModel, _ prevPercent: CGFloat, _ spaceRequired: Bool, _ lineGap: CGFloat) -> CGFloat {
|
||||||
|
|
||||||
|
let shapeLayer = CAShapeLayer()
|
||||||
|
shapeLayer.frame = containerLayer.frame
|
||||||
|
shapeLayer.lineWidth = lineWidth()
|
||||||
|
//lineSizeObject.getValueBasedOnApplicationWidth()
|
||||||
|
shapeLayer.fillColor = nil
|
||||||
|
shapeLayer.strokeColor = UIColor.mfGet(forHex: chartModel.color).cgColor
|
||||||
|
|
||||||
|
let arcCenter = shapeLayer.position
|
||||||
|
let radius = shapeLayer.bounds.size.width / 2.0 - lineWidth()/2.0
|
||||||
|
//lineSizeObject.getValueBasedOnApplicationWidth() / 2.0
|
||||||
|
let clockwise = true
|
||||||
|
|
||||||
|
let value: CGFloat = chartModel.percent
|
||||||
|
let gap: CGFloat = spaceRequired ? lineGap : 0.0
|
||||||
|
let startAngle = ((prevPercent / 100.0) * 2 * .pi) - (0.5 * .pi)
|
||||||
|
let endAngle = ((value / 100.0) * 2 * .pi) + startAngle - gap
|
||||||
|
let circlePath = UIBezierPath(arcCenter: arcCenter,
|
||||||
|
radius: radius,
|
||||||
|
startAngle: startAngle,
|
||||||
|
endAngle: endAngle,
|
||||||
|
clockwise: clockwise)
|
||||||
|
|
||||||
|
shapeLayer.path = circlePath.cgPath
|
||||||
|
containerLayer.addSublayer(shapeLayer)
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
func clearLayers() {
|
||||||
|
containerLayer.sublayers?.forEach({ $0.removeFromSuperlayer() })
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateContainer() {
|
||||||
|
heightConstraint?.constant = sizeObject.getValueBasedOnApplicationWidth()
|
||||||
|
updateLabelContainer()
|
||||||
|
setNeedsDisplay()
|
||||||
|
}
|
||||||
|
|
||||||
|
func lineWidth() -> CGFloat {
|
||||||
|
return doughnutChartModel?.lineWidth ?? 30
|
||||||
|
//lineSizeObject.getValueBasedOnApplicationWidth() + 5
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateLabelContainer() {
|
||||||
|
labelContainer.leftPin?.constant = lineWidth()
|
||||||
|
labelContainer.topPin?.constant = lineWidth()
|
||||||
|
labelContainer.setNeedsDisplay()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
179
MVMCoreUI/Molecules/DoughnutChartView.swift
Normal file
179
MVMCoreUI/Molecules/DoughnutChartView.swift
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
//
|
||||||
|
// DoughnutChartView.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Murugan, Vimal on 26/12/19.
|
||||||
|
// Copyright © 2019 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
@objcMembers open class DoughnutChartView: View {
|
||||||
|
|
||||||
|
var doughnutChart = DoughnutChart(frame: CGRect.zero)
|
||||||
|
var colorLablesStack = ColorViewLabelsStack()
|
||||||
|
var container = MVMCoreUICommonViewsUtility.commonView()
|
||||||
|
var doughnutChartModel: DoughnutChartModel? {
|
||||||
|
get { return model as? DoughnutChartModel }
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func setupView() {
|
||||||
|
super.setupView()
|
||||||
|
guard container.superview == nil else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
addSubview(container)
|
||||||
|
doughnutChart.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
container.addSubview(doughnutChart)
|
||||||
|
colorLablesStack.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
container.addSubview(colorLablesStack)
|
||||||
|
|
||||||
|
NSLayoutConstraint.constraintPinSubview(container, pinTop: true, pinBottom: true, pinLeft: true, pinRight: true)
|
||||||
|
doughnutChart.leadingAnchor.constraint(equalTo: container.leadingAnchor).isActive = true
|
||||||
|
doughnutChart.topAnchor.constraint(equalTo: container.topAnchor, constant: PaddingFour).isActive = true
|
||||||
|
container.bottomAnchor.constraint(greaterThanOrEqualTo: doughnutChart.bottomAnchor).isActive = true
|
||||||
|
|
||||||
|
let containerBottomAnchor = container.bottomAnchor.constraint(equalTo: doughnutChart.bottomAnchor)
|
||||||
|
containerBottomAnchor.priority = UILayoutPriority(rawValue: 200)
|
||||||
|
containerBottomAnchor.isActive = true
|
||||||
|
|
||||||
|
let colorLablesBottomAnchor = container.bottomAnchor.constraint(equalTo: colorLablesStack.bottomAnchor)
|
||||||
|
colorLablesBottomAnchor.priority = UILayoutPriority(rawValue: 204)
|
||||||
|
colorLablesBottomAnchor.isActive = true
|
||||||
|
|
||||||
|
let colorLablesTopAnchor = colorLablesStack.topAnchor.constraint(equalTo: doughnutChart.topAnchor)
|
||||||
|
colorLablesTopAnchor.priority = UILayoutPriority(rawValue: 204)
|
||||||
|
colorLablesTopAnchor.isActive = true
|
||||||
|
|
||||||
|
colorLablesStack.topAnchor.constraint(greaterThanOrEqualTo: doughnutChart.topAnchor).isActive = true
|
||||||
|
container.bottomAnchor.constraint(greaterThanOrEqualTo: colorLablesStack.bottomAnchor).isActive = true
|
||||||
|
container.trailingAnchor.constraint(greaterThanOrEqualTo: colorLablesStack.trailingAnchor).isActive = true
|
||||||
|
|
||||||
|
let centerY = colorLablesStack.centerYAnchor.constraint(equalTo: doughnutChart.centerYAnchor)
|
||||||
|
centerY.priority = .defaultLow
|
||||||
|
centerY.isActive = true
|
||||||
|
|
||||||
|
colorLablesStack.leadingAnchor.constraint(equalTo: doughnutChart.trailingAnchor, constant: PaddingThree).isActive = true
|
||||||
|
colorLablesStack.backgroundColor = UIColor.clear
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func updateView(_ size: CGFloat) {
|
||||||
|
super.updateView(size)
|
||||||
|
doughnutChart.updateView(size)
|
||||||
|
colorLablesStack.updateView(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func reset() {
|
||||||
|
super.reset()
|
||||||
|
colorLablesStack.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) {
|
||||||
|
super.setWithModel(model, delegateObject, additionalData)
|
||||||
|
doughnutChart.clearLayers()
|
||||||
|
colorLablesStack.removeAllItemViews()
|
||||||
|
doughnutChart.setWithModel(model, delegateObject, additionalData)
|
||||||
|
colorLablesStack.setWithModel(model, delegateObject, additionalData)
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
|
||||||
|
if model == nil {
|
||||||
|
let data = try! JSONSerialization.data(withJSONObject: json!)
|
||||||
|
let decoder = JSONDecoder()
|
||||||
|
let model = try! decoder.decode(DoughnutChartModel.self, from: data)
|
||||||
|
setWithModel(model, delegateObject, additionalData as? [String : AnyHashable])
|
||||||
|
} else {
|
||||||
|
setWithModel(model, delegateObject, additionalData as? [String : AnyHashable])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class ColorViewLabelsStack: MoleculeStackView {
|
||||||
|
|
||||||
|
var dougnutChartModel: DoughnutChartModel?
|
||||||
|
|
||||||
|
override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) {
|
||||||
|
let previousModel = self.dougnutChartModel
|
||||||
|
removeAllItemViews()
|
||||||
|
guard let dougnutChartModel = model as? DoughnutChartModel else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var items: [StackItem]?
|
||||||
|
if previousModel?.sections.count == dougnutChartModel.sections.count {
|
||||||
|
items = stackItems
|
||||||
|
}
|
||||||
|
stackItems = []
|
||||||
|
self.model = MoleculeStackModel(molecules: [])
|
||||||
|
for (index, chartItemModel) in dougnutChartModel.sections.enumerated() {
|
||||||
|
let colorViewWithLabel = items?[index].view as? ColorViewWithLabel ?? ColorViewWithLabel()
|
||||||
|
colorViewWithLabel.setWithModel(chartItemModel, delegateObject, additionalData)
|
||||||
|
addView(colorViewWithLabel, lastItem: index == dougnutChartModel.sections.count - 1)
|
||||||
|
}
|
||||||
|
self.dougnutChartModel = dougnutChartModel
|
||||||
|
restack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ColorViewWithLabel: View, MVMCoreUIViewConstrainingProtocol {
|
||||||
|
|
||||||
|
var label = Label.commonLabelB2(true)
|
||||||
|
var colorView = MVMCoreUICommonViewsUtility.commonView()
|
||||||
|
private var sizeObject = MFStyler.sizeObjectGeneric(forCurrentDevice: 8)!
|
||||||
|
var heightConstraint: NSLayoutConstraint?
|
||||||
|
|
||||||
|
override func setupView() {
|
||||||
|
super.setupView()
|
||||||
|
guard colorView.superview == nil else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
addSubview(colorView)
|
||||||
|
addSubview(label)
|
||||||
|
|
||||||
|
heightConstraint = colorView.heightAnchor.constraint(equalToConstant: sizeObject.getValueBasedOnApplicationWidth())
|
||||||
|
heightConstraint?.isActive = true
|
||||||
|
colorView.widthAnchor.constraint(equalTo: colorView.heightAnchor).isActive = true
|
||||||
|
colorView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
|
||||||
|
colorView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
|
||||||
|
|
||||||
|
label.leadingAnchor.constraint(equalTo: colorView.trailingAnchor, constant: PaddingOne).isActive = true
|
||||||
|
label.topAnchor.constraint(equalTo: topAnchor).isActive = true
|
||||||
|
trailingAnchor.constraint(greaterThanOrEqualTo: label.trailingAnchor).isActive = true
|
||||||
|
bottomAnchor.constraint(equalTo: label.bottomAnchor).isActive = true
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override func updateView(_ size: CGFloat) {
|
||||||
|
super.updateView(size)
|
||||||
|
label.updateView(size)
|
||||||
|
heightConstraint?.constant = sizeObject.getValueBased(onSize: size)
|
||||||
|
setNeedsDisplay()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func reset() {
|
||||||
|
super.reset()
|
||||||
|
label.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setAsMolecule() {
|
||||||
|
label.setAsMolecule()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func setWithModel(_ model: MoleculeProtocol?, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [String : AnyHashable]?) {
|
||||||
|
super.setWithModel(model, delegateObject, additionalData)
|
||||||
|
guard let chartItemModel = model as? ChartItemModel else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
label.setWithModel(chartItemModel.label, delegateObject, additionalData)
|
||||||
|
colorView.backgroundColor = UIColor.mfGet(forHex: chartItemModel.color)
|
||||||
|
}
|
||||||
|
|
||||||
|
override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) {
|
||||||
|
Label.setUILabel(label, withJSON: json?.optionalDictionaryForKey("label"), delegate: delegateObject, additionalData: additionalData)
|
||||||
|
colorView.backgroundColor = UIColor.mfGet(forHex: json?.optionalStringForKey("color") ?? "#000000")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -68,7 +68,8 @@
|
|||||||
@"dropDownListItem": DropDownFilterTableViewCell.class,
|
@"dropDownListItem": DropDownFilterTableViewCell.class,
|
||||||
@"headlineBodyButton": HeadlineBodyButton.class,
|
@"headlineBodyButton": HeadlineBodyButton.class,
|
||||||
@"eyebrowHeadlineBodyLink": EyebrowHeadlineBodyLink.class,
|
@"eyebrowHeadlineBodyLink": EyebrowHeadlineBodyLink.class,
|
||||||
@"stackItem": StackItem.class
|
@"stackItem": StackItem.class,
|
||||||
|
@"doughnutChart": DoughnutChartView.class
|
||||||
} mutableCopy];
|
} mutableCopy];
|
||||||
});
|
});
|
||||||
return mapping;
|
return mapping;
|
||||||
|
|||||||
@ -29,5 +29,6 @@ import Foundation
|
|||||||
ModelRegistry.register(LabelAttributeUnderlineModel.self)
|
ModelRegistry.register(LabelAttributeUnderlineModel.self)
|
||||||
ModelRegistry.register(LabelAttributeStrikeThroughModel.self)
|
ModelRegistry.register(LabelAttributeStrikeThroughModel.self)
|
||||||
ModelRegistry.register(LabelAttributeActionModel.self)
|
ModelRegistry.register(LabelAttributeActionModel.self)
|
||||||
|
ModelRegistry.register(DoughnutChartModel.self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user