I have a swift program that displays a chart using Chart. The code includes an X Axis Scale parameter but for some reason the last value (right most) on the x axis does not display. It should display Aug 2023. In checking the array used for the x axis labels I find that the last value is Aug 2023. I do not know how to overcome this obstacle. Any assistance will be appreciated. Below is a picture of the bottom of the chart and the code.
struct CustomChartView: View {
let vm: SQLDataVM = SQLDataVM.shared
let closingValues: [TradingDay]
let fundName: String
let numYears: Int
let maxCloseStruct: TradingDay
let maxClose: Double
let minCloseStruct: TradingDay
let minClose: Double
let yIncrment: Double
let yAxisValues: [Double]
let minTimeStampStruct: TradingDay
let minTimeStamp: Date
var dateComponent = DateComponents()
let maxTimeStampStruct: TradingDay
let maxTimeStamp: Date
var xAxisValues: [Date] = []
init (fundName: String, numYears: Int) {
self.fundName = fundName
self.numYears = numYears
closingValues = self.vm.QueryDatabase(fundName: fundName, numYears: numYears)
maxCloseStruct = self.closingValues.max(by: { (tradingDay1, tradingDay2) -> Bool in
return tradingDay1.close < tradingDay2.close
})!
maxClose = maxCloseStruct.close
minCloseStruct = closingValues.min(by: { (tradingDay1, tradingDay2) -> Bool in
return tradingDay1.close < tradingDay2.close
})!
minClose = minCloseStruct.close
yIncrment = (maxClose - minClose)/4
yAxisValues = [
minClose,
minClose + (1 * yIncrment),
minClose + (2 * yIncrment),
minClose + (3 * yIncrment),
maxClose
]
minTimeStampStruct = closingValues.min(by: { (tradingDay1, tradingDay2) -> Bool in
return tradingDay1.timeStamp < tradingDay2.timeStamp
})!
minTimeStamp = minTimeStampStruct.timeStamp
maxTimeStampStruct = closingValues.max(by: { (tradingDay1, tradingDay2) -> Bool in
return tradingDay1.timeStamp < tradingDay2.timeStamp
})!
maxTimeStamp = maxTimeStampStruct.timeStamp
xAxisValues.append(minTimeStamp)
for i in 1...11 {
dateComponent.month = i
let nextMonth = Calendar.current.date(byAdding: dateComponent, to: minTimeStamp)
xAxisValues.append(nextMonth!)
}
xAxisValues.append(maxTimeStamp)
print("\(xAxisValues[12])") // prints 2023-08-04 00:00:00 +0000
} // end init
var body: some View {
HStack(alignment: .center) {
VStack(alignment: .center) {
Chart(closingValues, id:\.id) {
LineMark(
x: .value("Date", $0.timeStamp, unit: .day),
y: .value("Closing", $0.close)
)
.foregroundStyle(.blue)
} // end chart
.frame(width: 1000, height: 700, alignment: .center)
.chartXAxisLabel(position: .bottom, alignment: .center, spacing: 15) {
Text("Date")
.font(.custom("Arial", size: 20))
}
.chartYAxisLabel(position: .leading, alignment: .center, spacing: 20) {
Text("Closing Value")
.font(.custom("Arial", size: 20))
}
.chartXAxis {
AxisMarks(values: xAxisValues) { value in
if let date = value.as(Date.self) {
AxisValueLabel(horizontalSpacing: -14, verticalSpacing: 10) {
VStack(alignment: .leading) {
Text(ChartMonthFormatter.string(from: date))
.font(.custom("Arial", size: 14))
Text(ChartYearFormatter.string(from: date))
.font(.custom("Arial", size: 14))
} // end v stack
} // end axis label
} // end if statement
AxisGridLine(centered: true, stroke: StrokeStyle(lineWidth: 1))
.foregroundStyle(Color.black)
AxisTick(centered: true, length: 0, stroke: .none)
}
} // end chart x axis
.chartXScale(domain: [xAxisValues[0], xAxisValues[12]])
.chartYAxis {
AxisMarks(position: .leading, values: yAxisValues) { value in
AxisGridLine(centered: true, stroke: StrokeStyle(lineWidth: 1))
.foregroundStyle(Color.black)
AxisTick(centered: true, length: 0, stroke: .none)
AxisValueLabel(horizontalSpacing: 10) {
if let yAxisValue = value.as(Double.self) {
let stringValue = String(format: "$%.02f", yAxisValue)
Text(stringValue)
.font(.custom("Arial", size: 14))
}
}
}
}
.chartYScale(domain: [minClose, maxClose])
.chartPlotStyle { plotArea in
plotArea.background(.white.opacity(0.9))
.border(.black, width: 1)
} // end chart plot style
} // end v stack
.frame(width: 1200, height: 900, alignment: .center)
} // end h stack
} // end some view
}
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I have a program that utilizes a Navigation Stack. I want each view to be centered on the screen and be a specific size. I accomplished this with some position logic which sets the views frame size and origin. There is unique position logic for each of the 3 view sizes, the Content View and 2 navigation destination views. When the Content View is first displayed the associated position logic code runs and the view is the correct size and centered. The same is true every time one of the 2 navigation destination views is displayed. Unfortunately, when I return to the Content View from a navigation destination view the position logic does not run again and the Content View is now the same size and position as the previous navigation destination view. How do I resolve this problem? Below is the position logic code associated with the Content View and how it is called.
@main
struct TableViewTestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.hostingWindowPositionHome(
screen: .main
)
}
}
}
extension View {
func hostingWindowPositionHome(
screen: NSScreen? = nil
) -> some View {
modifier(
WindowPositionModifierHome(
screen: screen
)
)
}
}
private struct WindowPositionModifierHome: ViewModifier {
let screen: NSScreen?
func body(content: Content) -> some View {
content.background(
HostingWindowFinderHome {
$0?.setPositionHome(in: screen)
}
)
}
}
private struct HostingWindowFinderHome: NSViewRepresentable {
var callback: (NSWindow?) -> ()
func makeNSView(context: Self.Context) -> NSView {
let view = NSView()
DispatchQueue.main.async { self.callback(view.window) }
return view
}
func updateNSView(_ nsView: NSView, context: Context) {
DispatchQueue.main.async { self.callback(nsView.window) }
}
}
extension NSWindow {
func setPositionHome(in screen: NSScreen?) {
let nsRectangle: NSRect = NSRect(x: 1055.0, y: 370.0, width: 450, height: 700)
setFrame(nsRectangle, display: true)
}
}
I have a program that uses 3 different windows, each in their own window group. In a button I can use openWindow() to call another window and it works perfectly. I watched the video at the link below and now am trying to convert my program to use a navigation stack instead of buttons. I got things to work using the code listed at the link with a few changes but am unable to get the navigation destination to use openWindow. I attempted to create a view builder but could not get it to work. After some additional research I am starting to think that the navigation destination expects to use the same window as the root view not a separate window/view and therefore, navigation destination wants just a view. But I am unsure. If someone could provide some guidance it would be appreciated.
https://developer.apple.com/videos/play/wwdc2022/10054/
struct ContentView: View {
@Environment (\.openWindow) private var openWindow
@StateObject private var dataModel = DataModel()
var body: some View {
VStack(alignment: .center) {
NavigationStack() {
List(Sections.allCases) { section in
Section(section.localizedName) {
ForEach(dataModel.stocks(in: section)) { stock in
NavigationLink(stock.listingName, value: stock)
.font(Font.custom("Arial", size: 16))
}
} // end section
} // end list
.scrollContentBackground(.hidden)
.background(Color.mint)
.navigationTitle("Stocks")
.navigationDestination(for: StockData.self) { stock in
Text("\(stock.listingName) - \(stock.name)")
// GenericTableView(content: openWindow(id: "table", value: stock.name))
// Cannot convert value of type '()' to expected argument type '() -> ContentView'
}
} // end navigation stack
} // end v stack
}
}
struct GenericTableView<Content:View>: View {
let content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
content
}
}
During the upgrade to Ventura it appears that Xcode was also upgraded to 14.0.1. In an attempt to use a new feature, Charts, I entered into a macOS app import Charts and I get an error message no such module Charts. If I use the same import Charts in an iOS app I do not get such an error. I am wondering if Charts in not available for macOS apps or did something go wrong during the Ventura upgrade. If it is the later, it makes sense to me to cleanly uninstall Xcode and reinstall. But it is unclear if just dragging Xcode from the application folder to the trash and emptying the trash completely uninstalls Xcode. As a side note, I do not ever remember Xcode being upgraded during an upgrade to macOS. Any input will be appreciated.
I am working with the new Charts Framework. The axis value labels for the x axis are dates (mm/dd/yy). I have 5 vertical grid lines and am trying to get the dates to be centered below the associated grid line with no success. One additional problem is that the values are in an array that contains 5 dates but only the first 4 get displayed. Any solutions will be appreciated. Below is the code.
struct LineChart: View {
private var localArray: [TradingDayPrices]
init(passedInArray: [TradingDayPrices]) {
self.localArray = passedInArray
}
var body: some View {
let minCloseValue: Double = localArray.map { $0.close }.min()!
let maxCloseValue: Double = localArray.map { $0.close }.max()!
let minDate: Date = localArray[0].timeStamp!
let itemCount: Int = localArray.count - 1
let maxDate: Date = localArray[itemCount].timeStamp!
Spacer()
GroupBox (label: Text("VOO Closing Values For The Past Year")
.font(.system(size: 20))
.fontWeight(.bold)
.frame(width: 700, height: 50, alignment: .center)) {
Chart {
ForEach(localArray) { item in
LineMark (
x: .value("TimeStamp", item.timeStamp!),
y: .value("Close", item.close)
)
.foregroundStyle(Color.blue)
.lineStyle(StrokeStyle(lineWidth: 1.25))
} // end for each
} // end chart
.padding(50)
.chartBackground { item in
Color.white
}
.chartXAxisLabel(position: .bottom, alignment: .center) {
Text("Date")
.font(.system(size: 14))
.foregroundColor(Color.black)
.frame(width: 50, height: 35, alignment: .bottom)
}
.chartYAxisLabel(position: .leading, alignment: .center, spacing: 0) {
Text("Closing Values")
.font(.system(size: 14))
.foregroundColor(Color.black)
}
.chartXAxis {
AxisMarks (values: GetXAxisLabels(min: minDate, max: maxDate)) { value in
AxisGridLine(stroke: StrokeStyle(lineWidth: 0.5))
.foregroundStyle(Color.gray)
AxisValueLabel() {
if let localDate = value.as(Date.self) {
let formattedDate = dateToStringFormatter.string(from: localDate)
Text(formattedDate)
.font(.system(size: 12))
.foregroundColor(Color.black)
}
} // end axis value label
} // end axis marks
} // end chart x axis
.chartYAxis {
AxisMarks (position: .leading, values: GetYAxisLabels(min: minCloseValue, max: maxCloseValue)) { value in
AxisGridLine(stroke: StrokeStyle(lineWidth: 0.5))
.foregroundStyle(Color.gray)
AxisValueLabel() {
if let localValue = value.as(Double.self) {
let formattedValue = String(format: "$%.2f", localValue)
Text(formattedValue)
.font(.system(size: 12))
.foregroundColor(Color.black)
}
}
} // end axis marks
} // end chart y axis
.chartXScale(domain: minDate...maxDate)
.chartYScale(domain: minCloseValue...maxCloseValue)
.frame(width: 700, height: 700, alignment: .center)
} // end group box
} // end of body
} // end of structure
func GetXAxisLabels(min: Date, max: Date) -> [Date] {
var xLabels: [Date] = []
let increment: Int = 90
for i in 0...3 {
let value = Calendar.current.date(byAdding: DateComponents(day: (i * increment)), to: min)!
xLabels.append(value)
}
xLabels.append(max)
print("\(xLabels)")
return xLabels
}
func GetYAxisLabels(min: Double, max: Double) -> [Double] {
var yLabels: [Double] = []
let increment: Double = (max - min) / 4
for i in 0...3 {
let value = min + (Double(i) * increment)
yLabels.append(value)
}
yLabels.append(max)
return yLabels
}
let dateToStringFormatter: DateFormatter = {
let result = DateFormatter()
result.dateFormat = "MM/dd/yy"
return result
}()