1 | 'use strict'
|
2 |
|
3 | const d3 = require('./d3.js')
|
4 |
|
5 | class 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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
97 |
|
98 | const titleOverflowsTop = y - this.height < 0 - this.size.titlePaddingTop
|
99 |
|
100 |
|
101 |
|
102 | const startsCloserToTop = y < this.size.containerHeight / 2
|
103 |
|
104 |
|
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 |
|
136 | module.exports = HoverBox
|