comparison d3.tip.js @ 0:42c058ce5b7c

Initial public commit of Exif-Graphr
author IBBoard <dev@ibboard.co.uk>
date Sun, 14 Aug 2016 20:46:16 +0100
parents
children a11817a35877
comparison
equal deleted inserted replaced
-1:000000000000 0:42c058ce5b7c
1 // d3.tip
2 // Copyright (c) 2013 Justin Palmer
3 //
4 // Tooltips for d3.js SVG visualizations
5
6 (function (root, factory) {
7 if (typeof define === 'function' && define.amd) {
8 // AMD. Register as an anonymous module with d3 as a dependency.
9 define(['d3'], factory)
10 } else {
11 // Browser global.
12 root.d3.tip = factory(root.d3)
13 }
14 }(this, function (d3) {
15
16 // Public - contructs a new tooltip
17 //
18 // Returns a tip
19 return function() {
20 var direction = d3_tip_direction,
21 offset = d3_tip_offset,
22 html = d3_tip_html,
23 node = initNode(),
24 svg = null,
25 point = null,
26 target = null
27
28 function tip(vis) {
29 svg = getSVGNode(vis)
30 point = svg.createSVGPoint()
31 document.body.appendChild(node)
32 }
33
34 // Public - show the tooltip on the screen
35 //
36 // Returns a tip
37 tip.show = function() {
38 var args = Array.prototype.slice.call(arguments)
39 if(args[args.length - 1] instanceof SVGElement) target = args.pop()
40
41 var content = html.apply(this, args),
42 poffset = offset.apply(this, args),
43 dir = direction.apply(this, args),
44 nodel = d3.select(node),
45 i = directions.length,
46 coords,
47 scrollTop = document.documentElement.scrollTop || document.body.scrollTop,
48 scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft
49
50 nodel.html(content)
51 .style({ opacity: 1, 'pointer-events': 'all' })
52
53 while(i--) nodel.classed(directions[i], false)
54 coords = direction_callbacks.get(dir).apply(this)
55 nodel.classed(dir, true).style({
56 top: (coords.top + poffset[0]) + scrollTop + 'px',
57 left: (coords.left + poffset[1]) + scrollLeft + 'px'
58 })
59
60 return tip
61 }
62
63 // Public - hide the tooltip
64 //
65 // Returns a tip
66 tip.hide = function() {
67 var nodel = d3.select(node)
68 nodel.style({ opacity: 0, 'pointer-events': 'none' })
69 return tip
70 }
71
72 // Public: Proxy attr calls to the d3 tip container. Sets or gets attribute value.
73 //
74 // n - name of the attribute
75 // v - value of the attribute
76 //
77 // Returns tip or attribute value
78 tip.attr = function(n, v) {
79 if (arguments.length < 2 && typeof n === 'string') {
80 return d3.select(node).attr(n)
81 } else {
82 var args = Array.prototype.slice.call(arguments)
83 d3.selection.prototype.attr.apply(d3.select(node), args)
84 }
85
86 return tip
87 }
88
89 // Public: Proxy style calls to the d3 tip container. Sets or gets a style value.
90 //
91 // n - name of the property
92 // v - value of the property
93 //
94 // Returns tip or style property value
95 tip.style = function(n, v) {
96 if (arguments.length < 2 && typeof n === 'string') {
97 return d3.select(node).style(n)
98 } else {
99 var args = Array.prototype.slice.call(arguments)
100 d3.selection.prototype.style.apply(d3.select(node), args)
101 }
102
103 return tip
104 }
105
106 // Public: Set or get the direction of the tooltip
107 //
108 // v - One of n(north), s(south), e(east), or w(west), nw(northwest),
109 // sw(southwest), ne(northeast) or se(southeast)
110 //
111 // Returns tip or direction
112 tip.direction = function(v) {
113 if (!arguments.length) return direction
114 direction = v == null ? v : d3.functor(v)
115
116 return tip
117 }
118
119 // Public: Sets or gets the offset of the tip
120 //
121 // v - Array of [x, y] offset
122 //
123 // Returns offset or
124 tip.offset = function(v) {
125 if (!arguments.length) return offset
126 offset = v == null ? v : d3.functor(v)
127
128 return tip
129 }
130
131 // Public: sets or gets the html value of the tooltip
132 //
133 // v - String value of the tip
134 //
135 // Returns html value or tip
136 tip.html = function(v) {
137 if (!arguments.length) return html
138 html = v == null ? v : d3.functor(v)
139
140 return tip
141 }
142
143 function d3_tip_direction() { return 'n' }
144 function d3_tip_offset() { return [0, 0] }
145 function d3_tip_html() { return ' ' }
146
147 var direction_callbacks = d3.map({
148 n: direction_n,
149 s: direction_s,
150 e: direction_e,
151 w: direction_w,
152 nw: direction_nw,
153 ne: direction_ne,
154 sw: direction_sw,
155 se: direction_se
156 }),
157
158 directions = direction_callbacks.keys()
159
160 function direction_n() {
161 var bbox = getScreenBBox()
162 return {
163 top: bbox.n.y - node.offsetHeight,
164 left: bbox.n.x - node.offsetWidth / 2
165 }
166 }
167
168 function direction_s() {
169 var bbox = getScreenBBox()
170 return {
171 top: bbox.s.y,
172 left: bbox.s.x - node.offsetWidth / 2
173 }
174 }
175
176 function direction_e() {
177 var bbox = getScreenBBox()
178 return {
179 top: bbox.e.y - node.offsetHeight / 2,
180 left: bbox.e.x
181 }
182 }
183
184 function direction_w() {
185 var bbox = getScreenBBox()
186 return {
187 top: bbox.w.y - node.offsetHeight / 2,
188 left: bbox.w.x - node.offsetWidth
189 }
190 }
191
192 function direction_nw() {
193 var bbox = getScreenBBox()
194 return {
195 top: bbox.nw.y - node.offsetHeight,
196 left: bbox.nw.x - node.offsetWidth
197 }
198 }
199
200 function direction_ne() {
201 var bbox = getScreenBBox()
202 return {
203 top: bbox.ne.y - node.offsetHeight,
204 left: bbox.ne.x
205 }
206 }
207
208 function direction_sw() {
209 var bbox = getScreenBBox()
210 return {
211 top: bbox.sw.y,
212 left: bbox.sw.x - node.offsetWidth
213 }
214 }
215
216 function direction_se() {
217 var bbox = getScreenBBox()
218 return {
219 top: bbox.se.y,
220 left: bbox.e.x
221 }
222 }
223
224 function initNode() {
225 var node = d3.select(document.createElement('div'))
226 node.style({
227 position: 'absolute',
228 top: 0,
229 opacity: 0,
230 'pointer-events': 'none',
231 'box-sizing': 'border-box'
232 })
233
234 return node.node()
235 }
236
237 function getSVGNode(el) {
238 el = el.node()
239 if(el.tagName.toLowerCase() === 'svg')
240 return el
241
242 return el.ownerSVGElement
243 }
244
245 // Private - gets the screen coordinates of a shape
246 //
247 // Given a shape on the screen, will return an SVGPoint for the directions
248 // n(north), s(south), e(east), w(west), ne(northeast), se(southeast), nw(northwest),
249 // sw(southwest).
250 //
251 // +-+-+
252 // | |
253 // + +
254 // | |
255 // +-+-+
256 //
257 // Returns an Object {n, s, e, w, nw, sw, ne, se}
258 function getScreenBBox() {
259 var targetel = target || d3.event.target,
260 bbox = {},
261 matrix = targetel.getScreenCTM(),
262 tbbox = targetel.getBBox(),
263 width = tbbox.width,
264 height = tbbox.height,
265 x = tbbox.x,
266 y = tbbox.y
267
268 point.x = x
269 point.y = y
270 bbox.nw = point.matrixTransform(matrix)
271 point.x += width
272 bbox.ne = point.matrixTransform(matrix)
273 point.y += height
274 bbox.se = point.matrixTransform(matrix)
275 point.x -= width
276 bbox.sw = point.matrixTransform(matrix)
277 point.y -= height / 2
278 bbox.w = point.matrixTransform(matrix)
279 point.x += width
280 bbox.e = point.matrixTransform(matrix)
281 point.x -= width / 2
282 point.y -= height / 2
283 bbox.n = point.matrixTransform(matrix)
284 point.y += height
285 bbox.s = point.matrixTransform(matrix)
286
287 return bbox
288 }
289
290 return tip
291 };
292
293 }));