Reputation: 31
I have a horizontal calendar where each month has a width of 183px
(pixels). I want to display a timespan bar on top of this horizontal calendar (See photo below) depending on a starting date and a ending date. So if I have a start date of:01-01-2020
and an end date of: 03-15-2020
that is about 2.5 months * 183px
which is the closes I could get, but what could I do or use to determine that: 03-15-2020 - 01-01-2020 = ~2.5 months
as accurate as possible? In addition I need this timespan bar to start on the current date of my horizontal calendar so if it starts on 02-01-2020
then the timespan div would start at left: 183px;
I am currently exploring date-fns
but have had no luck yet. Anything could help, thank you so much for your time. I am using React.js, Javascript, & Typescript.
Image of horizontal calendar and time span bar
Upvotes: 0
Views: 418
Reputation: 147403
You can calculate the width of the bar for a particular date range by getting the number of days in the range, then calculate the width as a percentage of the full width based on the percentage of days in the range to a full year.
i.e. eventWidth = daysInRange ÷ daysInYear * grahpFullWidth
If you just want to position something from the start of the year, then always use 1 Jan of the current year as the start of the range.
E.g. the following puts today's date on a bar that is 183px wide. You can change the graph by changing the style properties, e.g. set the width to 300px.
function getDayOfYear(date) {
// Use UTC to avoid any DST issues
let d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
let yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
return Math.ceil((d - yearStart) / 8.64e7) + 1;
}
function getDaysInYear(date) {
return getDayOfYear(new Date(date.getFullYear(), 11, 31));
}
function graphDate(date) {
let dayNum = getDayOfYear(date);
let daysInYear = getDaysInYear(date);
let timeline = document.getElementById('timeline');
let someEvent = document.getElementById('someEvent');
let dateText = document.getElementById('dateText');
let fullWidth = parseInt(window.getComputedStyle(timeline).getPropertyValue('width'));
let partWidth = fullWidth * dayNum / daysInYear;
someEvent.style.width = partWidth + 'px';
dateText.textContent = date.toLocaleString('en-GB',{
day: 'numeric',
month: 'short'
});
dateText.style.marginLeft = partWidth - 1 + 'px';
document.getElementById('yearLabel').textContent = date.getFullYear();
}
// Graph today
graphDate(new Date());
#timeline {
border: 1px solid red;
width: 183px;
height: 10px;
}
#someEvent {
border: 0;
height: 10px;
background-color: green;
width: 0px;
}
#startLabel {
width: 90px;
display: inline-block;
}
#yearLabel {
width: 90px;
display: inline-block;
font-size: 130%;
}
#dateText {
padding: 15px 0 0 3px;
border-left: 1px solid blue;
}
<div id="labels">
<span id="startLabel">1 Jan</span>
<span id="yearLabel"></span>
<span id="endLabel">31 Dec</span>
</div>
<div id="timeline">
<div id="someEvent"></div>
</div>
<div id="dateText"></div>
Upvotes: 1
Reputation: 79
The laziest way i can think of is to write the style for your bar component(which i assume is absolute and relative to calendat) with js, and based on between which months it is set the width calculated based on that. something like this
var newStyles = document.createElement('style')
document.head.append(newStyles)
newStyles.innerHTML = ".my-element {" +
"height: " + height + "px;" +
"width: 40px;" +
"color: #9b806b;" +
"}"
Upvotes: 0