@elektryk, да. Если Вам нужно только на один месяц и Вы не будете отображение на весь год делать, то можно упростить: PHP: $array = file('plusXY.txt'); $max_y = 0; $mg = '/' . date('mY') . '$/'; $debet = []; foreach ( $array as $stroka ) { $parts = explode(' ', $stroka); if (preg_match($mg, $parts[0])) { $debet[] = [ (int) substr( $parts[0], 0, 2 ), (int) $parts[1] ]; if($parts[1] > $max_y) { $max_y = (int) $parts[1]; } } } usort( $debet, function( $a, $b ) { return $a[0] - $b[0]; } ); echo $max_y ; В первоначальном варианте я предложил использовать объект DateTime в качестве значения даты. Он легко переводится в любой формат, но для отображения на месяц достаточно просто числа.
@elektryk, он через классы сделан: test.php PHP: <?php require_once ('grafik.class.php'); $img = new Grafik(2017, 7); $img->add_data('plusXY.txt', 'blue'); $img->add_data('minusXY.txt', 'cyan'); $img->display(1300, 400); grafik.class.php PHP: <?php require_once (__DIR__ . '/datagram.class.php'); require_once (__DIR__ . '/imgpng.class.php'); class Grafik { private $img; private $datagrams = []; private $offset = [ 'x' => 48, 'y' => 32, 'top' => 5, 'right' => 20 ]; private $step = [ 'x' => 1, 'y' => 1 ]; private $y_arr = [500, 1000, 2000, 5000, 10000, 15000, 20000, 25000, 50000, 75000, 100000, 150000, 200000, 250000, 300000, 400000, 500000, 600000, 700000, 800000, 900000, 1000000, 1500000]; private $start = [ 'x' => 1, 'y' => 0 ]; private $year = 0; private $month = 0; private $datastring = ''; private $max_x = 370; private $max_y = 10000; public function __construct($year, $month = 0) { if ($year > 0) { $this->year = (int) $year; } if ($month > 0 && $month < 13) { $this->month = (int) $month; $this->max_x = cal_days_in_month(CAL_GREGORIAN, $this->month, $this->year); $this->datastring = date("F Y", mktime(0, 0, 0, $this->month, 1, $this->year)); } else { $this->datastring = date("Y", mktime(0, 0, 0, 1, 1, $this->year)); } } public function add_data($filename, $color = 'black') { $a = new Datagram($filename, $this->year, $this->month); if ($this->max_y < $a->maxY()) { $this->max_y = $a->maxY(); } $this->datagrams[] = [$a, $color]; } public function display($width = 800, $height = 600) { $this->img = new ImgPNG($width, $height); $this->step['x'] = ($this->img->getSize('w') - $this->offset['x'] - $this->offset['right']) / ($this->max_x - $this->start['x']); $this->step['y'] = ($this->img->getSize('h') - $this->offset['y'] - $this->offset['top']) / ($this->max_y * 1.02 - $this->start['y']); $this->draw_grid(); foreach ($this->datagrams as $n => $d) { $this->draw_datagram($d[0]->getData(), $d[1], $n); } $this->draw_axes(); $this->img->display(); } private function draw_axes() { $this->img->setWidth(2); // ось X $this->img->add_line($this->offset['x'], $this->getY(0), $this->getX($this->max_x - 1), $this->getY(0), 'black'); // ось Y $this->img->add_line($this->offset['x'], $this->getY(0), $this->offset['x'], $this->offset['top'], 'black'); $this->img->setWidth(1); } private function draw_grid() { $xn = 0; for ($i = 0; $i < $this->max_x; $i++) { $x = $this->getX($i); $interval = ($this->month > 0)? 16: 32; if (($x - $xn) > $interval) { $this->img->add_line($x, $this->getY(0), $x, $this->offset['top']); if($this->month > 0) { $str = $i + 1; } else { $str = date_format(date_create_from_format( 'z Y', $i . ' ' . $this->year), 'j/m'); } $this->img->add_string($str, $x - 5, $this->getY(0) + 5, 'black'); $xn = $x; } } $this->img->add_string($this->datastring, $this->getX($this->max_x / 2) - 30, $this->getY(0) + 20, 'black'); $yn = $this->getY(0); foreach ($this->y_arr as $y) { if ($y <= $this->max_y) { $y1 = $this->getY($y); if (($yn - $y1) > 10) { $this->img->add_line($this->offset['x'], $y1, $this->getX($this->max_x - 1), $y1); $this->img->add_string($y, 5, $y1 - 5, 'black'); $yn = $y1; } } } } private function draw_datagram($arr, $color, $k = 0) { $t = 2; $this->img->setWidth($t); $s = [$this->start['x']-1, $this->start['y']]; foreach ($arr as $point) { $x = date_format($point[0], ($this->month > 0)? 'j': 'z') - 1; if($this->month == 0){$x++;} $this->img->add_line($this->getX($s[0]), $this->getY($s[1]), $this->getX($x), $this->getY($point[1]), $color); $s[0] = $x; $s[1] = $point[1]; } $this->img->setWidth(1); } private function getX($x) { return $this->offset['x'] + $x * $this->step['x']; } private function getY($y) { $h = $this->img->getSize('h'); return $h - $this->offset['y'] - $y * $this->step['y']; } } datagram.class.php PHP: <?php class Datagram { private $data = []; private $max_y = 0; public function __construct ($file_name, $year, $month = 0) { if (file_exists($file_name) && $year > 0) { $pattern = '/'; if ($month > 0 && $month < 13) { $pattern .= str_pad((int) $month, 2, "0", STR_PAD_LEFT); } $pattern .= str_pad((int) $year, 4, "0", STR_PAD_LEFT) . '$/'; $this->read( $file_name, $pattern ); $this->data_sort(); } } public function maxY() { return $this->max_y; } public function getData() { return $this->data; } public function getSum() { return array_sum(array_column($this->data, 1)); } private function read($file_name, $pattern) { $f = fopen( $file_name, 'r' ); while( $line = fgets( $f ) ) { $parts = explode(' ', $line); if (preg_match($pattern, $parts[0])) { $this->data[] = [ date_create_from_format( 'dmY', $parts[0] ), (int) $parts[1] ]; if($parts[1] > $this->max_y) { $this->max_y = (int) $parts[1]; } } } } private function data_sort() { usort( $this->data, function( $a, $b ) { return date_format($a[0], 'Ymd') - date_format($b[0], 'Ymd'); } ); } } imgpng.class.php PHP: <?php class ImgPNG { private $image_resourse; private $size = ['w' => 800, 'h' => 600]; private $colors = []; public function __construct($width, $height) { if ($width > 300 && $height > 200) { $this->size['w'] = (int) $width; $this->size['h'] = (int) $height; } $this->image_resourse = imagecreatetruecolor($this->size['w'], $this->size['h']); $this->create_colors(); imagefill ($this->image_resourse, 1, 1, $this->colors['white']); } public function setWidth($w) { if ($w >= 1) { imagesetthickness ( $this->image_resourse, (int)$w ); } } public function getSize($key = 'w') { if (isset($this->size[$key])) { return $this->size[$key]; } else { return 0; } } public function add_line($x1, $y1, $x2, $y2, $color = 'l_grey') { if (!isset($this->colors[$color])) { $color = 'magenta'; } imageline($this->image_resourse, (int)$x1, (int)$y1, (int)$x2, (int)$y2, $this->colors[$color]); } public function add_string($string, $x, $y, $color = 'l_grey') { if (!isset($this->colors[$color])) { $color = 'magenta'; } imagestring($this->image_resourse, 1, (int)$x, (int)$y, $string, $this->colors[$color]); } public function display() { header('Content-type: image/png'); imagepng($this->image_resourse, NULL, 0); } private function create_colors() { $this->colors['white'] = ImageColorAllocate ($this->image_resourse, 255, 255, 255); $this->colors['black'] = ImageColorAllocate ($this->image_resourse, 0, 0, 0); $this->colors['red'] = ImageColorAllocate ($this->image_resourse, 220, 60, 60); $this->colors['pink'] = ImageColorAllocate ($this->image_resourse, 220, 120, 80); $this->colors['green'] = ImageColorAllocate ($this->image_resourse, 50, 120, 0); $this->colors['blue'] = ImageColorAllocate ($this->image_resourse, 0, 50, 200); $this->colors['yellow'] = ImageColorAllocate ($this->image_resourse, 255, 220, 0); $this->colors['magenta'] = ImageColorAllocate ($this->image_resourse, 160, 0, 200); $this->colors['cyan'] = ImageColorAllocate ($this->image_resourse, 0, 180, 220); $this->colors['l_grey'] = ImageColorAllocate ($this->image_resourse, 220, 220, 220); $this->colors['d_grey'] = ImageColorAllocate ($this->image_resourse, 50, 50, 50); } } Для вывода на год в файле test.php достаточно убрать месяц.
@elektryk, в цветах поправьте grey на gray и imagecolorallocate строчными. Я этот код скопировал у Вас, но забыл поправить.
почему так получается?: Код (Text): //Определяем размер экрана $width='<script>var ScreenWidth = screen.width; document.write(ScreenWidth);</script>'; $height='<script>var ScreenHeight = screen.height;document.write(ScreenHeight);</script>'; echo''.$width.' x '.$height.'' , "<br>"; $w = (int) $width; $h = (int) $height; на выходе: 1600 x 900 0 0
@elektryk, Вы пытаетесь из строки получить число. 5 и 6 строчки не дадут Вам размер экрана. Это надо на стороне клиента javascript-ом определять размеры и передавать их на сервер. А почему именно размер экрана, а не размер окна браузера или размер блока, в котором будет картинка?
Вставляете в html-код страницы: HTML: <script>document.write('<img src="' + window.location.protocol + "//" + window.location.host + "/graf.php?wh=" + screen.width + 'x' + screen.height + '">');</script> Создаете файл graf.php, в котором такое содержимое: PHP: <?php require_once ('grafik.class.php'); // путь к файлу можно и другой $w = 800; $h = 400; $match = []; $god = date('Y'); $mesyac = date('n'); if (isset($_GET['wh']) && preg_match('/(\d{3,4})x(\d{3,4})/', $_GET['wh'], $match)) { $w = $match[1]; $h = $match[2]; } $img = new Grafik($god, $mesyac); $img->add_data('plusXY.txt', 'blue'); $img->add_data('minusXY.txt', 'cyan'); $img->display($w, $h);
с таким кодом: PHP: <?php $w = 800; $h = 400; //ищем количество дней в текущем месяце, попутно выясняя какой сейчас год и месяц $god = date('Y'); //значение текущего года $mesac = date('n'); //значение текущего месяца $number = cal_days_in_month(CAL_GREGORIAN, $mesac, $god); // вычисление дней //Определяем размер экрана if (isset($_GET['wh']) && preg_match('/(\d{3,4})x(\d{3,4})/', $_GET['wh'], $match)) { $w = $match[1]; $h = $match[2]; } require_once ('grafik.class.php'); $img = new Grafik('$god', '$mesac'); $img->add_data('plusXY.txt', 'green'); $img->add_data('minusXY.txt', 'red'); $img->display($w, $h); ?> получилось следующее: цифры поехали, и точек нет( и размер графика маловат(((
@elektryk, А зачем Вы год и месяц взяли в кавычки? Размер берется по-умолчанию 800 на 400 как написано в верху, если GET - параметров в нужном виде не передается. надо к скрипту обращаться с GET параметром wh: graf.php?wh=1600x900 Это реализовано в html с помощью javascript. P.S.: В файле graf.php закрывающий '?>' не только необязательный, а даже вредительский.
график встроен в как iframe в таблицу главного файла index.php Код (Text): <!DOCTYPE html PUBLIC "-//IETF//DTD HTML 2.0//EN" header('Content-Type: text/html; charset= utf-8');> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>График расходов и приходов</title> <style> .knopa { text-align: center; vertical-align: middle; height: 100%; width: 100%; color: black; font-size: 14pt; background: grey; border-radius: 5px;} </style> <style> .td { text-align: center; vertical-align: middle; width: 25%; height: 6%;} </style> <style> .vvod { text-align: center; vertical-align: middle; height: 100%; width: 100%; color: black; font-size: 14pt; background: white; border-radius: 5px;} </style> </head> <body> <form method="post" action="reg.php" id="myform"> <table height="99%" width="99%" align="center" valign="middle" border="0"> <tr> <td class="td"> <input type="submit" name="plus" value="Приход" form="myform" class="knopa"/> </td> <td class="td"> <input type="text" name="mani" size="22" placeholder="пример: 1000" form="myform" class="vvod"/> </td> <td class="td"> <input type="submit" name="minus" value="Расход" form="myform" class="knopa"/> </td> <td class="td"> <?php $fh = fopen('out.txt', 'r'); $varik = fgets($fh); fclose($fh); echo "Итог: $varik"; ?> </td> </tr> <tr> <td colspan="4" align="center" valign="middle"> <iframe width="100%" height="100%" src="graf.php" scrolling="no"> </td> </tr> </table> </form> </body> </html>
@elektryk, значит Вам нужно определять не размеры экрана, а размеры iframe. И src для iframe определяете так же как я выше писал для img. Или в src передаете не graf.php а html-документ со скриптом, что я писал выше. Можно так (файл html, который передается в iframe): HTML: <body style="margin:0;"> <script>document.write('<img src="' + window.location.protocol + "//" + window.location.host + "/graf.php?wh=" + document.body.clientWidth + 'x' + document.body.clientHeight + '">');</script> </body> Результат покажете?
ураааа!!!!! супер!!! можно ещё вопрос, как по вертикальной оси выставить только те значения, которые есть, а не шаблонные, как grafik.class.php в строке private $y_arr ?
Можно немного изменить метод для рисования сетки: PHP: private function draw_grid() { $xn = 0; for ($i = 0; $i < $this->max_x; $i++) { $x = $this->getX($i); $interval = ($this->month > 0)? 16: 32; if (($x - $xn) > $interval) { $this->img->add_line($x, $this->getY(0), $x, $this->offset['top']); if($this->month > 0) { $str = $i + 1; } else { $str = date_format(date_create_from_format( 'z Y', $i . ' ' . $this->year), 'j/m'); } $this->img->add_string($str, $x - 5, $this->getY(0) + 5, 'black'); $xn = $x; } } $this->img->add_string($this->datastring, $this->getX($this->max_x / 2) - 30, $this->getY(0) + 20, 'black'); $yn = $this->getY(0); for ($y = 500; $y <= ($this->max_y * 1.01); $y += 500) { $y1 = $this->getY($y); if (($yn - $y1) > 10) { $this->img->add_line($this->offset['x'], $y1, $this->getX($this->max_x - 1), $y1); $this->img->add_string($y, 5, $y1 - 5, 'black'); $yn = $y1; } } } Минимальный шаг 500 руб с учетом, что расстояние между делениями сетки не менее 10 пикселей.
Кроме того, что это проще, нагляднее и удобнее, а так же не создает лишней нагрузки на сервер - никаких преимуществ нет.
Доброе утро. Спасибо за вопросы и помощь, а также за примеры. Конкретная задача данного графика - визуализация доходов - расходов в онлайн режиме. Сервером могут пользоваться разные люди, вносить изменения и сразу же видеть результат. Этот график уже проверен на многих устройствах, в том числе с Linux, MacOS, iOS, Android, Ubuntu Phone. Всё замечательно отображается и работает. О чём-то другом даже не мечтаю. Спасибо всем ещё раз и отдельное огромное спасибо @Maputo