cleaning and revising donut
This commit is contained in:
parent
d96aa1c310
commit
d9337cadff
@ -91,6 +91,8 @@
|
|||||||
0A6BF4722360C56C0028F841 /* BaseDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */; };
|
0A6BF4722360C56C0028F841 /* BaseDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */; };
|
||||||
0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */; };
|
0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */; };
|
||||||
0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; };
|
0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; };
|
||||||
|
0A7ECC5D243CE85300C828E8 /* DoughnutChartItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7ECC5C243CE85300C828E8 /* DoughnutChartItemModel.swift */; };
|
||||||
|
0A7ECC5F243CEB1200C828E8 /* ColorViewWithLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7ECC5E243CEB1200C828E8 /* ColorViewWithLabel.swift */; };
|
||||||
0A7EF85B23D8A52800B2AAD1 /* EntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF85A23D8A52800B2AAD1 /* EntryFieldModel.swift */; };
|
0A7EF85B23D8A52800B2AAD1 /* EntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF85A23D8A52800B2AAD1 /* EntryFieldModel.swift */; };
|
||||||
0A7EF85D23D8A95600B2AAD1 /* TextEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF85C23D8A95600B2AAD1 /* TextEntryFieldModel.swift */; };
|
0A7EF85D23D8A95600B2AAD1 /* TextEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF85C23D8A95600B2AAD1 /* TextEntryFieldModel.swift */; };
|
||||||
0A7EF85F23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF85E23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift */; };
|
0A7EF85F23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF85E23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift */; };
|
||||||
@ -488,6 +490,8 @@
|
|||||||
0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyButton.swift; sourceTree = "<group>"; };
|
0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyButton.swift; sourceTree = "<group>"; };
|
||||||
0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = "<group>"; };
|
0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = "<group>"; };
|
||||||
0A7BAFA2232BE63400FB8E22 /* CheckboxLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxLabel.swift; sourceTree = "<group>"; };
|
0A7BAFA2232BE63400FB8E22 /* CheckboxLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxLabel.swift; sourceTree = "<group>"; };
|
||||||
|
0A7ECC5C243CE85300C828E8 /* DoughnutChartItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DoughnutChartItemModel.swift; sourceTree = "<group>"; };
|
||||||
|
0A7ECC5E243CEB1200C828E8 /* ColorViewWithLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorViewWithLabel.swift; sourceTree = "<group>"; };
|
||||||
0A7EF85A23D8A52800B2AAD1 /* EntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntryFieldModel.swift; sourceTree = "<group>"; };
|
0A7EF85A23D8A52800B2AAD1 /* EntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntryFieldModel.swift; sourceTree = "<group>"; };
|
||||||
0A7EF85C23D8A95600B2AAD1 /* TextEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEntryFieldModel.swift; sourceTree = "<group>"; };
|
0A7EF85C23D8A95600B2AAD1 /* TextEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEntryFieldModel.swift; sourceTree = "<group>"; };
|
||||||
0A7EF85E23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MdnEntryFieldModel.swift; sourceTree = "<group>"; };
|
0A7EF85E23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MdnEntryFieldModel.swift; sourceTree = "<group>"; };
|
||||||
@ -1340,9 +1344,11 @@
|
|||||||
D260105723CF9CC500764D80 /* Doughnut */ = {
|
D260105723CF9CC500764D80 /* Doughnut */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
0A7ECC5C243CE85300C828E8 /* DoughnutChartItemModel.swift */,
|
||||||
C695A69323C9909000BFB94E /* DoughnutChartModel.swift */,
|
C695A69323C9909000BFB94E /* DoughnutChartModel.swift */,
|
||||||
C695A69523C990BC00BFB94E /* DoughnutChart.swift */,
|
C695A69523C990BC00BFB94E /* DoughnutChart.swift */,
|
||||||
C695A69723C990C200BFB94E /* DoughnutChartView.swift */,
|
C695A69723C990C200BFB94E /* DoughnutChartView.swift */,
|
||||||
|
0A7ECC5E243CEB1200C828E8 /* ColorViewWithLabel.swift */,
|
||||||
);
|
);
|
||||||
path = Doughnut;
|
path = Doughnut;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -2067,6 +2073,7 @@
|
|||||||
D268C70C2386DFFD007F2C1C /* MoleculeStackItemModel.swift in Sources */,
|
D268C70C2386DFFD007F2C1C /* MoleculeStackItemModel.swift in Sources */,
|
||||||
DBEFFA04225A829700230692 /* Label.swift in Sources */,
|
DBEFFA04225A829700230692 /* Label.swift in Sources */,
|
||||||
D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */,
|
D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */,
|
||||||
|
0A7ECC5D243CE85300C828E8 /* DoughnutChartItemModel.swift in Sources */,
|
||||||
0A7EF85F23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift in Sources */,
|
0A7EF85F23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift in Sources */,
|
||||||
011D959B240451E3000E3791 /* RuleRequiredModel.swift in Sources */,
|
011D959B240451E3000E3791 /* RuleRequiredModel.swift in Sources */,
|
||||||
526A265C240D1FF700B0D828 /* ListTwoColumnCompareChangesModel.swift in Sources */,
|
526A265C240D1FF700B0D828 /* ListTwoColumnCompareChangesModel.swift in Sources */,
|
||||||
@ -2173,6 +2180,7 @@
|
|||||||
C695A67F23C9830600BFB94E /* UnOrderedListModel.swift in Sources */,
|
C695A67F23C9830600BFB94E /* UnOrderedListModel.swift in Sources */,
|
||||||
0AE98BB523FF18D2004C5109 /* Arrow.swift in Sources */,
|
0AE98BB523FF18D2004C5109 /* Arrow.swift in Sources */,
|
||||||
D2D90B442404789000DD6EC9 /* MoleculeContainerProtocol.swift in Sources */,
|
D2D90B442404789000DD6EC9 /* MoleculeContainerProtocol.swift in Sources */,
|
||||||
|
0A7ECC5F243CEB1200C828E8 /* ColorViewWithLabel.swift in Sources */,
|
||||||
94C0150A24215643005811A9 /* ActionTopAlertModel.swift in Sources */,
|
94C0150A24215643005811A9 /* ActionTopAlertModel.swift in Sources */,
|
||||||
012A88DB238ED45900FE3DA1 /* CarouselModel.swift in Sources */,
|
012A88DB238ED45900FE3DA1 /* CarouselModel.swift in Sources */,
|
||||||
D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */,
|
D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */,
|
||||||
|
|||||||
73
MVMCoreUI/Atomic/Molecules/Doughnut/ColorViewWithLabel.swift
Normal file
73
MVMCoreUI/Atomic/Molecules/Doughnut/ColorViewWithLabel.swift
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
//
|
||||||
|
// ColorViewWithLabel.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Kevin Christiano on 4/7/20.
|
||||||
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
|
||||||
|
open class ColorViewWithLabel: View {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public var label = Label.createLabelRegularBodySmall(true)
|
||||||
|
public var colorView = View()
|
||||||
|
private var sizeObject = MFStyler.sizeObjectGeneric(forCurrentDevice: 8)!
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Lifecycle
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public var heightConstraint: NSLayoutConstraint?
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Lifecycle
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open override func setupView() {
|
||||||
|
super.setupView()
|
||||||
|
|
||||||
|
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(equalTo: label.trailingAnchor).isActive = true
|
||||||
|
bottomAnchor.constraint(equalTo: label.bottomAnchor).isActive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func updateView(_ size: CGFloat) {
|
||||||
|
super.updateView(size)
|
||||||
|
label.updateView(size)
|
||||||
|
heightConstraint?.constant = sizeObject.getValueBased(onSize: size)
|
||||||
|
setNeedsDisplay()
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func reset() {
|
||||||
|
super.reset()
|
||||||
|
label.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - MoleculeViewProtocol
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
|
super.set(with: model, delegateObject, additionalData)
|
||||||
|
|
||||||
|
guard let chartItemModel = model as? DoughnutChartItemModel else { return }
|
||||||
|
|
||||||
|
label.set(with: chartItemModel.label, delegateObject, additionalData)
|
||||||
|
colorView.backgroundColor = chartItemModel.color.uiColor
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,23 +8,38 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
open class DoughnutChart: View {
|
|
||||||
var doughnutLayer = CALayer()
|
|
||||||
var titleLabel = Label.commonLabelH3(true)
|
|
||||||
var subTitleLabel = Label.commonLabelB2(true)
|
|
||||||
var doughnutChartModel: DoughnutChartModel? {
|
|
||||||
get { return model as? DoughnutChartModel }
|
|
||||||
}
|
|
||||||
var labelContainer = MVMCoreUICommonViewsUtility.commonView()
|
|
||||||
var labelContainerLeftConstraint: NSLayoutConstraint?
|
|
||||||
var labelContainerTopConstraint: NSLayoutConstraint?
|
|
||||||
var labelContainerBottomConstraint: NSLayoutConstraint?
|
|
||||||
var labelContainerRightConstraint: NSLayoutConstraint?
|
|
||||||
var heightConstraint: NSLayoutConstraint?
|
|
||||||
|
|
||||||
static let heightConstant: CGFloat = 150
|
open class DoughnutChart: View {
|
||||||
private var sizeObject = MFStyler.sizeObjectGeneric(forCurrentDevice: heightConstant)!
|
//--------------------------------------------------
|
||||||
var height: CGFloat = heightConstant {
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public var doughnutLayer = CALayer()
|
||||||
|
public var titleLabel = Label.createLabelRegularTitleLarge(true)
|
||||||
|
public var subTitleLabel = Label.createLabelRegularMicro(true)
|
||||||
|
public var labelContainer = View()
|
||||||
|
public static let heightConstant: CGFloat = 136
|
||||||
|
private var sizeObject = MFStyler.sizeObjectGeneric(forCurrentDevice: heightConstant)!
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Constraints
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public var labelContainerLeftConstraint: NSLayoutConstraint?
|
||||||
|
public var labelContainerTopConstraint: NSLayoutConstraint?
|
||||||
|
public var labelContainerBottomConstraint: NSLayoutConstraint?
|
||||||
|
public var labelContainerRightConstraint: NSLayoutConstraint?
|
||||||
|
public var heightConstraint: NSLayoutConstraint?
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Computed Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public var doughnutChartModel: DoughnutChartModel? {
|
||||||
|
get { return model as? DoughnutChartModel }
|
||||||
|
}
|
||||||
|
|
||||||
|
public var height: CGFloat = heightConstant {
|
||||||
didSet {
|
didSet {
|
||||||
if height != oldValue {
|
if height != oldValue {
|
||||||
sizeObject = MFStyler.sizeObjectGeneric(forCurrentDevice: height)!
|
sizeObject = MFStyler.sizeObjectGeneric(forCurrentDevice: height)!
|
||||||
@ -32,69 +47,73 @@ open class DoughnutChart: View {
|
|||||||
drawGraph()
|
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func setupView() {
|
|
||||||
super.setupView()
|
|
||||||
guard labelContainer.superview == nil else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
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
|
|
||||||
|
|
||||||
layer.addSublayer(doughnutLayer)
|
|
||||||
heightConstraint = heightAnchor.constraint(equalToConstant:
|
|
||||||
sizeObject.getValueBasedOnApplicationWidth())
|
|
||||||
heightConstraint?.isActive = true
|
|
||||||
widthAnchor.constraint(equalTo: heightAnchor).isActive = true
|
|
||||||
|
|
||||||
labelContainerLeftConstraint = labelContainer.leftAnchor.constraint(greaterThanOrEqualTo: leftAnchor, constant: lineWidth())
|
|
||||||
labelContainerLeftConstraint?.isActive = true
|
|
||||||
labelContainerTopConstraint = labelContainer.topAnchor.constraint(greaterThanOrEqualTo: topAnchor, constant: lineWidth())
|
|
||||||
labelContainerTopConstraint?.isActive = true
|
|
||||||
labelContainerRightConstraint = rightAnchor.constraint(greaterThanOrEqualTo: labelContainer.rightAnchor, constant: lineWidth())
|
|
||||||
labelContainerRightConstraint?.isActive = true
|
|
||||||
labelContainerBottomConstraint = bottomAnchor.constraint(greaterThanOrEqualTo: labelContainer.bottomAnchor, constant: lineWidth())
|
|
||||||
labelContainerBottomConstraint?.isActive = true
|
|
||||||
labelContainer.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
|
|
||||||
labelContainer.centerXAnchor.constraint(equalTo: 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
|
|
||||||
doughnutLayer.transform = CATransform3DMakeRotation(1 * .pi, 0.0, 0.0, 1.0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
|
//--------------------------------------------------
|
||||||
|
// MARK: - Lifecycle
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
open override func setupView() {
|
||||||
|
super.setupView()
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
layer.addSublayer(doughnutLayer)
|
||||||
|
heightConstraint = heightAnchor.constraint(equalToConstant: sizeObject.getValueBasedOnApplicationWidth())
|
||||||
|
heightConstraint?.isActive = true
|
||||||
|
widthAnchor.constraint(equalTo: heightAnchor).isActive = true
|
||||||
|
|
||||||
|
labelContainerLeftConstraint = labelContainer.leadingAnchor.constraint(greaterThanOrEqualTo: leadingAnchor, constant: lineWidth())
|
||||||
|
labelContainerLeftConstraint?.isActive = true
|
||||||
|
labelContainerTopConstraint = labelContainer.topAnchor.constraint(greaterThanOrEqualTo: topAnchor, constant: lineWidth())
|
||||||
|
labelContainerTopConstraint?.isActive = true
|
||||||
|
labelContainerRightConstraint = trailingAnchor.constraint(greaterThanOrEqualTo: labelContainer.trailingAnchor, constant: lineWidth())
|
||||||
|
labelContainerRightConstraint?.isActive = true
|
||||||
|
labelContainerBottomConstraint = bottomAnchor.constraint(greaterThanOrEqualTo: labelContainer.bottomAnchor, constant: lineWidth())
|
||||||
|
labelContainerBottomConstraint?.isActive = true
|
||||||
|
labelContainer.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
|
||||||
|
labelContainer.centerXAnchor.constraint(equalTo: 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
|
||||||
|
doughnutLayer.transform = CATransform3DMakeRotation(1 * .pi, 0, 0, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - MoleculeViewProtocol
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
super.set(with: model, delegateObject, additionalData)
|
super.set(with: model, delegateObject, additionalData)
|
||||||
clearLayers()
|
clearLayers()
|
||||||
guard let doughnutChartModel = doughnutChartModel else {
|
guard let doughnutChartModel = doughnutChartModel else { return }
|
||||||
return
|
|
||||||
}
|
|
||||||
titleLabel.setOptional(with: doughnutChartModel.title, delegateObject, additionalData)
|
titleLabel.setOptional(with: doughnutChartModel.title, delegateObject, additionalData)
|
||||||
subTitleLabel.setOptional(with: doughnutChartModel.subtitle, delegateObject, additionalData)
|
subTitleLabel.setOptional(with: doughnutChartModel.subtitle, delegateObject, additionalData)
|
||||||
titleLabel.textAlignment = .center
|
titleLabel.textAlignment = .center
|
||||||
@ -103,78 +122,83 @@ open class DoughnutChart: View {
|
|||||||
drawGraph()
|
drawGraph()
|
||||||
}
|
}
|
||||||
|
|
||||||
func drawGraph() {
|
//--------------------------------------------------
|
||||||
clearLayers()
|
// MARK: - Draw Graph
|
||||||
let widthHeight = sizeObject.getValueBasedOnApplicationWidth()
|
//--------------------------------------------------
|
||||||
doughnutLayer.frame = CGRect(x: 0, y: 0,
|
|
||||||
width: widthHeight,
|
private func drawGraph() {
|
||||||
height: widthHeight)
|
clearLayers()
|
||||||
if let doughnutChart = doughnutChartModel {
|
let widthHeight = sizeObject.getValueBasedOnApplicationWidth()
|
||||||
var prevPercent: CGFloat = 0.0
|
doughnutLayer.frame = CGRect(x: 0, y: 0, width: widthHeight, height: widthHeight)
|
||||||
for model in doughnutChart.sections {
|
|
||||||
|
if let doughnutChart = doughnutChartModel {
|
||||||
|
var prevPercent: CGFloat = 0.0
|
||||||
|
for model in doughnutChart.sections {
|
||||||
prevPercent += drawBar(model, prevPercent)
|
prevPercent += drawBar(model, prevPercent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func drawBar(_ chartModel: DoughnutChartItemModel, _ prevPercent: CGFloat) -> CGFloat {
|
private func drawBar(_ chartModel: DoughnutChartItemModel, _ prevPercent: CGFloat) -> CGFloat {
|
||||||
|
|
||||||
let shapeLayer = CAShapeLayer()
|
let shapeLayer = CAShapeLayer()
|
||||||
shapeLayer.frame = doughnutLayer.frame
|
shapeLayer.frame = doughnutLayer.frame
|
||||||
shapeLayer.lineWidth = lineWidth()
|
shapeLayer.lineWidth = lineWidth()
|
||||||
shapeLayer.fillColor = nil
|
shapeLayer.fillColor = nil
|
||||||
shapeLayer.strokeColor = chartModel.color.uiColor.cgColor
|
shapeLayer.strokeColor = chartModel.color.uiColor.cgColor
|
||||||
|
|
||||||
let arcCenter = shapeLayer.position
|
let arcCenter = shapeLayer.position
|
||||||
let radius = shapeLayer.bounds.size.width / 2.0 - lineWidth()/2.0
|
let radius = shapeLayer.bounds.size.width / 2.0 - lineWidth() / 2.0
|
||||||
|
|
||||||
let value: CGFloat = chartModel.percent
|
let value: CGFloat = chartModel.percent
|
||||||
let gap: CGFloat = spaceRequired() ? lineGap() : 0.0
|
let gap: CGFloat = spaceRequired() ? lineGap() : 0.0
|
||||||
let startAngle = ((prevPercent / 100.0) * 2 * .pi) - (0.5 * .pi)
|
let startAngle = ((prevPercent / 100.0) * 2 * .pi) - (0.5 * .pi)
|
||||||
let endAngle = ((value / 100.0) * 2 * .pi) + startAngle - gap
|
let endAngle = ((value / 100.0) * 2 * .pi) + startAngle - gap
|
||||||
let circlePath = UIBezierPath(arcCenter: arcCenter,
|
let circlePath = UIBezierPath(arcCenter: arcCenter,
|
||||||
radius: radius,
|
radius: radius,
|
||||||
startAngle: startAngle,
|
startAngle: startAngle,
|
||||||
endAngle: endAngle,
|
endAngle: endAngle,
|
||||||
clockwise: true)
|
clockwise: true)
|
||||||
|
|
||||||
shapeLayer.path = circlePath.cgPath
|
shapeLayer.path = circlePath.cgPath
|
||||||
doughnutLayer.addSublayer(shapeLayer)
|
doughnutLayer.addSublayer(shapeLayer)
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
func clearLayers() {
|
private func clearLayers() {
|
||||||
doughnutLayer.sublayers?.forEach({ $0.removeFromSuperlayer() })
|
doughnutLayer.sublayers?.forEach{ $0.removeFromSuperlayer() }
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateContainer() {
|
public func updateContainer() {
|
||||||
heightConstraint?.constant = sizeObject.getValueBasedOnApplicationWidth()
|
|
||||||
updateLabelContainer()
|
|
||||||
setNeedsDisplay()
|
|
||||||
}
|
|
||||||
|
|
||||||
func lineWidth() -> CGFloat {
|
heightConstraint?.constant = sizeObject.getValueBasedOnApplicationWidth()
|
||||||
return 30
|
updateLabelContainer()
|
||||||
}
|
setNeedsDisplay()
|
||||||
|
}
|
||||||
|
|
||||||
func lineGap() -> CGFloat {
|
public func lineWidth() -> CGFloat {
|
||||||
|
return 12
|
||||||
|
}
|
||||||
|
|
||||||
|
public func lineGap() -> CGFloat {
|
||||||
//If array is having the single item then no space required
|
//If array is having the single item then no space required
|
||||||
return doughnutChartModel?.sections.count == 1 ? 0.0 : 0.05
|
return doughnutChartModel?.sections.count == 1 ? 0.0 : 0.05
|
||||||
}
|
}
|
||||||
|
|
||||||
func spaceRequired() -> Bool {
|
public func spaceRequired() -> Bool {
|
||||||
return doughnutChartModel?.spaceRequired ?? true
|
return doughnutChartModel?.spaceRequired ?? true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func updateLabelContainer() {
|
||||||
|
|
||||||
func updateLabelContainer() {
|
|
||||||
labelContainer.setNeedsDisplay()
|
labelContainer.setNeedsDisplay()
|
||||||
labelContainer.layoutIfNeeded()
|
labelContainer.layoutIfNeeded()
|
||||||
let radius = sizeObject.getValueBasedOnApplicationWidth()/2 - lineWidth()
|
let radius = sizeObject.getValueBasedOnApplicationWidth() / 2 - lineWidth()
|
||||||
let labelheight = labelContainer.frame.height/2
|
let labelheight = labelContainer.frame.height / 2
|
||||||
let padding = sizeObject.getValueBasedOnApplicationWidth()/2 - sqrt(max(0, pow(radius, 2) - pow(labelheight, 2)))
|
let padding = sizeObject.getValueBasedOnApplicationWidth() / 2 - sqrt(max(0, pow(radius, 2) - pow(labelheight, 2)))
|
||||||
|
|
||||||
labelContainerLeftConstraint?.constant = padding
|
labelContainerLeftConstraint?.constant = round(padding)
|
||||||
labelContainerRightConstraint?.constant = padding
|
labelContainerRightConstraint?.constant = round(padding)
|
||||||
labelContainerTopConstraint?.constant = max(radius - labelheight, labelheight)
|
labelContainerTopConstraint?.constant = max(radius - labelheight, labelheight)
|
||||||
labelContainerBottomConstraint?.constant = max(radius - labelheight, labelheight)
|
labelContainerBottomConstraint?.constant = max(radius - labelheight, labelheight)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,44 @@
|
|||||||
|
//
|
||||||
|
// DoughnutChartItemModel.swift
|
||||||
|
// MVMCoreUI
|
||||||
|
//
|
||||||
|
// Created by Kevin Christiano on 4/7/20.
|
||||||
|
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
|
@objcMembers public class DoughnutChartItemModel: MoleculeModelProtocol {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public var backgroundColor: Color?
|
||||||
|
public static var identifier: String = "doughnutChartItem"
|
||||||
|
public var moleculeName: String = DoughnutChartItemModel.identifier
|
||||||
|
public var label: LabelModel
|
||||||
|
@Percent public var percent: CGFloat
|
||||||
|
public var color: Color
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Keys
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
private enum CodingKeys: String, CodingKey {
|
||||||
|
case backgroundColor
|
||||||
|
case label
|
||||||
|
case percent
|
||||||
|
case color
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Initializer
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
public init(percent: CGFloat, color: Color, label: LabelModel) {
|
||||||
|
self.percent = percent
|
||||||
|
self.color = color
|
||||||
|
self.label = label
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,7 +8,12 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
@objcMembers public class DoughnutChartModel: MoleculeModelProtocol {
|
@objcMembers public class DoughnutChartModel: MoleculeModelProtocol {
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public var backgroundColor: Color?
|
public var backgroundColor: Color?
|
||||||
public static var identifier: String = "doughnutChart"
|
public static var identifier: String = "doughnutChart"
|
||||||
public var moleculeName: String = DoughnutChartModel.identifier
|
public var moleculeName: String = DoughnutChartModel.identifier
|
||||||
@ -17,22 +22,11 @@ import Foundation
|
|||||||
public var sections: [DoughnutChartItemModel]
|
public var sections: [DoughnutChartItemModel]
|
||||||
public var spaceRequired: Bool?
|
public var spaceRequired: Bool?
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Initializer
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
public init(sections: [DoughnutChartItemModel]) {
|
public init(sections: [DoughnutChartItemModel]) {
|
||||||
self.sections = sections
|
self.sections = sections
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objcMembers public class DoughnutChartItemModel: MoleculeModelProtocol {
|
|
||||||
public var backgroundColor: Color?
|
|
||||||
public static var identifier: String = "doughnutChartItem"
|
|
||||||
public var moleculeName: String = DoughnutChartItemModel.identifier
|
|
||||||
public var label: LabelModel
|
|
||||||
@Percent public var percent: CGFloat
|
|
||||||
public var color: Color
|
|
||||||
|
|
||||||
public init(percent: CGFloat, color: Color, label: LabelModel) {
|
|
||||||
self.percent = percent
|
|
||||||
self.color = color
|
|
||||||
self.label = label
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -8,18 +8,26 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
@objcMembers open class DoughnutChartView: View {
|
@objcMembers open class DoughnutChartView: View {
|
||||||
var doughnutChart = DoughnutChart(frame: CGRect.zero)
|
//--------------------------------------------------
|
||||||
|
// MARK: - Properties
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
|
var doughnutChart = DoughnutChart(frame: .zero)
|
||||||
var colorLablesStack = ColorViewLabelsStack()
|
var colorLablesStack = ColorViewLabelsStack()
|
||||||
|
|
||||||
var doughnutChartModel: DoughnutChartModel? {
|
var doughnutChartModel: DoughnutChartModel? {
|
||||||
get { return model as? DoughnutChartModel }
|
get { return model as? DoughnutChartModel }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - Lifecycle
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
open override func setupView() {
|
open override func setupView() {
|
||||||
super.setupView()
|
super.setupView()
|
||||||
guard doughnutChart.superview == nil else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
doughnutChart.translatesAutoresizingMaskIntoConstraints = false
|
doughnutChart.translatesAutoresizingMaskIntoConstraints = false
|
||||||
addSubview(doughnutChart)
|
addSubview(doughnutChart)
|
||||||
colorLablesStack.translatesAutoresizingMaskIntoConstraints = false
|
colorLablesStack.translatesAutoresizingMaskIntoConstraints = false
|
||||||
@ -65,6 +73,10 @@ import Foundation
|
|||||||
colorLablesStack.reset()
|
colorLablesStack.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------
|
||||||
|
// MARK: - MoleculeViewProtocol
|
||||||
|
//--------------------------------------------------
|
||||||
|
|
||||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
|
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
|
||||||
super.set(with: model, delegateObject, additionalData)
|
super.set(with: model, delegateObject, additionalData)
|
||||||
|
|
||||||
@ -82,6 +94,7 @@ import Foundation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - MVMCoreUIViewConstrainingProtocol
|
||||||
extension DoughnutChartView: MVMCoreUIViewConstrainingProtocol {
|
extension DoughnutChartView: MVMCoreUIViewConstrainingProtocol {
|
||||||
open func horizontalAlignment() -> UIStackView.Alignment {
|
open func horizontalAlignment() -> UIStackView.Alignment {
|
||||||
return .leading
|
return .leading
|
||||||
@ -89,6 +102,7 @@ extension DoughnutChartView: MVMCoreUIViewConstrainingProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ColorViewLabelsStack: MoleculeStackView {
|
class ColorViewLabelsStack: MoleculeStackView {
|
||||||
|
|
||||||
override func createStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
|
override func createStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
|
||||||
guard let stackItemModels = stackModel?.molecules else { return }
|
guard let stackItemModels = stackModel?.molecules else { return }
|
||||||
for model in stackItemModels {
|
for model in stackItemModels {
|
||||||
@ -99,53 +113,3 @@ class ColorViewLabelsStack: MoleculeStackView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ColorViewWithLabel: View {
|
|
||||||
|
|
||||||
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(equalTo: 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()
|
|
||||||
}
|
|
||||||
|
|
||||||
override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
|
|
||||||
super.set(with: model, delegateObject, additionalData)
|
|
||||||
guard let chartItemModel = model as? DoughnutChartItemModel else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
label.set(with: chartItemModel.label, delegateObject, additionalData)
|
|
||||||
colorView.backgroundColor = chartItemModel.color.uiColor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user