Как разрешить пользователю создавать аннотации на MSChart?

#c# #charts #annotations #mschart

#c# #Диаграммы #аннотации #mschart

Вопрос:

Как создать аннотацию на ходу и как включить размещение конечным пользователем Annotation.BeginPlacement() ? Я пытался сделать это несколькими способами, но не смог заставить его работать. Он должен отображаться в режиме реального времени после вызова BeginPlacement() .

Документации по этому вопросу практически нет — и в основном нет — поэтому я не могу найти никакой помощи по этой проблеме.

То, что я пробовал до сих пор, это создать аннотацию и поместить ее с помощью anchorX / Y , установить для всех разрешающих флагов значение true и вызвать BeginPlacement() во время перемещения мыши, но не может видеть аннотацию при ее размещении и не будет помещаться на свое место соответственно. Например, LineAnnotation начинается в правильном положении, но не заканчивается там, где я его оставил. Когда я перемещаю его так, чтобы он начинался с моих диаграмм {0,0}, он достигнет конечной точки.

Что я хочу знать, так это когда и как использовать эти доступные инструменты? То, что я пытаюсь сделать, это позволить пользователю рисовать аннотации на диаграмме и использовать их в качестве инструментов при анализе диаграмм.

Ответ №1:

Вам нужно рассчитать правильные позиции. Помните, что перемещение мыши не даст вам позиции (проценты) или значения (данные), а пиксели. Вы можете преобразовать их, используя различные функции axis. Официально они работают только в событии xxxPaint, но во время событий мыши они также работают нормально.

Обновление: есть два способа привязки:

  • Либо с помощью «Позиций«, то есть процентов, либо «Значений», то есть значений данных.

Вот пример 1-го рода:

введите описание изображения здесь

     LineAnnotation laNew = null;

    private void chart1_MouseDown(object sender, MouseEventArgs e)
    {
        if (cbx_drawAnnotation.Checked)
        {
            Axis ax = chart1.ChartAreas[0].AxisX;
            Axis ay = chart1.ChartAreas[0].AxisY;
            laNew = new LineAnnotation();
            chart1.Annotations.Add(laNew);
            double vx = ax.ValueToPosition(ax.PixelPositionToValue(e.X));
            double vy = ay.ValueToPosition(ay.PixelPositionToValue(e.Y));
            laNew.X = vx;
            laNew.Y = vy;
        }
    }


    private void chart1_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button.HasFlag(MouseButtons.Left) amp;amp; cbx_drawAnnotation.Checked)
        {
            Axis ax = chart1.ChartAreas[0].AxisX;
            Axis ay = chart1.ChartAreas[0].AxisY;
            double vx = ax.ValueToPosition(ax.PixelPositionToValue(e.X))- laNew.X;
            double vy = ay.ValueToPosition(ay.PixelPositionToValue(e.Y)) - laNew.Y;
            laNew.Width =  Math.Min(100, vx);
            laNew.Height =  Math.Min(100, vy);
            laNew.LineColor = rb_green.Checked ? Color.Green : Color.Red;
            laNew.AllowMoving = true;  // optional
        }
    }
  

Это работает нормально, если вам не нужно каким-либо образом изменить масштаб оси, например, изменить минимальные и / или максимальные значения оси.

  • В этом случае вам нужно привязать к значениям данных.

Сначала нам нужно связать Annotation с Axes , а также установить IsSizeAlwaysRelative false . Затем мы можем вычислить значения привязки и размера:

 private void chart1_MouseDown(object sender, MouseEventArgs e)
{
    if (cbx_drawAnnotation.Checked)
    {
        Axis ax = chart1.ChartAreas[0].AxisX;
        Axis ay = chart1.ChartAreas[0].AxisY;
        laNew = new LineAnnotation();
        chart1.Annotations.Add(laNew);

        laNew.IsSizeAlwaysRelative = false;

        laNew.AxisX = ax;
        laNew.AxisY = ay;

        laNew.AnchorX = ax.PixelPositionToValue(e.X);
        laNew.AnchorY = ay.PixelPositionToValue(e.Y);

        laNew.LineColor = rb_green.Checked ? Color.Green : Color.Red;
        laNew.AllowMoving = true;
    }
}


private void chart1_MouseMove(object sender, MouseEventArgs e)
{
    if (e.Button.HasFlag(MouseButtons.Left) amp;amp; cbx_drawAnnotation.Checked)
    {
        Axis ax = chart1.ChartAreas[0].AxisX;
        Axis ay = chart1.ChartAreas[0].AxisY;

        laNew.Width = ax.PixelPositionToValue(e.X) - laNew.AnchorX;   // values
        laNew.Height = ay.PixelPositionToValue(e.Y) - laNew.AnchorY;  
    }
}
  

Обратите внимание, как теперь я могу масштабировать максимум, а также изменять размер диаграммы, и аннотации остаются с точками данных..:

введите описание изображения здесь

Обновление: чтобы ограничить строку ChartArea , добавьте это в определение в MouseDown событии:

  laNew.ClipToChartArea = chart1.ChartAreas[0].Name;
  

Чтобы исключение не покидало диаграмму, добавьте это к условию в MouseMove ..:

 .. amp;amp; chart1.ClientRectangle.Contains(e.Location)
  

Комментарии:

1. Я заметил, что вы используете проценты по ширине и высоте LineAnnotation . Возможно ли получить его в значениях оси? Я разрешаю изменять размер временного окна (только с помощью оси min / max, без масштабирования), и строки не «изменяют размер» правильно. РЕДАКТИРОВАТЬ: или ваша диаграмма просто 100×100 …?

2. Это верно. Все элементы диаграммы. Значения Position.xxx указаны в процентах от соответствующего контейнера. Я рассмотрю возможность перехода от этого типа привязки к привязке относительно значений точек данных..

3. Было бы здорово, если бы вы нашли решение… Заранее спасибо!

4. Привязка начальной точки проста, но каким-то образом размер не является. Странно. Я буду держать вас в курсе..

5. Выполнено. Пожалуйста, протестируйте!