@@ -5,6 +5,10 @@ import defaults from '../core/core.defaults';
55import Arc from '../elements/element.arc' ;
66import { isArray , valueOrDefault } from '../helpers/helpers.core' ;
77
8+ /**
9+ * @typedef { import("../core/core.controller").default } Chart
10+ */
11+
812const PI = Math . PI ;
913const DOUBLE_PI = PI * 2 ;
1014const HALF_PI = PI / 2 ;
@@ -96,13 +100,45 @@ defaults.set('doughnut', {
96100 }
97101} ) ;
98102
103+ function getRatioAndOffset ( rotation , circumference , cutout ) {
104+ let ratioX = 1 ;
105+ let ratioY = 1 ;
106+ let offsetX = 0 ;
107+ let offsetY = 0 ;
108+ // If the chart's circumference isn't a full circle, calculate size as a ratio of the width/height of the arc
109+ if ( circumference < DOUBLE_PI ) {
110+ let startAngle = rotation % DOUBLE_PI ;
111+ startAngle += startAngle >= PI ? - DOUBLE_PI : startAngle < - PI ? DOUBLE_PI : 0 ;
112+ const endAngle = startAngle + circumference ;
113+ const startX = Math . cos ( startAngle ) ;
114+ const startY = Math . sin ( startAngle ) ;
115+ const endX = Math . cos ( endAngle ) ;
116+ const endY = Math . sin ( endAngle ) ;
117+ const contains0 = ( startAngle <= 0 && endAngle >= 0 ) || endAngle >= DOUBLE_PI ;
118+ const contains90 = ( startAngle <= HALF_PI && endAngle >= HALF_PI ) || endAngle >= DOUBLE_PI + HALF_PI ;
119+ const contains180 = startAngle === - PI || endAngle >= PI ;
120+ const contains270 = ( startAngle <= - HALF_PI && endAngle >= - HALF_PI ) || endAngle >= PI + HALF_PI ;
121+ const minX = contains180 ? - 1 : Math . min ( startX , startX * cutout , endX , endX * cutout ) ;
122+ const minY = contains270 ? - 1 : Math . min ( startY , startY * cutout , endY , endY * cutout ) ;
123+ const maxX = contains0 ? 1 : Math . max ( startX , startX * cutout , endX , endX * cutout ) ;
124+ const maxY = contains90 ? 1 : Math . max ( startY , startY * cutout , endY , endY * cutout ) ;
125+ ratioX = ( maxX - minX ) / 2 ;
126+ ratioY = ( maxY - minY ) / 2 ;
127+ offsetX = - ( maxX + minX ) / 2 ;
128+ offsetY = - ( maxY + minY ) / 2 ;
129+ }
130+ return { ratioX, ratioY, offsetX, offsetY} ;
131+ }
132+
99133class DoughnutController extends DatasetController {
100134
101135 constructor ( chart , datasetIndex ) {
102136 super ( chart , datasetIndex ) ;
103137
104138 this . innerRadius = undefined ;
105139 this . outerRadius = undefined ;
140+ this . offsetX = undefined ;
141+ this . offsetY = undefined ;
106142 }
107143
108144 linkScales ( ) { }
@@ -133,62 +169,31 @@ class DoughnutController extends DatasetController {
133169 return ringIndex ;
134170 }
135171
172+ /**
173+ * @param {string } mode
174+ */
136175 update ( mode ) {
137- var me = this ;
138- var chart = me . chart ;
139- var chartArea = chart . chartArea ;
140- var opts = chart . options ;
141- var ratioX = 1 ;
142- var ratioY = 1 ;
143- var offsetX = 0 ;
144- var offsetY = 0 ;
145- var meta = me . _cachedMeta ;
146- var arcs = meta . data ;
147- var cutout = opts . cutoutPercentage / 100 || 0 ;
148- var circumference = opts . circumference ;
149- var chartWeight = me . _getRingWeight ( me . index ) ;
150- var maxWidth , maxHeight , i , ilen ;
151-
152- // If the chart's circumference isn't a full circle, calculate size as a ratio of the width/height of the arc
153- if ( circumference < DOUBLE_PI ) {
154- var startAngle = opts . rotation % DOUBLE_PI ;
155- startAngle += startAngle >= PI ? - DOUBLE_PI : startAngle < - PI ? DOUBLE_PI : 0 ;
156- var endAngle = startAngle + circumference ;
157- var startX = Math . cos ( startAngle ) ;
158- var startY = Math . sin ( startAngle ) ;
159- var endX = Math . cos ( endAngle ) ;
160- var endY = Math . sin ( endAngle ) ;
161- var contains0 = ( startAngle <= 0 && endAngle >= 0 ) || endAngle >= DOUBLE_PI ;
162- var contains90 = ( startAngle <= HALF_PI && endAngle >= HALF_PI ) || endAngle >= DOUBLE_PI + HALF_PI ;
163- var contains180 = startAngle === - PI || endAngle >= PI ;
164- var contains270 = ( startAngle <= - HALF_PI && endAngle >= - HALF_PI ) || endAngle >= PI + HALF_PI ;
165- var minX = contains180 ? - 1 : Math . min ( startX , startX * cutout , endX , endX * cutout ) ;
166- var minY = contains270 ? - 1 : Math . min ( startY , startY * cutout , endY , endY * cutout ) ;
167- var maxX = contains0 ? 1 : Math . max ( startX , startX * cutout , endX , endX * cutout ) ;
168- var maxY = contains90 ? 1 : Math . max ( startY , startY * cutout , endY , endY * cutout ) ;
169- ratioX = ( maxX - minX ) / 2 ;
170- ratioY = ( maxY - minY ) / 2 ;
171- offsetX = - ( maxX + minX ) / 2 ;
172- offsetY = - ( maxY + minY ) / 2 ;
173- }
174-
175- for ( i = 0 , ilen = arcs . length ; i < ilen ; ++ i ) {
176- arcs [ i ] . _options = me . _resolveDataElementOptions ( i , mode ) ;
177- }
178-
179- chart . borderWidth = me . getMaxBorderWidth ( ) ;
180- maxWidth = ( chartArea . right - chartArea . left - chart . borderWidth ) / ratioX ;
181- maxHeight = ( chartArea . bottom - chartArea . top - chart . borderWidth ) / ratioY ;
182- chart . outerRadius = Math . max ( Math . min ( maxWidth , maxHeight ) / 2 , 0 ) ;
183- chart . innerRadius = Math . max ( chart . outerRadius * cutout , 0 ) ;
184- chart . radiusLength = ( chart . outerRadius - chart . innerRadius ) / ( me . _getVisibleDatasetWeightTotal ( ) || 1 ) ;
185- chart . offsetX = offsetX * chart . outerRadius ;
186- chart . offsetY = offsetY * chart . outerRadius ;
176+ const me = this ;
177+ const chart = me . chart ;
178+ const { chartArea, options} = chart ;
179+ const meta = me . _cachedMeta ;
180+ const arcs = meta . data ;
181+ const cutout = options . cutoutPercentage / 100 || 0 ;
182+ const chartWeight = me . _getRingWeight ( me . index ) ;
183+ const { ratioX, ratioY, offsetX, offsetY} = getRatioAndOffset ( options . rotation , options . circumference , cutout ) ;
184+ const borderWidth = me . getMaxBorderWidth ( ) ;
185+ const maxWidth = ( chartArea . right - chartArea . left - borderWidth ) / ratioX ;
186+ const maxHeight = ( chartArea . bottom - chartArea . top - borderWidth ) / ratioY ;
187+ const outerRadius = Math . max ( Math . min ( maxWidth , maxHeight ) / 2 , 0 ) ;
188+ const innerRadius = Math . max ( outerRadius * cutout , 0 ) ;
189+ const radiusLength = ( outerRadius - innerRadius ) / ( me . _getVisibleDatasetWeightTotal ( ) || 1 ) ;
190+ me . offsetX = offsetX * outerRadius ;
191+ me . offsetY = offsetY * outerRadius ;
187192
188193 meta . total = me . calculateTotal ( ) ;
189194
190- me . outerRadius = chart . outerRadius - chart . radiusLength * me . _getRingWeightOffset ( me . index ) ;
191- me . innerRadius = Math . max ( me . outerRadius - chart . radiusLength * chartWeight , 0 ) ;
195+ me . outerRadius = outerRadius - radiusLength * me . _getRingWeightOffset ( me . index ) ;
196+ me . innerRadius = Math . max ( me . outerRadius - radiusLength * chartWeight , 0 ) ;
192197
193198 me . updateElements ( arcs , 0 , mode ) ;
194199 }
@@ -214,6 +219,9 @@ class DoughnutController extends DatasetController {
214219 const centerY = ( chartArea . top + chartArea . bottom ) / 2 ;
215220 const innerRadius = reset && animationOpts . animateScale ? 0 : me . innerRadius ;
216221 const outerRadius = reset && animationOpts . animateScale ? 0 : me . outerRadius ;
222+ const firstOpts = me . _resolveDataElementOptions ( start , mode ) ;
223+ const sharedOptions = me . _getSharedOptions ( mode , arcs [ start ] , firstOpts ) ;
224+ const includeOptions = me . _includeOptions ( mode , sharedOptions ) ;
217225 let startAngle = opts . rotation ;
218226 let i ;
219227
@@ -225,21 +233,23 @@ class DoughnutController extends DatasetController {
225233 const index = start + i ;
226234 const circumference = me . _circumference ( index , reset ) ;
227235 const arc = arcs [ i ] ;
228- const options = arc . _options || { } ;
229236 const properties = {
230- x : centerX + chart . offsetX ,
231- y : centerY + chart . offsetY ,
237+ x : centerX + me . offsetX ,
238+ y : centerY + me . offsetY ,
232239 startAngle,
233240 endAngle : startAngle + circumference ,
234241 circumference,
235242 outerRadius,
236- innerRadius,
237- options
243+ innerRadius
238244 } ;
245+ if ( includeOptions ) {
246+ properties . options = me . _resolveDataElementOptions ( index , mode ) ;
247+ }
239248 startAngle += circumference ;
240249
241250 me . _updateElement ( arc , index , properties , mode ) ;
242251 }
252+ me . _updateSharedOptions ( sharedOptions , mode ) ;
243253 }
244254
245255 calculateTotal ( ) {
@@ -255,10 +265,6 @@ class DoughnutController extends DatasetController {
255265 }
256266 }
257267
258- /* if (total === 0) {
259- total = NaN;
260- }*/
261-
262268 return total ;
263269 }
264270
@@ -270,7 +276,6 @@ class DoughnutController extends DatasetController {
270276 return 0 ;
271277 }
272278
273- // gets the max border or hover width to properly scale pie charts
274279 getMaxBorderWidth ( arcs ) {
275280 var me = this ;
276281 var max = 0 ;
@@ -324,8 +329,8 @@ class DoughnutController extends DatasetController {
324329 /**
325330 * @private
326331 */
327- _getRingWeight ( dataSetIndex ) {
328- return Math . max ( valueOrDefault ( this . chart . data . datasets [ dataSetIndex ] . weight , 1 ) , 0 ) ;
332+ _getRingWeight ( datasetIndex ) {
333+ return Math . max ( valueOrDefault ( this . chart . data . datasets [ datasetIndex ] . weight , 1 ) , 0 ) ;
329334 }
330335
331336 /**
0 commit comments