| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- <?php
- class graph{
-
- public function render(array $graph = [], array $size = [], array $colors = [], array $colors_line = []){
-
- $graph = array_merge([
- "title" => "Title",
- "subtitle" => "description",
- "grad_x" => 25,
- "grad_y" => 20,
- "x_label" => "<= x =>",
- "y_label" => "<= y =>",
- "antialias" => false,
- "data" => []
- ], $graph);
-
- $size = array_merge([
- "image_width" => 750,
- "image_height" => 500,
- "x" => 90,
- "y" => 50,
- "width" => 650,
- "height" => 300,
- "square" => 11,
- "column" => 6
- ], $size);
-
- $colors = array_merge([
- "bg" => new ImagickPixel("#1d2021"),
- "lines_bg" => new ImagickPixel("#3c3836"),
- "outline" => new ImagickPixel("#a89984"),
- "text" => new ImagickPixel("#ebdbb2"),
- "transparent" => new ImagickPixel("transparent")
- ], $colors);
-
- $colors_line = array_merge([
- new ImagickPixel("#83a598"),
- new ImagickPixel("#fb4934"),
- new ImagickPixel("#b8bb26"),
- new ImagickPixel("#fabd2f"),
- new ImagickPixel("#d3869b"),
- new ImagickPixel("#8ec07c"),
- new ImagickPixel("#fe8019"),
- new ImagickPixel("#458588"),
- new ImagickPixel("#cc241d"),
- new ImagickPixel("#98971a"),
- new ImagickPixel("#d79921"),
- new ImagickPixel("#b16286"),
- new ImagickPixel("#689d6a"),
- new ImagickPixel("#d65d0e"),
- new ImagickPixel("#a89984") // other
- ], $colors_line);
-
- $not_enough_data = false;
-
- // compute datapoint max ranges
- $max_range_x = 0;
- $max_range_y = 0;
- if(count($graph["data"]) === 0){
-
- $not_enough_data = true;
- }else{
-
- foreach($graph["data"] as $datapoint => $value){
-
- if(count($value) < 2){
-
- $not_enough_data = true;
- }else{
-
- $nv1 = [];
- $nv2 = [];
- foreach($value as $k => $v){
-
- $nv1[] = $v[0];
- $nv2[] = $v[1];
- }
-
- $max1 = max($nv1);
- $max2 = max($nv2);
- if($max_range_x < $max1){ $max_range_x = $max1; }
- if($max_range_y < $max2){ $max_range_y = $max2; }
- }
- }
- }
- $im = new Imagick();
- $im->newImage($size["image_width"], $size["image_height"], $colors["bg"]);
- $im->setImageFormat("png");
- $draw = new ImagickDraw();
- //
- // Draw background grid
- //
- $draw->setStrokeColor($colors["lines_bg"]);
- $draw->setStrokeAntialias($graph["antialias"]);
- $draw->setStrokeWidth(1);
- $draw->setFillColor($colors["transparent"]);
- $text = new ImagickDraw();
- $text->setFontSize(11);
- $text->setTextAntialias($graph["antialias"]);
- $text->setFillColor($colors["text"]);
- // vertical lines
- $offset = $size["width"] / ($graph["grad_x"] - 1);
- for($i=0; $i<$graph["grad_x"]; $i++){
-
- $x = round($size["x"] + ($offset * $i));
-
- if(
- $i === 0 ||
- $i === $graph["grad_x"] - 1
- ){
-
- $draw->setStrokeColor($colors["outline"]);
- }else{
-
- $draw->setStrokeColor($colors["lines_bg"]);
- }
-
- $draw->line(
- $x,
- $size["y"],
- $x,
- $size["y"] + $size["height"],
- );
-
- if($not_enough_data === false){
- // add numbas
- $number = number_format(round(($graph["grad_x"] - 1 - $i) * ($max_range_x / ($graph["grad_x"] - 1))));
- $number_width = $im->queryFontMetrics($text, $number)["textWidth"];
-
- $im->annotateImage(
- $text,
- round($x - ($number_width / 2)),
- $size["y"] + $size["height"] + 14,
- 0,
- $number
- );
- }
- }
- // horizontal lines
- $text->setTextAlignment(Imagick::ALIGN_RIGHT);
- $offset = $size["height"] / ($graph["grad_y"] - 1);
- $vertical_text_size = 0;
- for($i=0; $i<$graph["grad_y"]; $i++){
-
- $y = round($size["y"] + ($offset * $i));
-
- if(
- $i === 0 ||
- $i === $graph["grad_y"] - 1
- ){
-
- $draw->setStrokeColor($colors["outline"]);
- }else{
-
- $draw->setStrokeColor($colors["lines_bg"]);
- }
-
- $draw->line(
- $size["x"] + 1,
- $y,
- $size["x"] + $size["width"] - 1,
- $y,
- );
-
- if($not_enough_data === false){
- $val = number_format(round(($graph["grad_y"] - 1 - $i) * ($max_range_y / ($graph["grad_y"] - 1))));
- $query = $im->queryFontMetrics($text, $val);
-
- if($query["textWidth"] > $vertical_text_size){
-
- $vertical_text_size = $query["textWidth"];
- }
-
- // add numbas
- $im->annotateImage(
- $text,
- $size["x"] - 4,
- $y + 4,
- 0,
- $val
- );
- }
- }
- //
- // Draw legend
- //
- $text->setTextAlignment(Imagick::ALIGN_LEFT);
- $top_padding = 44;
- $c = count($colors_line);
- $padding = $size["width"] / $size["column"];
- $line = new ImagickDraw();
- //$line->setStrokeWidth(1);
- $line->setStrokeAntialias($graph["antialias"]);
- if($not_enough_data === false){
- $i = 0;
- foreach($graph["data"] as $datafield => $data){
-
- $used_color = $colors_line[$i % $c];
- $draw->setStrokeColor($used_color);
- $row = floor($i / $size["column"]);
-
- $x = round($size["x"] + (($i % $size["column"]) * $padding));
- $y = $size["y"] + $size["height"] + $top_padding + ($row * 17);
-
- // draw legend
- $draw->rectangle(
- $x,
- $y,
- $x + $size["square"],
- $y + $size["square"]
- );
-
- $im->annotateImage(
- $text,
- $x + $size["square"] + 4,
- $y + 10,
- 0,
- $datafield
- );
-
- //
- // Draw lines
- //
- $line->setStrokeColor($used_color);
- $old_x = null;
- $old_y = null;
- $continue = true;
-
- foreach($data as $field){
-
- // field 0 = hour (sorted)
- // field 1 = datapoint
-
- $x = $size["x"] + (($max_range_x - $field[0]) * ($size["width"] / $max_range_x));
- $y = $size["y"] + (($max_range_y - $field[1]) * ($size["height"] / $max_range_y));
-
- if($continue){
-
- $continue = false;
- $old_x = $x;
- $old_y = $y;
- continue;
- }
-
- $line->line($old_x, $old_y, $x, $y);
-
- $old_x = $x;
- $old_y = $y;
- }
-
- $i++;
- }
- }
- //
- // add background labels
- //
- $text->setFontSize(13);
- $text->setFillColor($colors["bg"]);
- $draw->setFillColor($colors["text"]);
- $draw->setStrokeColor($colors["transparent"]);
- // horizontal
- $label_width_x = $im->queryFontMetrics($text, $graph["x_label"]);
- $x_x = $size["x"] + ($size["width"] / 2) - ($label_width_x["textWidth"] / 2);
- $x_y = $size["y"] + $size["height"] + ($not_enough_data ? 21 : 30);
- $draw->rectangle(
- $x_x - 2,
- $x_y - $label_width_x["textHeight"] + 4,
- $x_x + $label_width_x["textWidth"] + 2,
- $x_y + 3,
- );
- // vertical
- $label_width_y = $im->queryFontMetrics($text, $graph["y_label"]);
- $y_x = $size["x"] - $label_width_y["textHeight"] - 13 - $vertical_text_size;
- $y_y = $size["y"] + ($size["height"] / 2) - ($label_width_y["textWidth"] / 2);
- $draw->rectangle(
- $y_x + 4,
- $y_y - 2,
- $y_x + $label_width_y["textHeight"] + 3,
- $y_y + $label_width_y["textWidth"] + 2,
- );
- $im->drawImage($draw);
- $im->drawImage($line);
- // horizontal text
- $im->annotateImage(
- $text,
- $x_x,
- $x_y,
- 0,
- $graph["x_label"]
- );
- // vertical text
- $im->annotateImage(
- $text,
- $y_x + $label_width_y["textHeight"],
- $y_y + $label_width_y["textWidth"],
- 270,
- $graph["y_label"]
- );
- //
- // draw title + subtext
- //
- $text->setFontSize(20);
- $text->setFontWeight(900);
- $text->setFillColor($colors["text"]);
- $im->annotateImage(
- $text,
- $size["x"],
- $size["y"] - 25,
- 0,
- $graph["title"]
- );
- $text->setFontSize(13);
- $text->setFontWeight(100);
- $im->annotateImage(
- $text,
- $size["x"],
- $size["y"] - 10,
- 0,
- $graph["subtitle"]
- );
- if($not_enough_data){
-
- // add not enough data notice
- $rect = new ImagickDraw();
- $rect->setFillColor($colors["bg"]);
- $rect->setStrokeColor($colors_line[1]);
-
- $rect_w = 200;
- $rect_h = 24;
-
- $rect_x = round($size["x"] + ($size["width"] / 2) - ($rect_w / 2));
- $rect_y = round($size["y"] + ($size["height"] / 2) - ($rect_h / 2));
-
- $rect->rectangle(
- $rect_x,
- $rect_y,
- $rect_x + $rect_w,
- $rect_y + $rect_h
- );
-
- $im->drawImage($rect);
-
- $label = "Not enough data";
-
- $text->setFontWeight(900);
- $query = $im->queryFontMetrics($text, $label);
-
- $im->annotateImage(
- $text,
- round($size["x"] + ($size["width"] / 2) - ($query["textWidth"] / 2)),
- round($size["y"] + ($size["height"] / 2) + ($query["textHeight"] / 2)) - 3,
- 0,
- $label
- );
- }
- return $im->getImageBlob();
- }
- }
|