C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Вопрос по графикам TChart
Admin
Отправлено: 16.04.2004, 13:23


Владимир

Группа: Администратор
Сообщений: 1190



Есть TChart в нем несколько Series (графиков)

Нужно чтобы рядом с каждым графиком выводилась
некая информация (строка текста) :
или справа(как на приложенном графике — "Гр 1" и "Гр 2"),
или прямо рядом с линией графика.

Легенда не годится, так как график будет печататься на ч/б принтере,
и цвета не будет — а нужно конкретное обозначение -
какой график для чего.

Или если-бы можно было-бы как-то нарисовать
для Series->Marks->Label не для всех точек серии,
а только для одной(любой) из точек и вывести там
некую информацию.

Ваши предложения... wink.gif


Присоединить изображение

Присоединить изображение

Admin
Отправлено: 16.04.2004, 14:39


Владимир

Группа: Администратор
Сообщений: 1190



Нашел решение. smile.gif

в .h

CODE

private: // User declarations
void __fastcall SeriesGetMarkText(TChartSeries *Sender,
int ValueIndex, AnsiString &MarkText);


в .cpp

CODE

//---------------------------------------------------------------------------

TLineSeries *Ls = new TLineSeries(this);
Ls->ParentChart = Chart;
Ls->Marks->Visible = true;
Ls->OnGetMarkText = SeriesGetMarkText;
Ls->Marks->ArrowLength = 16;
...

void __fastcall TForm1::SeriesGetMarkText(TChartSeries *Sender,
int ValueIndex, AnsiString &MarkText)
{
if(ValueIndex != nPoz) MarkText = "";
else MarkText = ((TLineSeries*)Sender)->Title;
}
//---------------------------------------------------------------------------


В результате выводится 1 Mark в указанной nPoz позиции
(нужная мне строка, в данном случае название серии Title)

Отредактировано Admin — 16/04/2004, 16:51
Gedeon
Отправлено: 16.04.2004, 15:23


Ветеран

Группа: Модератор
Сообщений: 1742



Да просто все однако бывает, а я тут уже нагородил вывод текста на канве, с высотой по У в зависимости от последнего значения Series, а Х всегда постоянный. Геморройно тем, что после любой перерисовки нужно перебирать серии и рисовать, плюс расчет изменения масштаба при изменении размеров.
Admin
Отправлено: 16.04.2004, 15:45


Владимир

Группа: Администратор
Сообщений: 1190



К сожалению и у этого решения есть минусы. sad.gif

Почему только это так плохо реализовано -
нужно было к свойству Title у Series добавить
возможность вывода этого Title в указанном месте.
А то если несколько графиков — и как их различать
прикажете (особенно в распечатке на ч/б принтере ?)

ToGedeon:
Если не сложно, приведите код вашего решения.
Gedeon
Отправлено: 19.04.2004, 08:44


Ветеран

Группа: Модератор
Сообщений: 1742



В пятницу подумал проблема решена и не сохранил исходник, за сегодня накидаю, выложу.
Gedeon
Отправлено: 19.04.2004, 15:33


Ветеран

Группа: Модератор
Сообщений: 1742



Вот накидал:
CODE

void __fastcall TForm1::Button1Click(TObject *Sender)
{ // это так кошки, на которых тренироваться
TFastLineSeries * S = new TFastLineSeries(this);
TFastLineSeries * S1 = new TFastLineSeries(this);
TFastLineSeries * S2 = new TFastLineSeries(this);
for(int i=0; i<10;i++){
S->AddXY(i,i,"",clRed);
S1->AddXY(i,i+1,"",clRed);
S2->AddXY(i,i+2,"",clRed);
}

Chart1->AddSeries(S);
Chart1->AddSeries(S1);
Chart1->AddSeries(S2);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Chart1AfterDraw(TObject *Sender)
{ // собственно само рисование (от кошек не зависит)
int SeriesCount = Chart1->SeriesCount();
if(SeriesCount==0) return;

double MaxAxisValue = Chart1->Series[0]->MaxYValue();
double MinAxisValue = Chart1->Series[0]->MinYValue();

int X = Chart1->Width-60; /* 60 — расстояние от правого края чарта до графика — расстояние от графика до текста*/


for(int i=0; i<SeriesCount; i++){
if(MaxAxisValue<Chart1->Series[i]->MaxYValue()){
MaxAxisValue=Chart1->Series[i]->MaxYValue(); /*максимальное значение всех серий*/
}
if(MinAxisValue>Chart1->Series[i]->MinYValue()){
MinAxisValue=Chart1->Series[i]->MinYValue(); /*минимальное значение всех серий*/
}
}
double AxisHeight = MaxAxisValue — MinAxisValue; /* высота оси*/
for(int i=0; i<SeriesCount; i++){
int Y;
Y = Chart1->Height — Chart1->Height*
(Chart1->Series[i]->YValues->Value[Chart1->Series[i]->XValues->Count()-1]
/AxisHeight) +20; /* 20 — расстояние от верха чарта до графика — половина высоты текста*/
Chart1->Canvas->TextOutA(X,Y,("Test" + IntToStr(i)));
}
}
//---------------------------------------------------------------------------

Изображение того, что удалось получить пытаюсь приложить, хрен пойму как это делать. Это все действительно конечно если ось У линейная, иначе надо пересматривать алгоритм расчета массштаба, да и все это в таком виде подходит только под конкретный график (из-за чисел описанных в коментариях, но если порыть свойства можно эти значения и рассчитать). Это конечно далекий от совершенства пример, так просто идея, тут наверняка можно чего-нибудь соптимизировать.

Отредактировано Gedeon — 19/04/2004, 16:39

Присоединить изображение

Присоединить изображение

Admin
Отправлено: 19.04.2004, 16:36


Владимир

Группа: Администратор
Сообщений: 1190



Большое спасибо, то что и было нужно biggrin.gif

Только чуть подправил:

CODE

//---------------------------------------------------------------------------
void __fastcall TForm1::Chart1AfterDraw(TObject *Sender)
{
int SeriesCount = Chart1->SeriesCount();
if(SeriesCount==0) return;

for(int i=0; i<SeriesCount; i++){
int LastValueIndex = Chart1->Series[i]->LastValueIndex;
int X = Chart1->Series[i]->CalcXPos(LastValueIndex);
int Y = Chart1->Series[i]->CalcYPos(LastValueIndex);
Chart1->Canvas->TextOutA(X,Y-10,("Test" + IntToStr(i)));
}
}
//---------------------------------------------------------------------------


P.S. И не забыть поставить MarginRight, чтобы надпись влезла,
типа Chart1->MarginRight = 10;


Отредактировано Admin — 19/04/2004, 17:43
Gedeon
Отправлено: 19.04.2004, 16:45


Ветеран

Группа: Модератор
Сообщений: 1742



Тут вот еще что подумалось, если значения сойдутся близко в конце графика, нужно проверять разницу между У и тогда соответственно рассчитать Х, т.е. сместить второй на несколько позиций вправо.
Admin
Отправлено: 19.04.2004, 16:54


Владимир

Группа: Администратор
Сообщений: 1190



Вот так получилось.


Присоединить изображение

Присоединить изображение


Вернуться в Вопросы программирования в C++Builder