@@ -3,6 +3,10 @@ import defaults from '../core/core.defaults';
33import Arc from '../elements/element.arc' ;
44import { isArray , valueOrDefault } from '../helpers/helpers.core' ;
55
6+ /**
7+ * @typedef { import("../core/core.controller").default } Chart
8+ */
9+
610const PI = Math . PI ;
711const DOUBLE_PI = PI * 2 ;
812const HALF_PI = PI / 2 ;
@@ -94,13 +98,45 @@ defaults.set('doughnut', {
9498 }
9599} ) ;
96100
101+ function getRatioAndOffset ( rotation , circumference , cutout ) {
102+ let ratioX = 1 ;
103+ let ratioY = 1 ;
104+ let offsetX = 0 ;
105+ let offsetY = 0 ;
106+ // If the chart's circumference isn't a full circle, calculate size as a ratio of the width/height of the arc
107+ if ( circumference < DOUBLE_PI ) {
108+ let startAngle = rotation % DOUBLE_PI ;
109+ startAngle += startAngle >= PI ? - DOUBLE_PI : startAngle < - PI ? DOUBLE_PI : 0 ;
110+ const endAngle = startAngle + circumference ;
111+ const startX = Math . cos ( startAngle ) ;
112+ const startY = Math . sin ( startAngle ) ;
113+ const endX = Math . cos ( endAngle ) ;
114+ const endY = Math . sin ( endAngle ) ;
115+ const contains0 = ( startAngle <= 0 && endAngle >= 0 ) || endAngle >= DOUBLE_PI ;
116+ const contains90 = ( startAngle <= HALF_PI && endAngle >= HALF_PI ) || endAngle >= DOUBLE_PI + HALF_PI ;
117+ const contains180 = startAngle === - PI || endAngle >= PI ;
118+ const contains270 = ( startAngle <= - HALF_PI && endAngle >= - HALF_PI ) || endAngle >= PI + HALF_PI ;
119+ const minX = contains180 ? - 1 : Math . min ( startX , startX * cutout , endX , endX * cutout ) ;
120+ const minY = contains270 ? - 1 : Math . min ( startY , startY * cutout , endY , endY * cutout ) ;
121+ const maxX = contains0 ? 1 : Math . max ( startX , startX * cutout , endX , endX * cutout ) ;
122+ const maxY = contains90 ? 1 : Math . max ( startY , startY * cutout , endY , endY * cutout ) ;
123+ ratioX = ( maxX - minX ) / 2 ;
124+ ratioY = ( maxY - minY ) / 2 ;
125+ offsetX = - ( maxX + minX ) / 2 ;
126+ offsetY = - ( maxY + minY ) / 2 ;
127+ }
128+ return { ratioX, ratioY, offsetX, offsetY} ;
129+ }
130+
97131class DoughnutController extends DatasetController {
98132
99133 constructor ( chart , datasetIndex ) {
100134 super ( chart , datasetIndex ) ;
101135
102136 this . innerRadius = undefined ;
103137 this . outerRadius = undefined ;
138+ this . offsetX = undefined ;
139+ this . offsetY = undefined ;
104140 }
105141
106142 linkScales ( ) { }
@@ -131,61 +167,31 @@ class DoughnutController extends DatasetController {
131167 return ringIndex ;
132168 }
133169
170+ /**
171+ * @param {string } mode
172+ */
134173 update ( mode ) {
135174 const me = this ;
136175 const chart = me . chart ;
137- const chartArea = chart . chartArea ;
138- const opts = chart . options ;
139- let ratioX = 1 ;
140- let ratioY = 1 ;
141- let offsetX = 0 ;
142- let offsetY = 0 ;
176+ const { chartArea, options} = chart ;
143177 const meta = me . _cachedMeta ;
144178 const arcs = meta . data ;
145- const cutout = opts . cutoutPercentage / 100 || 0 ;
146- const circumference = opts . circumference ;
179+ const cutout = options . cutoutPercentage / 100 || 0 ;
147180 const chartWeight = me . _getRingWeight ( me . index ) ;
148-
149- // If the chart's circumference isn't a full circle, calculate size as a ratio of the width/height of the arc
150- if ( circumference < DOUBLE_PI ) {
151- let startAngle = opts . rotation % DOUBLE_PI ;
152- startAngle += startAngle >= PI ? - DOUBLE_PI : startAngle < - PI ? DOUBLE_PI : 0 ;
153- const endAngle = startAngle + circumference ;
154- const startX = Math . cos ( startAngle ) ;
155- const startY = Math . sin ( startAngle ) ;
156- const endX = Math . cos ( endAngle ) ;
157- const endY = Math . sin ( endAngle ) ;
158- const contains0 = ( startAngle <= 0 && endAngle >= 0 ) || endAngle >= DOUBLE_PI ;
159- const contains90 = ( startAngle <= HALF_PI && endAngle >= HALF_PI ) || endAngle >= DOUBLE_PI + HALF_PI ;
160- const contains180 = startAngle === - PI || endAngle >= PI ;
161- const contains270 = ( startAngle <= - HALF_PI && endAngle >= - HALF_PI ) || endAngle >= PI + HALF_PI ;
162- const minX = contains180 ? - 1 : Math . min ( startX , startX * cutout , endX , endX * cutout ) ;
163- const minY = contains270 ? - 1 : Math . min ( startY , startY * cutout , endY , endY * cutout ) ;
164- const maxX = contains0 ? 1 : Math . max ( startX , startX * cutout , endX , endX * cutout ) ;
165- const maxY = contains90 ? 1 : Math . max ( startY , startY * cutout , endY , endY * cutout ) ;
166- ratioX = ( maxX - minX ) / 2 ;
167- ratioY = ( maxY - minY ) / 2 ;
168- offsetX = - ( maxX + minX ) / 2 ;
169- offsetY = - ( maxY + minY ) / 2 ;
170- }
171-
172- for ( let i = 0 , ilen = arcs . length ; i < ilen ; ++ i ) {
173- arcs [ i ] . _options = me . _resolveDataElementOptions ( i , mode ) ;
174- }
175-
176- chart . borderWidth = me . getMaxBorderWidth ( ) ;
177- const maxWidth = ( chartArea . right - chartArea . left - chart . borderWidth ) / ratioX ;
178- const maxHeight = ( chartArea . bottom - chartArea . top - chart . borderWidth ) / ratioY ;
179- chart . outerRadius = Math . max ( Math . min ( maxWidth , maxHeight ) / 2 , 0 ) ;
180- chart . innerRadius = Math . max ( chart . outerRadius * cutout , 0 ) ;
181- chart . radiusLength = ( chart . outerRadius - chart . innerRadius ) / ( me . _getVisibleDatasetWeightTotal ( ) || 1 ) ;
182- chart . offsetX = offsetX * chart . outerRadius ;
183- chart . offsetY = offsetY * chart . outerRadius ;
181+ const { ratioX, ratioY, offsetX, offsetY} = getRatioAndOffset ( options . rotation , options . circumference , cutout ) ;
182+ const borderWidth = me . getMaxBorderWidth ( ) ;
183+ const maxWidth = ( chartArea . right - chartArea . left - borderWidth ) / ratioX ;
184+ const maxHeight = ( chartArea . bottom - chartArea . top - borderWidth ) / ratioY ;
185+ const outerRadius = Math . max ( Math . min ( maxWidth , maxHeight ) / 2 , 0 ) ;
186+ const innerRadius = Math . max ( outerRadius * cutout , 0 ) ;
187+ const radiusLength = ( outerRadius - innerRadius ) / ( me . _getVisibleDatasetWeightTotal ( ) || 1 ) ;
188+ me . offsetX = offsetX * outerRadius ;
189+ me . offsetY = offsetY * outerRadius ;
184190
185191 meta . total = me . calculateTotal ( ) ;
186192
187- me . outerRadius = chart . outerRadius - chart . radiusLength * me . _getRingWeightOffset ( me . index ) ;
188- me . innerRadius = Math . max ( me . outerRadius - chart . radiusLength * chartWeight , 0 ) ;
193+ me . outerRadius = outerRadius - radiusLength * me . _getRingWeightOffset ( me . index ) ;
194+ me . innerRadius = Math . max ( me . outerRadius - radiusLength * chartWeight , 0 ) ;
189195
190196 me . updateElements ( arcs , 0 , mode ) ;
191197 }
@@ -211,6 +217,9 @@ class DoughnutController extends DatasetController {
211217 const centerY = ( chartArea . top + chartArea . bottom ) / 2 ;
212218 const innerRadius = reset && animationOpts . animateScale ? 0 : me . innerRadius ;
213219 const outerRadius = reset && animationOpts . animateScale ? 0 : me . outerRadius ;
220+ const firstOpts = me . _resolveDataElementOptions ( start , mode ) ;
221+ const sharedOptions = me . _getSharedOptions ( mode , arcs [ start ] , firstOpts ) ;
222+ const includeOptions = me . _includeOptions ( mode , sharedOptions ) ;
214223 let startAngle = opts . rotation ;
215224 let i ;
216225
@@ -222,21 +231,23 @@ class DoughnutController extends DatasetController {
222231 const index = start + i ;
223232 const circumference = me . _circumference ( index , reset ) ;
224233 const arc = arcs [ i ] ;
225- const options = arc . _options || { } ;
226234 const properties = {
227- x : centerX + chart . offsetX ,
228- y : centerY + chart . offsetY ,
235+ x : centerX + me . offsetX ,
236+ y : centerY + me . offsetY ,
229237 startAngle,
230238 endAngle : startAngle + circumference ,
231239 circumference,
232240 outerRadius,
233- innerRadius,
234- options
241+ innerRadius
235242 } ;
243+ if ( includeOptions ) {
244+ properties . options = me . _resolveDataElementOptions ( index , mode ) ;
245+ }
236246 startAngle += circumference ;
237247
238248 me . _updateElement ( arc , index , properties , mode ) ;
239249 }
250+ me . _updateSharedOptions ( sharedOptions , mode ) ;
240251 }
241252
242253 calculateTotal ( ) {
@@ -252,10 +263,6 @@ class DoughnutController extends DatasetController {
252263 }
253264 }
254265
255- /* if (total === 0) {
256- total = NaN;
257- }*/
258-
259266 return total ;
260267 }
261268
@@ -267,7 +274,6 @@ class DoughnutController extends DatasetController {
267274 return 0 ;
268275 }
269276
270- // gets the max border or hover width to properly scale pie charts
271277 getMaxBorderWidth ( arcs ) {
272278 const me = this ;
273279 let max = 0 ;
@@ -321,8 +327,8 @@ class DoughnutController extends DatasetController {
321327 /**
322328 * @private
323329 */
324- _getRingWeight ( dataSetIndex ) {
325- return Math . max ( valueOrDefault ( this . chart . data . datasets [ dataSetIndex ] . weight , 1 ) , 0 ) ;
330+ _getRingWeight ( datasetIndex ) {
331+ return Math . max ( valueOrDefault ( this . chart . data . datasets [ datasetIndex ] . weight , 1 ) , 0 ) ;
326332 }
327333
328334 /**
0 commit comments