I am trying to set the minimum date value of a date picker in SwiftUI using #Binding and #State.
I have three steppers, one for days, one for hours, and one for minutes. These are used to set the values of DateComponents.
What I want to see is the DatePicker adjust to the minimum date and time as I use the steppers. Is this possible?
I have edited this post and deleted all of the code examples because they were irrelevant to the solution. The problems were caused by deprecated DatePicker initializer code. See the answer below.
Here is the solution. Minimum and maximum dates were deprecated in SwiftUI DatePickers. The changes and solution were posted here: https://sarunw.com/posts/swiftui-changes-in-xcode-11-beta-4
If the link does not work, here are the examples.
DatePicker deprecated initializers
Initializers with minimumDate and maximumDate are gone. Now we initialized it with ClosedRange, PartialRangeThrough, and PartialRangeFrom.
We use PartialRangeFrom for minimumDate.
DatePicker("Minimum Date",
selection: $selectedDate,
in: Date()...,
displayedComponents: [.date])
We use PartialRangeThrough for maximumDate.
DatePicker("Maximum Date",
selection: $selectedDate,
in: ...Date(),
displayedComponents: [.date])
If you want to enforce both minimumDate and maximumDate use ClosedRange
#State var selectedDate = Date()
var dateClosedRange: ClosedRange<Date> {
let min = Calendar.current.date(byAdding: .day, value: -1, to: Date())!
let max = Calendar.current.date(byAdding: .day, value: 1, to: Date())!
return min...max
}
DatePicker(
selection: $selectedDate,
in: dateClosedRange,
displayedComponents: [.hourAndMinute, .date],
label: { Text("Due Date") }
)
In all of the examples, the Date() can be replaced with a binding that is of type Date.
Related
I'm implementing a Picker in SwiftUI. The picker values are strings that vary in size, but the picker itself has a maxWidth due to UI limitations. Some of the strings won't fit, and that's fine with me. However, at the moment, the string is wrapped, increasing the height of the picker, like so:
I'd like to limit the string to just one line, truncating the string, and keeping the picker height the same.
I've tried
.frame(maxHeight: 20)
.clipped()
.contentShape(Rectangle())
on the picker, but that gives me this:
I'd like to truncate the string. How can I do this? NOTE: it should only truncate here, not in the dropdown list.
I've played around with .lineLimit(1), .multilineTextAlignment(.leading), .truncationMode(.tail), on both the text in the ForEach block, and on the picker itself, but no luck so far.
Here is the full code that I have now:
Picker("Theme", selection: $selectedThemeRawValue) {
ForEach(Theme.allCases.map({$0.rawValue}), id: \.self) { value in
Text(value)
.lineLimit(1)
.multilineTextAlignment(.leading)
.truncationMode(.tail)
}
}
.accentColor(.primary)
.frame(maxHeight: 20)
.clipped()
.contentShape(Rectangle())
.lineLimit(1)
.multilineTextAlignment(.leading)
.truncationMode(.tail)
Does anyone have an idea on how I can do this?
I'd just like to know whether there's a bug in macOS or if I have to make changes in code with currency formatted TextFields.
My problem: just a simple TextField in SwiftUI like
TextField("amountOnDeadline",value: $startValue, formatter: Formatters.currencyFormatter)
The formatter ist pretty simple:
static let currencyFormatter: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.maximumFractionDigits = 2
return formatter
}()
Build and run!
The offered field is displayed as currency field. Great! But when I enter a number like 123, the field is reset to 0.00 € (or the value displayed on start).
Only when I exactly mark the 0.00 without the currency symbol and enter a value, the new value is taken.
This is not very user friendly. Is it something I have to live with or is there a solution for this problem? e.g. a special config in NumberFormatter.
Instead of using NumberFormatter you can use currency(code:) FormatStyle with TextField init(_:value:format:prompt:).
TextField("amountOnDeadline",value: $startValue, format: .currency(code: Locale.current.currencyCode ?? "EUR"))
This will not reset the field to 0.00 even if you remove the currency symbol.
I want following Google Chart (Column Chart) to show its first label on horizontal axis. Also I want each column to have same width; first and last column need a change. How is it possible?
var chartDataRaw = [{
"month": "201211",
"articles": 41467
}, {
"month": "201212",
"articles": 31820
}, {
"month": "201301",
"articles": 43817
}, {
"month": "201302",
"articles": 42773
}, {
"month": "201303",
"articles": 38695
}, {
"month": "201304",
"articles": 41257
}];
var dataTable = new google.visualization.DataTable();
dataTable.addColumn('date', 'Month');
dataTable.addColumn('number', 'Articles');
var i = 1;
//chartDataRaw is array of objects, requested from server. looped through jquery each to fill dataTable
$.each(chartDataRaw, function () {
var year = this.month.substring(0, 4);
var month = this.month.substring(4);
var dataItem = [new Date(year, month), this.articles];
dataTable.addRow(dataItem);
});
var options = {
title: 'Company Coverage',
hAxis: {
title: 'Last Six Months',
titleTextStyle: {
color: 'red'
},
format: 'MMM, yyyy',
fontSize: '8px'
},
vAxis: {
textPosition: 'none'
},
trendlines: {
0: {
color: 'black',
lineWidth: 3,
opacity: 0.4
}
},
legend: 'none'
};
var monthYearFormatter = new google.visualization.DateFormat({
pattern: "MMM, yyyy"
});
monthYearFormatter.format(dataTable, 0); //change date format to render on chart
var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
chart.draw(dataTable, options);
http://jsfiddle.net/YyYsN/2/
Edit: Added chart data
Executive Summary
You are committing several mortal sins:
You are not defining dates right
You have no y axis values distorting your data
You are using columns to describe a continuous series
You are predicting based on only 6 data points
You are not defining dates right
Look at the value for January 2013. It says 31,820 articles. The issue is your data says there were 43,817 articles in January. What the heck is going on?
Javascript Date Objects use month values from 0-11, not 1-12. That means when you convert the dates, you need to change your function.
Old:
var dataItem = [new Date(year, month), this.articles];
New:
var dataItem = [new Date(year, month - 1), this.articles];
You have no y axis values distorting your data
Compare the second bar to the third bar. What is the ratio between the two? It looks like the second bar is around .5 gridlines, and the third bar is around 3.5 gridlines. That is a 700% increase in articles!
Only if you look at the data, it's actually going from 31,820 to 43,817, and increase of only 37%.
Bar charts should always start from zero, otherwise you get incredibly distorted perspective of the data, especially when there are no labels to boot.
Old:
vAxis: {
textPosition: 'none',
},
New:
vAxis: {
textPosition: 'none',
minValue: 0
},
You are using columns to describe a continuous series
Columns show discrete items. If I want to poll how many kids in a class like dogs, cats, and iguanas, a column chart is great since it allows me to compare the popularity (height) across unrelated categories (horizontal). Columns are okay for showing sales per month (or articles per month), but by making them columns you are implying that the columns should be compared as individual items, not as a progressing series.
If you want to show that these data items are connected (as implied by the trendline) it would make much more sense to show an area chart.
(Ideally, the area chart would show articles over the last 30 days, and have daily data, rather than a monthly compilation since months are arbitrary cutoffs, and things like weekends and holidays probably have a significant impact on your data which further distorts what you're trying to show).
Old
var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
New
var chart = new google.visualization.AreaChart(document.getElementById('chart_div'));
You are predicting based on only 6 data point
Six points does not a trend make. Your data's highest value is the second point, yet you are showing the trend increasing over time. Perhaps the trendline suggests an upward trend (since the later values are higher than the first value), but as soon as you move 1 month forward you will have a descending trendline (barring a massive increase in articles).
This makes no rational sense. 5 months of data are the same. How can changing 1 month of a 6-month series change the direction of the trendline? Forecasting is iffy-enough as it is (see the Black Swan theory), but doing it on a minimal 6-month series likely isn't the best. This means the trendline should probably be removed altogether since it not only doesn't convey useful information, it potentially conveys incorrect information.
Summary
That said, if you just want your left and right columns not to be cut off, you can change the following code:
Old
hAxis: {
title: 'Last Six Months',
titleTextStyle: {
color: 'red'
},
format: 'MMM, yyyy',
fontSize: '8px',
},
New
hAxis: {
title: 'Last Six Months',
titleTextStyle: {
color: 'red'
},
format: 'MMM, yyyy',
fontSize: '8px',
minValue: new Date(2012,9),
maxValue: new Date(2013,4)
},
fixed it myself by changing corechart visualization version to 1.1
google.load("visualization", "1.1", {packages:["corechart"]});
I have created a bar chart using google Column Chart, now
I have only integer values in my datatable but google divide acis with float values, is there a way to force chart mark only integers?
is there any way to show value labels on top or inside bar chart? I found some way for image chart, but I whould like to keep chart interactive
There is no direct solution to this as yet because annotations are not supported in column chart. But let me share a work around for this: You can create a combo chart with two series having same data (as that of your column chart) along with the annotation column. Set the type of the first series to bars and that of the other series to line. Finally, specify visibleInLegend, lineWidth, and pointSize properties of the second series to false and 0s respectively.
var data = new google.visualization.DataTable();
data.addColumn({ type: 'string', label: 'Labels' });
data.addColumn({ type: 'number', label: 'Bar Series' });
data.addColumn({ type: 'number', label: 'Line Series' });
data.addColumn({ type: 'string', role: 'annotation' });
data.addRows([['Label1', 10, 10, '10'],
['Label1', 20, 20, '20'],
['Label1', 40, 40, '40'],
['Label1', 5, 5, '5'],
['Label1', 30, 30, '30'],
]);
var barchart = new google.visualization.ComboChart(document.getElementById('bar_element'));
var options = {series: [{ type: 'bars' },
{ type: 'line', lineWidth: 0, visibleInLegend:false, pointSize: 0}]};
barchart.draw(data, options);
For your first problem you can use gridlines property, take a look at this post to see how you can use it.
For the second question I don't really understand. When you go on a bar with your mouse, the popup with values isn't already displayed on the top of the bar?
For some reason the date formatter using a pattern isn't working at all in my application. One thing that has crossed my mind is that it doesn't allow formatting for the x axis. Here's a snippet:
var dataTable = new google.visualization.DataTable();
dataTable.addColumn('date', 'YearMonth');
dataTable.addColumn('number', 'Beds');
dataTable.addColumn('number', 'Rooms');
var monthYearFormatter = new google.visualization.DateFormat({ pattern: "MMM yyyy" });
monthYearFormatter.format(dataTable, 0);
So elsewhere in a loop I do the following:
dataTable.addRow(d, currentRow.Beds, currentRow.Rooms]);
Where "d" is a valid date. It isn't formatted at all though, however when I do all of this, it just displays the default format.
Anyone done this before?
In order to format the values on the x-axis, you must use the format attribute in the options:
hAxis: { format: 'MMM yyyy' }
The line:
monthYearFormatter.format(dataTable, 0);
formats the values in the chart and must be written after the data inserting into the dataTable object.
#FrankyFred's answer works only for the labels over the axis and not the toolTip.
If you want to format the text on the toolTip so that what you have is right:
var monthYearFormatter = new google.visualization.DateFormat({
pattern: "MMM yyyy"
});
monthYearFormatter.format(dataTable, 0);