d3js line graph not showing - javascript

I am working on creating a line graph and I am having a rather trivial issue. I am using d3js V4 and the specific code is as follows:
$(scope.container).append($('<svg id="svgimg" width="640" height="350" style="margin-left:auto;margin-right:auto;"></svg>'));
var mainGroup = d3.select("#svgimg").append("g");
d3.select("#svgimg").call(d3.zoom().on("zoom",function(){
mainGroup.attr("transform","translate(" + d3.event.transform.x+","+d3.event.transform.y+") scale ("+d3.event.transform.k+")" );
}));
var parseTime = d3.timeParse("%d-%y");
var svg = $("#svgimg"),
margin = {top:20,right:20,bottom:20,left:20},
width = +Number(svg.attr("width")) - margin.left -margin.right,
height = +Number(svg.attr("height")) - margin.top-margin.bottom,
g = mainGroup.append("g").attr("transform","translate("+margin.left+","+margin.top+")");
//console.log(width);
//console.log(height);
var n = 2000;
// random = d3.randomNormal(0,.2),
// data = d3.range(n).map(random);
var x =d3.scaleTime()
.domain([new Date(2017,10,1),new Date(2017,10,31)])
.range([0,width]);
var y = d3.scaleLinear()
.domain([0,2000])
.range([height,0]);
var line = d3.line()
.x(function(d,i){return x(parseTime(d.date));})
.y(function(d,i){return y(Number(+d.distance));});
g.append("defs").append("clipPath")
.attr("id","clip")
.append("rect")
.attr("width",width)
.attr("height",height)
g.append("g")
.attr("class","axis axis--x")
.attr("transform","translate(0,"+y(0)+")")
.call(d3.axisBottom(x))
g.append("g")
.attr("class","axis axis--y")
.call(d3.axisLeft(y))
g.append("g")
//.attr("clip-path","url(#clip)")
.append("path")
.datum(scope.data)
.attr("d",line)
.attr("class","linea");
svg.innerHTML = svg.innerHTML;
Where scope is an object (this) with a number of components.
Specifically, the line for the line graph is not visible while the side and bottom scales are. Further, upon inspection, the path element has the some associated data and if only I could see it, could begin debugging.
Any info would be greatly appreciated
Edit: The scope.data object contains an array of objects with time,date,distance and stamp fields. The graph "d" attribute is showing an X range from -25000 -> 25000 with a Y value of 155. I should be seeing a horizontal line from left side to right side but this is not happening. Also, I believe the time parsing to be the major culprit. The time value has been temporarily modified to be equal to a UTC datetime string.
Edit: The time is a UTC datetime string similar to:
Tue Sep 19 2017 09:33:42 GMT+1000 (AEST)
With rows differing by +- 10 minutes
I am currently using the following code:
var parseTime = d3.timeParse(d3.timeFormat.utc);
The complete array as from parsed json from browser
results
:
[{time: "Tue Sep 19 2017 09:33:42 GMT+1000 (AEST)", date: "11:00 AM",
distance: "1000", stamp: "0"},…]
0
:
{time: "Tue Sep 19 2017 09:33:42 GMT+1000 (AEST)", date: "11:00 AM",
distance: "1000", stamp: "0"}
1
:
{time: "Tue Sep 19 2017 09:23:42 GMT+1000 (AEST)", date: "11:00 AM",
distance: "1000", stamp: "0"}
2
:
{time: "Tue Sep 19 2017 09:13:42 GMT+1000 (AEST)", date: "11:00 AM",
distance: "1000", stamp: "0"}
3
:
{time: "Tue Sep 19 2017 09:03:42 GMT+1000 (AEST)", date: "11:00 AM",
distance: "1000", stamp: "0"}
4
:
{time: "Tue Sep 19 2017 08:53:42 GMT+1000 (AEST)", date: "11:00 AM",
distance: "1000", stamp: "0"}
5
:
{time: "Tue Sep 19 2017 08:43:42 GMT+1000 (AEST)", date: "11:00 AM",
distance: "1000", stamp: "0"}
6
:
{time: "Tue Sep 19 2017 08:33:42 GMT+1000 (AEST)", date: "11:00 AM",
distance: "1000", stamp: "0"}
7
:
{time: "Tue Sep 19 2017 08:23:42 GMT+1000 (AEST)", date: "11:00 AM",
distance: "1000", stamp: "0"}
8
:
{time: "Tue Sep 19 2017 08:13:42 GMT+1000 (AEST)", date: "11:00 AM",
distance: "1000", stamp: "0"}
I appologise for not posting earlier however, I felt it was irrelevant as no edits in any way have brought the path element into view.

#Gerado Furtado
Thank you for your patience, you may have answered the question without realising it. The answer was to ensure the "scope.data[].time" attribute was parsed with "new Date(scope.data[].time)" and the solution has worked. Thank you again, Patrick.

Related

Count Full Year from Date String

I'm currently working in Node with mongoose as a database. I have two models product and customer .whenever a customer buy a product, the current Date gets stored in SellingDate attribute of the product. Now the thing I want to achieve is that when we give a random Date as input, it should compare it with all Selling dates of all products up to one year, and return us COUNT OF ALL DATES THAT LIE BETWEEN ONE YEAR. For example , if we have 5 records in database i.e
{
"Sun Feb 25 2015" , "Fri Mar 25 2015" , "Sat Dec 25 2015" , "Mon Feb 25 2016"
}
and I give " Sun Feb 25, 2015" as input it should return 2 as output because we have two dates between Feb 2015 - Feb 2016 .... and it should compare dates in String format because I store the date in "Day Month Date Year" format ...
You could do an aggregation where you first convert the date strings to a date using $toDate and also keep track of the year using $year. Then you can $match all documents within the given date range, and finally $group by the year and $count:
YourModel.aggregate([
{ "$addFields": {
"year":{ "$year": {
"$toDate": "$date"
}
} }},
{
$match: {
// define your range of years here, it would be 2015 - 2016 in your case
year: {$gte: 2016, $lte: 2020}
}
},
{
$group: {
_id: {year: "$year"}
}
},
{
$count: "totalCountPerYearRange"
}
]);
As long as the date strings are in an array - using [] NOT {} (which defines an object that requires property:value pairs), then you can convert the strings into dates and do simple comparisons. The following will return an array, where you can simply get the array's length for the count.
let myDates = [
"Thu Jan 07 2016",
"Tue Mar 01 2016",
"Wed May 25 2016",
"Sat Jun 25 2016",
"Sun Aug 14 2016",
"Fri Nov 18 2016",
"Fri Jan 06 2017",
"Sun Apr 16 2017",
"Sun May 21 2017",
"Sun Jul 30 2017",
"Fri Sep 22 2017",
"Sun Nov 12 2017",
"Sun Dec 24 2017"
]
let firstDate = new Date("Wed May 25 2016");
let lastDate = new Date("Thu May 25 2017");
let matches = myDates.filter(d => {if (new Date(d) >= firstDate && new Date(d) <= lastDate) return d});
console.log(matches);
console.log(matches.length);

Is there a way to return items from an array after a certain time using date-fns or JavaScript

I am currently using the date-fns library in my Angular application and I am using the helper called isWeekend to return some time slot items from an array that only fall on a weekend.
However, I can't find a way to return the Weekend items after a certain time such as 'after 1pm'.
Please see below:
There are two dates with a time after 13:00:00 (1 PM)
There are two dates with a time before 13:00:00 (1 PM)
I need to adjust my filter to accommodate for the times which are after 13:00:00 (1 PM) and on the weekend.
const days = [
{ date: "Sun Jul 25 2020 15:30:00 GMT+0100 (British Summer Time)" },
{ date: "Sun Jul 25 2020 19:00:00 GMT+0100 (British Summer Time)" },
{ date: "Sat Jul 25 2020 05:00:00 GMT+0100 (British Summer Time)" },
{ date: "Sat Jul 25 2020 02:00:00 GMT+0100 (British Summer Time)" }
];
const filteredDays = days.filter((day) => {
console.log(dateFns.isWeekend(day.date));
// Need a solution for dateFns.isWeekend and after 13:00:00 or 1 PM
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/date-fns/1.30.1/date_fns.min.js"></script>
You can extract the 'hours' component of the date with the same library's getHours function, and then see if the number it returns is 13 or higher. Combined with your existing usage of isWeekend, your filter is quite simple.
Note: This library is going to run both of those functions based on the user's current locale, while your dates are specifying a timezone. Just something to keep in mind.
const days = [
{ date: "Sun Jul 25 2020 15:30:00 GMT+0100 (British Summer Time)" },
{ date: "Sun Jul 25 2020 19:00:00 GMT+0100 (British Summer Time)" },
{ date: "Sat Jul 25 2020 05:00:00 GMT+0100 (British Summer Time)" },
{ date: "Sat Jul 25 2020 02:00:00 GMT+0100 (British Summer Time)" }
];
const filteredDays = days.filter((day) => {
return dateFns.isWeekend(day.date) && dateFns.getHours(day.date) >= 13;
});
console.log(filteredDays);
<script src="https://cdnjs.cloudflare.com/ajax/libs/date-fns/1.30.1/date_fns.min.js"></script>

JavaScript: How to efficiently retrieve array object item to a certain property?

Given this array object:
[{eventTitle=Event title 1, eventId=xyz1#google.com, startDate=Sun Mar 18 00:00:00 GMT+01:00 2018, endDate=Mon Mar 19 00:00:00 GMT+01:00 2018},
{eventTitle=Event title 2, eventId=xyz2#google.com, startDate=Tue Mar 19 00:00:00 GMT+01:00 2019, endDate=Wed Mar 20 00:00:00 GMT+01:00 2019},
{eventTitle=Event title 3, eventId=xyz3#google.com, startDate=Fri Mar 20 00:00:00 GMT+01:00 2020, endDate=Sat Mar 21 00:00:00 GMT+01:00 2020},
.
.
.]
How to efficiently retrieve the corresponding startDate to a certain eventTitle without looping/searching through the array? For example, I have Event title 2 and want to get Tue Mar 19 00:00:00 GMT+01:00 2019.
EDIT:
The array object is sorted by startDate.
You can apply a binary search on your array. Provided your array is sorted. -> O(log(n))
[obj1,obj2,obj3....obj100]
test the object in the middle (obj50), then decide if you have to
search in the half [obj1...obj49] or in the half [obj51...obj100]
Otherwise you can pass your objects (Events) into an other data structure like a tree. -> O(log(n))
Just looping through your whole array wouldn't be efficient, but if you don't repeat it with too many its would be fine as well. But sorting your array from the beginning would be the best solution.
Edit:
The following code shows a basic example of an binary search implementation.
const events = [{
eventTitle: "Event title 1",
eventId: "xyz1#google.com",
startDate: "Sun Mar 18 00:00:00 GMT+01:00 2018",
endDate: "Mon Mar 19 00:00:00 GMT+01:00 2018"
},
{
eventTitle: "Event title 2",
eventId: "xyz2#google.com",
startDate: "Tue Mar 19 00:00:00 GMT+01:00 2019",
endDate: "Wed Mar 20 00:00:00 GMT+01:00 2019"
},
{
eventTitle: "Event title 3",
eventId: "xyz3#google.com",
startDate: "Fri Mar 20 00:00:00 GMT+01:00 2020",
endDate: "Sat Mar 21 00:00:00 GMT+01:00 2020"
},
{
eventTitle: "Event title 4",
eventId: "xyz4#google.com",
startDate: "Fri Mar 21 00:00:00 GMT+01:00 2021",
endDate: "Sat Mar 22 00:00:00 GMT+01:00 2021"
},
{
eventTitle: "Event title 5",
eventId: "xyz5#google.com",
startDate: "Fri Mar 22 00:00:00 GMT+01:00 2022",
endDate: "Sat Mar 23 00:00:00 GMT+01:00 2022"
}
];
function binarySearch(array, value, borderLeft, borderRight) {
if (borderLeft <= borderRight) {
var index = Math.floor((borderLeft + borderRight) / 2);
var number = getNumberFromTitle(array[index].eventTitle);
if (number == value) {
return array[index].startDate;
} else if (number > value) {
return binarySearch(array, value, borderLeft, index - 1);
} else {
return binarySearch(array, value, index + 1, borderRight);
}
} else {
return null;
}
}
function getNumberFromTitle(title) {
var tmp = title.split(" ");
return tmp[tmp.length - 1];
}
console.log(binarySearch(events, 4, 0, events.length - 1));
You can create mapper util. First, it will loop once, O(n). Later all call will be O(1)
I have working code:
https://gist.github.com/deepakshrma/4b6a0a31b4582d6418ec4f76b7439781
function Mapper(array , key){
this.map = array.reduce(function(map, item){
var val = item[key];
if(!map[val]){
map[val] = [];
}
map[val].push(item);
return map;
},{});
}
Mapper.FIRST_INDEX = 0;
Mapper.prototype.find = function find(key){
return this.map[key] && this.map[key][Mapper.FIRST_INDEX]//return blank array
};
Mapper.prototype.findAll = function find(key, returnUndefined){
return this.map[key] && this.map[key] || (returnUndefined? undefined: []);//return blank array
};
var users = [{eventTitle:"Event title 1", eventId:"xyz1#google.com", startDate:"Sun Mar 18 00:00:00 GMT+01:00 2018", endDate:"Mon Mar 19 00:00:00 GMT+01:00 2018"},
{eventTitle:"Event title 2", eventId:"xyz2#google.com", startDate:"Tue Mar 19 00:00:00 GMT+01:00 2019", endDate:"Wed Mar 20 00:00:00 GMT+01:00 2019"},
{eventTitle:"Event title 3", eventId:"xyz3#google.com", startDate:"Fri Mar 20 00:00:00 GMT+01:00 2020", endDate:"Sat Mar 21 00:00:00 GMT+01:00 2020"}];
//How to use
var userMapper = new Mapper(users , 'eventTitle');
console.log(userMapper.find("Event title 2"));
var userToFind = ["Event title 3", "Event title 2"];
var reqUsers = userToFind.map(function(name){
return userMapper.find(name);
});
console.log(reqUsers);
If you only have the array, you have no option but to search through it.
But if you're going to have to search it more than once, you can make a single pass through it to produce a Map, so that subsequent searches are sublinear (faster than searching through the array with a loop). You'd do that like this:
const map = new Map(theArray.map(entry => [entry.eventTitle, entry.startDate]));
Then getting by title is:
const startDate = map.get("some title");
Live Example:
const theArray = [
{eventTitle: "Event title 1", eventId: "xyz1#google.com", startDate: "Sun Mar 18 00:00:00 GMT+01:00 2018", endDate: "Mon Mar 19 00:00:00 GMT+01:00 2018"},
{eventTitle: "Event title 2", eventId: "xyz2#google.com", startDate: "Tue Mar 19 00:00:00 GMT+01:00 2019", endDate: "Wed Mar 20 00:00:00 GMT+01:00 2019"},
{eventTitle: "Event title 3", eventId: "xyz3#google.com", startDate: "Fri Mar 20 00:00:00 GMT+01:00 2020", endDate: "Sat Mar 21 00:00:00 GMT+01:00 2020"},
];
// Building it:
const map = new Map(theArray.map(entry => [entry.eventTitle, entry.startDate]));
// Using it:
console.log(map.get("Event title 2")); // "Tue Mar 19 00:00:00 GMT+01:00 2019"
console.log(map.get("Event title 3")); // "Fri Mar 20 00:00:00 GMT+01:00 2020"
console.log(map.get("no such event title")); // undefined
.as-console-wrapper {
max-height: 100% !important;
}
(You can do the same thing with an object instead of a Map (just be sure to create it with Object.create(null) so it doesn't have a prototype), but Map is specifically designed for this.)
Note that this example assumes there's only one event for each title. If there may be more than one, you need to build the map differently so that it points you to an array of only entries for that title.

React-Native sort array of objects by date value within object

We have an array of objects like this:
{key: "T62", currentWinnerName: "Test Register", dateCreated: Fri Jan 18 2019 18:17:50 GMT+0000 (Greenwich Mean Time)}
{key: "T68", currentWinnerName: "Test Register", dateCreated: Wed Jan 23 2019 14:57:40 GMT+0000 (Greenwich Mean Time)}
{key: "T58", currentWinnerName: "Test Register", dateCreated: Fri Jan 18 2019 15:57:45 GMT+0000 (Greenwich Mean Time)}
We need to sort the array based on the dateCreated value within the array.
I've tried various sort methods but unable to get the order to change.
if I understand correctly your object is array. then you can do like this way.
var obj = [
{
key: "T62",
currentWinnerName: "Test Register",
dateCreated: "Fri Jan 18 2019 18:17:50 GMT+0000 (Greenwich Mean Time)"
},
{
key: "T68",
currentWinnerName: "Test Register",
dateCreated: "Wed Jan 23 2019 14:57:40 GMT+0000 (Greenwich Mean Time)"
},
{
key: "T58",
currentWinnerName: "Test Register",
dateCreated: "Fri Jan 18 2019 15:57:45 GMT+0000 (Greenwich Mean Time)"}
];
let sortedObj = obj.sort(function(a,b){
return new Date(b.dateCreated) - new Date(a.dateCreated);
});
console.log(sortedObj);
Have you tried something like this :
const getTimestamp = (dateString)=> new Date(dateString).getTime();
const isOlder = (object1, object2)=> getTimestamp(object1.dateCreated) < getTimestamp(object2.dateCreated) ? -1 : 1;
const sortedArr = arr.sort(isOlder);
arr is your array. But you have to make dateCreated a string. This worked for me.

Inserting events from json object to fullcalendar

Hello folks I am trying to utilize the fullcalendar to display some holidays I have acquired from a json object.
JSON looks as follows.
var holidayObj = [
{
"holidayName" : "Boxing Day",
"holidayStart" : "May, 26 Oct 2014 13:00:00 EST",
"holidayEnd" : "May, 26 Oct 2014 13:00:00 EST"
}
{
"holidayName" : "Some other Day",
"holidayStart" : "May, 23 Oct 2014 13:00:00 EST",
"holidayEnd" : "May, 23 Oct 2014 13:00:00 EST"
}
];
My JS code to display the events on fullcalendar is as follows.
$.each(holidayObj, function(i, item) {
holidayNameText = item.holidayName;
console.log(holidayNameText); //"Boxing Day"
holidayStart = item.holidayStart; //May, 26 Oct 2014 13:00:00 EST
holidayEnd = item.holidayEnd; //May, 26 Oct 2014 13:00:00 EST
var eventObject = {
title: holidayNameText,
start: holidayStart,
end : holidayEnd,
allDay:true
};
$('#calendar').fullCalendar('renderEvent', eventObject, true);
console.log(eventObject.start);
});
For some reason the events don't seem to be populating on the calendar. Can anyone help me identify what the cause might may be?
Thank you.
You are missing a comma to separate the array elements:
var holidayObj = [{
"holidayName": "Boxing Day",
"holidayStart": "May, 26 Oct 2014 13:00:00 EST",
"holidayEnd": "May, 26 Oct 2014 13:00:00 EST"
}, {
"holidayName": "Some other Day",
"holidayStart": "May, 23 Oct 2014 13:00:00 EST",
"holidayEnd": "May, 23 Oct 2014 13:00:00 EST"
}];
By fixing it, it works fine (see the events in October).
Demo: http://jsfiddle.net/IrvinDominin/EGbHt/

Categories

Resources