/// <summary> /// Handles the mouse move event /// </summary> /// <param name="e"></param> protected override void OnMouseMove(MouseEventArgs e) { if (_isDragging) { Region rg = new Region(); Rectangle gb = _graph.GetGraphBounds(); if (_selectedSlider != null) { rg.Union(_selectedSlider.Bounds); int x = e.X; int index = _breaks.IndexOf(_selectedSlider); if (x > gb.Right) { x = gb.Right; } if (x < gb.Left) { x = gb.Left; } if (index > 0) { if (x < _breaks[index - 1].Position + 2) { x = (int)_breaks[index - 1].Position + 2; } } if (index < _breaks.Count - 1) { if (x > _breaks[index + 1].Position - 2) { x = (int)_breaks[index + 1].Position - 2; } } _selectedSlider.Position = x; rg.Union(_selectedSlider.Bounds); Invalidate(rg); } return; } bool overSlider = false; foreach (BreakSlider slider in _breaks) { if (slider.Bounds.Contains(e.Location) || slider.HandleBounds.Contains(e.Location)) { overSlider = true; } } if (_dragCursor && !overSlider) { Cursor = Cursors.Arrow; _dragCursor = false; } if (!_dragCursor && overSlider) { _dragCursor = true; Cursor = Cursors.SizeWE; } base.OnMouseMove(e); }
/// <summary> /// Given a scheme, this will build the break list to match approximately. This does not /// force the interval method to build a new scheme. /// </summary> public void UpdateBreaks() { if (_isRaster) { UpdateRasterBreaks(); return; } if (_scheme == null) { return; } IFeatureCategory selectedCat = null; if (_selectedSlider != null) { selectedCat = _selectedSlider.Category as IFeatureCategory; } Breaks.Clear(); Statistics stats = _scheme.Statistics; Rectangle gb = _graph.GetGraphBounds(); _graph.ColorRanges.Clear(); foreach (IFeatureCategory category in _scheme.GetCategories()) { ColorRange cr = new ColorRange(category.GetColor(), category.Range); _graph.ColorRanges.Add(cr); BreakSlider bs = new BreakSlider(gb, _graph.Minimum, _graph.Maximum, cr) { Color = _breakColor, SelectColor = _selectedBreakColor }; if (selectedCat != null && category == selectedCat) { bs.Selected = true; _selectedSlider = bs; _graph.SelectedRange = cr; } bs.Value = category.Maximum != null?double.Parse(category.Maximum.ToString()) : stats.Maximum; bs.Category = category; Breaks.Add(bs); } Breaks.Sort(); // Moving a break generally affects both a maximum and a minimum. // Point to the next category to actuate that. for (int i = 0; i < Breaks.Count - 1; i++) { Breaks[i].NextCategory = Breaks[i + 1].Category; // We use the maximums to set up breaks. Minimums should simply // be set to work with the maximums of the previous category. Breaks[i + 1].Category.Minimum = Breaks[i].Value; } if (Breaks.Count == 0) { return; } int breakIndex = 0; BreakSlider nextSlider = Breaks[breakIndex]; int count = 0; if (_graph?.Bins == null) { return; } foreach (double value in _values) { if (value < nextSlider.Value) { count++; continue; } nextSlider.Count = count; while (value > nextSlider.Value) { breakIndex++; if (breakIndex >= Breaks.Count) { break; } nextSlider = Breaks[breakIndex]; } count = 0; } }