How to change xAxisTickFormatting in ngx-charts-line-chart based on timeline selection? - ngx-charts

By default, ticks are formatted based on time range selection in timeline. If it pans across days it shows month and if it is with in a day, it shows only time. This is great!
Now I want to localize these ticks. I could provide xAxisTickFormatting to get this done but I want to have the formatting based on the time range selection. "MMM DD" or "HH:MM" based on the current time range selection.
For this I need to change the formatting function dynamically on time range selection event. Is there such an event? Or is there any other way to achieve this?

In your chart, among the other attributes, you can declare
<ngx-charts-bar-horizontal-normalized
...
[xAxis]="true"
[xAxisTickFormatting]='formatPercent'
...
</ngx-charts-bar-horizontal-normalized>
formatPercent is a function declared in your .ts file (I'm using Angular) written like
formatPercent(val) {
if (val <= 100) {
return val + '%';
}
}
For any reference check the documentation here
Hope this helps.

It looks like, date is formatted based on the d3 logic. It uses the precision available to that tick. So if date is 12/15/2020 11:30:00, precision is at minute level. Similarly if date is 12/15/2020 00:00:00, precision is at day level.
Now we can choose the format options accordingly.
var locale = 'fr-FR'; // 'en-US'
function formatDate(value) {
let formatOptions;
if (value.getSeconds() !== 0) {
formatOptions = { second: '2-digit' };
} else if (value.getMinutes() !== 0) {
formatOptions = { hour: '2-digit', minute: '2-digit' };
} else if (value.getHours() !== 0) {
formatOptions = { hour: '2-digit' };
} else if (value.getDate() !== 1) {
formatOptions = value.getDay() === 0 ? { month: 'short', day: '2-digit' } : { weekday: 'short', day: '2-digit' };
} else if (value.getMonth() !== 0) {
formatOptions = { month: 'long' };
} else {
formatOptions = { year: 'numeric' };
}
return new Intl.DateTimeFormat(locale, formatOptions).format(value);
}
var dates = ['12/15/2020 11:30:30', '12/15/2020 11:30:00', '12/15/2020 11:00:00', '12/15/2020 00:00:00', '12/13/2020 00:00:00', '12/01/2020 00:00:00', '01/01/2020 00:00:00'];
for (date of dates) {
console.log(date, '=>', formatDate(new Date(date)));
}
Now this function can be used as
<ngx-charts-line-chart
[xAxis]="true"
[xAxisTickFormatting]="formatDate">
</ngx-charts-line-chart>

Related

Vuejs: how to loop start time to multiply end time with var x

I have data start_time, end_time, x, and result. I want to display it in the select option, the first option is the initial data start_time, and continues to loop multiples of variable x and ends until the value is equal to end_time. here are the expectations.
Here my view:
<select class="form-control">
<option>08:00:00</option>
<option>08:15:00</option>
<option>08:30:00</option>
<option>08:45:00</option>
<option>09:00:00</option>
<option>...</option>
<option>19:00:00</option>
</select>
This is my code:
data: function () {
return {
start_time: '08:00:00',
end_time: '19:00:00',
x: 15,
result:'',
}
},
computed:{
}
What you can do is create a computed property which returns an array of all the available time options given the start_time and the end_time constraints. Then loop it to your <option/> element using v-for.
<select class="form-control">
<option v-for="(time, index) in times" :key="index">{{time}}</option>
</select>
computed: {
times() {
// transform the start_time and end_time to Date for easier comparison.
let startTime = new Date(`1/1/1970 ${this.start_time}`);
const endTime = new Date(`1/1/1970 ${this.end_time}`);
// This interval is in Minutes.
const interval = this.x * 60000;
// The result array where we will store the time
const results = [];
while (startTime.getTime() <= endTime.getTime()) {
results.push(`${this.formatTime(startTime)}`);
startTime = new Date(startTime.getTime() + interval);
}
return results;
}
},
methods: {
formatTime(date) {
// format the date here...
return '00:00:00';
}
}
For formatting date, you can either use third-party library to do the job, or you can use vanilla javascript.
formatTime(date) {
const hours = date.getHours().toString().padStart(2, "0");
const minutes = date.getMinutes().toString().padStart(2, "0");
const seconds = date.getSeconds().toString().padStart(2, "0");
return `${hours}:${minutes}:${seconds}`;
}
Here is a working demo.

VueJs: To Disable all dates up to specific date based on condition

I have datepicker below :
import Datepicker from 'vuejs-datepicker';
<datepicker :disabled-dates="disabledDates" v-model="dateTime" :format="customFormatter" width="100%" name="Date"></datepicker>
If CurrentDay == "Monday" then, disable all dates up to last friday of previous week. Otherwise, disable all dates up to last friday of current week.
export default {
created: function() {
var currentDate = new Date().toJSON().slice(0,10).replace(/-/g,'-');
var CurrentDay = moment().format('dddd'); //new Date().getDay();
if (CurrentDay == "Monday"){
this.disabledDates= {
to: new Date(2020, 2, 5) // Here disable all dates up to last friday of the previous week.
};
}
else{
this.disabledDates= {
to: new Date(2020, 2, 5) //Here disable all dates up to last friday of the current week.
};
}
}
}
sandbox
<template>
<div id="app">
Current date: {{ date }}
<Datepicker v-if="date" :value="today" :disabled-dates="disabledDates"/>
</div>
</template>
<script>
import Datepicker from "vuejs-datepicker/dist/vuejs-datepicker.esm.js";
export default {
data() {
return {
today: new Date(),
date: null,
disabledDates: {}
};
},
components: {
Datepicker
},
methods: {
// Utility: To get date by day
// In our case to get last week friday & this week friday
// first param: current date / any select date as reference
// second param: day, in our case friday ie. 5
// third param: week, in our case last week ie. -7 (7 days from now) & current week ie. 0
getDateByDay(currDate, day, week = 0) {
var reqDate = currDate;
var reqDay = day - currDate.getDay() + week;
reqDate.setDate(reqDate.getDate() + reqDay);
return {
day: reqDate.getDate(),
month: reqDate.getMonth(),
year: reqDate.getFullYear()
};
},
// Strategy / logic to block on basis of monday / other days
strategy({ year, month, day }) {
this.date = new Date(year, month, day);
let getDay = this.date.getDay();
console.log({ getDay });
// Check if monday ie. 0
if (getDay === 1) {
let { day, month, year } = this.getDateByDay(this.date, 6, -7 * 2);
// Get last friday date & block upto last friday
this.disabledDates.to = new Date(year, month, day);
}
// OTHER THAN MODAY
else {
let { day, month, year } = this.getDateByDay(this.date, 6, -7);
// Get current friday & block uptp current friday
this.disabledDates.to = new Date(year, month, day);
}
}
},
mounted() {
// invoke blocking function with any date
this.strategy({ year: 2020, month: 2, day: 25 });
}
};
</script>
PS: You can modify logic as per your use case by passing desired params.

Subtract 2 times in react-native

I want to subtract two times and check if check_in time > 12Hr then navigate to checkin screen. This is my code snippet
class SplashView extends Component {
componentDidMount() {
const curr_time = moment().format('hh:mm:ss');
const checkin_time = moment(this.props.datetime).format('hh:mm:ss');
// const diff = moment.duration(checkin_time.diff(curr_time));
console.log("TIME&&&&&&&&", curr_time, checkin_time);
setTimeout(() => {
if (this.props.employee_id === null) {
this.props.navigation.navigate('Login');
} else {
this.props.navigation.navigate('Checkin');
}
}, 1000)
}
render() {
return ();
}
}
I'm using moment.js and the value of this.props.datetime is '2019-02-04 14:52:01'. This is my checkin time.
You can get the difference in hours like this:
const diff = moment.duration(checkin_time.diff(curr_time)).as('hours');
Or you can just use moment's diff function
const diff = checkin_time.diff(curr_time, 'hours')
and then compare if (diff > 12) { ... }

TypeError: expected dynamic type 'double' but had type 'string'

I'm running into this error when trying to use datePickerAndroid and setting the state afterwards.
Error Message
I feel like the problem may be from the initial state being a new Date() but not 100% sure.
_isAndroid = async () => {
let {action, year, month, day} = await DatePickerAndroid.open({
date: this.props.startDate,
});
if (action === DatePickerAndroid.dismissedAction) {
this.props.closeModal()
} else {
const date = year + "-" + month + "-" + day
this.props.onDateChange(date)
}
}
Prop Function:
onDateChange = (newDate) => {
this.setState({currentDate: newDate}) // <- This one is breaking
let dates = this.state.dates;
let index = this.state.currentIndex;
if (this.state.currentKey === "start") {
dates[index].start = newDate
} else {
dates[index].end = newDate
}
this.setState({dates: dates});
}
I've narrowed it down to the first setState, and I've tried making the initial state a string as well as setting the state to a simple string but still getting the error.
For DatePickerAndroid
expected dynamic type double
In other words native component wants time, but you put string. You this.props.startDate is string, transfer time in time format. Example:
const {action, year, month, day} = await DatePickerAndroid.open({
date: new Date() // <- This is Date, not string!
});
Good luck!

Dojo's dijit.calendar and isDisabledDate

I'd like to use the dijit.calendar widget, but be able to set disabled dates from an array of dates. All the examples point out how to disable weekends, but I need to disable special dates too.
Can anyone point me in the right direction to utilize a custom function in the isDisabledDate, rather than just whats in dojo.date.locale?
I've tried writing a function, and putting it inside the isDisabledDate attribute, but all I get is errors.
I'm making a huge assumption here, that you're populating your array for each month displayed via an XHR request. This XHR request returns an array of strings in Y-m-d format (i.e. ['2011-11-29','2011-11-30']). Another slight assumption is that the XHR request returns an array of dates that should be enabled, but this can be reversed by swapping the disable = true; and disable = false; lines
I don't know how much detail to go into without being patronizing, so if anything is unclear I'll try to clarify afterwards.
dojo.provide("custom.Calendar");
dojo.declare("custom.Calendar", dijit.Calendar, {
_xhr: null,
// Month/Year navigation buttons clicked
_adjustDisplay: function(){
// Ensure all dates are initially enabled (prevents seepage)
this.isDisabledDate = function(date) {
return false;
};
this.inherited(arguments);
this._disableAndPopulate();
},
constructor: function(){
this.inherited(arguments);
this._disableAndPopulate();
},
// Month drop down box
_onMonthSelect: function(){
// Ensure all dates are initially enabled (prevents seepage)
this.isDisabledDate = function(date) {
return false;
};
this.inherited(arguments);
this._disableAndPopulate();
},
// Set disabled dates and re-render calendar
_disableAndPopulate: function(){
var currDate = this.currentFocus;
// Get Lower bound date
var startDate = new Date();
startDate.setFullYear(currDate.getFullYear(), currDate.getMonth(), -5);
// Create ymd dates manually (10x faster than dojo.date.locale.format)
var startMonth = (startDate.getMonth()<9 ? '0' + (startDate.getMonth()+1) : startDate.getMonth()+1);
var startDay = (startDate.getDate()<10 ? '0' + startDate.getDate() : startDate.getDate());
var ymdStartDate = startDate.getFullYear() + '-' + startMonth + '-' + startDay;
// Get Upper bound date
var endDate = new Date();
endDate.setFullYear(currDate.getFullYear(), currDate.getMonth() + 1, 14);
// Create ymd dates manually (10x faster than dojo.date.locale.format)
var endMonth = (endDate.getMonth()<9 ? '0' + (endDate.getMonth()+1) : endDate.getMonth()+1);
var endDay = (endDate.getDate()<10 ? '0' + endDate.getDate() : endDate.getDate());
var ymdEndDate = endDate.getFullYear() + '-' + endMonth + '-' + endDay;
var calendar = this;
// Get IssueDates
var issueDates;
// If an existing xhr request is still running, cancel it before starting a new one
if (this._xhr) {
this._xhr.cancel();
}
this._xhr = dojo.xhrGet({
url: "http://.....", // url of server-side script
content: {
startDate: ymdStartDate, // Earliest possible date displayed on current month
endDate: ymdEndDate, // Last possible date displayed on current month
filters: {} // Any additional criteria which your server-side script uses to determine which dates to return
},
failOk: true, // Prevent error being logged to console when previous XHR calls are cancelled
load: function(data){
issueDates = dojo.fromJson(data);
if (issueDates === undefined) {
// Error with xhr
} else {
calendar.isDisabledDate = function(date) {
var disable = true;
// Create ymdDate manually (10x faster than dojo.date.locale.format)
var month = (date.getMonth()<9 ? '0' + (date.getMonth()+1) : date.getMonth()+1);
var day = (date.getDate()<10 ? '0' + date.getDate() : date.getDate());
var ymdDate = date.getFullYear() + '-' + month + '-' + day;
// Loop through array returned from XHR request, if it contains current date then
// current date should not be disabled
for (key in issueDates) {
if (issueDates[key] == ymdDate) {
disable = false;
break;
}
}
return disable;
};
calendar._populateGrid(); // Refresh calendar display
}
},
// Log any errors to console (except when XHR request is cancelled)
error: function(args) {
if (args.dojoType == 'cancel') {
// Request cancelled
} else {
console.error(args);
}
}
});
},
onClose: function() {
// If an existing xhr request is still running, cancel it before starting a new one
if (this._xhr) {
this._xhr.cancel();
}
}
});
AMD style:
CalendarLite.js.uncompressed.js in dojo 1.7.1 contains the isDisabledDate function:
isDisabledDate: function(/*===== dateObject, locale =====*/){
// summary:
// May be overridden to disable certain dates in the calendar e.g. `isDisabledDate=dojo.date.locale.isWeekend`
// dateObject: Date
// locale: String?
// tags:
// extension
/*=====
return false; // Boolean
=====*/
},
...
You could re-implement the function using this example:
var myCalendar = declare(Calendar, {
datesToDisable : [],
constructor: function(args) {
this.inherited("constructor", arguments);
this.datesToDisable = args.datesToDisable;
},
isDisabledDate: function(/*Date*/date, /*String?*/locale){
return array.some(this.datesToDisable, function(item) {
return dojo.compare(item, date, "date") === 0;
});
}
});
Then you can use the following constructor and datesToDisable parameter to specify your array.
var someCalendar = new myCalendar({datesToDisable: [new Date(...),....,new Date(....)]},...);
or try this for a fast and dirty solution:
var someCalendar = new Calendar(...);
someCalendar.datesToDisable = [new Date(...),....,new Date(....)];
someCalendar.isDisabledDate = function(/*Date*/date, /*String?*/locale){
return array.some(this.datesToDisable, function(item) {
return date.compare(item, date, "date") === 0;
});
}
But I would recommend the first approach. The assumption is that you know AMD style in order to "import" dijit/Calendar, dojo/_base/array and dojo/date (for "date.compare()" to work).
Cheers!
You can add list of holidays in an array with its timestamp and use indexOf method to find matching dates while populating the calendar in the overriding function of isDisabledDate
var holidays = new Array();
var holidDt = new Date("October 2, 2012");
holidays.push(holidDt.getTime());
Now access the holiday array and check its presence. If present disable, else enable by overriding the isDisabledDate function
isDisabledDate: function(d) {
var dt = new Date(d);
var dayN = dt.getDay();
dt.setHours(0, 0, 0, 0);
/**
* Condition for
* 1. Weekends
* 2. Holidays (holiday array needs to be updated with holiday times)
*/
return ((!((dayN > 0) && (dayN < 6))) || (arrayUtil.indexOf(holidays, dt.getTime()) >= 0));
}