/// <summary> /// Scales the value used to determine the size of the Bubble. /// </summary> /// <param name="graph">The Chart Graphics object</param> /// <param name="common">The Common elements object</param> /// <param name="area">Chart area for this chart</param> /// <param name="value">Value to scale.</param> /// <returns>Scaled values.</returns> private float ScaleBubbleSize(ChartGraphics graph, CommonElements common, ChartArea area, double value) { // Check if scaling numbers are detected if (!_scaleDetected) { // Try to find bubble size scale in the custom series properties _minAll = double.MaxValue; _maxAll = double.MinValue; foreach (Series ser in common.DataManager.Series) { if (String.Compare(ser.ChartTypeName, Name, true, System.Globalization.CultureInfo.CurrentCulture) == 0 && ser.ChartArea == area.Name && ser.IsVisible()) { // Check if custom properties are set to specify scale if (ser.IsCustomPropertySet(CustomPropertyName.BubbleScaleMin)) { _minAll = Math.Min(_minAll, CommonElements.ParseDouble(ser[CustomPropertyName.BubbleScaleMin])); } if (ser.IsCustomPropertySet(CustomPropertyName.BubbleScaleMax)) { _maxAll = Math.Max(_maxAll, CommonElements.ParseDouble(ser[CustomPropertyName.BubbleScaleMax])); } // Check if attribute for max. size is set if (ser.IsCustomPropertySet(CustomPropertyName.BubbleMaxSize)) { _maxPossibleBubbleSize = CommonElements.ParseDouble(ser[CustomPropertyName.BubbleMaxSize]); if (_maxPossibleBubbleSize < 0 || _maxPossibleBubbleSize > 100) { throw(new ArgumentException(SR.ExceptionCustomAttributeIsNotInRange0to100("BubbleMaxSize"))); } } // Check if attribute for min. size is set if (ser.IsCustomPropertySet(CustomPropertyName.BubbleMinSize)) { _minPossibleBubbleSize = CommonElements.ParseDouble(ser[CustomPropertyName.BubbleMinSize]); if (_minPossibleBubbleSize < 0 || _minPossibleBubbleSize > 100) { throw(new ArgumentException(SR.ExceptionCustomAttributeIsNotInRange0to100("BubbleMinSize"))); } } // Check if custom properties set to use second Y value (bubble size) as label text labelYValueIndex = 0; if (ser.IsCustomPropertySet(CustomPropertyName.BubbleUseSKSizeorLabel) && String.Compare(ser[CustomPropertyName.BubbleUseSKSizeorLabel], "true", StringComparison.OrdinalIgnoreCase) == 0) { labelYValueIndex = 1; break; } } } // Scale values are not specified - auto detect if (_minAll == double.MaxValue || _maxAll == double.MinValue) { double minSer = double.MaxValue; double maxSer = double.MinValue; foreach (Series ser in common.DataManager.Series) { if (ser.ChartTypeName == Name && ser.ChartArea == area.Name && ser.IsVisible()) { foreach (DataPoint point in ser.Points) { if (!point.IsEmpty) { // Check required Y values number if (point.YValues.Length < YValuesPerPoint) { throw (new InvalidOperationException(SR.ExceptionChartTypeRequiresYValues(Name, YValuesPerPoint.ToString(CultureInfo.InvariantCulture)))); } minSer = Math.Min(minSer, point.YValues[1]); maxSer = Math.Max(maxSer, point.YValues[1]); } } } } if (_minAll == double.MaxValue) { _minAll = minSer; } if (_maxAll == double.MinValue) { _maxAll = maxSer; } } // Calculate maximum bubble size SKSize areaSize = graph.GetAbsoluteSize(area.PlotAreaPosition.Size); _maxBubleSize = (float)(Math.Min(areaSize.Width, areaSize.Height) / (100.0 / _maxPossibleBubbleSize)); _minBubleSize = (float)(Math.Min(areaSize.Width, areaSize.Height) / (100.0 / _minPossibleBubbleSize)); // Calculate scaling variables depending on the Min/Max values if (_maxAll == _minAll) { _valueScale = 1; _valueDiff = _minAll - (_maxBubleSize - _minBubleSize) / 2f; } else { _valueScale = (_maxBubleSize - _minBubleSize) / (_maxAll - _minAll); _valueDiff = _minAll; } _scaleDetected = true; } // Check if value do not exceed Min&Max if (value > _maxAll) { return(0F); } if (value < _minAll) { return(0F); } // Return scaled value return((float)((value - _valueDiff) * _valueScale) + _minBubleSize); }