PureBasic - форум

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » PureBasic - форум » Вопросы по PureBasic » Существует ли модуль создания графиков?


Существует ли модуль создания графиков?

Сообщений 1 страница 6 из 6

1

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

0

2

один из https://www.purebasic.fr/english/viewto … mp;t=73000

https://github.com/Hoeppner1867/PureBasic

0

3

https://www.purebasic.fr/english/viewto … mp;t=67464

0

4

Пётр
Если рисовать много графиков на одном поле, надо переделывать, так как автоматически рассчитывает сетку и для второго графика сетка накладывается с учётом максимального и минимального значений.

Вот поигрался (и перевёл на русский язык).

Код:
EnableExplicit

;{ Simple Graph }

   ; Еще одна штука для простых "визуальных эффектов"
   ;   2017         (c) Luna Sole
   ;    v1.0.0.4       (+ взаимодействие с мышью)         
   

   ; Рисует график с двумя линиями на заданном изображении с использованием векторной библиотеки PB
   ; hImgOut            Изображение PB для рисования может быть любого размера [кроме, возможно, «очень низкого» разрешения ^^]
   ; GraphData()         массив с элементами для визуализации, должен содержать как минимум 1 элемент [начиная с 0]
   ; OutGeoData()         map для получения данных, необходимых для обработки взаимодействия с мышью. map key = координата X на изображении графика, value = связанный индекс GraphData()
   ; Average            сколько элементов используется для расчета среднего значения для текущего элемента? 2 минимально, если меньше будет отключено
   ; GridStepX            Шаг сетки X [вертикальные линии], измеренное в количестве GraphData (). используйте 0 для отключения
   ; GridStepY            Шаг сетки Y [горизонтальные линии], измеренное в значениях GraphData (). 0 для отключения
   ; FontSize            размер шрифта текстовых меток. используйте 0, чтобы отключить метки
   ; ColorN            цвета для элементов графика (RGB)
   ; RETURN:            нет, изображение изменено в случае успеха
   Procedure DrawSimpleGraph (hImgOut, Array GraphData(1), Map OutGeoData(), Average, GridStepX = 10, GridStepY = 10, FontSize = 9, Color1 = $00DDDD, Color2 = $DDDD00)
      ClearMap(OutGeoData())                  ; сбросить данные мыши
      
      Protected maxItems = ArraySize(GraphData())   ; количество пунктов (X)
      Protected maxValues                     ; количество значений (Y)
      Protected highValue, lowValue            ; самые высокие и самые низкие значения GraphData
      Protected t                           ; общая временная переменная
      If maxItems < 0 : ProcedureReturn :   EndIf   ; выйти, если массив GraphData недействителен

      ; Найти минимум и максимум значений, чтобы трансформировать шкалу
      Protected Dim TData(0)
      CopyArray(GraphData(), TData())
      SortArray(TData(), #PB_Sort_Ascending)
      lowValue = TData(0)
      highValue = TData(maxItems)
      FreeArray(TData())
      
      ; сделать вещи, чтобы лучше подогнать фоновую сетку
      If GridStepY > 0
         If highValue >= 0
            highValue + GridStepY - highValue % GridStepY
         ElseIf highValue
            highValue - highValue % GridStepY
         EndIf
         If lowValue > 0
            lowValue  - lowValue  % GridStepY
         ElseIf lowValue < 0
            lowValue  - (GridStepY + lowValue  % GridStepY)
         EndIf
      EndIf
      maxValues = highValue - lowValue
      If maxValues <= 0
         maxValues = 1
      EndIf
      ; загрузить шрифт для текстовых меток
      Protected Font
      If FontSize > 0
         Font = LoadFont(#PB_Any, "arial", FontSize)
         If Not IsFont(Font) ; и так далее
            Font = LoadFont(#PB_Any, "tahoma", FontSize)
            If Not IsFont(Font) ; и так далее.. :)
               Font = LoadFont(#PB_Any, "consolas", FontSize)
            EndIf
         EndIf
      EndIf
      
      ; рисовать данные в изображение
      If StartVectorDrawing(ImageVectorOutput(hImgOut, #PB_Unit_Pixel))
         ; [n] - определить смещения графиков / размеры текстовых меток и т. д.
         Protected.d oX = 1.0, oY = oX
         Protected.d mtW = 1.0, mtH = mtW
         If IsFont(Font)
            VectorFont(FontID(Font), FontSize)
            If VectorTextWidth(Str(highValue)) > VectorTextWidth(Str(lowValue)) ; задаём ширину текста
               oX = VectorTextWidth(Str(highValue)) + 2.0
            Else
               oX = VectorTextWidth(Str(lowValue)) + 2.0
            EndIf
            oY = VectorTextHeight("0A") + 2.0
            If oX > oY
               oY = oX
            Else
               oX = oY
            EndIf
            mtW = VectorTextWidth(Str(maxItems)) * 1.2
            mtH = VectorTextHeight(Str(highValue)) * 0.8
         EndIf
         ;    ширина линии (в пикселях)
         Protected.d LineWidth = 1.0
         ;    множители для масштабирования координат графика
         Protected.d mX = (VectorOutputWidth() - oX * 2.0) / (maxItems + Bool(maxItems = 0))   
         Protected.d mY = (VectorOutputHeight() - oY * 2.0) / maxValues
         ;   временные переменные, используемые при рисовании
         Protected.d cX, cY
         
         ; [0] - рисовать текстовые метки и линии сетки
         VectorSourceColor($77FFFFFF) ; цвет меток и сетки шкалы
         Protected.d tLast
         ;   горизонтальные линии / метки
         tLast = oY + maxValues * mY + 5.0
         If GridStepY > 0
            For t = maxValues To 0 Step -1
               If t % GridStepY = 0 Or t = maxValues
                  cY = oY + t * mY
                  ; нарисовать текстовую метку
                  If IsFont(Font) And cY < tLast
                     MovePathCursor(oX - (2.0 + VectorTextWidth(Str(highValue - t))), cY - VectorTextHeight(Str(highValue - t)) * 0.5)
                     DrawVectorText(Str(highValue - t))
                     tLast = cY - mtH
                  EndIf
                  ; нарисовать линию сетки
                  MovePathCursor(oX, oY + mY * t)            
                  AddPathLine(oX + maxItems * mX, oY + mY * t)
               EndIf
            Next t
         EndIf
         ;   вертикальные линии / метки
         tLast = 0.0
         If GridStepX > 0   
            ;GridStepX + 1
            For t = 0 To maxItems
               If t % GridStepX = 0 Or t = maxItems
                  cX = oX + t * mX
                  cY = oY + maxValues * mY
                  ; нарисовать текстовую метку
                  If IsFont(Font) And cX > tLast
                     MovePathCursor(cX - VectorTextWidth(Str(t)) * 0.5, cY + 2.0)
                     DrawVectorText(Str(t))
                     tLast = cX + mtW
                  EndIf
                  ; нарисовать линию сетки
                  MovePathCursor(cX, oY)
                  AddPathLine(cX, cY)
               EndIf
            Next t
         EndIf
         ;   fin
         If GridStepX > 0 Or GridStepY > 0
            DashPath(1.0, 3.0)
         EndIf
         
         
         ; [1] - нарисуйте основную линию / элементы и сформируйте "геоданные"
         Protected.d gX = oX
         Protected.d gX2
         VectorSourceColor(Color1 | $FF000000)
         MovePathCursor(oX, oY + mY * (highValue - GraphData(0)))
         For t = 0 To maxItems
            cX = oX + mX * t
            cY = oY + mY * (highValue - GraphData(t))
            AddPathLine(cX, cY)         ; добавить линию
            AddPathCircle(cX, cY, 2.0)  	; добавить точку
            MovePathCursor(cX, cY)      ; восстановить позицию курсора
            
            ; построить те "геоданные", которые используются для работы с мышью
            gX2 = gX + (cX - gX) * 0.5
            While gX < gX2
               OutGeoData(Str(Int(gX))) = t - 1
               gX + 1.0
            Wend
            While gX < cX
               OutGeoData(Str(Int(gX))) = t
               gX + 1.0
            Wend
            gX = cX
         Next t
         StrokePath(LineWidth)
         
         
         ; [2] - нарисовать «тренд» / усредненную линию
         Protected NewList Avg() ; стек для хранения последних значений
         Protected.d Avg         ; рассчитать текущий результат
         If Average > maxItems + 1
            Average = maxItems + 1
         EndIf
         If Average > 1            ; имеет смысл рисовать, только если он больше 1
            While ListSize(Avg()) < Average
               AddElement(Avg())   ; 'экстраполировать' с использованием данных первого элемента, без этого все выглядит хуже для меня: 3
               Avg() = GraphData(0)
            Wend
            MovePathCursor(oX, oY + (highValue - GraphData(0)) * mY)
            For t = 0 To maxItems
               FirstElement(Avg())      ; все это работает как стековая структура с максимальной глубиной = Average
               DeleteElement(Avg())   
               LastElement(Avg())      
               AddElement(Avg())
               Avg() = GraphData(t)   ; нажать новый элемент
               Avg = 0.0            ; рассчитать среднее значение по последним элементам
               ForEach Avg()
                  Avg + Avg()
               Next
               cX = oX + mX * t
               cY = oY + (highValue - Avg / Average) * mY
               AddPathLine(cX, cY)  ; добавить линию
               AddPathCircle(cX, cY, 1.0) 	; добавить точку
               MovePathCursor(cX, cY)      ; восстановить позицию курсора
            Next t
            VectorSourceColor(Color2 | $FF000000)
            StrokePath(LineWidth)
         EndIf
         
         ; очистить
         FreeList(Avg())
         StopVectorDrawing()
      EndIf
      
      ; очистить
      If IsFont(Font)
         FreeFont(Font)
      EndIf
   EndProcedure
   
;}


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Тест / пример
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


; используется для обработки кликов мыши по графику
; mapkey - координата X изображения графика, value - соответствующий индекс в массиве GraphData()
Global NewMap GraphGeodata()

; Размеры графика
Global W = 800, H = 600
; Изображение для рисования графика
Global tImg
; Окно и холст для отображения графика
Global tWindow, tCanvas


; Эта процедура обрабатывает события мыши на холсте графика.
Procedure GraphCB()
   Protected cX = GetGadgetAttribute(tCanvas, #PB_Canvas_MouseX)
   Select EventType()
      Case #PB_EventType_LeftButtonDown:
         If FindMapElement(GraphGeodata(), Str(cX))
            Debug "Нажата левая кнопка мыши  " + GraphGeodata()
         EndIf
      Case #PB_EventType_LeftButtonUp:
         If FindMapElement(GraphGeodata(), Str(cX))
            Debug "Отпущена левая кнопка мыши  " + GraphGeodata()
         EndIf
      Case #PB_EventType_LeftClick:
         If FindMapElement(GraphGeodata(), Str(cX))
            Debug "Клик левой кнопкой мыши " + GraphGeodata()
         EndIf
         
      Case #PB_EventType_RightButtonDown:
         If FindMapElement(GraphGeodata(), Str(cX))
            Debug "Нажата правая кнопка мыши " + GraphGeodata()
         EndIf
      Case #PB_EventType_RightButtonUp:
         If FindMapElement(GraphGeodata(), Str(cX))
            Debug "Отпущена правая кнопка мыши " + GraphGeodata()
         EndIf
      Case #PB_EventType_RightClick:
         If FindMapElement(GraphGeodata(), Str(cX))
            Debug "Клик правой кнопкой мыши " + GraphGeodata()
         EndIf
         
      Case #PB_EventType_MouseMove:
         If FindMapElement(GraphGeodata(), Str(cX))
            Debug "Мышь наведена на элемент " + GraphGeodata()
         EndIf
   EndSelect
EndProcedure

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; сгенерировать графические данные
Dim GraphValues (127) ; размер массива определяет число точек по оси Y
Define t
Define j=0
For t = 0 To ArraySize(GraphValues())
; 	GraphValues(t) =Pow(t , 2)
; 	GraphValues(t) =60 * Cos(Radian(j-90))
	GraphValues(t) =60 * Sin(Radian(j-90))
	j+5
Next t

; создать изображение для получения вывода
tImg = CreateImage(#PB_Any, W, H, 32, $1B1B1B) ; цвет фона тут
; нарисовать график на созданном изображении
DrawSimpleGraph(tImg, GraphValues(), GraphGeodata(), 0, 10, 10, 12)

; рисуем ещё поверх
j=0
For t = 0 To ArraySize(GraphValues())
; 	GraphValues(t) =Pow(t , 2)
	GraphValues(t) =60 * Cos(Radian(j-90))
; 	GraphValues(t) =60 * Sin(Radian(j-90))
	j+5
Next t
DrawSimpleGraph(tImg, GraphValues(), GraphGeodata(), 0, 10, 10, 12, $80A800)

; рисуем ещё поверх
j=0
For t = 0 To ArraySize(GraphValues())
; 	GraphValues(t) =Pow(t , 2)
; 	GraphValues(t) =60 * Cos(Radian(j-90))
	GraphValues(t) = - 60 * Sin(Radian(j-90))
	j+5
Next t
DrawSimpleGraph(tImg, GraphValues(), GraphGeodata(), 0, 10, 10, 12, $9900FF)

; рисуем ещё поверх
; For t = 0 To ArraySize(GraphValues())
	; 	GraphValues(t) = t * 0.8 - 60 ; линия наклонная
; 	GraphValues(t) = 60*Exp(- t / 24) ; экпонента
; 	GraphValues(t) =60 * Abs(Sin(Radian(j-90)))
; Next t
; DrawSimpleGraph(tImg, GraphValues(), GraphGeodata(), 0, 10, 10, 12, $80A800)

; показать
tWindow = OpenWindow(#PB_Any, 0, 0, W, H, "График", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
tCanvas = CanvasGadget(#PB_Any, 0, 0, W, H)
SetGadgetAttribute(tCanvas, #PB_Canvas_Image, ImageID(tImg))
; привязать события, необходимые для взаимодействия с мышью
; BindEvent(#PB_Event_Gadget, @GraphCB(), tWindow, tCanvas, #PB_All)

; освободить изображение
FreeImage(tImg)

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow

Отредактировано AZJIO (28.08.2020 08:41:16)

0

5

разделил функции создания сетки и графика. Теперь можно создавать несколько графиков. Оптимизировать ещё есть куда. В AutoIt3 функция не имела привязки к точкам, если это прямая то можно получить начало и конец и нарисовать прямую, без деление участка на отрезки для каждой координаты.

Код:
EnableExplicit


Global.d cX0, cY0
Global.d mX, mY
Global highValue, maxItems

;{ Simple Graph }

; Еще одна штука для простых "визуальных эффектов"
;   2017         (c) Luna Sole
;    v1.0.0.4       (+ взаимодействие с мышью)         

; Рисует график с двумя линиями на заданном изображении с использованием векторной библиотеки PB
; hImgOut            Изображение PB для рисования может быть любого размера [кроме, возможно, «очень низкого» разрешения ^^]
; GraphData()         массив с элементами для визуализации, должен содержать как минимум 1 элемент [начиная с 0]
; GridStepX            Шаг сетки X [вертикальные линии], измеренное в количестве GraphData (). используйте 0 для отключения
; GridStepY            Шаг сетки Y [горизонтальные линии], измеренное в значениях GraphData (). 0 для отключения
; FontSize            размер шрифта текстовых меток. используйте 0, чтобы отключить метки
; ColorGrid            цвета для элементов графика (RGB)
; RETURN:            нет, изображение изменено в случае успеха
Procedure DrawGrid(hImgOut, Array GraphData.d(1), GridStepX = 10, GridStepY = 10, FontSize = 9, ColorGrid = $BBFFFFFF)	
	maxItems = ArraySize(GraphData())   ; количество пунктов (X)
	Protected maxValues        	; количество значений (Y)
	Protected lowValue        	; самые высокие и самые низкие значения GraphData
	Protected t            	; общая временная переменная
	If maxItems < 0 : ProcedureReturn :   EndIf	  ; выйти, если массив GraphData недействителен
	
	; минимум и максимум значений оси Х
	lowValue = -60
	highValue = 60
	
	; сделать вещи, чтобы лучше подогнать фоновую сетку
	If GridStepY > 0
    If highValue >= 0
    	highValue + GridStepY - highValue % GridStepY
    ElseIf highValue
    	highValue - highValue % GridStepY
    EndIf
    If lowValue > 0
    	lowValue  - lowValue  % GridStepY
    ElseIf lowValue < 0
    	lowValue  - (GridStepY + lowValue  % GridStepY)
    EndIf
	EndIf
	maxValues = highValue - lowValue
	If maxValues <= 0
    maxValues = 1
	EndIf
	
	; загрузить шрифт для текстовых меток
	Protected Font
	If FontSize > 0
    Font = LoadFont(#PB_Any, "arial", FontSize)
    If Not IsFont(Font) ; и так далее
    	Font = LoadFont(#PB_Any, "tahoma", FontSize)
    	If Not IsFont(Font) ; и так далее.. :)
        Font = LoadFont(#PB_Any, "consolas", FontSize)
    	EndIf
    EndIf
	EndIf
	
	; рисовать данные в изображение
	If StartVectorDrawing(ImageVectorOutput(hImgOut, #PB_Unit_Pixel))
    Protected.d oX = 1.0, oY = oX
    Protected.d mtW = 1.0, mtH = mtW
    ;   временные переменные, используемые при рисовании
    Protected.d cX, cY
    Protected.d tLast
    ; [n] - определить смещения графиков / размеры текстовых меток и т. д.
    If IsFont(Font)
    	VectorFont(FontID(Font), FontSize)
    	If VectorTextWidth(Str(highValue)) > VectorTextWidth(Str(lowValue)) ; задаём ширину текста
        oX = VectorTextWidth(Str(highValue)) + 2.0
    	Else
        oX = VectorTextWidth(Str(lowValue)) + 2.0
    	EndIf
    	oY = VectorTextHeight("0A") + 2.0
    	If oX > oY
        oY = oX
    	Else
        oX = oY
    	EndIf
    	mtW = VectorTextWidth(Str(maxItems)) * 1.2
    	mtH = VectorTextHeight(Str(highValue)) * 0.8
    EndIf
    ;    множители для масштабирования координат графика
    mX = (VectorOutputWidth() - oX * 2.0) / (maxItems + Bool(maxItems = 0))   
    mY = (VectorOutputHeight() - oY * 2.0) / maxValues
    
    ; [0] - рисовать текстовые метки и линии сетки
    VectorSourceColor(ColorGrid) ; цвет меток и сетки шкалы
                	 ;   горизонтальные линии / метки
    tLast = oY + maxValues * mY + 5.0
    If GridStepY > 0
    	For t = maxValues To 0 Step -1
        If t % GridStepY = 0 Or t = maxValues
        	cY = oY + t * mY
        	; нарисовать текстовую метку
        	If IsFont(Font) And cY < tLast
            MovePathCursor(oX - (2.0 + VectorTextWidth(Str(highValue - t))), cY - VectorTextHeight(Str(highValue - t)) / 2)
            DrawVectorText(Str(highValue - t))
            tLast = cY - mtH
        	EndIf
        	; нарисовать линию сетки
        	MovePathCursor(oX, oY + mY * t)            
        	AddPathLine(oX + maxItems * mX, oY + mY * t)
        EndIf
    	Next t
    EndIf
    ;   вертикальные линии / метки
    tLast = 0.0
    If GridStepX > 0   
    	;GridStepX + 1
    	For t = 0 To maxItems
        If t % GridStepX = 0 Or t = maxItems
        	cX = oX + t * mX
        	cY = oY + maxValues * mY
        	; нарисовать текстовую метку
        	If IsFont(Font) And cX > tLast
            MovePathCursor(cX - VectorTextWidth(Str(t)) / 2, cY + 2.0)
            DrawVectorText(Str(t))
            tLast = cX + mtW
        	EndIf
        	; нарисовать линию сетки
        	MovePathCursor(cX, oY)
        	AddPathLine(cX, cY)
        EndIf
    	Next t
    EndIf
    ;   fin
    If GridStepX > 0 Or GridStepY > 0
    	DashPath(1.0, 3.0)
    EndIf
    cX0 = oX
    cY0 = oY
    
    ; 	StrokePath(LineWidth)
    
    ; очистить
    StopVectorDrawing()
	EndIf
	
	; очистить
	If IsFont(Font)
    FreeFont(Font)
	EndIf
EndProcedure

; Color            цвет линии графика (RGB)
; LineWidth     ширина линии (в пикселях)
; Plot_Dot      показывать ли точки на графике
Procedure DrawGraph(hImgOut, Array GraphData.d(1), Color = $00DDDD, LineWidth.d = 1, Plot_Dot = 0)
	Protected t ; общая временная переменная
 ;   временные переменные, используемые при рисовании
	Protected.d cX, cY
	If StartVectorDrawing(ImageVectorOutput(hImgOut, #PB_Unit_Pixel))
    ; [1] - нарисуйте основную линию / элементы и сформируйте "геоданные"
    VectorSourceColor(Color | $FF000000) ; цвет линии (с добавлением альфа-канала)
    MovePathCursor(cX0, cY0 + mY * (highValue - GraphData(0)))
    For t = 0 To maxItems
    	cX = cX0 + mX * t
    	cY = cY0 + mY * (highValue - GraphData(t))
    	AddPathLine(cX, cY)         ; добавить линию
    	If Plot_Dot
        AddPathCircle(cX, cY, 2.0)	; добавить точку
    	EndIf
    	MovePathCursor(cX, cY)    ; восстановить позицию курсора
    Next
    ; 	DotPath(4, 10, #PB_Path_RoundEnd)
    StrokePath(LineWidth)
    
    ; очистить
    StopVectorDrawing()
	EndIf
EndProcedure
;}


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Тест / пример
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


; используется для обработки кликов мыши по графику
; mapkey - координата X изображения графика, value - соответствующий индекс в массиве GraphData()
Global NewMap GraphGeodata()

; Размеры графика
Global W = 800, H = 600
; Изображение для рисования графика
Global tImg
; Окно и холст для отображения графика
Global tWindow, tCanvas

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; сгенерировать графические данные
Global.d Dim GraphValues (127) ; размер массива определяет число точек по оси Y

; создать изображение для получения вывода
tImg = CreateImage(#PB_Any, W, H, 32, $1B1B1B) ; цвет фона тут
DrawGrid(tImg, GraphValues(), 10, 10, 12)
; нарисовать график на созданном изображении


Define t

; рисуем синусоиду (выпрямленный ток)
Define j=45
For t = 0 To ArraySize(GraphValues())
	GraphValues(t) =60 * Abs(Sin(Radian(j-90)))
	j+5
Next t
DrawGraph(tImg, GraphValues(), $00B1CB, 1, 1)

; рисуем поверх косинусоиду
j=0
For t = 0 To ArraySize(GraphValues())
	GraphValues(t) =60 * Cos(Radian(j-90))
	j+5
Next t
DrawGraph(tImg, GraphValues(), $80A800, 1)

; рисуем поверх синусоиду
j=0
For t = 0 To ArraySize(GraphValues())
	GraphValues(t) = - 60 * Sin(Radian(j-90))
	j+5
Next t
DrawGraph(tImg, GraphValues(), $9900FF, 1) ; $00A800

; рисуем экпоненту
For t = 0 To ArraySize(GraphValues())
	; 	GraphValues(t) = t * 0.8 - 60 ; линия наклонная
	GraphValues(t) = 60*Exp(- t / 24) ; экпонента
Next t
DrawGraph(tImg, GraphValues(), $2A04FF, 1)

; рисуем труеугольную
For t = 0 To ArraySize(GraphValues())
	GraphValues(t) = 20 * (t/10 - 2 * Round((t/10 + 1) / 2, #PB_Round_Down)) * Pow(-1, Round((t/10 + 1) / 2, #PB_Round_Down)) - 40 ; Треугольный
Next t
DrawGraph(tImg, GraphValues(), $FF8C00, 1)

; показать окно с графиком
tWindow = OpenWindow(#PB_Any, 0, 0, W, H, "График", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
tCanvas = CanvasGadget(#PB_Any, 0, 0, W, H)
SetGadgetAttribute(tCanvas, #PB_Canvas_Image, ImageID(tImg))

; освободить изображение
FreeImage(tImg)

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow

0

6

Продолжение улучшения.
Здесь линию можно задать началом и концом графика, то есть не перебирать в цикле для каждого значения. Аналогично создавая любой график, например синусоиду или экспоненту можно сделать с шагом Step 10 или другим, в зависимости от числа точек на волну, то есть снизить разрешение (при 40 точек на волну достаточно плавно) и даже сделать в виде ломаной кривой.

https://c.radikal.ru/c08/2008/79/3961e14e4f14t.jpg

Код:
EnableExplicit


Global.d cX0, cY0
Global.d mX, mY
Global xMax2, yMax2

;{ Simple Graph }

; Еще одна штука для простых "визуальных эффектов"
;   2017         (c) Luna Sole
;    v1.0.0.4       (+ взаимодействие с мышью)         

; Рисует график с двумя линиями на заданном изображении с использованием векторной библиотеки PB
; hImgOut            Изображение PB для рисования может быть любого размера [кроме, возможно, «очень низкого» разрешения ^^]
; xMax, xMin                  максимальная и максимальная величина X графика
; yMax                  максимальная величина Y графика
; GridStepX            Шаг сетки X [вертикальные линии], измеренное в количестве GraphData (). используйте 0 для отключения
; GridStepY            Шаг сетки Y [горизонтальные линии], измеренное в значениях GraphData (). 0 для отключения
; FontSize            размер шрифта текстовых меток. используйте 0, чтобы отключить метки
; ColorGrid            цвета для элементов графика (RGB)
; RETURN:            нет, изображение изменено в случае успеха
Procedure DrawGrid(hImgOut, xMax, xMin, yMax, GridStepX = 10, GridStepY = 10, FontSize = 9, ColorGrid = $BBFFFFFF)
	Protected maxValues ; разница между xMax - xMin
	Protected t ; переменная цикла для перечисления во времени, по оси Y
	If yMax < 1
    ProcedureReturn	; выйти, если данные из одной точки, график должен быть из нескольких точек по оси Y
	EndIf
	yMax2 = yMax   ; задаём внешний, чтобы перечислять в цикле
	
	; сделать вещи, чтобы лучше подогнать фоновую сетку
	If GridStepY > 0
    If xMax >= 0
    	xMax + GridStepY - xMax % GridStepY
    ElseIf xMax
    	xMax - xMax % GridStepY
    EndIf
    If xMin > 0
    	xMin  - xMin  % GridStepY
    ElseIf xMin < 0
    	xMin  - (GridStepY + xMin  % GridStepY)
    EndIf
	EndIf
	maxValues = xMax - xMin
	If maxValues <= 0
    maxValues = 1
	EndIf
	
	; минимум значений оси Х
	xMax2 = xMax
	
	; загрузить шрифт для текстовых меток
	Protected Font
	If FontSize > 0
    Font = LoadFont(#PB_Any, "arial", FontSize)
    If Not IsFont(Font) ; и так далее
    	Font = LoadFont(#PB_Any, "tahoma", FontSize)
    	If Not IsFont(Font) ; и так далее.. :)
        Font = LoadFont(#PB_Any, "consolas", FontSize)
    	EndIf
    EndIf
	EndIf
	
	; рисовать данные в изображение
	If StartVectorDrawing(ImageVectorOutput(hImgOut, #PB_Unit_Pixel))
    Protected.d oX = 1.0, oY = oX
    Protected.d mtW = 1.0, mtH = mtW
    ;   временные переменные, используемые при рисовании
    Protected.d cX, cY
    Protected.d tLast
    ; [n] - определить смещения графиков / размеры текстовых меток и т. д.
    If IsFont(Font)
    	VectorFont(FontID(Font), FontSize)
    	If VectorTextWidth(Str(xMax)) > VectorTextWidth(Str(xMin)) ; задаём ширину текста
        oX = VectorTextWidth(Str(xMax)) + 2.0
    	Else
        oX = VectorTextWidth(Str(xMin)) + 2.0
    	EndIf
    	oY = VectorTextHeight("0A") + 2.0
    	If oX > oY
        oY = oX
    	Else
        oX = oY
    	EndIf
    	mtW = VectorTextWidth(Str(yMax)) * 1.2
    	mtH = VectorTextHeight(Str(xMax)) * 0.8
    EndIf
    ;    множители для масштабирования координат графика
    mX = (VectorOutputWidth() - oX * 2.0) / (yMax + Bool(yMax = 0))   
    mY = (VectorOutputHeight() - oY * 2.0) / maxValues
    
    ; [0] - рисовать текстовые метки и линии сетки
    VectorSourceColor(ColorGrid) ; цвет меток и сетки шкалы
                	 ;   горизонтальные линии / метки
    tLast = oY + maxValues * mY + 5.0
    If GridStepY > 0
    	For t = maxValues To 0 Step -1
        If t % GridStepY = 0 Or t = maxValues
        	cY = oY + t * mY
        	; нарисовать текстовую метку
        	If IsFont(Font) And cY < tLast
            MovePathCursor(oX - (2.0 + VectorTextWidth(Str(xMax - t))), cY - VectorTextHeight(Str(xMax - t)) / 2)
            DrawVectorText(Str(xMax - t))
            tLast = cY - mtH
        	EndIf
        	; нарисовать линию сетки
        	MovePathCursor(oX, oY + mY * t)            
        	AddPathLine(oX + yMax * mX, oY + mY * t)
        EndIf
    	Next
    EndIf
    ;   вертикальные линии / метки
    tLast = 0.0
    If GridStepX > 0   
    	;GridStepX + 1
    	For t = 0 To yMax
        If t % GridStepX = 0 Or t = yMax
        	cX = oX + t * mX
        	cY = oY + maxValues * mY
        	; нарисовать текстовую метку
        	If IsFont(Font) And cX > tLast
            MovePathCursor(cX - VectorTextWidth(Str(t)) / 2, cY + 2.0)
            DrawVectorText(Str(t))
            tLast = cX + mtW
        	EndIf
        	; нарисовать линию сетки
        	MovePathCursor(cX, oY)
        	AddPathLine(cX, cY)
        EndIf
    	Next
    EndIf
    ;   fin
    If GridStepX > 0 Or GridStepY > 0
    	DashPath(1.0, 3.0)
    EndIf
    cX0 = oX
    cY0 = oY
    
    ; 	StrokePath(LineWidth)
    
    ; очистить
    StopVectorDrawing()
	EndIf
	
	; очистить
	If IsFont(Font)
    FreeFont(Font)
	EndIf
EndProcedure

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Тест / пример
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


; используется для обработки кликов мыши по графику
; mapkey - координата X изображения графика, value - соответствующий индекс в массиве GraphData()
Global NewMap GraphGeodata()

; Размеры графика
Global W = 800, H = 600
; Изображение для рисования графика
Global tImg
; Окно и холст для отображения графика
Global tWindow, tCanvas

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; сгенерировать графические данные
; 127 определяет число точек по оси Y

; создать изображение для получения вывода
tImg = CreateImage(#PB_Any, W, H, 32, $1B1B1B) ; цвет фона тут
DrawGrid(tImg, 60, -60, 127, 10, 10, 12)
; нарисовать график на созданном изображении
; Debug mX ; = 5.9
; Debug mY ; = 4
; Debug cX0 ; = 19.34375
; Debug cY0 ; = 19.34375


Define.d tmp, LineWidth = 1
Define t, j
Global Plot_Dot.b = 0
; Color            цвет линии графика (RGB)
; LineWidth     ширина линии (в пикселях)
; Plot_Dot      показывать ли точки на графике

Procedure DrawGraph(tmp.d, t)
	;   временные переменные, используемые при рисовании
	Protected.d cX, cY
	cX = cX0 + mX * t
	cY = cY0 + mY * (xMax2 - tmp)
	If t = 0
    MovePathCursor(cX0, cY)
	EndIf
	AddPathLine(cX, cY)         ; добавить линию
	If Plot_Dot
    AddPathCircle(cX, cY, 2.0)	; добавить точку
	EndIf
	MovePathCursor(cX, cY)    ; восстановить позицию курсора
EndProcedure


If StartVectorDrawing(ImageVectorOutput(tImg, #PB_Unit_Pixel)) ; открываем рисование
	
	; рисуем синусоиду (выпрямленный ток) жёлтая
	VectorSourceColor($FF00B1CB) ; задаём цвет линии (с добавлением альфа-канала слева ARGB)
	j = 45
	For t = 0 To yMax2
    tmp = 60 * Abs(Sin(Radian(j-90)))
    j+5
    DrawGraph(tmp, t)
	Next
	StrokePath(LineWidth) ; рисует график в заданном цвете
	
	
	; рисуем поверх косинусоиду
	VectorSourceColor($FF80A800)
	j = 0
	For t = 0 To yMax2
    tmp = 60 * Cos(Radian(j-90))
    j+5
    DrawGraph(tmp, t)
	Next
	StrokePath(LineWidth)
	
	; рисуем поверх синусоиду
	VectorSourceColor($FF9900FF) ; $00A800
	j=0
	For t = 0 To yMax2
    tmp = - 60 * Sin(Radian(j-90))
    j+5
    DrawGraph(tmp, t)
	Next
	StrokePath(LineWidth)
	
; 	Plot_Dot = 1
	; рисуем экпоненту
	VectorSourceColor($FF2A04FF)
	For t = 0 To yMax2 ; Step 6
    ; 	tmp = t * 0.8 - 60 ; линия наклонная
    tmp = 60 * Exp(- t / 24) ; экпонента
    DrawGraph(tmp, t)
	Next
	StrokePath(LineWidth)

	; рисуем линию
	VectorSourceColor($FF00A800)
	DrawGraph(- 60, 0) ; начало
	DrawGraph(127 * 0.8 - 60, 127) ; и конец линии
; 	For t = 0 To yMax2 Step 127
;     tmp = t * 0.8 - 60 ; линия наклонная
;     DrawGraph(tmp, t)
; 	Next
	StrokePath(LineWidth)
	
	; рисуем треугольную
	VectorSourceColor($FFFF8C00)
	For t = 0 To yMax2
    tmp = 20 * (t/10 - 2 * Round((t/10 + 1) / 2, #PB_Round_Down)) * Pow(-1, Round((t/10 + 1) / 2, #PB_Round_Down)) - 40 ; Треугольный
    DrawGraph(tmp, t)
	Next
	StrokePath(LineWidth)
	
	
	StopVectorDrawing()
EndIf


; показать окно с графиком
tWindow = OpenWindow(#PB_Any, 0, 0, W, H, "График", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
tCanvas = CanvasGadget(#PB_Any, 0, 0, W, H)
SetGadgetAttribute(tCanvas, #PB_Canvas_Image, ImageID(tImg))

; освободить изображение
FreeImage(tImg)

Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow

Отредактировано AZJIO (28.08.2020 22:36:09)

0


Вы здесь » PureBasic - форум » Вопросы по PureBasic » Существует ли модуль создания графиков?