본문 바로가기

IT/Winform & Devexpress

Devexpress 차트 Linq를 활용해서 클릭 위치에서 근접한 SeriesPoint 찾기 - Find nearest SeriesPoint when Click mouse button on the ChartControl


Devexpress Chartcontrol 에서 클릭 위치에서 가장 가까운 SeriesPoint 값을 찾아가는 방법에 대해서 알아보겠습니다.
(Find nearest SeriesPoint when Click mouse button on the ChartControl)


보통 클릭 했을 때 위치에 따른 액션을 취하고 싶을 때 MousedDown이나 Click과 관련된 이벤트를 불러올 것이고, 이때 마우스의 위치의 값으로 그래프내 포지션을 찾아가게 됩니다. diagram.PointToDiagram(new Point(e.x, e.y)) <- 이 메소드를 활용하여 차트 내 위치값을 얻어 올 수 있습니다.

문제는 애매한 중간점을 클릭 했을 때 발생합니다.


예를들어서 2개의 점이 있다고 가정해 봅시다. (0,0)과 (3.3)을 잇는 1차함수 그래프를 나타낼 것입니다.

이상태에서 마우스로 1,1 부근을 클릭하면 아무런 액션을 취하지 않습니다. 왜냐하면 정확한 시리즈 포인트를 클릭하지 않았기 대문이죠

그렇다면 (0,0)과 (3,3)중 어디를 기준으로 액션을 취해야 할까요?


Devexpress에는 Mouseover시 유사한 점을 찾아서 해당 포인트에 음영의 원으로 표시를 해주는 기능이 있습니다.(Line 차트에서 꼭 SeriesPoint의 정확한 위치를 Mouse over하지 않아도 시리즈포인트(파란색원)이 해당 위치를 알아서 서치해 갑니다.) 그렇다면 이기능을 이용해서 nearest Point의 위치 즉 가까운 시리즈 포인트 위치를 찾을 수 있을 것입니다.


그런데 그게 쉽지 않았습니다. devexpress help를 검색 해보니 아래와 같은 질문이 있었습니다.

Hi Dev team,
Now I am using ChartControl, and have a requirement need to get the nearest SeriesPoint when I Click mouse button on the ChartControl of anywhere.

=> 제가 원하는 기능에 대한 질문을 찾아냈습니다.

Hi,

While at present there is no built-in capability to find the nearest Series point via the ChartHitInfo API, you can manually iterate through the Series.Points collection and locate the SeriesPoint item with the nearest argument (value). Let me know if you find this approach appropriate or you need any clarification.

=> 제가 사용하는 버전보다 아래이긴 하지만 지원하지 않느다는 내용입니다. 그 아래 질문들을 봐도 전부 PointToDiagram을 사용하라는 이야기가 많습니다.


그렇다면 애매하게 (0,0)과 (3,3)의 중간을 선택 했을 때 어떤 점을 기준으로 액션을 취해야 할지 결정할 수 있는 방법이 뭐가 있을까요?


저는 Linq를 활용하기로 했습니다. 차트와 연결된 seriesPoint의 값을 Datatable에 저장 한 후 Linq를 사용해서 클릭된 포인트의 근사값을 구했습니다.

전략은 이렇습니다.

1. 클릭한 위치에서 왼쪽으로 가장 가까운 시리즈 포인트를 구한다. -> preTime

2. 클릭한 위치에서 오른쪽으로 가장 가까운 시리즈 포인트를 구한다. -> nextTime

3. (현재시간 - preTime) VS (nextTime - 현재시간)

4. 더 작은 값이 선택 되도록 한다.

Use linq rather than looking for Devexpress features, we can use Linq compare |clickedTime-preTime| and [nextTime-clickedTime|

Smaller values are smaller


저는 이렇게 Linq를 사용했지만 Devexpress 내장 기능중에 근접 포인트를 찾는 기능이 있다면 꼭 소개 부탁드립니다.

I have used Linq this way, but if you have idea to find nearest points in Devexpress features please tell me by comment


제 차트와 코드를 살짝 보여드리겠습니다.


private DataRow FindNearestPoint(DateTime time) // 2017.06 cms syk

        {

            DataTable dt = (DataTable)series.DataSource

            

            DataRow row;

            if (dt != null)

            {

                row = dt.NewRow();


                DateTime nextTime = time;

                Double nextValue = 0;

                DateTime preTime = time;

                Double preValue = 0;


                var nT =

                   (from dr in dt.AsEnumerable()

                    where dr.Field<DateTime>(Argument) >= time

                    select new

                    {

                        datetime = dr.Field<DateTime>(Argument),

                        value = dr.Field<float>(Value)

                    }).Take(1);


                nextTime = nT.First().datetime;

                nextValue = nT.First().value;


                var pT =

                     from dr in dt.AsEnumerable()

                     where dr.Field<DateTime>(Argument) <= time

                     select new

                     {

                         datetime = dr.Field<DateTime>(Argument),

                         value = dr.Field<float>(Value)

                     };

                preTime = nT.Last().datetime;

                preValue = nT.Last().value;


                if (nextTime - time >= time - preTime)

                {

                    row[Argument] = preTime;

                    row[Value] = preValue;

                }

                else

                {

                    row[Argument] = nextTime;

                    row[Value] = nextValue;

                }

                return row;

            }

            return null;

        }

반응형