protected function render_graph_pre_init()
 {
     // Do some common work to this object
     $this->i['identifier_width'] = $this->max_count > 0 ? ($this->i['graph_left_end'] - $this->i['left_start']) / $this->max_count : 1;
     if (!$this->i['hide_graph_identifiers']) {
         $identifier_count = $this->test_result->test_result_buffer->get_count();
         $longest_string = pts_strings::find_longest_string($this->graph_identifiers);
         $this->i['identifier_size'] = $this->text_size_bounds($longest_string, $this->i['identifier_size'], $this->i['min_identifier_size'], $this->i['identifier_width'] - 4);
         if ($this->i['identifier_size'] <= $this->i['min_identifier_size']) {
             list($text_width, $text_height) = pts_svg_dom::estimate_text_dimensions($longest_string, $this->i['min_identifier_size'] + 0.5);
             $this->i['bottom_offset'] += $text_width;
             $this->update_graph_dimensions($this->i['graph_width'], $this->i['graph_height'] + $text_width);
             if ($text_height + 4 > $this->i['identifier_width'] && $identifier_count > 3) {
                 // Show the identifiers as frequently as they will fit
                 $this->i['display_select_identifiers'] = ceil(($text_height + 4) / $this->i['identifier_width']);
             }
         }
     }
     $max_value = 0;
     foreach ($this->test_result->test_result_buffer->buffer_items as &$buffer_item) {
         if (!is_array($buffer_item->get_result_value())) {
             $max_value = max($max_value, $buffer_item->get_result_value());
         } else {
             $max_value = max($max_value, max($buffer_item->get_result_value()));
         }
     }
     $max_value *= 1.25;
     // leave room at top of graph
     $this->i['graph_max_value'] = round($max_value, $max_value < 10 ? 1 : 0);
 }
 protected function render_graph_pre_init()
 {
     // Do some common work to this object
     $graph_identifiers_count = count($this->graph_identifiers);
     if ($graph_identifiers_count > 1) {
         $identifier_count = $graph_identifiers_count + 1;
     } else {
         $identifier_count = 0;
         foreach (array_keys($this->graph_data) as $i) {
             $identifier_count = max(count($this->graph_data[$i]) - 1, $identifier_count);
         }
     }
     $this->i['identifier_width'] = $identifier_count > 0 ? ($this->i['graph_left_end'] - $this->i['left_start']) / $identifier_count : 1;
     $longest_string = pts_strings::find_longest_string($this->graph_identifiers);
     $this->i['identifier_size'] = $this->text_size_bounds($longest_string, $this->i['identifier_size'], $this->i['min_identifier_size'], $this->i['identifier_width'] - 4);
     if ($this->i['identifier_size'] <= $this->i['min_identifier_size']) {
         list($text_width, $text_height) = pts_svg_dom::estimate_text_dimensions($longest_string, $this->i['min_identifier_size'] + 0.5);
         $this->i['bottom_offset'] += $text_width;
         $this->update_graph_dimensions($this->i['graph_width'], $this->i['graph_height'] + $text_width);
         if ($text_height + 4 > $this->i['identifier_width'] && $graph_identifiers_count > 3) {
             // Show the identifiers as frequently as they will fit
             $this->i['display_select_identifiers'] = ceil(($text_height + 4) / $this->i['identifier_width']);
         }
     }
     $max_value = 0;
     foreach ($this->graph_data as $dataset) {
         $data_max = max($dataset);
         $max_value = $max_value > $data_max ? $max_value : $data_max;
     }
     $max_value *= 1.25;
     // leave room at top of graph
     $this->i['graph_max_value'] = round($max_value, $max_value < 10 ? 1 : 0);
 }
 protected function render_graph_heading($with_version = true)
 {
     $this->svg_dom->add_element('rect', array('x' => 0, 'y' => 0, 'width' => $this->i['graph_width'], 'height' => $this->i['top_heading_height'], 'fill' => self::$c['color']['main_headers']));
     $this->svg_dom->add_element('image', array('xlink:href' => pts_svg_dom::embed_png_image(PTS_CORE_STATIC_PATH . 'images/pts-77x40-white.png'), 'x' => 10, 'y' => round($this->i['top_heading_height'] / 40 + 1), 'width' => 77, 'height' => 40));
     $this->svg_dom->add_text_element($this->graph_title, array('x' => 100, 'y' => 4 + self::$c['size']['headers'], 'font-size' => self::$c['size']['headers'], 'fill' => self::$c['color']['background'], 'text-anchor' => 'start'));
     $this->svg_dom->add_text_element($this->i['graph_version'], array('x' => 100, 'y' => self::$c['size']['headers'] + 16, 'font-size' => self::$c['size']['key'], 'fill' => self::$c['color']['background'], 'text-anchor' => 'start', 'href' => 'http://www.phoronix-test-suite.com/'));
 }
 public function __construct($result_file)
 {
     $result_object = null;
     parent::__construct($result_object, $result_file);
     // System Identifiers
     if ($result_file->is_multi_way_comparison()) {
         // Multi way comparisons currently render the overview graph as blank
         $this->skip_graph = true;
         return;
     }
     $this->system_identifiers = $result_file->get_system_identifiers();
     if (count($this->system_identifiers) < 2) {
         // No point in generating this when there is only one identifier
         $this->skip_graph = true;
         return;
     }
     $result_objects = array();
     $test_titles = array();
     foreach ($result_file->get_result_objects() as $result_object) {
         if ($result_object->test_profile->get_display_format() == 'BAR_GRAPH') {
             array_push($result_objects, $result_object);
             array_push($test_titles, $result_object->test_profile->get_title());
             foreach ($result_object->test_result_buffer->buffer_items as &$buffer_item) {
                 pts_arrays::unique_push($this->graph_identifiers, $buffer_item->get_result_identifier());
             }
         }
     }
     $result_object_count = count($result_objects);
     if ($result_object_count < 3) {
         // No point in generating this if there aren't many tests
         $this->skip_graph = true;
         return;
     }
     $result_file->override_result_objects($result_objects);
     // Test Titles
     $this->i['identifier_size'] = 6.5;
     $this->i['graph_width'] = 1000;
     list($longest_title_width, $longest_title_height) = pts_svg_dom::estimate_text_dimensions(pts_strings::find_longest_string($test_titles), $this->i['identifier_size']);
     $this->i['left_start'] += 20;
     $this->graphs_per_row = min(count($this->system_identifiers) > 10 ? 6 : 10, floor(($this->i['graph_width'] - $this->i['left_start'] - $this->i['left_end_right']) / ($longest_title_width + 4)));
     $this->graph_item_width = floor(($this->i['graph_width'] - $this->i['left_start'] - $this->i['left_end_right']) / $this->graphs_per_row);
     $this->graph_row_count = ceil($result_object_count / $this->graphs_per_row);
     $this->i['top_start'] += 20 + count($this->system_identifiers) / 3 * $this->i['identifier_size'];
     $height = $this->i['top_start'] + $this->graph_row_count * ($this->graph_row_height + 15);
     $this->graph_title = $result_file->get_title();
     $this->graph_y_title = null;
     $this->i['graph_proportion'] = 'HIB';
     $this->i['show_background_lines'] = true;
     $this->update_graph_dimensions($this->i['graph_width'], $height, true);
     $this->result_file = $result_file;
     return true;
 }
 protected function render_graph_pre_init()
 {
     $this->i['min_time'] = strtotime(min($this->test_result->test_result_buffer->get_identifiers()));
     $this->i['max_time'] = strtotime(max($this->test_result->test_result_buffer->get_identifiers()));
     $this->i['spread_time'] = $this->i['max_time'] - $this->i['min_time'];
     // Do some common work to this object
     $graph_identifiers_count = count($this->graph_identifiers);
     $identifier_count = $graph_identifiers_count > 1 ? $graph_identifiers_count : count($this->graph_data[0]);
     $this->i['identifier_width'] = ($this->i['graph_left_end'] - $this->i['left_start']) / ($identifier_count + 1);
     $longest_string = pts_strings::find_longest_string($this->graph_identifiers);
     $this->i['identifier_size'] = $this->text_size_bounds($longest_string, $this->i['identifier_size'], $this->i['min_identifier_size'], $this->i['identifier_width'] - 4);
     if ($this->i['identifier_size'] <= $this->i['min_identifier_size']) {
         list($text_width, $text_height) = pts_svg_dom::estimate_text_dimensions($longest_string, $this->i['min_identifier_size'] + 0.5);
         $this->i['bottom_offset'] += $text_width;
         $this->update_graph_dimensions($this->i['graph_width'], $this->i['graph_height'] + $text_width);
         if ($text_height + 4 > $this->i['identifier_width'] && $graph_identifiers_count > 3) {
             // Show the identifiers as frequently as they will fit
             $this->i['display_select_identifiers'] = ceil(($text_height + 4) / $this->i['identifier_width']);
         }
     }
 }
 public function generate_display()
 {
     $bar_width = 580;
     $bar_height = 38;
     $heading_per_bar = 16;
     $title_bar_height = 35;
     $footer_bar_height = 14;
     $category_offsets = 0;
     $category_heights = 30;
     $categories = array();
     $border = 3;
     foreach ($this->bars as &$bar) {
         if ($bar['test_data']['h'] != null && !in_array($bar['test_data']['h'], $categories)) {
             array_push($categories, $bar['test_data']['h']);
         }
     }
     if (empty($this->keys)) {
         foreach ($this->bars as &$bar_index) {
             foreach (array_keys($bar_index['results']) as $result_identifier) {
                 if (!in_array($result_identifier, $this->keys)) {
                     array_push($this->keys, $result_identifier);
                 }
             }
         }
     }
     if (!empty($this->keys)) {
         list($longest_key_width, $key_line_height) = pts_svg_dom::estimate_text_dimensions(pts_strings::find_longest_string($this->keys), '', 10, true);
         $key_line_height += 18;
         $keys_per_line = max(floor($bar_width / max(1, $longest_key_width + 12)), 1);
         $title_key_offset = ceil(count($this->keys) / $keys_per_line) * $key_line_height;
     } else {
         $title_key_offset = 0;
     }
     $this->i['graph_width'] = $bar_width + $border * 2;
     $this->i['graph_height'] = ($bar_height + $heading_per_bar + $border) * count($this->bars) + $border + count($categories) * $category_heights + $title_bar_height + $title_key_offset + $footer_bar_height;
     $this->svg_dom = new pts_svg_dom(ceil($this->i['graph_width']), ceil($this->i['graph_height']));
     $text_color = '#e12128';
     $alt_text_color = '#646464';
     // Setup
     $start_x = $border;
     $end_x = $start_x + $bar_width;
     // Title bar
     $this->svg_dom->add_element('image', array('xlink:href' => 'https://openbenchmarking.org/static/images/ob-fulltext-183x32.png', 'x' => $end_x - 190, 'y' => 10, 'width' => 183, 'height' => 32));
     if (!empty($this->keys)) {
         $color_cache = array('e12128', '065695', '007400');
         for ($i = 0, $c = count($this->keys); $i < $c; $i++) {
             $component_x = $border + $i % $keys_per_line * ($longest_key_width + 10);
             $component_y = floor($i / $keys_per_line) * $key_line_height + $title_bar_height + 3;
             $key_color = self::color_cache('opc', $this->keys[$i], $color_cache);
             //$key_color = self::color_gradient('e12128', '065695', ($i / $c));
             $key_colors[$this->keys[$i]] = $key_color;
             $this->svg_dom->add_element('rect', array('x' => $component_x + 1, 'y' => $component_y, 'width' => 10, 'height' => 10, 'fill' => $key_color, 'stroke' => self::$c['color']['border'], 'stroke-width' => 1));
             $this->svg_dom->add_text_element($this->keys[$i], array('x' => $component_x + 15, 'y' => $component_y + 5, 'font-size' => 10, 'fill' => $key_color, 'text-anchor' => 'start'));
         }
     }
     $previous_category = null;
     foreach ($this->bars as $i => &$hmap) {
         $upper_y = $i * ($bar_height + $border + $heading_per_bar) + $border + $title_bar_height + $title_key_offset + $category_offsets + $heading_per_bar;
         if ($hmap['test_data']['h'] != null && $hmap['test_data']['h'] != $previous_category) {
             $this->svg_dom->add_text_element($hmap['test_data']['h'] . ' Tests', array('x' => $start_x + $bar_width / 2, 'y' => $upper_y, 'font-size' => 16, 'fill' => $text_color, 'text-anchor' => 'middle'));
             $category_offsets += $category_heights;
             $upper_y += $category_heights;
         }
         $previous_category = $hmap['test_data']['h'];
         $lower_y = $upper_y + $bar_height;
         $value_size = $bar_width / ($hmap['max_value'] - $hmap['min_value']);
         $prev_color = '#ffffff';
         $last_plot_x = $start_x;
         $this->svg_dom->add_text_element($hmap['test_data']['t'], array('x' => $start_x, 'y' => $upper_y, 'font-size' => 12, 'fill' => $text_color, 'text-anchor' => 'start'));
         $this->svg_dom->add_text_element($hmap['test_data']['a'], array('x' => $end_x, 'y' => $upper_y, 'font-size' => 10, 'fill' => $alt_text_color, 'text-anchor' => 'end'));
         if ($hmap['test_data']['p'] == 'LIB') {
             // Invert results
             $new_sections = array();
             foreach ($hmap['sections'] as $next_section => $next_section_value) {
                 $new_sections[$hmap['max_value'] - $next_section] = $next_section_value;
             }
             ksort($new_sections);
             $hmap['sections'] = $new_sections;
             foreach ($hmap['draw_lines'] as &$value) {
                 $value = $hmap['max_value'] - $value;
             }
             foreach ($hmap['results'] as &$value) {
                 $value = $hmap['max_value'] - $value;
             }
             sort($hmap['draw_lines']);
             $hmap['max_value'] -= $hmap['min_value'];
             $hmap['min_value'] = 0;
         }
         $prev_section = $hmap['min_value'];
         $max_section_value = max($hmap['sections']);
         /*
         for($i = $hmap['min_value']; $i <= $hmap['max_size'] && $hmap['bin_size'] > 0; $i += $hmap['bin_size'])
         {
         
         }
         */
         $color_weight = 0.61 - 0 / $max_section_value * 0.5;
         $background_color = self::color_gradient('#FFFFFF', '#000000', $color_weight);
         $this->svg_dom->add_element('rect', array('x' => $start_x, 'y' => $upper_y, 'width' => $bar_width, 'height' => $bar_height, 'fill' => $background_color));
         foreach ($hmap['sections'] as $next_section => $next_section_value) {
             $color_weight = 0.61 - $next_section_value / $max_section_value * 0.5;
             $color = self::color_gradient('#FFFFFF', '#000000', $color_weight);
             if ($next_section > $hmap['min_value']) {
                 $next_section = $next_section > $hmap['max_value'] ? $hmap['max_value'] : $next_section;
                 $plot_x = floor($last_plot_x + ($next_section - $prev_section) * $value_size);
                 $plot_x = $plot_x > $end_x ? $end_x : $plot_x;
                 if ($prev_color != $color || $color != $background_color) {
                     // don't uselessly paint background color, it's already painted
                     $this->svg_dom->draw_rectangle_gradient($last_plot_x, $upper_y, abs($plot_x - $last_plot_x), $bar_height, $prev_color, $color);
                 }
                 $last_plot_x = floor($plot_x - 0.6);
                 $prev_section = $next_section;
                 if ($next_section > $hmap['max_value']) {
                     break;
                 }
             }
             $prev_color = $color;
         }
         /*
         
         if($prev_color != $background_color && $plot_x < $end_x)
         {
         	$plot_x = $last_plot_x + $next_section + $hmap['bin_size'];
         	$plot_x = $plot_x > $end_x ? $end_x : $plot_x;
         	$this->svg_dom->draw_rectangle_gradient($last_plot_x, $upper_y, ceil($plot_x - $last_plot_x), $bar_height, $prev_color, $background_color);
         }
         if($last_plot_x < $end_x)
         {
         	// Fill in the blank
         	$this->svg_dom->add_element('rect', array('x' => $last_plot_x, 'y' => $upper_y, 'width' => ($end_x - $last_plot_x), 'height' => $bar_height, 'fill' => $prev_color));
         }
         */
         foreach ($hmap['draw_lines'] as $line_value) {
             $line_x = $start_x + ($line_value - $hmap['min_value']) * $value_size;
             $this->svg_dom->draw_svg_line($line_x, $upper_y, $line_x, $lower_y, self::$c['color']['border'], 1);
         }
         foreach ($hmap['results'] as $identifier => $value) {
             if (!isset($key_colors[$identifier])) {
                 continue;
             }
             $line_x = $start_x + ($value - $hmap['min_value']) * $value_size;
             if (false && $start_x + 10 < $line_x && $line_x < $end_x - 10) {
                 $this->svg_dom->draw_svg_line($line_x, $lower_y - 10, $line_x, $lower_y - 1, $key_colors[$identifier], 1);
                 $this->svg_dom->draw_svg_line($line_x, $lower_y + 10, $line_x, $lower_y + 1, $key_colors[$identifier], 1);
             }
             $this->svg_dom->draw_svg_line($line_x, $upper_y, $line_x, $lower_y, $key_colors[$identifier], 1);
         }
         $this->svg_dom->add_element('rect', array('x' => $start_x, 'y' => $upper_y, 'width' => $bar_width, 'height' => $bar_height, 'fill' => 'none', 'stroke' => self::$c['color']['border'], 'stroke-width' => 1));
     }
     // Footer
     $this->draw_arrow($start_x + 8, $lower_y + 8, $start_x + 1, $lower_y + 8, $alt_text_color, self::$c['color']['border'], 1);
     $this->svg_dom->add_text_element('Percentile Rank' . ($this->last_updated != null ? '; Data As Of ' . pts_strings::time_stamp_to_string($this->last_updated, 'j F Y') . ' For Trailing 200 Days' : null), array('x' => $start_x + 13, 'y' => $lower_y + 8, 'font-size' => 7, 'fill' => $alt_text_color, 'text-anchor' => 'start', 'dominant-baseline' => 'middle'));
     $this->svg_dom->add_text_element('OpenBenchmarking.org Performance Classification', array('x' => $end_x, 'y' => $lower_y + 8, 'font-size' => 7, 'fill' => $alt_text_color, 'text-anchor' => 'end', 'dominant-baseline' => 'middle'));
     return $this->svg_dom;
 }
 public static function xsl_results_viewer_graph_template()
 {
     $raw_xsl = file_get_contents(PTS_RESULTS_VIEWER_PATH . 'pts-results-viewer.xsl');
     // System Tables
     $conversions = array('systems', 'detailed_component', 'radar', 'overview', 'visualize');
     foreach ($conversions as $convert) {
         $graph_string = pts_svg_dom::html_embed_code('result-graphs/' . $convert . '.BILDE_EXTENSION', 'SVG', array('width' => 'auto', 'height' => 'auto'), true);
         $raw_xsl = str_replace('<!-- ' . strtoupper($convert) . ' TAG -->', $graph_string, $raw_xsl);
     }
     // Result Graphs
     $graph_string = pts_svg_dom::html_embed_code('result-graphs/<xsl:number value="position()" />.BILDE_EXTENSION', 'SVG', array('width' => 'auto', 'height' => 'auto'), true);
     $raw_xsl = str_replace('<!-- GRAPH TAG -->', $graph_string, $raw_xsl);
     return $raw_xsl;
 }
 protected function text_string_height($string, $size)
 {
     $dimensions = pts_svg_dom::estimate_text_dimensions($string, $size);
     return $dimensions[1];
 }
 public function render_graph_start()
 {
     // Needs to be at least 86px wide for the PTS logo
     $this->i['left_start'] = ceil(max(86, $this->text_string_width($this->longest_row_identifier, $this->i['identifier_size']) * 1.09 + 8));
     // Needs to be at least 46px tall for the PTS logo
     $top_identifier_height = max($this->text_string_height($this->longest_column_identifier, $this->i['identifier_size']) + 8, 48);
     $this->i['top_heading_height'] = 1;
     if ($this->graph_title != null) {
         $this->i['top_heading_height'] += round(self::$c['size']['headers'] + count($this->graph_sub_titles) * (self::$c['size']['sub_headers'] + 4));
     }
     $column_widths = array();
     $row_heights = array_fill(0, count($this->rows), ceil($this->i['identifier_size'] * 2.2));
     foreach ($this->columns as $i => $column) {
         $column_width = strlen($column);
         $column_index = -1;
         // See if any of the contained values in that column are longer than the column title itself
         foreach ($this->table_data[$i] as $row => &$column_data) {
             if (isset($column_data[$column_width])) {
                 $column = $column_data;
                 $column_width = strlen($column_data);
                 $column_index = $row;
             }
             if (strlen($column_data) > 64) {
                 // If it's too long break it into multiple rows
                 $row_heights[$row] = ceil($this->i['identifier_size'] * ceil(strlen($column_data) / 64)) + 18;
                 $column = substr($column, 0, 64);
             }
         }
         $column_widths[$i] = ceil($this->text_string_width($column, $this->i['identifier_size']) * 1.02) + 14;
     }
     $table_width = $this->longest_row_identifier + array_sum($column_widths);
     $table_height = array_sum($row_heights);
     $table_proper_height = $this->i['top_heading_height'] + $table_height + $top_identifier_height;
     $this->i['graph_width'] = $table_width + $this->i['left_start'] + 1;
     $this->i['graph_height'] = round($table_proper_height + 16);
     if (!empty($this->i['notes'])) {
         $this->i['graph_height'] += $this->note_display_height();
     }
     // Do the actual work
     $this->render_graph_pre_init();
     $this->render_graph_init();
     $this->svg_dom->add_element('rect', array('x' => 1, 'y' => 1, 'width' => $this->i['graph_width'] - 1, 'height' => $this->i['graph_height'] - 1, 'fill' => self::$c['color']['background'], 'stroke' => self::$c['color']['border'], 'stroke-width' => 1));
     // Start drawing
     if ($this->i['left_start'] >= 170 && $top_identifier_height >= 90) {
         $this->svg_dom->add_element('image', array('http_link' => 'http://www.phoronix-test-suite.com/', 'xlink:href' => pts_svg_dom::embed_png_image(PTS_CORE_STATIC_PATH . 'images/pts-160x83.png'), 'x' => round($this->i['left_start'] / 2 - 80), 'y' => round($top_identifier_height / 2 - 41.5 + $this->i['top_heading_height']), 'width' => 160, 'height' => 83));
     } else {
         $this->svg_dom->add_element('image', array('http_link' => 'http://www.phoronix-test-suite.com/', 'xlink:href' => pts_svg_dom::embed_png_image(PTS_CORE_STATIC_PATH . 'images/pts-80x42.png'), 'x' => round($this->i['left_start'] / 2 - 40), 'y' => round($top_identifier_height / 2 - 21 + $this->i['top_heading_height']), 'width' => 80, 'height' => 42));
     }
     // Draw the vertical table lines
     $v = round(($top_identifier_height + $table_height) / 2 + $this->i['top_heading_height']);
     // Heading
     if ($this->graph_title != null) {
         $this->svg_dom->add_element('rect', array('x' => 1, 'y' => 1, 'width' => $this->i['graph_width'] - 2, 'height' => $this->i['top_heading_height'], 'fill' => self::$c['color']['main_headers']));
         foreach ($this->graph_sub_titles as $i => $sub_title) {
             $vertical_offset = 16 + self::$c['size']['headers'] + $i * self::$c['size']['sub_headers'];
             $this->svg_dom->add_text_element($sub_title, array('x' => 5, 'y' => $vertical_offset, 'font-size' => self::$c['size']['sub_headers'], 'fill' => self::$c['color']['background'], 'text-anchor' => 'start'));
         }
         $this->svg_dom->draw_svg_line(1, $this->i['top_heading_height'], $this->i['graph_width'] - 1, $this->i['top_heading_height'], self::$c['color']['border'], 1);
     }
     // Write the rows
     $horizontal_offset = $top_identifier_height + $this->i['top_heading_height'];
     foreach ($this->rows as $i => $row_string) {
         if ($i % 2 == 0) {
             $this->svg_dom->add_element('rect', array('x' => 1, 'y' => $horizontal_offset, 'width' => $this->i['left_start'], 'height' => $row_heights[$i], 'fill' => self::$c['color']['body_light'], 'stroke' => self::$c['color']['border'], 'stroke-width' => 1));
         }
         $this->svg_dom->add_text_element($row_string, array('x' => $this->i['left_start'] - 4, 'y' => $horizontal_offset + 16, 'font-size' => $this->i['identifier_size'], 'fill' => self::$c['color']['text'], 'font-weight' => 'bold', 'text-anchor' => 'end'));
         $horizontal_offset += $row_heights[$i];
     }
     // Write the columns
     $y = $this->i['top_heading_height'] + $top_identifier_height / 2 - 6;
     $column_width_offset = $this->i['left_start'];
     foreach ($this->columns as $i => $col_string) {
         if ($i % 2 == 0) {
             $this->svg_dom->add_element('rect', array('x' => $column_width_offset, 'y' => $this->i['top_heading_height'], 'width' => $column_widths[$i], 'height' => $top_identifier_height, 'fill' => self::$c['color']['body_light'], 'stroke' => self::$c['color']['border'], 'stroke-width' => 1));
         }
         $this->svg_dom->add_text_element($col_string, array('x' => $column_width_offset + round($column_widths[$i] / 2), 'y' => $y, 'font-size' => $this->i['identifier_size'], 'fill' => self::$c['color']['text'], 'font-weight' => 'bold', 'text-anchor' => 'middle', 'dominant-baseline' => 'text-before-edge'));
         $column_width_offset += $column_widths[$i];
     }
     // Write the values
     $column_width_offset = $this->i['left_start'];
     $column_count = 0;
     foreach ($this->table_data as $column => &$column_data) {
         $x = $column_width_offset + round($column_widths[$column_count] / 2);
         $row_count = 0;
         $row_offset = $top_identifier_height + $this->i['top_heading_height'];
         foreach ($column_data as $row => &$value) {
             if (true || $column % 2 == 0 || $row % 2 != 1) {
                 $this->svg_dom->add_element('rect', array('x' => $column_width_offset, 'y' => $row_offset, 'width' => $column_widths[$column_count], 'height' => $row_heights[$row], 'fill' => self::$c['color'][$row % 2 == 0 ? 'body' : 'body_light'], 'stroke' => self::$c['color']['border'], 'stroke-width' => 1));
             }
             if (isset($value[64])) {
                 // If it's a long string that needs to be broken to multiple linesd we need textarea to do automatic word wrapping
                 $this->svg_dom->add_textarea_element($value, array('x' => $x, 'y' => $row_offset + 16, 'font-size' => $this->i['identifier_size'], 'fill' => self::$c['color']['text'], 'text-anchor' => 'middle', 'width' => $column_widths[$column_count] - 8));
             } else {
                 $this->svg_dom->add_text_element($value, array('x' => $x, 'y' => $row_offset + 16, 'font-size' => $this->i['identifier_size'], 'fill' => self::$c['color']['text'], 'text-anchor' => 'middle'));
             }
             $row_count++;
             $row_offset += $row_heights[$row];
         }
         $column_width_offset += $column_widths[$column_count];
         $column_count++;
     }
     // Bottom part
     $this->svg_dom->add_element('rect', array('x' => 0, 'y' => $table_proper_height, 'width' => $this->i['graph_width'], 'height' => $this->i['graph_height'] - $table_proper_height, 'fill' => self::$c['color']['headers']));
     $this->svg_dom->add_text_element(self::$c['text']['watermark'], array('x' => $this->i['graph_width'] - 2, 'y' => $this->i['graph_height'] - 3, 'font-size' => $this->i['identifier_size'], 'fill' => self::$c['color']['body_text'], 'text-anchor' => 'end', 'xlink:show' => 'new', 'xlink:href' => self::$c['text']['watermark_url']));
     if (!empty($this->i['notes'])) {
         $estimated_height = 0;
         $previous_section = null;
         foreach ($this->i['notes'] as $i => $note_r) {
             if ($note_r['section'] != null && $note_r['section'] !== $previous_section) {
                 $estimated_height += 2;
                 $this->svg_dom->add_textarea_element($note_r['section'] . ' Details', array('x' => 6, 'y' => $table_proper_height + 14 + $estimated_height, 'font-size' => self::$c['size']['key'] - 1, 'fill' => self::$c['color']['background'], 'text-anchor' => 'start', 'xlink:title' => $note_r['hover-title'], 'style' => 'font-weight: bold'), $estimated_height);
                 $estimated_height += 2;
                 $previous_section = $note_r['section'];
             }
             $this->svg_dom->add_textarea_element('- ' . $note_r['note'], array('x' => 6, 'y' => $table_proper_height + 14 + $estimated_height, 'font-size' => self::$c['size']['key'] - 1, 'fill' => self::$c['color']['background'], 'text-anchor' => 'start', 'xlink:title' => $note_r['hover-title']), $estimated_height);
         }
     }
 }
 public function render_graph_start()
 {
     // Needs to be at least 86px wide for the PTS logo
     $this->i['left_start'] = ceil(max(86, $this->text_string_width($this->longest_row_identifier, $this->i['identifier_size']) * 1.1 + 12));
     if ($this->column_heading_vertical) {
         $top_identifier_height = round($this->text_string_width($this->longest_column_identifier, $this->i['identifier_size']) * 1.1) + 12;
         $table_identifier_width = $this->text_string_height($this->longest_column_identifier, $this->i['identifier_size']);
     } else {
         $top_identifier_height = $this->text_string_height($this->longest_column_identifier, $this->i['identifier_size']) + 8;
         $table_identifier_width = round($this->text_string_width($this->longest_column_identifier, $this->i['identifier_size']) * 1.1) + 8;
     }
     // Needs to be at least 46px tall for the PTS logo
     $top_identifier_height = max($top_identifier_height, 48);
     if (defined('PHOROMATIC_TRACKER') || $this->is_multi_way) {
         $extra_heading_height = round($this->text_string_height($this->longest_column_identifier, self::$c['size']['headers']) * 1.25);
         $top_identifier_height += 6 + $extra_heading_height;
     }
     $this->i['top_heading_height'] = 8;
     if ($this->graph_title != null) {
         $this->i['top_heading_height'] += round(self::$c['size']['headers'] + count($this->graph_sub_titles) * (self::$c['size']['sub_headers'] + 4));
     }
     $table_max_value_width = ceil($this->text_string_width($this->i['graph_max_value'], $this->i['identifier_size']) * 1.02) + 2;
     $table_item_width = max($table_max_value_width, $table_identifier_width) + 2;
     $table_width = max($table_item_width * count($this->columns), floor($this->text_string_width($this->graph_title, 12) / $table_item_width) * $table_item_width);
     //$table_width = $table_item_width * count($this->columns);
     $table_line_height = round($this->text_string_height($this->i['graph_max_value'], $this->i['identifier_size']) + 8);
     $table_line_height_half = round($table_line_height / 2);
     $table_height = $table_line_height * count($this->rows);
     $table_proper_height = $this->i['top_heading_height'] + $table_height + $top_identifier_height;
     $this->i['graph_width'] = $table_width + $this->i['left_start'];
     $this->i['graph_height'] = round($table_proper_height + $table_line_height);
     if (!empty($this->i['notes'])) {
         $this->i['graph_height'] += $this->note_display_height();
     }
     // Do the actual work
     $this->render_graph_pre_init();
     $this->render_graph_init();
     $this->svg_dom->add_element('rect', array('x' => 1, 'y' => 1, 'width' => $this->i['graph_width'] - 1, 'height' => $this->i['graph_height'] - 1, 'fill' => self::$c['color']['background'], 'stroke' => self::$c['color']['border'], 'stroke-width' => 1));
     // Start drawing
     if ($this->i['left_start'] >= 170 && $top_identifier_height >= 90) {
         $this->svg_dom->add_element('image', array('http_link' => 'http://www.phoronix-test-suite.com/', 'xlink:href' => pts_svg_dom::embed_png_image(PTS_CORE_STATIC_PATH . 'images/pts-160x83.png'), 'x' => round($this->i['left_start'] / 2 - 80), 'y' => round($top_identifier_height / 2 - 41.5 + $this->i['top_heading_height']), 'width' => 160, 'height' => 83));
     } else {
         $this->svg_dom->add_element('image', array('http_link' => 'http://www.phoronix-test-suite.com/', 'xlink:href' => pts_svg_dom::embed_png_image(PTS_CORE_STATIC_PATH . 'images/pts-80x42.png'), 'x' => round($this->i['left_start'] / 2 - 40), 'y' => round($top_identifier_height / 2 - 21 + $this->i['top_heading_height']), 'width' => 80, 'height' => 42));
     }
     // Draw the vertical table lines
     $v = round(($top_identifier_height + $table_height) / 2 + $this->i['top_heading_height']);
     $table_columns_end = $this->i['left_start'] + $table_item_width * count($this->columns);
     $this->svg_dom->draw_svg_line($this->i['left_start'], $v, $table_columns_end, $v, self::$c['color']['body'], $table_height + $top_identifier_height, array('stroke-dasharray' => $table_item_width . ',' . $table_item_width));
     if ($table_columns_end < $this->i['graph_width']) {
         $this->svg_dom->add_element('rect', array('x' => $table_columns_end, 'y' => $this->i['top_heading_height'], 'width' => $this->i['graph_width'] - $table_columns_end, 'height' => $table_height + $top_identifier_height, 'fill' => self::$c['color']['body_light']));
     }
     // Background horizontal
     $this->svg_dom->draw_svg_line(round($table_columns_end / 2), $top_identifier_height + $this->i['top_heading_height'], round($table_columns_end / 2), $table_proper_height, self::$c['color']['body_light'], $table_columns_end, array('stroke-dasharray' => $table_line_height . ',' . $table_line_height));
     // Draw the borders
     $this->svg_dom->draw_svg_line($this->i['left_start'], $v, $table_columns_end + ($table_columns_end < $this->i['graph_width'] ? $table_item_width : 0), $v, self::$c['color']['border'], $table_height + $top_identifier_height, array('stroke-dasharray' => '1,' . ($table_item_width - 1)));
     // Heading
     if ($this->graph_title != null) {
         $this->svg_dom->add_element('rect', array('x' => 1, 'y' => 1, 'width' => $this->i['graph_width'] - 2, 'height' => $this->i['top_heading_height'], 'fill' => self::$c['color']['main_headers']));
         $this->svg_dom->add_text_element($this->graph_title, array('x' => 5, 'y' => self::$c['size']['headers'] + 2, 'font-size' => self::$c['size']['headers'], 'fill' => self::$c['color']['background'], 'text-anchor' => 'start'));
         foreach ($this->graph_sub_titles as $i => $sub_title) {
             $vertical_offset = 16 + self::$c['size']['headers'] + $i * self::$c['size']['sub_headers'];
             $this->svg_dom->add_text_element($sub_title, array('x' => 5, 'y' => $vertical_offset, 'font-size' => self::$c['size']['sub_headers'], 'fill' => self::$c['color']['background'], 'text-anchor' => 'start'));
         }
         $this->svg_dom->draw_svg_line(1, $this->i['top_heading_height'], $this->i['graph_width'] - 1, $this->i['top_heading_height'], self::$c['color']['border'], 1);
     }
     // Write the rows
     $row = 1;
     foreach ($this->rows as $i => $row_string) {
         if ($row_string instanceof pts_graph_ir_value == false) {
             $row_string = new pts_graph_ir_value($row_string);
         }
         $text_color = $row_string->get_attribute('alert') ? self::$c['color']['alert'] : self::$c['color']['text'];
         $v = round($top_identifier_height + $this->i['top_heading_height'] + $row * $table_line_height - 4);
         $this->svg_dom->add_text_element($row_string, array('x' => $this->i['left_start'] - 2, 'y' => $v, 'font-size' => $this->i['identifier_size'], 'fill' => $text_color, 'font-weight' => 'bold', 'text-anchor' => 'end', 'xlink:href' => $row_string->get_attribute('href')));
         $row++;
     }
     // Write the identifiers
     if (defined('PHOROMATIC_TRACKER') || $this->is_multi_way) {
         $last_identifier = null;
         $last_changed_col = 0;
         $show_keys = array_keys($this->table_data);
         array_push($show_keys, 'Temp: Temp');
         foreach ($show_keys as $current_col => $system_identifier) {
             $identifier = pts_strings::colon_explode($system_identifier);
             if (isset($identifier[0]) && $identifier[0] != $last_identifier) {
                 if ($current_col == $last_changed_col) {
                     $last_identifier = $identifier[0];
                     continue;
                 }
                 $paint_color = $this->get_paint_color($identifier[0]);
                 if ($this->i['top_heading_height'] > 0) {
                     $extra_heading_height = $this->i['top_heading_height'];
                 }
                 $x = $this->i['left_start'] + 1 + $last_changed_col * $table_item_width;
                 $x_end = $this->i['left_start'] + $last_changed_col * $table_item_width + $table_item_width * ($current_col - $last_changed_col);
                 $this->svg_dom->add_element('rect', array('x' => $x, 'y' => 0, 'width' => $table_item_width * ($current_col - $last_changed_col) - 2, 'height' => $extra_heading_height, 'fill' => $paint_color));
                 if ($identifier[0] != 'Temp') {
                     $this->svg_dom->draw_svg_line($this->i['left_start'] + $current_col * $table_item_width + 1, 1, $this->i['left_start'] + $current_col * $table_item_width + 1, $table_proper_height, $paint_color, 1);
                 }
                 //$x = $this->i['left_start'] + ($last_changed_col * $table_item_width) + ($this->i['left_start'] + ($current_col * $table_item_width) - $this->i['left_start'] + ($last_changed_col * $table_item_width));
                 $this->svg_dom->add_text_element($last_identifier, array('x' => round($x + ($x_end - $x) / 2), 'y' => self::$c['size']['axis_headers'] + 4, 'font-size' => self::$c['size']['axis_headers'], 'fill' => self::$c['color']['background'], 'font-weight' => 'bold', 'text-anchor' => 'middle'));
                 $last_identifier = $identifier[0];
                 $last_changed_col = $current_col;
             }
         }
     }
     $table_identifier_offset = $table_item_width / 2 + $table_identifier_width / 2 - 1;
     foreach ($this->columns as $i => $col_string) {
         if ($this->column_heading_vertical) {
             $x = $this->i['left_start'] + $i * $table_item_width + $table_identifier_offset;
             $y = $this->i['top_heading_height'] + $top_identifier_height - 4;
             $this->svg_dom->add_text_element($col_string, array('x' => $x, 'y' => $y, 'font-size' => $this->i['identifier_size'], 'fill' => self::$c['color']['text'], 'font-weight' => 'bold', 'text-anchor' => 'end', 'transform' => 'rotate(90 ' . $x . ' ' . $y . ')'));
         } else {
             $x = $this->i['left_start'] + $i * $table_item_width + $table_item_width / 2;
             $y = $this->i['top_heading_height'] + $top_identifier_height / 2;
             $this->svg_dom->add_text_element($col_string, array('x' => $x, 'y' => $y, 'font-size' => $this->i['identifier_size'], 'fill' => self::$c['color']['text'], 'font-weight' => 'bold', 'text-anchor' => 'middle', 'dominant-baseline' => 'text-before-edge'));
         }
     }
     // Write the columns
     foreach ($this->table_data as $index => &$table_values) {
         if (!is_array($table_values)) {
             // TODO: determine why sometimes $table_values is empty or not an array
             continue;
         }
         if ($this->is_multi_way && ($c = strpos($index, ':')) !== false) {
             $index = substr($index, $c + 1);
         }
         $col = array_search(strval($index), $this->columns);
         if ($col === false) {
             continue;
         } else {
             // unset this since it shouldn't be needed anymore and will then wipe out it from where multiple results have same name
             unset($this->columns[$col]);
         }
         foreach ($table_values as $i => &$result_table_value) {
             $row = $i - 1;
             // if using $row, the alignment may be off sometimes
             $hover = array();
             $text_color = self::$c['color']['text'];
             $bold = false;
             if ($result_table_value == null) {
                 continue;
             }
             if ($result_table_value instanceof pts_graph_ir_value) {
                 if (($t = $result_table_value->get_attribute('std_percent')) > 0) {
                     array_push($hover, 'STD Dev: ' . $t . '%');
                 }
                 if (($t = $result_table_value->get_attribute('std_error')) != 0) {
                     array_push($hover, ' STD Error: ' . $t);
                 }
                 if (defined('PHOROMATIC_TRACKER') && ($t = $result_table_value->get_attribute('delta')) != 0) {
                     $bold = true;
                     $text_color = $t < 0 ? self::$c['color']['alert'] : self::$c['color']['headers'];
                     array_push($hover, ' Change: ' . pts_math::set_precision(100 * $t, 2) . '%');
                 } else {
                     if ($result_table_value->get_attribute('highlight') == true) {
                         $text_color = self::$c['color']['highlight'];
                     } else {
                         if ($result_table_value->get_attribute('alert') == true) {
                             $text_color = self::$c['color']['alert'];
                         }
                     }
                 }
                 $value = $result_table_value->get_value();
                 $spans_col = $result_table_value->get_attribute('spans_col');
             } else {
                 $value = $result_table_value;
                 $spans_col = 1;
             }
             $left_bounds = $this->i['left_start'] + $col * $table_item_width;
             $right_bounds = $this->i['left_start'] + ($col + max(1, $spans_col)) * $table_item_width;
             if ($spans_col > 1) {
                 if ($col == 1) {
                     $background_paint = $i % 2 == 1 ? self::$c['color']['background'] : self::$c['color']['body'];
                 } else {
                     $background_paint = $i % 2 == 0 ? self::$c['color']['body_light'] : self::$c['color']['body'];
                 }
                 $y = round($this->i['top_heading_height'] + $top_identifier_height + ($row + 1) * $table_line_height);
                 $this->svg_dom->add_element('rect', array('x' => $left_bounds, 'y' => $y + 1, 'width' => $right_bounds - $left_bounds, 'height' => $table_line_height, 'fill' => $background_paint));
             }
             $x = $left_bounds + ($right_bounds - $left_bounds) / 2;
             $this->svg_dom->add_text_element($result_table_value, array('x' => $x, 'y' => round($this->i['top_heading_height'] + $top_identifier_height + ($row + 2) * $table_line_height - 3), 'font-size' => $this->i['identifier_size'], 'fill' => $text_color, 'text-anchor' => 'middle', 'xlink:title' => implode('; ', $hover), 'xlink:href' => $result_table_value->get_attribute('href')));
             //$row++;
         }
     }
     //$this->svg_dom->draw_svg_line(($table_columns_end / 2), ($top_identifier_height + $this->i['top_heading_height']), round($table_columns_end / 2), $this->i['graph_height'], self::$c['color']['border'], $table_columns_end, array('stroke-dasharray' => '1,' . ($table_line_height - 1)));
     $this->svg_dom->draw_svg_line(round($table_columns_end / 2), $top_identifier_height + $this->i['top_heading_height'], round($table_columns_end / 2), $table_proper_height, self::$c['color']['body_light'], $table_columns_end, array('stroke-dasharray' => 1 . ',' . ($table_line_height - 1)));
     // Bottom part
     $this->svg_dom->add_element('rect', array('x' => 0, 'y' => $table_proper_height, 'width' => $this->i['graph_width'], 'height' => $this->i['graph_height'] - $table_proper_height, 'fill' => self::$c['color']['headers']));
     $this->svg_dom->add_text_element(self::$c['text']['watermark'], array('x' => $this->i['graph_width'] - 2, 'y' => $this->i['graph_height'] - 3, 'font-size' => $this->i['identifier_size'], 'fill' => self::$c['color']['body_text'], 'text-anchor' => 'end', 'xlink:show' => 'new', 'xlink:href' => self::$c['text']['watermark_url']));
     if (isset($this->d['link_alternate_view']) && $this->d['link_alternate_view']) {
         $this->svg_dom->add_text_element(0, array('x' => 6, 'y' => $this->i['graph_height'] - 3, 'font-size' => 7, 'fill' => self::$c['color']['background'], 'text-anchor' => 'start', 'xlink:show' => 'new', 'xlink:href' => $this->d['link_alternate_view'], 'show' => 'replace', 'font-weight' => 'bold'));
     }
     if (!empty($this->i['notes'])) {
         $estimated_height = 0;
         $previous_section = null;
         foreach ($this->i['notes'] as $i => $note_r) {
             if ($note_r['section'] != null && $note_r['section'] !== $previous_section) {
                 $estimated_height += 2;
                 $this->svg_dom->add_textarea_element($note_r['section'] . ' Details', array('x' => 6, 'y' => $table_proper_height + $table_line_height + $estimated_height, 'font-size' => self::$c['size']['key'] - 1, 'fill' => self::$c['color']['background'], 'text-anchor' => 'start', 'xlink:title' => $note_r['hover-title'], 'style' => 'font-weight: bold'), $estimated_height);
                 $estimated_height += 2;
                 $previous_section = $note_r['section'];
             }
             $this->svg_dom->add_textarea_element('- ' . $note_r['note'], array('x' => 6, 'y' => $table_proper_height + $table_line_height + $estimated_height, 'font-size' => self::$c['size']['key'] - 1, 'fill' => self::$c['color']['background'], 'text-anchor' => 'start', 'xlink:title' => $note_r['hover-title']), $estimated_height);
         }
     }
     $this->rendered_rows = $row;
 }