Skip to content

Commit bbcd56b

Browse files
committed
Merge branch 'release/1.1.1'
Fixes #1
2 parents 4c9a018 + 1fda324 commit bbcd56b

11 files changed

Lines changed: 266 additions & 80 deletions

File tree

CHANGELOG

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
= 1.1.1
2+
* Configurable tooltip font sizes
3+
* Fix mouse position for retina displays - Issue #1
4+
* Explicit support for retina (@2x) images
5+
* Better Retina support and consistency in general
6+
17
= 1.1.0
28
* Move the requestAnimationFrame and general performance enhancements
39
* Implement Images support in bubbles

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,12 @@ This is the exploded view of possbile options (with included defaults)
4444
textColor: "#fff" // Bubble label color
4545
textType: "helvetica" // Font
4646

47-
popoverOpts: { // Control the look of the hover popover
47+
popoverOpts: { // Control the look of the hover popover
4848
textFont: 'helvetica',
4949
textColor: '#fff',
5050
fillColor: '#333',
51+
labelSize: 22, // Popover Heading size
52+
metricSize: 14, // Popover Metric size
5153
opacity: 0.6,
5254
}
5355
}
@@ -97,6 +99,14 @@ Example of a data object with an image covering 60% of the bubble:
9799
}
98100
```
99101

102+
##### Retina
103+
104+
If your `img_src` value contains `@2x` it will be treated as a retina image and
105+
be downsized (by 2) for display.
106+
107+
If you do not specify `@2x` images, and the client pixel density is greater
108+
than 1, this module will reduce the image size to prefer image clarity over size.
109+
100110
#### Loading Spinner
101111

102112
There is a provided Spinner object you can use to show a loading animation if

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "bubblechart",
33
"description": "BubbleChart is a JavaScript module for the comparative visualization of two dimensional data in a bubble chart.",
4-
"version": "1.1.0",
4+
"version": "1.1.1",
55
"license": "Apache 2.0",
66
"homepage": "https://github.com/jondavidjohn/bubblechart",
77
"bugs": "https://github.com/jondavidjohn/bubblechart/issues",

src/classes/BubbleChart.coffee

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,11 @@ class @BubbleChart
3434
c.context = c.getContext '2d'
3535

3636
# Adjust for retina if needed
37-
ratio = 1
38-
if window.devicePixelRatio? and window.devicePixelRatio > 1
39-
if c.context.webkitBackingStorePixelRatio == 2
40-
window.devicePixelRatio = 1
41-
42-
if window.devicePixelRatio > 1
43-
c.style.height = "#{c.height}px"
44-
c.style.width = "#{c.width}px"
45-
c.width = c.width * ratio
46-
c.height = c.height * ratio
37+
ratio = BubbleChart.getPixelRatio c.context
38+
c.style.height = "#{c.height}px"
39+
c.style.width = "#{c.width}px"
40+
c.width = c.width * ratio
41+
c.height = c.height * ratio
4742

4843
# Attach Canvas Mouse/Touch events
4944
c.style.position = "relative"
@@ -62,6 +57,18 @@ class @BubbleChart
6257
if @data.length
6358
@reload()
6459

60+
@getBackingStoreRatio: (context) ->
61+
context.webkitBackingStorePixelRatio or
62+
context.mozBackingStorePixelRatio or
63+
context.msBackingStorePixelRatio or
64+
context.oBackingStorePixelRatio or
65+
context.backingStorePixelRatio or 1
66+
67+
@getPixelRatio: (context) ->
68+
ratio = window.devicePixelRatio or 1
69+
backingStoreRatio = BubbleChart.getBackingStoreRatio(context)
70+
ratio / backingStoreRatio
71+
6572
reload: () ->
6673
@bubbles = []
6774
@metricTotal = (d.data for d in @data).reduce (a, b) -> a + b

src/classes/BubbleChart/Bubble.coffee

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,16 +105,25 @@ class BubbleChart.Bubble
105105
render: () ->
106106
if @img_src?
107107
@img.onload = () =>
108+
canvas = document.createElement 'canvas'
109+
ctx = canvas.getContext '2d'
110+
bsRatio = BubbleChart.getBackingStoreRatio ctx
111+
112+
if @img_src.indexOf('@2x') is not -1
113+
@img.height = @img.height / 2
114+
@img.width = @img.width / 2
115+
else if bsRatio > 1
116+
@img.height = @img.height / bsRatio
117+
@img.width = @img.width / bsRatio
118+
108119
while @img.width > @diameter * @img_area
109120
@img.height = @img.height * 0.75
110121
@img.width = @img.width * 0.75
111-
canvas = document.createElement 'canvas'
112122
canvas.height = @img.height
113123
canvas.width = @img.width + 2
114124
img_arc_x = @img.width / 2 + 2
115125
img_arc_y = @img.height / 2
116126
img_arc_r = @img.width / 2
117-
ctx = canvas.getContext '2d'
118127
ctx.save()
119128
ctx.beginPath()
120129
ctx.arc img_arc_x, img_arc_y, img_arc_r, 0, Math.PI * 2, true
@@ -135,8 +144,9 @@ class BubbleChart.Bubble
135144
)
136145
@img.src = @img_src
137146
@pre = document.createElement 'canvas'
138-
@pre.height = @pre.width = (@diameter + 3) * window.devicePixelRatio
139147
pre_context = @pre.getContext '2d'
148+
ratio = BubbleChart.getPixelRatio pre_context
149+
@pre.height = @pre.width = (@diameter + 3) * ratio
140150
pre_context.beginPath()
141151
pre_context.fillStyle = @fillColor
142152
pre_context.arc @radius + 1, @radius + 1, @radius, 0, Math.PI * 2, true
@@ -148,15 +158,15 @@ class BubbleChart.Bubble
148158
pre_context.stroke()
149159

150160
if @textColor
151-
pre_context.font = "20px '#{@textFont}'"
161+
pre_context.font = "#{20 * ratio}px '#{@textFont}'"
152162
pre_context.fillStyle = @textColor
153163
text_measurement = pre_context.measureText @label
154164
if text_measurement.width + 12 < @diameter
155165
spacingX = @radius - (text_measurement.width / 2)
156166
spacingY = @radius + (14 / 2)
157167
pre_context.fillText @label, spacingX, spacingY
158168
else
159-
pre_context.font = "12px helvetica"
169+
pre_context.font = "#{12 * ratio}px helvetica"
160170
text_measurement = pre_context.measureText @label
161171
if text_measurement.width + 7 < @diameter
162172
spacingX = @radius - (text_measurement.width / 2)

src/classes/BubbleChart/Pointer.coffee

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,13 @@ class BubbleChart.Pointer
4040
grabbingBubble: ->
4141
@bubble? and @bubble.grabbed
4242

43-
getPixelRatio: (c) ->
44-
ratio = 1
45-
if window.devicePixelRatio? and c.context.webkitBackingStorePixelRatio < 2
46-
ratio = window.devicePixelRatio
47-
ratio
48-
4943
getPosition: do ->
5044
top = {}
5145
left = {}
5246
(e) ->
5347
element = e.target or e.srcElement
5448
element_id = element.id
55-
pr = @getPixelRatio(element)
49+
pr = BubbleChart.getPixelRatio(element.getContext '2d')
5650
unless top[element_id]? and left[element_id]?
5751
top[element_id] = 0
5852
left[element_id] = 0

src/classes/BubbleChart/Popover.coffee

Lines changed: 91 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,64 +3,106 @@ class BubbleChart.Popover
33
constructor : (bubble, o) ->
44
@bubble = bubble
55
@fillColor = o.fillColor or '#333'
6-
@textColor = o.textColor or '#fff'
6+
@textColor = o.textColor or '#FFF'
77
@textFont = o.textFont or 'helvetica'
88
@opacity = o.opacity or 0.8
9-
@lineHeight = 20
9+
@labelSize = o.labelSize or 18
10+
@metricSize = o.metricSize or 12
1011
@last_draw = null
12+
@textDems = {}
13+
@pre = null
14+
15+
getTextDems: (context, text, size, font) ->
16+
if not @textDems["#{text}#{size}#{font}"]?
17+
# Width is easy
18+
context.font = "#{size}px '#{font}'"
19+
width = context.measureText(text).width
20+
21+
# Height is a bit tricky
22+
d = document.createElement "span"
23+
d.style.fontSize = "#{size}px"
24+
d.style.fontFamily = font
25+
d.style.visibility = "hidden"
26+
d.textContent = text
27+
document.body.appendChild d
28+
height = d.offsetHeight
29+
document.body.removeChild d
30+
@textDems["#{text}#{size}#{font}"] =
31+
width: width
32+
height: height
33+
@textDems["#{text}#{size}#{font}"]
34+
35+
calculateTriangle: (base_width, height, ratio) ->
36+
triangle =
37+
x: 0, y: 0
38+
x2:0, y2:0
39+
x3:0, y3:0
1140

12-
clear: (context) ->
13-
if @last_draw?
14-
context.clearRect @last_draw.x, @last_draw.y, @last_draw.w, @last_draw.h
15-
@last_draw = null
41+
triangle.x -= base_width / 2
42+
triangle.x2 = triangle.x + base_width / 2
43+
triangle.x3 = triangle.x + base_width
44+
45+
if height > 0
46+
triangle.y += height - (26 * ratio)
47+
else
48+
triangle.y += height + (48 * ratio)
49+
50+
triangle.y2 = triangle.y + height
51+
triangle.y3 = triangle.y
52+
53+
triangle
1654

1755
paint: (pointer, context) ->
1856
return unless pointer.current?
57+
ratio = BubbleChart.getPixelRatio context
1958

20-
context.font = "17px '#{@textFont}'"
21-
label_measurement = context.measureText @bubble.label
22-
metric_measurement = context.measureText "#{@bubble.data} #{@bubble.metric}"
23-
lineWidth = if label_measurement.width > metric_measurement.width
24-
label_measurement.width + 15
25-
else
26-
metric_measurement.width + 15
59+
labelSize = @labelSize
60+
metricSize = @metricSize
61+
lr_pad = 8 * ratio
62+
tb_pad = 5 * ratio
63+
triangle_width = 16 * ratio
64+
triangle_height = 8 * ratio
65+
metric_text = "#{@bubble.data} #{@bubble.metric}"
2766

28-
labelX = pointer.current.x - 14
29-
labelY = pointer.current.y - 26 - @lineHeight * 2
30-
triangle =
31-
x: 0, y: 0
32-
x2:0, y2:0
33-
x3:0, y3:0
67+
l_dems = @getTextDems context, @bubble.label, labelSize, @textFont
68+
m_dems = @getTextDems context, metric_text, metricSize, @textFont
69+
70+
lineWidth = (Math.max(l_dems.width, m_dems.width) + (lr_pad * 2)) * ratio
71+
lineHeight = Math.max(l_dems.height, m_dems.height) * ratio
72+
73+
box_height = (lineHeight * 2) + (tb_pad * 2)
74+
75+
labelX = pointer.current.x - (14 * ratio)
76+
labelY = pointer.current.y - box_height - triangle_height - (tb_pad * 2)
3477

3578
if labelY < 0
36-
labelY = pointer.current.y + 26
37-
triangle.y = pointer.current.y + 26
38-
triangle.y3 = triangle.y - 4
79+
labelY = pointer.current.y + (40 * ratio)
80+
triangle = @calculateTriangle(triangle_width, - triangle_height, ratio)
3981
else
40-
triangle.y = pointer.current.y - 16
41-
triangle.y3 = pointer.current.y - 10
82+
triangle = @calculateTriangle(triangle_width, triangle_height, ratio)
4283

43-
# triangle setup
44-
triangle.x = pointer.current.x - 8
45-
triangle.x2 = triangle.x + 16
46-
triangle.y2 = triangle.y
47-
triangle.x3 = triangle.x2 - 8
84+
triangle.x += pointer.current.x
85+
triangle.y += pointer.current.y
86+
triangle.x2 += pointer.current.x
87+
triangle.y2 += pointer.current.y
88+
triangle.x3 += pointer.current.x
89+
triangle.y3 += pointer.current.y
4890

4991
# right edge case
5092
if labelX + lineWidth > context.canvas.width
5193
labelX -= labelX + lineWidth - context.canvas.width
5294

95+
@last_draw =
96+
x: labelX
97+
y: labelY - (triangle_height)
98+
w: lineWidth + 2
99+
h: box_height + (triangle_height * 2)
100+
53101
context.beginPath()
54102
context.fillStyle = @fillColor
55103
context.globalAlpha = @opacity
56104

57-
@last_draw =
58-
x: labelX
59-
y: labelY
60-
w: lineWidth
61-
h: @lineHeight * 2 + 10 + (triangle.y3 - triangle.y) + 5
62-
63-
context.roundedRect labelX, labelY, lineWidth, @lineHeight * 2 + 10, 7
105+
context.roundedRect labelX, labelY, lineWidth, box_height, 7 * ratio
64106

65107
context.moveTo triangle.x, triangle.y
66108
context.lineTo triangle.x2, triangle.y2
@@ -70,12 +112,20 @@ class BubbleChart.Popover
70112

71113
context.globalAlpha = 1
72114

115+
73116
context.fillStyle = @textColor
74-
context.fillText @bubble.label, labelX + 7, labelY + @lineHeight
117+
context.font = "#{labelSize * ratio}px #{@textFont}"
118+
context.fillText @bubble.label, labelX + lr_pad, labelY + lineHeight
75119

76-
context.font = "11px #{@textFont}"
77-
detailX = labelX + 7
78-
detailY = labelY + @lineHeight * 2
79-
context.fillText "#{@bubble.data} #{@bubble.metric}", detailX, detailY
120+
context.font = "#{metricSize * ratio}px #{@textFont}"
121+
detailX = labelX + lr_pad
122+
detailY = labelY + lineHeight * 2
123+
context.fillText metric_text, detailX, detailY
80124

81125
context.closePath()
126+
127+
128+
clear: (context) ->
129+
if @last_draw?
130+
context.clearRect @last_draw.x, @last_draw.y, @last_draw.w, @last_draw.h
131+
@last_draw = null

test/classes/BubbleChart/PointerTest.js

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,6 @@
2121
equal(pointer.grabbingBubble(), false);
2222
});
2323

24-
test('getPixelRatio', function() {
25-
var pointer = new Pointer(),
26-
canvas = document.getElementById('test_canvas');
27-
28-
canvas.context = canvas.getContext('2d');
29-
30-
window.devicePixelRatio = 2;
31-
canvas.context.webkitBackingStorePixelRatio = 1;
32-
equal(pointer.getPixelRatio(canvas), window.devicePixelRatio);
33-
34-
window.devicePixelRatio = 2;
35-
canvas.context.webkitBackingStorePixelRatio = 2;
36-
equal(pointer.getPixelRatio(canvas), 1);
37-
});
38-
3924
test('getPosition', function() {
4025
var pointer = new Pointer(),
4126
element = document.getElementById('test_canvas'),
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<title>BubbleChart.Point Tests</title>
6+
<link rel="stylesheet" href="qunit/qunit/qunit.css">
7+
</head>
8+
<body>
9+
<div id="qunit"></div>
10+
<div id="qunit-fixture">
11+
<canvas id='test_canvas'></canvas>
12+
</div>
13+
<script src="../../qunit/qunit/qunit.js"></script>
14+
<script src="../../../dist/bubblechart.js"></script>
15+
<script src="PopoverTest.js"></script>
16+
</body>
17+
</html>

0 commit comments

Comments
 (0)