I am developing a portal with Blazor. The website will show some timeseries data in a chart.
For the charts I use Blazorise.Charts (1.0.5).
I want the chart to show the full date at the start of a day and between the days only hours (in a 24h format) and minutes. However it seems the Blazorise LineChartOptions do not accept my input.
My data model:
public class point
{
public double Value;
public DateTime ReceivedOn;
}
The options I use
public LineChartOptions _LineChartOptions { get; set; } = new LineChartOptions()
{
Parsing = new ChartParsing
{
XAxisKey = "ReceivedOn",
YAxisKey = "Value",
},
Scales = new ChartScales()
{
X = new ChartAxis()
{
Display = true,
Type = "timeseries",
Title = new ChartScaleTitle
{
Display = true,
Text = "Date"
},
Ticks = new ChartAxisTicks
{
StepSize = 1,
Major = new ChartAxisMajorTick
{
Enabled = true
},
},
}
}
}
I also tried adding the Time = new ChartAxisTime, but that option does not seem to work if you use Ticks.
The result I get when using these settings is:
Chart
Like you can see, it seems almost what I want, however the labels need to be in the HH:mm format and the date needs to be in the yyyy-MM-dd format.
What do I need to change to get this result?
I ran into the same issue. Honestly, after reading the Chart.js documentation, I just stopped trying to feed DateTime objects directly into the blazorise chart. According to the Chart.js documentation, it must be converted somewhere in blazorise, because the dates are fed into Chart.js as strings anyway. So I converted my DateTime[] to a string[] with DateTime pattern "O" (o Format Specifier de-DE Culture 2008-10-31T17:04:32.0000000) and everything went fine.
Furthermore, try time first instead of timeseries as the x scale type. Type timeseries behaves strangely on non-equidistant data.
My LineChartOptions:
public static LineChartOptions CreateLineChartOptions()
{
return new LineChartOptions()
{
Scales = new ChartScales()
{
X = new ChartAxis()
{
Type = "time",
Time = new ChartAxisTime()
{
Unit = "minute",
MinUnit = "minute"
}
}
}
};
}
My labels are wrongly formatted like yours; I'm still working on that.
My Razor Call:
<LineChart #ref="lineChart" TItem="double" Options="#LineChartOptions" />
For a minimum example, you can even leave the ChartAxisTime() object. It should run without it.
My minimal result:
Related
I have a problem when I visualize dates in my application.
I have a asp.net core application. I have razor pages. The culture set in my server is English, so the date format is mm-dd-yyyy.
Now we have users in USA and in Italy. So dates must be shown in different ways: "mm-dd-yyyy" in USA and "dd-mm-yyyy" in Italy.
We do not have this problem in input tag:
<input type="date" asp-for="#item.MyDate" />
Obviously it work because in my input tag I set the type=date. If I set
<input type="text" asp-for="#item.MyDate" />
It would not work anymore.
Now I have the problem with labels and span.. I cannot set the type of the data in those tags. So the date is always shown in English.
How can I solve this problem? Exists a way to solve it without js or without modifying the server?
Thank you
The culture set in my server is English, so the date format is
mm-dd-yyyy. Now we have users in USA and in Italy. So dates must be
shown in different ways: "mm-dd-yyyy" in USA and "dd-mm-yyyy" in
Italy.
In this scenario, firstly, you should get the user-culture, or user browser's language even we can consider http request header as well.
Based on that, we can decide which date format should display in view. Using Custom Middleware we can achieve that. I can provide an work around showing the middleware example
DateFormatterMiddleware:
public class DateFormatterMiddleware
{
private readonly RequestDelegate next;
public DateFormatterMiddleware(RequestDelegate next) { this.next = next; }
public async Task InvokeAsync(HttpContext context)
{
var userLanguages = context.Request.Headers.AcceptLanguage;
var selectLan = userLanguages.ToString();
var languages = selectLan.Split(',')
.Select(StringWithQualityHeaderValue.Parse)
.OrderByDescending(s => s.Quality.GetValueOrDefault(1));
var userLan = languages.Select(val => val.Value).ToList();
foreach (var item in userLan)
{
DateTime currentDate = DateTime.Now;
if (item.Contains("en-US") || item.Contains("it-IT"))
{
if (item == "en-US")
{
var enUS_Format = currentDate.ToString("MM-dd-yyyy", CultureInfo.CreateSpecificCulture("en-US"));
context.Session.SetString("DateFormat", enUS_Format);
break;
}
if (item == "it-IT")
{
var italy_Format = currentDate.ToString("dd-MM-yyyy", CultureInfo.CreateSpecificCulture("it-IT"));
context.Session.SetString("DateFormat", italy_Format);
break;
}
}
}
await next(context);
}
}
Resgister DateFormatterMiddleware In Program.cs:
builder.Services.AddSession();
app.UseSession();
Use DateFormatterMiddleware In Program.cs:
app.UseMiddleware<DateFormatterMiddleware>();
View
#inject IHttpContextAccessor _httpcontext;
#{
var data = _httpcontext.HttpContext?.Session.GetString("DateFormat")?.ToString();
}
<h3>User Current Date Format :#data</h3>
Output
Note: If you need any further assistance you could refer to following guideline.
How you can set user-culture
Inside-out user culture
I am able to export table data to excel dynamically, but some of the data like long numbers and negative values are formatted
Below is the UI Table data
[enter image description here][1]
exported data to CSV
[enter image description here][2]
when I select the long values it showing the proper value on top of excel, and -ve values are appended with '......
Code :
jQuery.sap.require("sap.ui.core.util.Export");
jQuery.sap.require("sap.ui.core.util.ExportTypeCSV");
sap.ui.define([
'jquery.sap.global',
'sap/ui/core/mvc/Controller',
'sap/ui/model/json/JSONModel'
], function(jQuery, Controller, JSONModel) {
"use strict";
var vSrcMATNR;
var oEvtBus = sap.ui.getCore().getEventBus();
var TableController = Controller.extend("UtilLoad.Util", {
exportToExcel: function(oTable) {
var that = this;
var aColumns = oTable.getColumns();
var aItems = oTable.getItems();
var aTemplate = [];
for (var i = 0; i < aColumns.length; i++) {
var oColumn = {
name: aColumns[i].getHeader().getText(),
template: {
content: {
path: null
}
}
};
if (aItems.length > 0) {
oColumn.template.content.path = aItems[0].getCells()[i].getBinding("text").getPath();
}
aTemplate.push(oColumn);
}
var oExport = new sap.ui.core.util.Export({
// Type that will be used to generate the content. Own ExportType’s can be created to support other formats
exportType: new sap.ui.core.util.ExportTypeCSV({
separatorChar : ",",
charset : "utf-8"
}),
// Pass in the model created above
models: oTable.getModel(),
// binding information for the rows aggregation
rows: {
path: "/"
},
// column definitions with column name and binding info for the content
columns: aTemplate
});
oExport.saveFile().always(function() {
this.destroy();
});
},
fnDate: function(sDate) {
if (sDate) {
var oDateFormat = sap.ui.core.format.DateFormat.getDateTimeInstance({
pattern: "dd-MM-yyyy"
});
return oDateFormat.format(new Date(sDate));
} else {
return sDate;
}
}
});
return TableController;
});
from SAP documentation advicing to use data export functionality , please what is it and how
https://openui5.hana.ondemand.com/#docs/api/symbols/sap.ui.core.util.ExportTypeCSV.html
Thanks
Rajesh
Please convert that numbers into string by giving Tab Space between double quotes in the return statement.
{
name: "Stock",
template: {
content: {
parts: ["StockPosition"],
formatter: function(value) {
return " " + value;
}
}
}
}
please find below screen shot
exported excel data
vH,
Yes,main concern is while transforming data to excel.By appending tab character (\x09) I can avoid scientific notation in excel.
Not sure is the best solution or not
Thanks
Rajesh
Concerning your problem with values being formatted in scientific notation like 2.85E+12:
it is generally not a good idea to deal with precise large numbers in JavaScript, because JavaScript uses double precision floating point numbers as defined in the IEEE 754 standard. They lose precision very quickly!
Just try
console.log(9999999999999999);
the result will be
10000000000000000
If you want to avoid scientific notation in JavaScript, you have to write your own toString-function by concatenating each digit
function convertToString(fNumber){
var sResult='';
do{
var iDigit = fNumber%10;
fNumber=Math.trunc(fNumber/10);
sResult = iDigit+sResult;
}while(fNumber>0)
return sResult;
}
But your main problem is Excel!
If your csv-file looks like this
Customer;Product;EAN;Price
SAP;Hana;1234567890123;1000
SAP;R/3;1234567890124;-1000
SAP;OpenUI5;1234567890126;9999999999999999
Excel will show a table that contains scientific notation again!
Customer Product EAN Price
SAP Hana 1,23E+12 1000
SAP R/3 1,23E+12 -1000
SAP OpenUI5 1,23E+12 1E+16
I am trying to set up a customization that will dynamically display values in a series of fields using a switch statement.
If we focus on one field I have a String List
public static class SMSPlans
{
public const string A = "A";
public const string B = "B";
public const string C = "C";
public const string Z = "Z";
}
[PXDBString(2, IsUnicode = true)]
[PXDefault(SMSPlans.Z)]
[PXUIField(DisplayName = "SMS Plan Selected")]
[PXStringList(
new string[]
{
SMSPlans.A,
SMSPlans.B,
SMSPlans.C,
SMSPlans.Z
},
new string[]
{
"Plan A",
"Plan B",
"Plan C",
"No Text Plan"
})]
I would like to when this field is set to any one of the allowable values populate a series of fields with corresponding fixed values as shown in the image below (0 is default value currently would show up if any plan is selected)
I planned on using the formula functions and using a switch statement to set my desired value that would look like
[PXFormula(null,typeof(Switch<Case<Where<Current<UsrMPSMSPlanSelected, Equal<SMSPlans.A>>,0>))]
I am stuck however on:
How I need to use the _RowSelect() or other event handlers
What if any value would be stored in the database for these fields assigned by the switch statment
finally is this switch structured correctly as it is not currently working
From what I can tell you have a few ways to handle this.
1) With PXFormula attribute tags - your Switch definition is mostly correct in the sample above but depending on where you have it the PXFormula definition itself is incorrect. What I would do is put the PXFormula tag on the fields that need to be updated.
For example, if your field is UsrMinText use the following:
[PXFormula(typeof(Switch<Case<Where<UsrMPSMSPlanSelected,Equal<SMSPlans.A>>,{value if true},{value if false or more case statements}))]
2) Personally for this type of customization I would use an actual event method in the BLC to do this. A good example of this is in the help guide for the events.
protected void Batch_ManualStatus_FieldUpdating(PXCache sender, PXFieldUpdatingEventArgs e)
{
Batch batch = (Batch)e.Row;
if (batch != null && e.NewValue != null)
{
switch ((string)e.NewValue)
{
case "H":
batch.Hold = true;
batch.Released = false;
batch.Posted = false;
break;
case "B":
batch.Hold = false;
batch.Released = false;
batch.Posted = false;
break;
case "U":
batch.Hold = false;
batch.Released = true;
batch.Posted = false;
break;
case "P":
batch.Hold = false;
batch.Released = true;
batch.Posted = true;
break;
}
}
}
In either method, the value that will be stored in the database is whatever you specify in either the {True}/{False} values for PXFormula or the values specified in the actual switch methods.
One thing to remember is field order in the DACS is important. I'd read through the training information and help guides for more information on this.
I am using eclipse e4. I have three timeseries which has inputs dynamically from GUI.
/*some code to calculate the entries from a hashmap*/
for (i = 0; i < statValue.length; i++) {
if(statValue[i].equals("MIN"))
{
timeseries[i] = new TimeSeries(entries.getKey()+statValue[i],Second.class);
}
if(statValue[i].equals("MAX"))
{
timeseries[i] = new TimeSeries(entries.getKey()+statValue[i],Second.class);
}
if(statValue[i].equals("AVG"))
{
timeseries[i] = new TimeSeries(entries.getKey()+statValue[i],Second.class);
}
/* some code to calcluate the input to the timeseries */
if(statValue[i].equals("MIN")){
for(Entry<Timestamp,Long> seriesData : MinutesToMin.entrySet()){
System.out.println(new Second(seriesData.getKey())+" "+seriesData.getValue());
timeseries[i].add(new Second(seriesData.getKey()), seriesData.getValue());
}
dataset.addSeries(timeseries[i]);
}
System.out.println("MAX");
if(statValue[i].equals("MAX")){
for(Entry<Timestamp,Long> seriesData : MinutesToMax.entrySet()){
System.out.println(new Second(seriesData.getKey())+" "+seriesData.getValue());
timeseries[i].add(new Second(seriesData.getKey()), seriesData.getValue());
}
dataset.addSeries(timeseries[i]);
}
System.out.println("AVG");
if(statValue[i].equals("AVG")){
for(Entry<Timestamp,Long> seriesData : MinutesToAvg.entrySet()){
System.out.println(new Second(seriesData.getKey())+" "+seriesData.getValue());
timeseries[i].add(new Second(seriesData.getKey()), seriesData.getValue());
}
dataset.addSeries(timeseries[i]);
}
}
After the series are displayed in Jfreechart. In my code the timeseries may change depending on the "statValue" that I select from my GUI. The timeseries gets dynamically added. I do not want to add the timeseries if it is already present. How to check if timeseries is already present and is it is present I want to remove it.?
Every TimeSeries has a key to identify it. To see if a TimeSeries exists in a TimeSeriesCollection use the getSeries(Comparable) method in that class - it will return null if there is no series with that key. If it returns a non-null value, then you can call the removeSeries(TimeSeries) method to remove it.
I have a GWT project for which the locale is set to fr. I have a custom text field that uses a number format to validate and format the numerical inputs.
The formatting works fine but not the input validation. Here is a snapshot of the method that validates that the new value is a valid percentage (this is called onValueChanged):
private void validateNumber(String newVal){
logger.debug("value changed, newVal="+newVal+", current="+current);
// Attempt to parse value
double val=0;
try{
val=Double.parseDouble(newVal);
}catch(NumberFormatException e){
logger.warn("parsing failed",e);
try{
val=getFormatter().parse(newVal);
}catch(NumberFormatException ex){
logger.warn("parsing with nb format failed",ex);
// on failure: restore previous value
setValue(current,false);
return;
}
}
//some check on min and max value here
}
For example if the starting value is set by the program to "0.2" it will show up as 20,00 % hence using the correct decimal separator.
Now:
if I input 0,1 I get a numberformat exception.
if I input 0.1 it show as 10,00 %
if I 10% (without the space before the '%'), I get a numberformat exception
Do you know how I can modify the method to have 0,1 and 10% identified as valid inputs?
As Colin mentioned, you definitely want to parse and format using a GWT Number Format object, not Double, so the parsing and formatting are properly locale specific.
Below is some code snippets I could find to parse, validate and format a percent number.
Note however the edit process has the % unit hard-coded outside of the text box value, hence no conversion between 20,45% and 0.2045 in the edit process, 20,45 is entered directly and visualized as such. I vaguely recall struggling with such conversion during the edit process but forgot the details as it was a while back. So if it is a critical part of your question and requirements then I am afraid the examples below may be of limited value. Anyway, here they are!
Notations:
TextBox txt = new TextBox();
NumberFormat _formatFloat = NumberFormat.getFormat("#,##0.00");
NumberFormat _formatPercent = NumberFormat.getFormat("##0.00%");
Parsing text entry like "20,45" as 20.45 (not "20,45%" as 0.2045):
txt.setText("20,45"); // French locale format example, % symbol hard-coded outside of text box.
try {
float amount = (float) _formatFloat.parse(txt.getText());
} catch (NumberFormatException e) ...
Parsing & Validating text entry like "20,45":
private class PercentEntryValueChangeHandler implements ValueChangeHandler<String>
{
#Override
public void onValueChange(ValueChangeEvent<String> event)
{
validatePercent((TextBox) event.getSource());
}
};
private void validatePercent(final TextBox percentTextBox)
{
try
{
if (!percentTextBox.getText().isEmpty())
{
final float val = (float) _formatFloat.parse(percentTextBox.getText());
if (isValid(val))
percentTextBox.setText(_formatFloat.format(val));
else
{
percentTextBox.setFocus(true);
percentTextBox.setText("");
Window.alert("Please give me a valid value!");
}
}
}
catch (NumberFormatException e)
{
percentTextBox.setFocus(true);
percentTextBox.setText("");
Window.alert("Error: entry is not a valid number!");
}
}
private boolean isValid(float val) { return 12.5 < val && val < 95.5; }
txt.addValueChangeHandler(new PercentEntryValueChangeHandler());
Formatting 20.45 as "20,45":
float val = 20.45;
txt.setText(_formatFloat.format(val));
Formatting 0.2045 as "20,45%" (read only process, the text box is not editable, the % is set inside the text box):
float val = 0.2045;
txt.setText(_formatPercent.format((double)(val))); // * 100 embedded inside format.
It is not fancy and probably far from perfect but it works!
Any feedback on how to improve upon this implementation is more than welcome and appreciated!
I hope it helps anyway.
I managed to make it work by changing the code to the following:
private void validateNumber(String newVal){
double val=0;
try{
val=getFormatter().parse(newVal);
}catch(NumberFormatException e){
boolean ok=false;
try{
val=NumberFormat.getDecimalFormat().parse(newVal);
ok=true;
}catch(NumberFormatException e1){}
if(!ok){
try{
val=Double.parseDouble(newVal);
}catch(NumberFormatException ex){
setValue(current,false);
// inform user
Window.alert(Proto2.errors.myTextField_NAN(newVal));
return;
}
}
}