]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | /**\r |
2 | * @class Ext.chart.label.Callout\r | |
3 | * @extends Ext.draw.modifier.Modifier\r | |
4 | *\r | |
5 | * This is a modifier to place labels and callouts by additional attributes.\r | |
6 | */\r | |
7 | Ext.define('Ext.chart.label.Callout', {\r | |
8 | extend: 'Ext.draw.modifier.Modifier',\r | |
9 | \r | |
10 | prepareAttributes: function (attr) {\r | |
11 | if (!attr.hasOwnProperty('calloutOriginal')) {\r | |
12 | attr.calloutOriginal = Ext.Object.chain(attr);\r | |
13 | // No __proto__, nor getPrototypeOf in IE8,\r | |
14 | // so manually saving a reference to 'attr' after chaining.\r | |
15 | attr.calloutOriginal.prototype = attr;\r | |
16 | }\r | |
17 | if (this._previous) {\r | |
18 | this._previous.prepareAttributes(attr.calloutOriginal);\r | |
19 | }\r | |
20 | },\r | |
21 | \r | |
22 | setAttrs: function (attr, changes) {\r | |
23 | var callout = attr.callout,\r | |
24 | origin = attr.calloutOriginal,\r | |
25 | bbox = attr.bbox.plain,\r | |
26 | width = (bbox.width || 0) + attr.labelOverflowPadding,\r | |
27 | height = (bbox.height || 0) + attr.labelOverflowPadding,\r | |
28 | dx, dy;\r | |
29 | \r | |
30 | if ('callout' in changes) {\r | |
31 | callout = changes.callout;\r | |
32 | }\r | |
33 | \r | |
34 | if ('callout' in changes || 'calloutPlaceX' in changes || 'calloutPlaceY' in changes || 'x' in changes || 'y' in changes) {\r | |
35 | var rotationRads = 'rotationRads' in changes ? origin.rotationRads = changes.rotationRads : origin.rotationRads,\r | |
36 | x = 'x' in changes ? (origin.x = changes.x) : origin.x,\r | |
37 | y = 'y' in changes ? (origin.y = changes.y) : origin.y,\r | |
38 | calloutPlaceX = 'calloutPlaceX' in changes ? changes.calloutPlaceX : attr.calloutPlaceX,\r | |
39 | calloutPlaceY = 'calloutPlaceY' in changes ? changes.calloutPlaceY : attr.calloutPlaceY,\r | |
40 | calloutVertical = 'calloutVertical' in changes ? changes.calloutVertical : attr.calloutVertical,\r | |
41 | temp;\r | |
42 | \r | |
43 | // Normalize Rotations\r | |
44 | rotationRads %= Math.PI * 2;\r | |
45 | if (Math.cos(rotationRads) < 0) {\r | |
46 | rotationRads = (rotationRads + Math.PI) % (Math.PI * 2);\r | |
47 | }\r | |
48 | \r | |
49 | if (rotationRads > Math.PI) {\r | |
50 | rotationRads -= Math.PI * 2;\r | |
51 | }\r | |
52 | \r | |
53 | if (calloutVertical) {\r | |
54 | rotationRads = rotationRads * (1 - callout) - Math.PI / 2 * callout;\r | |
55 | temp = width;\r | |
56 | width = height;\r | |
57 | height = temp;\r | |
58 | } else {\r | |
59 | rotationRads = rotationRads * (1 - callout);\r | |
60 | }\r | |
61 | changes.rotationRads = rotationRads;\r | |
62 | \r | |
63 | \r | |
64 | // Placing a label in the middle of a pie slice (x/y)\r | |
65 | // if callout doesn't exists (callout=0),\r | |
66 | // or outside the pie slice (calloutPlaceX/Y) if it does (callout=1).\r | |
67 | changes.x = x * (1 - callout) + calloutPlaceX * callout;\r | |
68 | changes.y = y * (1 - callout) + calloutPlaceY * callout;\r | |
69 | \r | |
70 | \r | |
71 | dx = calloutPlaceX - x;\r | |
72 | dy = calloutPlaceY - y;\r | |
73 | // Finding where the callout line intersects the bbox of the label\r | |
74 | // if it were to go to the center of the label,\r | |
75 | // and make that intersection point the end of the callout line.\r | |
76 | // Effectively, the end of the callout line traces label's bbox when chart is rotated.\r | |
77 | if (Math.abs(dy * width) > Math.abs(dx * height)) {\r | |
78 | // on top/bottom\r | |
79 | if (dy > 0) {\r | |
80 | changes.calloutEndX = changes.x - (height / 2) * (dx / dy) * callout;\r | |
81 | changes.calloutEndY = changes.y - (height / 2) * callout;\r | |
82 | } else {\r | |
83 | changes.calloutEndX = changes.x + (height / 2) * (dx / dy) * callout;\r | |
84 | changes.calloutEndY = changes.y + (height / 2) * callout;\r | |
85 | }\r | |
86 | } else {\r | |
87 | // on left/right\r | |
88 | if (dx > 0) {\r | |
89 | changes.calloutEndX = changes.x - width / 2;\r | |
90 | changes.calloutEndY = changes.y - (width / 2) * (dy / dx) * callout;\r | |
91 | } else {\r | |
92 | changes.calloutEndX = changes.x + width / 2;\r | |
93 | changes.calloutEndY = changes.y + (width / 2) * (dy / dx) * callout;\r | |
94 | }\r | |
95 | }\r | |
96 | // Since the length of the callout line is adjusted depending on the label's position\r | |
97 | // and dimensions, we hide the callout line if the length becomes negative.\r | |
98 | if (changes.calloutStartX && changes.calloutStartY) {\r | |
99 | changes.calloutHasLine =\r | |
100 | (dx > 0 && changes.calloutStartX < changes.calloutEndX) ||\r | |
101 | (dx <= 0 && changes.calloutStartX > changes.calloutEndX) ||\r | |
102 | (dy > 0 && changes.calloutStartY < changes.calloutEndY) ||\r | |
103 | (dy <= 0 && changes.calloutStartY > changes.calloutEndY);\r | |
104 | } else {\r | |
105 | changes.calloutHasLine = true;\r | |
106 | }\r | |
107 | }\r | |
108 | \r | |
109 | return changes;\r | |
110 | },\r | |
111 | \r | |
112 | pushDown: function (attr, changes) {\r | |
113 | changes = this.callParent([attr.calloutOriginal, changes]);\r | |
114 | return this.setAttrs(attr, changes);\r | |
115 | },\r | |
116 | \r | |
117 | popUp: function (attr, changes) {\r | |
118 | attr = attr.prototype;\r | |
119 | changes = this.setAttrs(attr, changes);\r | |
120 | if (this._next) {\r | |
121 | return this._next.popUp(attr, changes);\r | |
122 | } else {\r | |
123 | return Ext.apply(attr, changes);\r | |
124 | }\r | |
125 | }\r | |
126 | }); |