This repository has been archived by the owner on Nov 10, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
SVGGraphPie3DGraph.php
153 lines (138 loc) · 5.11 KB
/
SVGGraphPie3DGraph.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
<?php
/**
* Copyright (C) 2010-2014 Graham Breach
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* For more information, please contact <[email protected]>
*/
require_once 'SVGGraphPieGraph.php';
class Pie3DGraph extends PieGraph {
protected function Draw()
{
// modify pad_bottom to make PieGraph do the hard work
$pb = $this->pad_bottom;
$space = $this->height - $this->pad_top - $this->pad_bottom;
if($space < $this->depth)
$this->depth = $space / 2;
$this->pad_bottom += $this->depth;
$this->Calc();
$this->pad_bottom = $pb;
return PieGraph::Draw();
}
/**
* Override the parent to draw 3D slice
*/
protected function GetSlice($item, $angle_start, $angle_end, $radius_x,
$radius_y, &$attr, $single_slice)
{
$x_start = $y_start = $x_end = $y_end = 0;
$angle_start += $this->s_angle;
$angle_end += $this->s_angle;
$this->CalcSlice($angle_start, $angle_end, $radius_x, $radius_y,
$x_start, $y_start, $x_end, $y_end);
$outer = $angle_end - $angle_start > M_PI ? 1 : 0;
$sweep = $this->reverse ? 0 : 1;
$side_start = $this->reverse ? M_PI : M_PI * 2;
$side_end = $this->reverse ? M_PI * 2 : M_PI;
$path = '';
$angle_start_lower = $this->LowerHalf($angle_start);
$angle_end_lower = $this->LowerHalf($angle_end);
// cope with the lower half filled exactly
if($single_slice ||
($this->reverse && $angle_start == M_PI && $angle_end == M_PI * 2) ||
(!$this->reverse && $angle_start == 0 && $angle_end == M_PI)) {
$angle_end_lower = $angle_start_lower = true;
}
if($angle_start_lower || $angle_end_lower || $outer) {
if($angle_start_lower && $angle_end_lower && $outer) {
// if this is a big slice with both sides at bottom, need 2 edges
$path .= $this->GetEdge($angle_start, $side_end, $radius_x, $radius_y);
$path .= $this->GetEdge($side_start, $angle_end, $radius_x, $radius_y);
} else {
// if an edge is in the top half, need to truncate to x-radius
$angle_start_trunc = $angle_start_lower ? $angle_start : $side_start;
$angle_end_trunc = $angle_end_lower ? $angle_end : $side_end;
$path .= $this->GetEdge($angle_start_trunc, $angle_end_trunc, $radius_x, $radius_y);
}
}
if($single_slice) {
$attr_path = array('d' => $path);
$attr_ellipse = array(
'cx' => $this->x_centre, 'cy' => $this->y_centre,
'rx' => $radius_x, 'ry' => $radius_y
);
return $this->Element('g', $attr, NULL,
$this->Element('path', $attr_path) .
$this->Element('ellipse', $attr_ellipse));
} else {
$outer = ($angle_end - $angle_start > M_PI ? 1 : 0);
$sweep = ($this->reverse ? 0 : 1);
$attr['d'] = $path . "M{$this->x_centre},{$this->y_centre} " .
"L$x_start,$y_start A{$radius_x} {$radius_y} 0 " .
"$outer,$sweep $x_end,$y_end z";
return $this->Element('path', $attr);
}
}
/**
* Returns the path for an edge
*/
protected function GetEdge($angle_start, $angle_end, $radius_x, $radius_y,
$double_curve = false)
{
$x_start = $y_start = $x_end = $y_end = 0;
$this->CalcSlice($angle_start, $angle_end, $radius_x, $radius_y,
$x_start, $y_start, $x_end, $y_end);
$y_end_depth = $y_end + $this->depth;
$outer = 0; // edge is never > PI
$sweep = $this->reverse ? 0 : 1;
$path = "M$x_start,$y_start v{$this->depth} " .
"A{$radius_x} {$radius_y} 0 " .
"$outer,$sweep $x_end,$y_end_depth v-{$this->depth} ";
if($double_curve) {
$sweep = $sweep ? 0 : 1;
$path .= "A{$radius_x} {$radius_y} 0 " .
"$outer,$sweep $x_start,$y_start ";
}
return $path;
}
/**
* Returns TRUE if the angle is in the lower half of the pie
*/
protected function LowerHalf($angle)
{
$angle = fmod($angle, M_PI * 2);
return ($this->reverse && $angle > M_PI && $angle < M_PI * 2) ||
(!$this->reverse && $angle < M_PI && $angle > 0);
}
/**
* Overlays the gradient on the pie sides
*/
protected function PieExtras()
{
$overlay = '';
if(is_array($this->depth_shade_gradient)) {
$gradient_id = $this->AddGradient($this->depth_shade_gradient);
$start = $this->reverse ? M_PI : M_PI * 2;
$end = $this->reverse ? M_PI * 2 : M_PI;
$bottom = array(
'd' => $this->GetEdge($start, $end, $this->radius_x, $this->radius_y, true),
'fill' => "url(#{$gradient_id})"
);
$overlay = $this->Element('path', $bottom);
}
return $overlay;
}
}