/** * Draws a label */ protected function DrawLabel($dataset, $index, &$gobject) { if (is_null($gobject['item']) && empty($gobject['content'])) { return ''; } if (is_null($gobject['item'])) { // convert to string - numbers will confuse TextSize() $content = (string) $gobject['content']; } else { if (is_callable($this->data_label_callback)) { $content = call_user_func($this->data_label_callback, $dataset, $gobject['item']->key, $gobject['item']->value); if (is_null($content)) { $content = ''; } } else { $content = $gobject['item']->Data('label'); } if (is_null($content)) { $content = !is_null($gobject['content']) ? $gobject['content'] : $this->units_before_label . Graph::NumString($gobject['item']->value) . $this->units_label; } } if ($content == '') { return ''; } $style = $this->graph->DataLabelStyle($dataset, $index, $gobject['item']); if (!is_null($gobject['item'])) { $this->ItemStyles($style, $gobject['item']); } elseif ($dataset === '_user') { $this->UserStyles($style, $gobject); } $type = $style['type']; $font_size = max(4, (double) $style['font_size']); $space = (double) $style['space']; if ($type == 'box' || $type == 'bubble') { $label_pad_x = $style['pad_x']; $label_pad_y = $style['pad_y']; } else { $label_pad_x = $label_pad_y = 0; } // reasonable approximation of the baseline position $text_baseline = $font_size * 0.85; // get size of label list($tw, $th) = Graph::TextSize($content, $font_size, $style['font_adjust'], $this->encoding, $style['angle'], $font_size); $label_w = $tw + $label_pad_x * 2; $label_h = $th + $label_pad_y * 2; $label_wp = $label_w + $space * 2; $label_hp = $label_h + $space * 2; $pos = NULL; if ($dataset === '_user') { // user label, so convert coordinates $pos = isset($gobject['position']) ? $gobject['position'] : 'above'; $xy = $this->coords->TransformCoords($gobject['x'], $gobject['y']); $gobject['x'] = $xy[0]; $gobject['y'] = $xy[1]; } else { // try to get position from item if (!is_null($gobject['item'])) { $pos = $gobject['item']->Data('data_label_position'); } // find out from graph class where this label should go if (is_null($pos)) { $pos = $this->graph->DataLabelPosition($dataset, $index, $gobject['item'], $gobject['x'], $gobject['y'], $gobject['width'], $gobject['height'], $label_wp, $label_hp); } } // convert position string to an actual location list($x, $y, $anchor, $hpos, $vpos) = $res = Graph::RelativePosition($pos, $gobject['y'], $gobject['x'], $gobject['y'] + $gobject['height'], $gobject['x'] + $gobject['width'], $label_w, $label_h, $space, true); // if the position is outside, use the alternative colours $colour = $style['colour']; $back_colour = $style['back_colour']; if (strpos($hpos . $vpos, 'o') !== FALSE) { if (!empty($style['altcolour'])) { $colour = $style['altcolour']; } if (!empty($style['back_altcolour'])) { $back_colour = $style['back_altcolour']; } } $text = array('font-family' => $style['font'], 'font-size' => $font_size, 'fill' => $colour); $label_markup = ''; // rotation if ($style['angle'] != 0) { // need text size pre-rotation list($tbw, $tbh) = Graph::TextSize($content, $font_size, $style['font_adjust'], $this->encoding, 0, $font_size); if ($anchor == 'middle') { $text['x'] = $x; } elseif ($anchor == 'start') { $text['x'] = $x + $label_pad_x + ($tw - $tbw) / 2; } else { $text['x'] = $x - $label_pad_x - ($tw - $tbw) / 2; } $text['y'] = $y + $label_h / 2 - $tbh / 2 + $text_baseline; } else { if ($anchor == 'start') { $text['x'] = $x + $label_pad_x; } elseif ($anchor == 'end') { $text['x'] = $x - $label_pad_x; } else { $text['x'] = $x; } $text['y'] = $y + $label_pad_y + $text_baseline; } // make x right for bounding box if ($anchor == 'middle') { $x -= $label_w / 2; } elseif ($anchor == 'end') { $x -= $label_w; } if ($style['angle'] != 0) { // rotate text around centre of box $rx = $x + $label_w / 2; $ry = $y + $label_h / 2; $text['transform'] = "rotate({$style['angle']},{$rx},{$ry})"; /** DEBUG: text position and rotation point $label_markup .= $this->graph->Element('circle', array('cx' => $text['x'], 'cy' => $text['y'], 'r' => 2, 'fill' => '#f0f')); $label_markup .= $this->graph->Element('circle', array('cx' => $rx, 'cy' => $ry, 'r' => 2)); **/ } if ($anchor != 'start') { $text['text-anchor'] = $anchor; } if (!empty($style['font_weight']) && $style['font_weight'] != 'normal') { $text['font-weight'] = $style['font_weight']; } $surround = array(); $element = null; if ($type == 'box') { $element = $this->BoxLabel($x, $y, $label_w, $label_h, $style, $surround); } elseif ($type == 'bubble') { $style['tail_direction'] = $this->graph->DataLabelTailDirection($dataset, $index, $hpos, $vpos); $element = $this->BubbleLabel($x, $y, $label_w, $label_h, $style, $surround); } elseif ($type == 'line') { $style['tail_direction'] = $this->graph->DataLabelTailDirection($dataset, $index, $hpos, $vpos); $element = $this->LineLabel($x, $y, $label_w, $label_h, $style, $surround); } // if there is a box or bubble, draw it if ($element) { $surround['stroke'] = $style['stroke']; if ($style['stroke_width'] != 1) { $surround['stroke-width'] = (double) $style['stroke_width']; } // add shadow if not completely transparent if ($style['shadow_opacity'] > 0) { $shadow = $surround; $offset = 2 + floor($style['stroke_width'] / 2); $shadow['transform'] = "translate({$offset},{$offset})"; $shadow['fill'] = $shadow['stroke'] = '#000'; $shadow['opacity'] = $style['shadow_opacity']; $label_markup .= $this->graph->Element($element, $shadow); } $label_markup .= $this->graph->Element($element, $surround); } if (!empty($back_colour)) { $outline = array('stroke-width' => '3px', 'stroke' => $back_colour, 'stroke-linejoin' => 'round'); $t1 = array_merge($outline, $text); $label_markup .= $this->graph->Text($content, $font_size, $t1); } $label_markup .= $this->graph->Text($content, $font_size, $text); $group = array(); if (isset($gobject['id']) && !is_null($gobject['id'])) { $group['id'] = $gobject['id']; } // start off hidden? if ($gobject['click'] == 'show') { $group['opacity'] = 1; } elseif ($gobject['click'] == 'hide' || $gobject['fade']) { $group['opacity'] = 0; } $label_markup = $this->graph->Element('g', $group, NULL, $label_markup); return $label_markup; }