UNPKG

4.28 kBJavaScriptView Raw
1'use strict'
2
3const d3 = require('./d3.js')
4
5class HoverBox {
6 constructor (container, setup) {
7 this.container = container
8 this.setup = setup
9 this.showen = false
10 this.point = null
11
12 this.size = {
13 titleHeight: 36,
14 lineWidth: 1,
15 marginTop: 3,
16 marginBottom: 3,
17 titlePaddingTop: 5,
18 legendHeight: 28,
19 pointHeight: 10,
20 containerHeight: container.node().getBoundingClientRect().height
21 }
22
23 const legendTopOffset = this.size.titleHeight + this.size.lineWidth +
24 this.size.marginTop
25
26 const hoverBoxHeight = legendTopOffset + this.size.marginBottom +
27 this.setup.numLines * this.size.legendHeight
28
29 this.height = hoverBoxHeight + this.size.pointHeight
30 this.width = 136
31
32 // create main svg element
33 this.svg = this.container.append('svg')
34 .classed('hover', true)
35 .attr('width', this.width)
36 .attr('height', this.height)
37
38 this.dataBox = this.svg.append('g')
39 .classed('data-box', true)
40
41 // create background
42 this.dataBox.append('rect')
43 .classed('background', true)
44 .attr('rx', 5)
45 .attr('width', this.width)
46 .attr('height', hoverBoxHeight)
47 this.svg.append('path')
48 .classed('pointer', true)
49 .classed('above-curve', true)
50 .attr('d', `M${this.width / 2 - this.size.pointHeight} ${hoverBoxHeight} ` +
51 `L${this.width / 2} ${this.height} ` +
52 `L${this.width / 2 + this.size.pointHeight} ${hoverBoxHeight} Z`)
53 this.svg.append('path')
54 .classed('pointer', true)
55 .classed('below-curve', true)
56 .attr('d', `M${this.width / 2 - this.size.pointHeight} ${this.size.pointHeight} ` +
57 `L${this.width / 2} 0 ` +
58 `L${this.width / 2 + this.size.pointHeight} ${this.size.pointHeight} Z`)
59 this.dataBox.append('rect')
60 .classed('line', true)
61 .attr('width', this.width)
62 .attr('height', this.size.lineWidth)
63 .attr('y', this.size.titleHeight)
64
65 // create title text
66 this.title = this.dataBox.append('text')
67 .classed('title', true)
68 .attr('y', this.size.titlePaddingTop)
69 .attr('x', this.width / 2)
70 .attr('dy', '1em')
71
72 // create content text
73 this.values = []
74 for (let i = 0; i < this.setup.numLines; i++) {
75 this.dataBox.append('text')
76 .classed('legend', true)
77 .attr('y', legendTopOffset + i * this.size.legendHeight)
78 .attr('dy', '1em')
79 .attr('x', 12)
80 .text(this.setup.shortLegend[i])
81
82 const valueText = this.dataBox.append('text')
83 .classed('value', true)
84 .attr('y', legendTopOffset + i * this.size.legendHeight)
85 .attr('dy', '1em')
86 .attr('x', 72)
87 this.values.push(valueText)
88 }
89 }
90
91 setPoint (point) {
92 this.point = point
93 }
94
95 setPosition (x, y) {
96 // Check if we should flip the hover box so it is below the data point, pointing up.
97 // First check if any inner content of the hover box pokes above this graph area
98 const titleOverflowsTop = y - this.height < 0 - this.size.titlePaddingTop
99
100 // We shouldn't flip if this box starts closer to the container's bottom than the top
101 // because it will overflow the bottom by further than it would have overflowed the top
102 const startsCloserToTop = y < this.size.containerHeight / 2
103
104 // So: flip if it overflows the top by less than flipping would overflow the bottom
105 const belowCurve = titleOverflowsTop && startsCloserToTop
106
107 this.dataBox.attr('transform', `translate(0, ${(belowCurve ? this.size.pointHeight : 0)})`)
108 this.svg
109 .style('top', Math.round(belowCurve ? y : y - this.height) + 'px')
110 .style('left', Math.round(x - this.width / 2) + 'px')
111 .classed('above-curve', !belowCurve)
112 .classed('below-curve', belowCurve)
113 }
114
115 setDate (date) {
116 this.title.text(d3.timeFormat('%I:%M:%S.%L %p')(date))
117 }
118
119 setData (data) {
120 for (let i = 0; i < this.setup.numLines; i++) {
121 this.values[i].text(data[i] + ' ' + this.setup.unit)
122 }
123 }
124
125 show () {
126 this.showen = true
127 this.svg.classed('visible', true)
128 }
129
130 hide () {
131 this.showen = false
132 this.svg.classed('visible', false)
133 }
134}
135
136module.exports = HoverBox