1 | <?php |
||
2 | |||
3 | /** |
||
4 | * Echoes an image tag of Google Charts map from sorted array of 'country_code' => 'number of visits' (sort by DESC) |
||
5 | * |
||
6 | */ |
||
7 | function yourls_stats_countries_map( $countries, $id = null ) { |
||
8 | |||
9 | yourls_do_action( 'pre_stats_countries_map' ); |
||
10 | |||
11 | // if $id is null then assign a random string |
||
12 | if( $id === null ) |
||
13 | $id = uniqid ( 'yourls_stats_map_' ); |
||
14 | |||
15 | $data = array_merge( array( 'Country' => 'Hits' ), $countries ); |
||
16 | $data = yourls_google_array_to_data_table( $data ); |
||
17 | |||
18 | $options = array( |
||
19 | 'backgroundColor' => "white", |
||
20 | 'colorAxis' => "{colors:['A8D0ED','99C4E4','8AB8DB','7BACD2','6BA1C9','5C95C0','4D89B7','3E7DAE','2E72A5','1F669C']}", |
||
21 | 'width' => "550", |
||
22 | 'height' => "340", |
||
23 | 'theme' => 'maximized' |
||
24 | ); |
||
25 | $options = yourls_apply_filter( 'stats_countries_map_options', $options ); |
||
26 | |||
27 | $map = yourls_google_viz_code( 'GeoChart', $data, $options, $id ); |
||
28 | |||
29 | echo yourls_apply_filter( 'stats_countries_map', $map, $countries, $options, $id ); |
||
30 | } |
||
31 | |||
32 | /** |
||
33 | * Echoes an image tag of Google Charts pie from sorted array of 'data' => 'value' (sort by DESC). Optional $limit = (integer) limit list of X first countries, sorted by most visits |
||
34 | * |
||
35 | */ |
||
36 | function yourls_stats_pie( $data, $limit = 10, $size = '340x220', $id = null ) { |
||
37 | |||
38 | yourls_do_action( 'pre_stats_pie' ); |
||
39 | |||
40 | // if $id is null then assign a random string |
||
41 | if( $id === null ) |
||
42 | $id = uniqid ( 'yourls_stats_pie_' ); |
||
43 | |||
44 | // Trim array: $limit first item + the sum of all others |
||
45 | if ( count( $data ) > $limit ) { |
||
46 | $i= 0; |
||
47 | $trim_data = array( 'Others' => 0 ); |
||
48 | foreach( $data as $item=>$value ) { |
||
49 | $i++; |
||
50 | if( $i <= $limit ) { |
||
51 | $trim_data[$item] = $value; |
||
52 | } else { |
||
53 | $trim_data['Others'] += $value; |
||
54 | } |
||
55 | } |
||
56 | $data = $trim_data; |
||
57 | } |
||
58 | |||
59 | // Scale items |
||
60 | $_data = yourls_scale_data( $data ); |
||
61 | |||
62 | list($width, $height) = explode( 'x', $size ); |
||
63 | |||
64 | $options = array( |
||
65 | 'theme' => 'maximized', |
||
66 | 'width' => $width, |
||
67 | 'height' => $height, |
||
68 | 'colors' => "['A8D0ED','99C4E4','8AB8DB','7BACD2','6BA1C9','5C95C0','4D89B7','3E7DAE','2E72A5','1F669C']", |
||
69 | 'legend' => 'none', |
||
70 | 'chartArea' => '{top: "5%", height: "90%"}', |
||
71 | 'pieSliceText' => 'label', |
||
72 | ); |
||
73 | $options = yourls_apply_filter( 'stats_pie_options', $options ); |
||
74 | |||
75 | $script_data = array_merge( array( 'Country' => 'Value' ), $_data ); |
||
76 | $script_data = yourls_google_array_to_data_table( $script_data ); |
||
77 | |||
78 | $pie = yourls_google_viz_code( 'PieChart', $script_data, $options, $id ); |
||
79 | |||
80 | echo yourls_apply_filter( 'stats_pie', $pie, $data, $limit, $size, $options, $id ); |
||
81 | } |
||
82 | |||
83 | /** |
||
84 | * Build a list of all daily values between d1/m1/y1 to d2/m2/y2. |
||
85 | * |
||
86 | */ |
||
87 | function yourls_build_list_of_days( $dates ) { |
||
88 | /* Say we have an array like: |
||
0 ignored issues
–
show
Coding Style
introduced
by
Loading history...
|
|||
89 | $dates = array ( |
||
90 | 2009 => array ( |
||
91 | '08' => array ( |
||
92 | 29 => 15, |
||
93 | 30 => 5, |
||
94 | ), |
||
95 | '09' => array ( |
||
96 | '02' => 3, |
||
97 | '03' => 5, |
||
98 | '04' => 2, |
||
99 | '05' => 99, |
||
100 | ), |
||
101 | ), |
||
102 | ) |
||
103 | */ |
||
104 | |||
105 | if( !$dates ) |
||
106 | return array(); |
||
107 | |||
108 | // Get first & last years from our range. In our example: 2009 & 2009 |
||
109 | $first_year = key( $dates ); |
||
110 | $_keys = array_keys( $dates ); |
||
111 | $last_year = end( $_keys ); |
||
112 | reset( $dates ); |
||
113 | |||
114 | // Get first & last months from our range. In our example: 08 & 09 |
||
115 | $first_month = key( $dates[ $first_year ] ); |
||
116 | $_keys = array_keys( $dates[ $last_year ] ); |
||
117 | $last_month = end( $_keys ); |
||
118 | reset( $dates ); |
||
119 | |||
120 | // Get first & last days from our range. In our example: 29 & 05 |
||
121 | $first_day = key( $dates[ $first_year ][ $first_month ] ); |
||
122 | $_keys = array_keys( $dates[ $last_year ][ $last_month ] ); |
||
123 | $last_day = end( $_keys ); |
||
124 | |||
125 | unset( $_keys ); |
||
126 | |||
127 | // Now build a list of all years (2009), month (08 & 09) and days (all from 2009-08-29 to 2009-09-05) |
||
128 | $list_of_years = array(); |
||
129 | $list_of_months = array(); |
||
130 | $list_of_days = array(); |
||
131 | for ( $year = $first_year; $year <= $last_year; $year++ ) { |
||
132 | $_year = sprintf( '%04d', $year ); |
||
133 | $list_of_years[ $_year ] = $_year; |
||
134 | $current_first_month = ( $year == $first_year ? $first_month : '01' ); |
||
135 | $current_last_month = ( $year == $last_year ? $last_month : '12' ); |
||
136 | for ( $month = $current_first_month; $month <= $current_last_month; $month++ ) { |
||
137 | $_month = sprintf( '%02d', $month ); |
||
138 | $list_of_months[ $_month ] = $_month; |
||
139 | $current_first_day = ( $year == $first_year && $month == $first_month ? $first_day : '01' ); |
||
140 | $current_last_day = ( $year == $last_year && $month == $last_month ? $last_day : yourls_days_in_month( $month, $year) ); |
||
141 | for ( $day = $current_first_day; $day <= $current_last_day; $day++ ) { |
||
142 | $day = sprintf( '%02d', $day ); |
||
143 | $key = date( 'M d, Y', mktime( 0, 0, 0, $_month, $day, $_year ) ); |
||
144 | $list_of_days[ $key ] = isset( $dates[$_year][$_month][$day] ) ? $dates[$_year][$_month][$day] : 0; |
||
145 | } |
||
146 | } |
||
147 | } |
||
148 | |||
149 | return array( |
||
150 | 'list_of_days' => $list_of_days, |
||
151 | 'list_of_months' => $list_of_months, |
||
152 | 'list_of_years' => $list_of_years, |
||
153 | ); |
||
154 | } |
||
155 | |||
156 | /** |
||
157 | * Echoes an image tag of Google Charts line graph from array of values (eg 'number of clicks'). |
||
158 | * |
||
159 | * $legend1_list & legend2_list are values used for the 2 x-axis labels. $id is an HTML/JS id |
||
160 | * |
||
161 | */ |
||
162 | function yourls_stats_line( $values, $id = null ) { |
||
163 | |||
164 | yourls_do_action( 'pre_stats_line' ); |
||
165 | |||
166 | // if $id is null then assign a random string |
||
167 | if( $id === null ) |
||
168 | $id = uniqid ( 'yourls_stats_line_' ); |
||
169 | |||
170 | // If we have only 1 day of data, prepend a fake day with 0 hits for a prettier graph |
||
171 | if ( count( $values ) == 1 ) |
||
172 | array_unshift( $values, 0 ); |
||
173 | |||
174 | // Keep only a subset of values to keep graph smooth |
||
175 | $values = yourls_array_granularity( $values, 30 ); |
||
176 | |||
177 | $data = array_merge( array( 'Time' => 'Hits' ), $values ); |
||
178 | $data = yourls_google_array_to_data_table( $data ); |
||
179 | |||
180 | $options = array( |
||
181 | "legend" => "none", |
||
182 | "pointSize" => "3", |
||
183 | "theme" => "maximized", |
||
184 | "curveType" => "function", |
||
185 | "width" => 430, |
||
186 | "height" => 220, |
||
187 | "hAxis" => "{minTextSpacing: 80, maxTextLines: 1, maxAlternation: 1}", |
||
188 | "vAxis" => "{minValue: 0, format: '#'}", |
||
189 | "colors" => "['#2a85b3']", |
||
190 | ); |
||
191 | $options = yourls_apply_filter( 'stats_line_options', $options ); |
||
192 | |||
193 | $lineChart = yourls_google_viz_code( 'LineChart', $data, $options, $id ); |
||
194 | |||
195 | echo yourls_apply_filter( 'stats_line', $lineChart, $values, $options, $id ); |
||
196 | } |
||
197 | |||
198 | /** |
||
199 | * Return the number of days in a month. From php.net, used if PHP built without calendar functions |
||
200 | * |
||
201 | */ |
||
202 | function yourls_days_in_month( $month, $year ) { |
||
203 | // calculate number of days in a month |
||
204 | return $month == 2 ? ( $year % 4 ? 28 : ( $year % 100 ? 29 : ( $year % 400 ? 28 : 29 ) ) ) : ( ( $month - 1 ) % 7 % 2 ? 30 : 31 ); |
||
205 | } |
||
206 | |||
207 | /** |
||
208 | * Get max value from date array of 'Aug 12, 2012' = '1337' |
||
209 | * |
||
210 | */ |
||
211 | function yourls_stats_get_best_day( $list_of_days ) { |
||
212 | $max = max( $list_of_days ); |
||
213 | foreach( $list_of_days as $k=>$v ) { |
||
214 | if ( $v == $max ) |
||
215 | return array( 'day' => $k, 'max' => $max ); |
||
216 | } |
||
217 | } |
||
218 | |||
219 | /** |
||
220 | * Return domain of a URL |
||
221 | * |
||
222 | */ |
||
223 | function yourls_get_domain( $url, $include_scheme = false ) { |
||
224 | $parse = @parse_url( $url ); // Hiding ugly stuff coming from malformed referrer URLs |
||
225 | |||
226 | // Get host & scheme. Fall back to path if not found. |
||
227 | $host = isset( $parse['host'] ) ? $parse['host'] : ''; |
||
228 | $scheme = isset( $parse['scheme'] ) ? $parse['scheme'] : ''; |
||
229 | $path = isset( $parse['path'] ) ? $parse['path'] : ''; |
||
230 | if( !$host ) |
||
231 | $host = $path; |
||
232 | |||
233 | if ( $include_scheme && $scheme ) |
||
234 | $host = $scheme.'://'.$host; |
||
235 | |||
236 | return $host; |
||
237 | } |
||
238 | |||
239 | /** |
||
240 | * Return favicon URL |
||
241 | * |
||
242 | */ |
||
243 | function yourls_get_favicon_url( $url ) { |
||
244 | return yourls_match_current_protocol( '//www.google.com/s2/favicons?domain=' . yourls_get_domain( $url, false ) ); |
||
245 | } |
||
246 | |||
247 | /** |
||
248 | * Scale array of data from 0 to 100 max |
||
249 | * |
||
250 | */ |
||
251 | function yourls_scale_data( $data ) { |
||
252 | $max = max( $data ); |
||
253 | if( $max > 100 ) { |
||
254 | foreach( $data as $k=>$v ) { |
||
255 | $data[$k] = intval( $v / $max * 100 ); |
||
256 | } |
||
257 | } |
||
258 | return $data; |
||
259 | } |
||
260 | |||
261 | /** |
||
262 | * Tweak granularity of array $array: keep only $grain values. This make less accurate but less messy graphs when too much values. See http://code.google.com/apis/chart/formats.html#granularity |
||
263 | * |
||
264 | */ |
||
265 | function yourls_array_granularity( $array, $grain = 100, $preserve_max = true ) { |
||
266 | if ( count( $array ) > $grain ) { |
||
267 | $max = max( $array ); |
||
268 | $step = intval( count( $array ) / $grain ); |
||
269 | $i = 0; |
||
270 | // Loop through each item and unset except every $step (optional preserve the max value) |
||
271 | foreach( $array as $k=>$v ) { |
||
272 | $i++; |
||
273 | if ( $i % $step != 0 ) { |
||
274 | if ( $preserve_max == false ) { |
||
275 | unset( $array[$k] ); |
||
276 | } else { |
||
277 | if ( $v < $max ) |
||
278 | unset( $array[$k] ); |
||
279 | } |
||
280 | } |
||
281 | } |
||
282 | } |
||
283 | return $array; |
||
284 | } |
||
285 | |||
286 | /** |
||
287 | * Transform data array to data table for Google API |
||
288 | * |
||
289 | */ |
||
290 | function yourls_google_array_to_data_table( $data ){ |
||
291 | $str = "var data = google.visualization.arrayToDataTable([\n"; |
||
292 | foreach( $data as $label => $values ){ |
||
293 | if( !is_array( $values ) ) { |
||
294 | $values = array( $values ); |
||
295 | } |
||
296 | $str .= "\t['$label',"; |
||
297 | foreach( $values as $value ){ |
||
298 | if( !is_numeric( $value ) && strpos( $value, '[' ) !== 0 && strpos( $value, '{' ) !== 0 ) { |
||
299 | $value = "'$value'"; |
||
300 | } |
||
301 | $str .= "$value"; |
||
302 | } |
||
303 | $str .= "],\n"; |
||
304 | } |
||
305 | $str = substr( $str, 0, -2 ) . "\n"; // remove the trailing comma/return, reappend the return |
||
306 | $str .= "]);\n"; // wrap it up |
||
307 | return $str; |
||
308 | } |
||
309 | |||
310 | /** |
||
311 | * Return javascript code that will display the Google Chart |
||
312 | * |
||
313 | */ |
||
314 | function yourls_google_viz_code( $graph_type, $data, $options, $id ) { |
||
315 | $function_name = 'yourls_graph' . $id; |
||
316 | $code = "\n<script id=\"$function_name\" type=\"text/javascript\">\n"; |
||
317 | $code .= "function $function_name() { \n"; |
||
318 | |||
319 | $code .= "$data\n"; |
||
320 | |||
321 | $code .= "var options = {\n"; |
||
322 | foreach( $options as $field => $value ) { |
||
323 | if( !is_numeric( $value ) && strpos( $value, '[' ) !== 0 && strpos( $value, '{' ) !== 0 ) { |
||
324 | $value = "\"$value\""; |
||
325 | } |
||
326 | $code .= "\t'$field': $value,\n"; |
||
327 | } |
||
328 | $code = substr( $code, 0, -2 ) . "\n"; // remove the trailing comma/return, reappend the return |
||
329 | $code .= "\t}\n"; |
||
330 | |||
331 | $code .= "new google.visualization.$graph_type( document.getElementById('visualization_$id') ).draw( data, options );"; |
||
332 | $code .= "}\n"; |
||
333 | $code .= "google.setOnLoadCallback( $function_name );\n"; |
||
334 | $code .= "</script>\n"; |
||
335 | $code .= "<div id=\"visualization_$id\"></div>\n"; |
||
336 | |||
337 | return $code; |
||
338 | } |
||
339 | |||
340 |