Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
fordecyt_2019
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Rodrigo Tapia-McClung
fordecyt_2019
Commits
b34bf9c4
Commit
b34bf9c4
authored
Sep 06, 2019
by
Rodrigo Tapia-McClung
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update to arrow functions
parent
9bd35625
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
254 additions
and
256 deletions
+254
-256
grijalva_charts.js
public/fordecyt_2019/js/grijalva_charts.js
+254
-256
No files found.
public/fordecyt_2019/js/grijalva_charts.js
View file @
b34bf9c4
...
@@ -101,10 +101,11 @@ const summarizeData = (allData, indicator) => {
...
@@ -101,10 +101,11 @@ const summarizeData = (allData, indicator) => {
.
rollup
(
v
=>
{
return
indicator
==
"costa"
||
indicator
==
"df"
?
d3
.
mean
(
v
,
v
=>
v
.
value
)
:
d3
.
sum
(
v
,
v
=>
v
.
value
)
})
.
rollup
(
v
=>
{
return
indicator
==
"costa"
||
indicator
==
"df"
?
d3
.
mean
(
v
,
v
=>
v
.
value
)
:
d3
.
sum
(
v
,
v
=>
v
.
value
)
})
.
entries
(
data2
)
.
entries
(
data2
)
// map "key" and "value" from d3.nest().rollup() to date and value
// map "key" and "value" from d3.nest().rollup() to date and value
.
map
(
group
=>
{
return
{
.
map
(
group
=>
{
date
:
new
Date
(
group
.
key
),
return
{
value
:
group
.
value
date
:
new
Date
(
group
.
key
),
}
value
:
group
.
value
}
})
})
});
});
// order data[i].values.date
// order data[i].values.date
...
@@ -112,7 +113,7 @@ const summarizeData = (allData, indicator) => {
...
@@ -112,7 +113,7 @@ const summarizeData = (allData, indicator) => {
return
data
;
return
data
;
}
}
function
makeIndicatorGraph
()
{
const
makeIndicatorGraph
=
()
=>
{
let
data
=
[],
let
data
=
[],
width
=
450
,
width
=
450
,
...
@@ -141,7 +142,7 @@ function makeIndicatorGraph() {
...
@@ -141,7 +142,7 @@ function makeIndicatorGraph() {
legendContainer
=
"legendZone"
,
legendContainer
=
"legendZone"
,
updateData
;
updateData
;
function
chart
(
selection
)
{
const
chart
=
selection
=>
{
// get data ranges using values from displayName
// get data ranges using values from displayName
minDate
=
d3
.
min
(
data
[
0
].
values
,
d
=>
{
minDate
=
d3
.
min
(
data
[
0
].
values
,
d
=>
{
return
d
[
displayName
];
return
d
[
displayName
];
...
@@ -152,7 +153,7 @@ function makeIndicatorGraph() {
...
@@ -152,7 +153,7 @@ function makeIndicatorGraph() {
});
});
maxDate
=
d3
.
timeDay
.
offset
(
maxDate
,
15
)
// get next month to get correct x-axis alignment
maxDate
=
d3
.
timeDay
.
offset
(
maxDate
,
15
)
// get next month to get correct x-axis alignment
selection
.
each
(
function
()
{
selection
.
each
(
()
=>
{
// add graph svg to selected container on webpage
// add graph svg to selected container on webpage
let
areaSVG
=
selection
let
areaSVG
=
selection
...
@@ -233,28 +234,178 @@ function makeIndicatorGraph() {
...
@@ -233,28 +234,178 @@ function makeIndicatorGraph() {
//console.log("data: ", data.map(d => d.values));
//console.log("data: ", data.map(d => d.values));
let
maxDomain
=
d3
.
max
(
data
.
map
(
d
=>
d
.
values
).
flat
().
map
(
d
=>
d
.
value
));
yLine
.
domain
([
0
,
maxDomain
]).
nice
();
//yLine.domain([0, d3.max(data[0].values, d => d.value)]).nice();
// add axes
let
xaxis
=
g
.
select
(
".x.axis"
);
xaxis
.
call
(
d3
.
axisBottom
(
xLine
)
// .ticks(d3.timeMonth.every(1))
// .tickFormat(d3.timeFormat("%b '%y"))
)
.
selectAll
(
"text"
)
//.attr("y", 0)
//.attr("x", 9)
.
attr
(
"y"
,
15
)
.
attr
(
"x"
,
0
)
.
attr
(
"dy"
,
".35em"
)
.
attr
(
"font-size"
,
"12px"
)
//.attr("transform", "rotate(90)")
//.style("text-anchor", "start");
.
style
(
"text-anchor"
,
"middle"
)
.
style
(
"fill"
,
"#b2b2b2"
);
// format x-axis lines for minor and major ticks
//TODO: check this line to separate years starting in Jan. Maybe it is not needed
xaxis
.
selectAll
(
"g.tick line"
)
.
attr
(
"y2"
,
d
=>
{
// d is the tick value
if
(
d3
.
timeFormat
(
"%m"
)(
d
)
==
"01"
)
//if it is Jan
return
-
height
-
6
;
else
return
6
;
})
.
attr
(
"transform"
,
d
=>
{
// d is the tick value
if
(
d3
.
timeFormat
(
"%m"
)(
d
)
==
"01"
)
//if it is Jan
return
"translate(0,6)"
;
})
.
attr
(
"class"
,
d
=>
{
// d is the tick value
if
(
d3
.
timeFormat
(
"%m"
)(
d
)
==
"01"
)
//if it is Jan
return
"yearTick"
;
});
let
yaxis
=
g
.
select
(
".y.axis"
);
yaxis
.
transition
()
.
duration
(
500
)
.
call
(
d3
.
axisLeft
(
yLine
)
/*.tickFormat(d3.format(".2s"))*/
);
// color axis labels
g
.
selectAll
(
".y.axis g.tick text"
)
.
style
(
"fill"
,
"#b2b2b2"
);
// function (d,i) {return (i%2)?"red":"blue";})
let
title
=
selection
.
select
(
".title.label"
);
title
.
text
(
chart
.
title
())
.
style
(
"fill"
,
"#b2b2b2"
);
selection
.
select
(
".title.label"
)
.
append
(
"tspan"
)
.
attr
(
"class"
,
"far"
)
.
html
(
"
\
uf059"
)
//.style("color", "#b2b2b2")
.
style
(
"cursor"
,
"pointer"
)
.
on
(
"click"
,
()
=>
{
// when clicking ? display modal with information about indicator
$
(
"#explainIndicatorModal"
).
on
(
"show.bs.modal"
,
()
=>
{
let
indicatorName
=
indicatorsNames
[
indicators
.
indexOf
(
id
)]
$
(
"#explainIndicatorModal"
).
find
(
"#explainIndicatorModalTitle"
).
text
(
indicatorName
);
$
(
"#explainIndicatorModal"
).
find
(
".modal-body"
).
html
(
indicatorVars
[
id
].
explanation
);
});
$
(
"#explainIndicatorModal"
).
modal
();
});
// update chart
updateData
=
()
=>
{
let
time
=
map
.
timeDimension
.
getCurrentTime
();
// update data ranges using values from displayName and lineVariables
minDate
=
d3
.
min
(
data
[
0
].
values
,
d
=>
{
return
d
[
displayName
];
});
minDate
=
d3
.
timeDay
.
offset
(
minDate
,
-
15
)
// get previous month to get correct x-axis alignment
maxDate
=
d3
.
max
(
data
[
0
].
values
,
d
=>
{
return
d
[
displayName
];
});
maxDate
=
d3
.
timeDay
.
offset
(
maxDate
,
15
)
// get next month to get correct x-axis alignment
// update axes' domain
xLine
.
domain
([
minDate
,
maxDate
])
//.nice()
//.nice(d3.timeMonth)
.
range
([
0
,
width
-
margin
.
left
-
margin
.
right
-
30
])
.
clamp
(
true
);
//yLine.domain(d3.extent(data, function(d) { return d[lineVariables[0]]; }))
//yLine.domain([0, d3.max(data, function(d) { return d[lineVariables[0]]; })]).nice()
// Calculate min and max values of data to define chart y-axis domain
//let minDomain = d3.min(data.map(d => d.values).flat().map(d => d.value));
let
maxDomain
=
d3
.
max
(
data
.
map
(
d
=>
d
.
values
).
flat
().
map
(
d
=>
d
.
value
));
let
maxDomain
=
d3
.
max
(
data
.
map
(
d
=>
d
.
values
).
flat
().
map
(
d
=>
d
.
value
));
yLine
.
domain
([
0
,
maxDomain
]).
nice
();
yLine
.
domain
([
0
,
maxDomain
])
//yLine.domain([0, d3.max(data[0].values, d => d.value)]).nice();
//yLine.domain([0, d3.max(data[0].values, d => d.value)]).nice()
.
range
([
height
-
margin
.
left
-
margin
.
right
,
0
+
35
])
.
nice
();
// filter data to only use the ones needed for current time
let
filteredData
=
[];
data
.
forEach
((
d
,
i
)
=>
{
filteredData
.
push
({
name
:
d
.
name
,
values
:
[]
});
d
.
values
.
filter
(
v
=>
{
if
(
v
.
date
<=
new
Date
(
time
))
{
filteredData
[
i
].
values
.
push
(
v
);
}
});
});
// update axes
let
g
=
selection
.
select
(
".lineChart"
);
//
add axe
s
//
update axis line with no tick
s
let
xaxis
=
g
.
select
(
".x.axis"
);
let
xaxis
=
g
.
select
(
".x.axis"
);
xaxis
.
call
(
xaxis
.
transition
()
.
duration
(
500
)
.
call
(
d3
.
axisBottom
(
xLine
)
d3
.
axisBottom
(
xLine
)
// .ticks(d3.timeMonth.every(1))
.
ticks
(
0
)
// .tickFormat(d3.timeFormat("%b '%y"))
.
tickSize
(
0
)
);
// update axis ticks - one for each month
let
xaxisTicks
=
g
.
select
(
".x.axis-ticks"
);
let
monthsInGraph
=
[];
userDates
.
forEach
(
d
=>
{
monthsInGraph
.
push
(
new
Date
(
d
));
});
xaxisTicks
.
transition
()
.
duration
(
500
)
.
call
(
d3
.
axisBottom
(
xLine
)
.
tickValues
(
monthsInGraph
)
.
tickFormat
(
""
)
);
// update axis month labels depending on how many months there are
let
xaxisLabels
=
g
.
select
(
".x.axis-month-labels"
);
// FIXME: check how this displays ticks when there are many months/years
// this fix gives up to 10 ticks
// maybe need to set up more conditions
let
numberOfTicks
=
monthsInGraph
.
length
<
6
?
d3
.
timeMonth
.
every
(
1
)
:
6
;
xaxisLabels
.
transition
().
duration
(
500
)
.
call
(
d3
.
axisBottom
(
xLine
)
.
ticks
(
numberOfTicks
)
.
tickFormat
(
d3
.
timeFormat
(
"%b"
))
)
)
.
selectAll
(
"text"
)
.
selectAll
(
"text"
)
//.attr("y", 0)
.
style
(
"fill"
,
"#b2b2b2"
)
//.attr("x", 9)
.
attr
(
"font-size"
,
"12px"
);
.
attr
(
"y"
,
15
)
.
attr
(
"x"
,
0
)
// update axis year labels depending on how many months there are
.
attr
(
"dy"
,
".35em"
)
let
xaxisYearLabels
=
g
.
select
(
".x.axis-year-labels"
);
.
attr
(
"font-size"
,
"12px"
)
xaxisYearLabels
.
transition
().
duration
(
500
)
//.attr("transform", "rotate(90)")
.
call
(
//.style("text-anchor", "start");
d3
.
axisBottom
(
xLine
)
.
style
(
"text-anchor"
,
"middle"
)
.
ticks
(
numberOfTicks
)
.
style
(
"fill"
,
"#b2b2b2"
);
.
tickFormat
(
d3
.
timeFormat
(
"'%y"
))
)
.
selectAll
(
"text"
)
.
style
(
"fill"
,
"#b2b2b2"
)
.
attr
(
"font-size"
,
"12px"
);
// format x-axis lines for minor and major ticks
// format x-axis lines for minor and major ticks
//TODO: check this line to separate years starting in Jan. Maybe it is not needed
//TODO: check this line to separate years starting in Jan. Maybe it is not needed
...
@@ -278,248 +429,95 @@ function makeIndicatorGraph() {
...
@@ -278,248 +429,95 @@ function makeIndicatorGraph() {
yaxis
.
transition
()
yaxis
.
transition
()
.
duration
(
500
)
.
duration
(
500
)
.
call
(
d3
.
axisLeft
(
yLine
)
.
call
(
d3
.
axisLeft
(
yLine
)
/*.tickFormat(d3.format(".2s"))*/
.
tickFormat
(
yAxisFormat
));
);
// color axis labels
// color axis labels
g
.
selectAll
(
".y.axis g.tick text"
)
g
.
selectAll
(
".y.axis g.tick text"
)
.
style
(
"fill"
,
"#b2b2b2"
);
// function (d,i) {return (i%2)?"red":"blue";})
let
title
=
selection
.
select
(
".title.label"
);
title
.
text
(
chart
.
title
())
.
style
(
"fill"
,
"#b2b2b2"
);
.
style
(
"fill"
,
"#b2b2b2"
);
selection
.
select
(
".title.label"
)
// define line
.
append
(
"tspan"
)
let
line
=
d3
.
line
()
.
attr
(
"class"
,
"far"
)
.
defined
(
d
=>
d
)
.
html
(
"
\
uf059"
)
.
curve
(
d3
.
curveMonotoneX
)
//.style("color", "#b2b2b2")
.
x
(
d
=>
xLine
(
d
.
date
))
.
style
(
"cursor"
,
"pointer"
)
.
y
(
d
=>
yLine
(
d
.
value
));
.
on
(
"click"
,
()
=>
{
// when clicking ? display modal with information about indicator
$
(
"#explainIndicatorModal"
).
on
(
"show.bs.modal"
,
()
=>
{
// get lines
let
indicatorName
=
indicatorsNames
[
indicators
.
indexOf
(
id
)]
let
lines
=
g
.
select
(
".lines"
);
$
(
"#explainIndicatorModal"
).
find
(
"#explainIndicatorModalTitle"
).
text
(
indicatorName
);
lines
.
selectAll
(
"path.line"
)
$
(
"#explainIndicatorModal"
).
find
(
".modal-body"
).
html
(
indicatorVars
[
id
].
explanation
);
.
data
(
filteredData
)
});
.
join
(
"path"
)
// handle enter, update, and exit automagically
$
(
"#explainIndicatorModal"
).
modal
();
.
attr
(
"stroke"
,
(
d
,
i
)
=>
{
});
return
i
==
0
?
defaultLineColor
:
lineColors
(
i
-
1
);
//});
// update chart
updateData
=
function
()
{
let
time
=
map
.
timeDimension
.
getCurrentTime
();
// update data ranges using values from displayName and lineVariables
minDate
=
d3
.
min
(
data
[
0
].
values
,
d
=>
{
return
d
[
displayName
];
});
minDate
=
d3
.
timeDay
.
offset
(
minDate
,
-
15
)
// get previous month to get correct x-axis alignment
maxDate
=
d3
.
max
(
data
[
0
].
values
,
d
=>
{
return
d
[
displayName
];
});
maxDate
=
d3
.
timeDay
.
offset
(
maxDate
,
15
)
// get next month to get correct x-axis alignment
// update axes' domain
xLine
.
domain
([
minDate
,
maxDate
])
//.nice()
//.nice(d3.timeMonth)
.
range
([
0
,
width
-
margin
.
left
-
margin
.
right
-
30
])
.
clamp
(
true
);
//yLine.domain(d3.extent(data, function(d) { return d[lineVariables[0]]; }))
//yLine.domain([0, d3.max(data, function(d) { return d[lineVariables[0]]; })]).nice()
// Calculate min and max values of data to define chart y-axis domain
//let minDomain = d3.min(data.map(d => d.values).flat().map(d => d.value));
let
maxDomain
=
d3
.
max
(
data
.
map
(
d
=>
d
.
values
).
flat
().
map
(
d
=>
d
.
value
));
yLine
.
domain
([
0
,
maxDomain
])
//yLine.domain([0, d3.max(data[0].values, d => d.value)]).nice()
.
range
([
height
-
margin
.
left
-
margin
.
right
,
0
+
35
])
.
nice
();
// filter data to only use the ones needed for current time
let
filteredData
=
[];
data
.
forEach
((
d
,
i
)
=>
{
filteredData
.
push
({
name
:
d
.
name
,
values
:
[]
});
d
.
values
.
filter
(
v
=>
{
if
(
v
.
date
<=
new
Date
(
time
))
{
filteredData
[
i
].
values
.
push
(
v
);
}
});
})
})
.
attr
(
"class"
,
"line"
)
// update axes
.
attr
(
"fill"
,
"none"
)
let
g
=
selection
.
select
(
".lineChart"
);
.
attr
(
"stroke-linejoin"
,
"round"
)
.
attr
(
"stroke-linecap"
,
"round"
)
// update axis line with no ticks
.
attr
(
"stroke-width"
,
1.5
)
let
xaxis
=
g
.
select
(
".x.axis"
);
.
attr
(
"d"
,
d
=>
line
(
d
.
values
))
xaxis
.
transition
()
.
duration
(
500
)
// get circles
.
call
(
let
circles
=
g
.
select
(
".circles"
),
d3
.
axisBottom
(
xLine
)
tooltip
=
d3
.
select
(
".tooltip"
);
.
ticks
(
0
)
//tooltipFormat = d3.timeFormat("%b "%y"),
.
tickSize
(
0
)
//tooltipFormat = d3.format(",.2f")
);
//tooltipFormat = d3.format(",.3s");
// update axis ticks - one for each month
circles
.
selectAll
(
"g"
)
// using nested data, so need to make a g to contain stuff
let
xaxisTicks
=
g
.
select
(
".x.axis-ticks"
);
.
data
(
filteredData
)
let
monthsInGraph
=
[];
.
join
(
// handle enter, update, and exit separately for overall g circle containers
userDates
.
forEach
(
d
=>
{
enter
=>
enter
monthsInGraph
.
push
(
new
Date
(
d
));
.
append
(
"g"
)
});
.
attr
(
"class"
,
d
=>
d
.
name
)
.
attr
(
"stroke"
,
(
d
,
i
)
=>
{
xaxisTicks
.
transition
()
return
i
==
0
?
defaultPointColor
:
pointColors
(
i
-
1
);
.
duration
(
500
)
.
call
(
d3
.
axisBottom
(
xLine
)
.
tickValues
(
monthsInGraph
)
.
tickFormat
(
""
)
);
// update axis month labels depending on how many months there are
let
xaxisLabels
=
g
.
select
(
".x.axis-month-labels"
);
// FIXME: check how this displays ticks when there are many months/years
// this fix gives up to 10 ticks
// maybe need to set up more conditions
let
numberOfTicks
=
monthsInGraph
.
length
<
6
?
d3
.
timeMonth
.
every
(
1
)
:
6
;
xaxisLabels
.
transition
().
duration
(
500
)
.
call
(
d3
.
axisBottom
(
xLine
)
.
ticks
(
numberOfTicks
)
.
tickFormat
(
d3
.
timeFormat
(
"%b"
))
)
.
selectAll
(
"text"
)
.
style
(
"fill"
,
"#b2b2b2"
)
.
attr
(
"font-size"
,
"12px"
);
// update axis year labels depending on how many months there are
let
xaxisYearLabels
=
g
.
select
(
".x.axis-year-labels"
);
xaxisYearLabels
.
transition
().
duration
(
500
)
.
call
(
d3
.
axisBottom
(
xLine
)
.
ticks
(
numberOfTicks
)
.
tickFormat
(
d3
.
timeFormat
(
"'%y"
))
)
.
selectAll
(
"text"
)
.
style
(
"fill"
,
"#b2b2b2"
)
.
attr
(
"font-size"
,
"12px"
);
// format x-axis lines for minor and major ticks
//TODO: check this line to separate years starting in Jan. Maybe it is not needed
xaxis
.
selectAll
(
"g.tick line"
)
.
attr
(
"y2"
,
d
=>
{
// d is the tick value
if
(
d3
.
timeFormat
(
"%m"
)(
d
)
==
"01"
)
//if it is Jan
return
-
height
-
6
;
else
return
6
;
})
.
attr
(
"transform"
,
d
=>
{
// d is the tick value
if
(
d3
.
timeFormat
(
"%m"
)(
d
)
==
"01"
)
//if it is Jan
return
"translate(0,6)"
;
})
})
.
attr
(
"class"
,
d
=>
{
// d is the tick value
.
attr
(
"fill"
,
(
d
,
i
)
=>
{
if
(
d3
.
timeFormat
(
"%m"
)(
d
)
==
"01"
)
//if it is Jan
return
i
==
0
?
defaultPointColor
:
pointColors
(
i
-
1
);
return
"yearTick"
;
}),
});
update
=>
update
.
attr
(
"class"
,
d
=>
d
.
name
)
let
yaxis
=
g
.
select
(
".y.axis"
);
yaxis
.
transition
()
.
duration
(
500
)
.
call
(
d3
.
axisLeft
(
yLine
)
.
tickFormat
(
yAxisFormat
));
// color axis labels
g
.
selectAll
(
".y.axis g.tick text"
)
.
style
(
"fill"
,
"#b2b2b2"
);
// define line
let
line
=
d3
.
line
()
.
defined
(
d
=>
d
)
.
curve
(
d3
.
curveMonotoneX
)
.
x
(
d
=>
xLine
(
d
.
date
))
.
y
(
d
=>
yLine
(
d
.
value
));
// get lines
let
lines
=
g
.
select
(
".lines"
);
lines
.
selectAll
(
"path.line"
)
.
data
(
filteredData
)
.
join
(
"path"
)
// handle enter, update, and exit automagically
.
attr
(
"stroke"
,
(
d
,
i
)
=>
{
.
attr
(
"stroke"
,
(
d
,
i
)
=>
{
return
i
==
0
?
default
LineColor
:
line
Colors
(
i
-
1
);
return
i
==
0
?
default
PointColor
:
point
Colors
(
i
-
1
);
})
})
.
attr
(
"class"
,
"line"
)
.
attr
(
"fill"
,
(
d
,
i
)
=>
{
.
attr
(
"fill"
,
"none"
)
return
i
==
0
?
defaultPointColor
:
pointColors
(
i
-
1
);
.
attr
(
"stroke-linejoin"
,
"round"
)
}),
.
attr
(
"stroke-linecap"
,
"round"
)
exit
=>
exit
.
remove
()
.
attr
(
"stroke-width"
,
1.5
)
)
.
attr
(
"d"
,
d
=>
line
(
d
.
values
))
// nested join
.
selectAll
(
"circle"
).
data
(
d
=>
d
.
values
)
// access internal values array for circles here
// get circles
.
join
(
// handle enter, update, and exit separately for circles
let
circles
=
g
.
select
(
".circles"
),
enter
=>
enter
tooltip
=
d3
.
select
(
".tooltip"
);
.
append
(
"circle"
)
//tooltipFormat = d3.timeFormat("%b "%y"),
.
attr
(
"class"
,
"circle"
)
//tooltipFormat = d3.format(",.2f")
.
attr
(
"r"
,
2.5
)
//tooltipFormat = d3.format(",.3s");
.
attr
(
"cx"
,
d
=>
xLine
(
d
.
date
))
.
attr
(
"cy"
,
d
=>
yLine
(
d
.
value
))
circles
.
selectAll
(
"g"
)
// using nested data, so need to make a g to contain stuff
.
on
(
"mouseover"
,
d
=>
{
.
data
(
filteredData
)
tooltip
.
html
(
`
${
tooltipFormat
(
d
.
value
)}
${
tooltipUnits
}
`
);
.
join
(
// handle enter, update, and exit separately for overall g circle containers
let
tpWidth
=
tooltip
.
node
().
offsetWidth
;
// to center tooltip
enter
=>
enter
tooltip
.
style
(
"left"
,
`
${
d3
.
event
.
pageX
-
tpWidth
/
2
}
px`
)
.
append
(
"g"
)
.
style
(
"top"
,
`
${
d3
.
event
.
pageY
-
23
}
px`
)
.
attr
(
"class"
,
d
=>
d
.
name
)
.
style
(
"font-family"
,
"Consolas, courier"
)
.
attr
(
"stroke"
,
(
d
,
i
)
=>
{
.
style
(
"font-size"
,
"10pt"
)
return
i
==
0
?
defaultPointColor
:
pointColors
(
i
-
1
);
.
transition
()
})
.
duration
(
200
)
.
attr
(
"fill"
,
(
d
,
i
)
=>
{
.
style
(
"opacity"
,
.
9
);
return
i
==
0
?
defaultPointColor
:
pointColors
(
i
-
1
);
})
}),
.
on
(
"mouseout"
,
()
=>
{
update
=>
update
tooltip
.
transition
()
.
attr
(
"class"
,
d
=>
d
.
name
)
.
duration
(
500
)
.
attr
(
"stroke"
,
(
d
,
i
)
=>
{
.
style
(
"opacity"
,
0
);
return
i
==
0
?
defaultPointColor
:
pointColors
(
i
-
1
);
}),
})
update
=>
update
.
attr
(
"fill"
,
(
d
,
i
)
=>
{
.
attr
(
"cx"
,
d
=>
xLine
(
d
.
date
))
return
i
==
0
?
defaultPointColor
:
pointColors
(
i
-
1
);
.
attr
(
"cy"
,
d
=>
yLine
(
d
.
value
)),
}),
exit
=>
exit
.
remove
()
exit
=>
exit
.
remove
()
);
)
}
// nested join
});
.
selectAll
(
"circle"
).
data
(
d
=>
d
.
values
)
// access internal values array for circles here
.
join
(
// handle enter, update, and exit separately for circles
enter
=>
enter
.
append
(
"circle"
)
.
attr
(
"class"
,
"circle"
)
.
attr
(
"r"
,
2.5
)
.
attr
(
"cx"
,
d
=>
xLine
(
d
.
date
))
.
attr
(
"cy"
,
d
=>
yLine
(
d
.
value
))
.
on
(
"mouseover"
,
d
=>
{
tooltip
.
html
(
`
${
tooltipFormat
(
d
.
value
)}
${
tooltipUnits
}
`
);
let
tpWidth
=
tooltip
.
node
().
offsetWidth
;
// to center tooltip
tooltip
.
style
(
"left"
,
`
${
d3
.
event
.
pageX
-
tpWidth
/
2
}
px`
)
.
style
(
"top"
,
`
${
d3
.
event
.
pageY
-
23
}
px`
)
.
style
(
"font-family"
,
"Consolas, courier"
)
.
style
(
"font-size"
,
"10pt"
)
.
transition
()
.
duration
(
200
)
.
style
(
"opacity"
,
.
9
);
})
.
on
(
"mouseout"
,
()
=>
{
tooltip
.
transition
()
.
duration
(
500
)
.
style
(
"opacity"
,
0
);
}),
update
=>
update
.
attr
(
"cx"
,
d
=>
xLine
(
d
.
date
))
.
attr
(
"cy"
,
d
=>
yLine
(
d
.
value
)),
exit
=>
exit
.
remove
()
);
}
});
//});
}
}
chart
.
width
=
function
(
value
)
{
chart
.
width
=
function
(
value
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment