GyverPortal icon indicating copy to clipboard operation
GyverPortal copied to clipboard

Графики JQuery

Open DAK85 opened this issue 2 years ago • 194 comments

Раз в новый портал внедряется возможность юзать jquery, решил исследовать Инет на предмет графиков с использованием данной библиотеки. http://www.flotcharts.org/downloads/ Вот это мне понравилось, даже сейчас скажу чем именно понравилось:

  1. Все твои скрипты на создание различных графиков занимают 1,58 МБ, а все сжатые скрипты FLOT всего 156 кБ
  2. Проверил совместимость флот с актуальной версией jquery, всё отлично работает.
  3. Много примеров и на сколько я понимаю, это очень мощный и гибкий инструмент, есть документация и много примеров Просто как вариант, сам у себя пока не использую графики в проекте, но а вдруг эта идея тебе понравится.

DAK85 avatar Sep 07 '22 02:09 DAK85

Все твои скрипты на создание различных графиков занимают 1,58 М

Все три типа графиков никто не будет юзать в одном проекте. На данный момент у меня переделана опять файловая система, и файлы графиков больше не дублируются несколько раз в папках

GyverLibs avatar Sep 07 '22 07:09 GyverLibs

Да я просто, скачал сегодня эту штуку, посмотрел каких там только графиков нет.... Доберусь до других проектов, посмотрю на графики. До сих пор ещё не попробовал

DAK85 avatar Sep 07 '22 07:09 DAK85

А так добавим ессесн. Я их в принципе видел, это самые популярные веб графики

GyverLibs avatar Sep 07 '22 07:09 GyverLibs

Вообще мне понравилось как работает лог. То есть подключаем буфер и пишем в него данные, потом буфер выводим в лог. Может так же сделать, там где запускаем портал, делаем для для графика количество линий, количество точек по x,y... А в конструкторе просто объявляем график, указывая его дополнительные параметры.

DAK85 avatar Sep 07 '22 09:09 DAK85

Может и так, это будет уже полноценный крупный модуль. И будут проблемы с типами данных, но они в целом решаемы

GyverLibs avatar Sep 07 '22 09:09 GyverLibs

Намучался в усмерть, но однако получилось сделать часть кода. flot

DAK85 avatar Sep 08 '22 11:09 DAK85

Лолллл

GyverLibs avatar Sep 08 '22 11:09 GyverLibs

Не спешите смеяться раньше времени, сейчас немного код причешу, думаю моя затея будет по душе!

DAK85 avatar Sep 08 '22 11:09 DAK85

Конечно по душе) просто графики выглядят как бык нассал) это чисто по точкам строится, без привязки к одной оси как времени?

GyverLibs avatar Sep 08 '22 11:09 GyverLibs

нет, это я строю таким макаром

      if (millis() - tmr > 1000) {
        tmr = millis();
        portal.flot.write(0,random(1000),random(1000));
        portal.flot.write(1,random(1000),random(1000));
        portal.flot.write(2,random(1000),random(1000));

x и y делаю рандомно, можно привязать к millis()

DAK85 avatar Sep 08 '22 11:09 DAK85

Не, так не пойдет. Нужно делать отдельный класс графика, и дать возможность билдеру его выводить напрямую от объекта

GyverLibs avatar Sep 08 '22 11:09 GyverLibs

да я вроде так и делал flot.zip да я бы без класса просто сдох бы сегодня Вывод пока черз одно место, но я просто тестировал

void GP_FLOT(GyverPortal& portal){
		int _a[]={0,1,2,3};
		byte _j=0;
		String s;
		s.reserve(1000);
		s+=F("<link href='/GP_flot.css' rel='stylesheet' type='text/css'>\n"
		"<script language='javascript' src='/GP_jquery.js'></script>\n"
		"<script language='javascript' src='/GP_flot.js'></script>\n"
		"<script>\n$(function(){\n");
		while (_j<3){
			s+=F("var d");
			s+=_j;
			s+=F("=");
			s+=portal.flot.read(_a[_j]);
			s+=F(";\n");
			_j++;
		}
		s+=F("$.plot(\"#flotplot\", [");
		_j=0;
		while (_j<3){
			s+=F("d");
			s+=_j;
		if (_j!=2)	s+=F(",");
			_j++;
		}
		s+=F("]);})</script>\n;<div id='flotplot'></div>");
		GP.SEND(s);
}

DAK85 avatar Sep 08 '22 13:09 DAK85

нет, не так. Нужен класс графика, то есть создаём график GP_plot plot; Конфигурируем, пишем туда plot.write(blahblah); И отправляем GP.SEND(plot); и SEND принимает SEND(GP_plot& plot); И всё завязано на динамической памяти

GyverLibs avatar Sep 08 '22 13:09 GyverLibs

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

DAK85 avatar Sep 08 '22 13:09 DAK85

не, это фигня) в самом портале не должно быть никаких буферов. Сделай код для визуала, я подом допилю бэкэнд

GyverLibs avatar Sep 08 '22 13:09 GyverLibs

я веб-сериал тоже отдельно выношу, чтобы их можно было несколько штук сделать и вывести с кайфом

GyverLibs avatar Sep 08 '22 14:09 GyverLibs

Я запутался, в самом портале буфера появляются только после portal.flot.start("ДлинаБуфера1,ДлинаБуфера2,....,ДлинаБуфераN"); Если сделать стоп, то они уходят в небытье. Вроде по феншую, Веб сериал и сейчас с небольшими изменениями можно несколько штук напилить, в этом есть смысл, согласен. Но то, как сделано сейчас, это очень классно, не могу понять зачем отдельно каждый график объявлять. Ведь по факту один и тот же буфер можно объявить 1 раз и выводить его хоть в 15 разных графиков в разных вариациях, делать зум, менять интервал, можно напилить интерфейс, подобный Заббиксу

DAK85 avatar Sep 08 '22 14:09 DAK85

ну вот нужно тебе на одной странице два графика вывести. Всё, приехали

GyverLibs avatar Sep 08 '22 14:09 GyverLibs

"ДлинаБуфера1,ДлинаБуфера2,....,ДлинаБуфераN"

уууу нет, это по максимум нелогично и некрасиво. Объекты должны быть, и всё, не надо изобретать велосипеды)

GyverLibs avatar Sep 08 '22 14:09 GyverLibs

ну вот нужно тебе на одной странице два графика вывести. Всё, приехали

не убедил, у меня это легко получится. Плюс все эти графики будут обновляться по ajax. и на несколько графиков можно будет запихать одну и ту же кривую... Допустим график температура - давление, тут же рядом график с той же температурой и мощностью нагревателя, при этом не будет уходить лишняя память, так бы пришлось температуру писать одновременно на 2-3 графика, а так только в один буфер

DAK85 avatar Sep 08 '22 14:09 DAK85

не, не поддерживаю такой кипиш. Не должно быть у портала внутри каких то составных буферов, всё должно быть отдельно. И лог тоже должен быть отдельным модулем. А память можно сэкономить другими подходами

GyverLibs avatar Sep 08 '22 14:09 GyverLibs

я нумб в программировании, честно, я как бы сделал отдельных класс для работы с буферами (звучит прикольно), просто я его подцепляю к классу портала, так как хочу, чтобы при обработке события /flot_upd? без лишнего геммороя одной строкой отдавать данные для построения графика.

DAK85 avatar Sep 08 '22 15:09 DAK85

сделаю по красоте масимально)

GyverLibs avatar Sep 08 '22 15:09 GyverLibs

опять несколько идей появилось, надо всё добавить(

GyverLibs avatar Sep 08 '22 15:09 GyverLibs

я пока фигачу до результата, а там посмотрим, может мои идею можно будет переложить на иные алгоритмы. А тебе надо пока выкинуть из головы все идеи,и заняться ненавистными делами (документацией и примерами) Я вообще за графики взялся, чтобы хоть как то оправдать внедрение jquery

DAK85 avatar Sep 08 '22 15:09 DAK85

не, на доку пока нет времени, видос не успеваю доделать и дел семейных очень много гора)

GyverLibs avatar Sep 08 '22 15:09 GyverLibs

Понимаешь, я хочу сделать так, чтобы джава сделала запрос G1X1Y2G2X2Y3, а портал в ответ дал строку, которая бы содержала данные для первой кривой(при этом х разделил на 10 а y на 100) и для второй кривоой (при этом x разделил на 100 а y на 1000), ява взяла данные и построили график. При это не обнуляя буфер, чтобы можно было и другие графики строить, сейчас допиливаю функцию чтения а в конструкторе минимум параметров (название осей и номера буферов кривых и всё)

DAK85 avatar Sep 08 '22 15:09 DAK85

пока не очень понял, главное чтобы это не стало графиком одного применения, котоырй сложно переделать под что то другое в случае чего

GyverLibs avatar Sep 08 '22 15:09 GyverLibs

Ладно, поехали, класс буфера

class GPflot {
public:
/*
Хотел как проще для инициализации сделать, пришлось подключать строки, делаем portal.flot.start("100,20,50");
Эта строка запустит 2 буфера (на Х и на У), но так же запомнит начало и длинну каждого по отдельности
Скажем кому сколько надо, хочете 1 линию на 100 точек, или 10 линий на 50, нет ограничений, только ресурсы МК
*/
void start(String _str="20") {			
	if (_state) return;
        _str += ',';
	int _count=0;
	for (int8_t _i=0;_i<_str.length();_i++) if (_str[_i]==',') _count++;
	head = new int [_count];
	BufLen = new int [_count];
	pos = new int [_count];
	pos[0]=0;
	for (int8_t _i=0;_i<_count;_i++){
		int _length=_str.substring(0,_str.indexOf(",")).toInt();
		head[_i]=0;
		BufLen[_i]=_length;
		if (_i>0) pos[_i]=pos[_i-1]+_length;
		size+=_length;
		_str=_str.substring(_str.indexOf(",")+1);
	}
        buffer_x = new unsigned long [size]; //что то мне показалось, что по Х мало кто будет юзать отрицательные значения
	buffer_y = new long [size];
	for (int _i=0;_i<size;_i++) {		//без этого очень всё плохо, мусор из памяти надо почистить
		buffer_x[_i]=NULL;
		buffer_y[_i]=NULL;
	}
	_state=true;
}
    ~GPflot() {
        stop();
    }
    
    void stop() {
        if (_state) {
		delete [] buffer_x;
		delete [] buffer_y;
		delete [] head;
		delete [] pos;
		delete [] BufLen;
		buffer_x = nullptr;
		buffer_y = nullptr;
		head = nullptr;
		pos = nullptr;
		BufLen = nullptr;
		_state = false;
        }
    }
    
// запись в буфер (по кругу, не очищая буфер от значений, просто его зацикливаем)
// выбираем номер буыера и пихаем в него данные
    void write(uint8_t num, unsigned long xn, long yn) {
        if (_state){
		if (head[num]<BufLen[num]){
			buffer_x[head[num]+pos[num]]=xn;
			buffer_y[head[num]+pos[num]]=yn;
			head[num]++;
		} else {
			buffer_x[head[num]+pos[num]]=xn;
			buffer_y[head[num]+pos[num]]=yn;
			head[num]=0;
		}
	_available=true; //эта штука говорит о том, что была произведена запись после последнего считывания

	}
    }
    
//В реад передаём параметры для формирования правильного ответа (номер буфера, делители по x и по y)
//1GdelxXdelyY2GdelxXdelyY --- 1G1X2Y2G2X3Y	

	String read(String _str) {
		String s;
		s+="[";
		uint8_t _count=0;
		for (int8_t _i=0;_i<_str.length();_i++) if (_str[_i]=='G') _count++; //кол-во кривых
		for (int8_t _i=0;_i<_count;_i++){					//извлекаем параметры 
			uint8_t num=_str.substring(0,_str.indexOf("G")).toInt();	//номер кривой
			_str=_str.substring(_str.indexOf("G")+1);			//избавляемся от лишнего
			uint8_t delx=_str.substring(0,_str.indexOf("X")).toInt();	//делитель по Х
			_str=_str.substring(_str.indexOf("X")+1);			//избавляемся от лишнего
			uint8_t dely=_str.substring(0,_str.indexOf("Y")).toInt();	//делитель по У
			_str=_str.substring(_str.indexOf("Y")+1);			//избавляемся от лишнего
			double _delx=pow(10,delx);					//кол-во знаков переводим в 10 в степени N
			double _dely=pow(10,dely);
			float _bufTemp_x, _bufTemp_y;					//временные переменные
			s +="[";
			for (int _i=pos[num]+head[num];_i<(pos[num]+BufLen[num]);_i++) {	//чтение по кругу, где то тут небольшой глюк, 
				_bufTemp_x=buffer_x[_i]/_delx;					//позже найду
				_bufTemp_y=buffer_y[_i]/_dely;
				s+="[";
				s+=_bufTemp_x;
				s+=",";
				s+=_bufTemp_y;
				s+="],";
			}
			for (int _i=pos[num];_i<(pos[num]+head[num]);_i++) {
				_bufTemp_x=buffer_x[_i]/_delx;
				_bufTemp_y=buffer_y[_i]/_dely;
				s+="[";
				s+=_bufTemp_x;
				s+=",";
				s+=_bufTemp_y;
				s+="],";
			}
			s[s.length()-1]=']';
			if ( _i < _count-1) s+=",";
		}
		s+="]";
		_available=false;				//это лишнее - удалить
		return s;	//по итогу строка вида [[[x,y],[x,y],[],[]],[[],[],[],[],[],[],[],[]],[[],[],[]]]
    }
    
    bool available() {						//лишнее, но это пока не точно
        return (_available&&_state);
    }
    
    bool state() {
        return _state;
    }
    
private:
	bool _available=false;
	bool _state=false;
	unsigned long* buffer_x = nullptr;
	long* buffer_y = nullptr;
	int* head = nullptr;
	int* BufLen = nullptr;
	int* pos = nullptr;
	int size=0;
};

Теперь конструктор выглядит так (это не последняя версия, просто почти час ночи) В последней версии не будет передаваться портал, будет скрипт запроса, который сам в автомате будет получать данные, заставим яву поработать, пока просто тест

GP_FLOT("1G1X1Y2G1X2Y",portal);

кастом плот

void GP_FLOT(const String& strinit,GyverPortal& portal){
		String s;
		s.reserve(1000);
		s+=F("<link href='/GP_flot.css' rel='stylesheet' type='text/css'>\n"
		"<script language='javascript' src='/GP_jquery.js'></script>\n"
		"<script language='javascript' src='/GP_flot.js'></script>\n"
		"<script>\n$(function(){\n var data=");
		s+=portal.flot.read(strinit);
		s+=F("\n$.plot(\"#flotplot\", data);"
		"})</script>\n<div id='flotplot'></div>");
		GP.SEND(s);
}

Запуск трёх буферов по 25 точек в каждом

    portal.flot.start("25,25,25");
    portal.start();
    Serial.println("Portal run");
    while (portal.tick()){
      static uint32_t tmr;
      if (millis() - tmr > 1000) {
        tmr = millis();
        portal.flot.write(0,millis()/1000,random(1000));
        portal.flot.write(1,millis()/1000,random(1000));
        portal.flot.write(2,millis()/1000,random(1000));

Результат такой: flot

DAK85 avatar Sep 08 '22 16:09 DAK85

круто! Пока не осилю разобраться, сначала нужно ОТА от Дениса интегрировать

GyverLibs avatar Sep 08 '22 17:09 GyverLibs