From e1841e6108570cb3908d60f85d68fc3dc5b3f393 Mon Sep 17 00:00:00 2001 From: Osmisto Date: Sat, 1 Sep 2012 15:23:05 -0500 Subject: [PATCH] new feature: banners, small images with status of the cake, that can be embedded --- app/refresher.php | 19 ++ configs/nginx.conf.devenv | 10 + lib/drawers/progress1.php | 111 ++++++++ lib/drawers/progress1.svg | 521 ++++++++++++++++++++++++++++++++++ lib/update_kml.php | 6 + static/banner/.gitignore | 2 + static/img/progress1-demo.png | Bin 0 -> 12517 bytes 7 files changed, 669 insertions(+) create mode 100644 app/refresher.php create mode 100644 lib/drawers/progress1.php create mode 100644 lib/drawers/progress1.svg create mode 100644 static/banner/.gitignore create mode 100644 static/img/progress1-demo.png diff --git a/app/refresher.php b/app/refresher.php new file mode 100644 index 0000000..887db87 --- /dev/null +++ b/app/refresher.php @@ -0,0 +1,19 @@ +getMessage(); + } +?> \ No newline at end of file diff --git a/configs/nginx.conf.devenv b/configs/nginx.conf.devenv index 54e7c4b..f0072db 100644 --- a/configs/nginx.conf.devenv +++ b/configs/nginx.conf.devenv @@ -55,5 +55,15 @@ ${NGINX_CONF_MODS} proxy_buffering off; proxy_read_timeout 3600; } + + location /banner/ { + root ${SRC_ROOT}/static; + try_files $uri @refresher; + } + + location @refresher { + rewrite ^/banner/(.*)$ /app/refresher.php/?q=$1 last; + proxy_pass http://127.0.0.1:${HTTPD_PORT}; + } } } diff --git a/lib/drawers/progress1.php b/lib/drawers/progress1.php new file mode 100644 index 0000000..7f963a7 --- /dev/null +++ b/lib/drawers/progress1.php @@ -0,0 +1,111 @@ + array('621a1a', 'c43636'), + 'middle' => array('774600', 'd17b00'), + 'high' => array('00221a', '006e5a')); + + +function draw($pie_id, $base_name, $ext, $args) { + if (!in_array($ext, array('png', 'svg'))) + throw new Exception("Selected banner type does not support output extension '$ext'"); + + // Firstly draw svg. We need it either way + $svg_output = draw_svg($pie_id, $base_name, $args); + + if ($ext == 'svg') { + header("Content-type: image/svg+xml;"); + readfile($svg_output); + exit; + } + + if ($ext == 'png') { + $png_output = convert_to_png($svg_output, $base_name); + header("Content-type: image/png;"); + readfile($png_output); + exit; + } +} + +function draw_svg($pie_id, $base_name, $args) { + global $output_dir; + global $svg_template; + global $bg_schemes; + + $bar_start = 59.4; + $bar_end = 383.9; + $bar_len = $bar_end - $bar_start; + + $svg_output = $output_dir . $base_name . '.svg'; + if (file_exists($svg_output)) + return $svg_output; + + // Parse + $xdoc = new DomDocument; + $xdoc->Load($svg_template); + $xp = new DomXPath($xdoc); + + // Get progress from DB + $result = pg_query("SELECT state FROM pieces WHERE pie = " . $pie_id); + $states = pg_fetch_all_columns($result, 0); + $progress = array(0,0,0,0,0,0,0,0,0,0); + $full_sum = 9 * count($states); + $current_sum = 0; + foreach ($states as $st) { + $progress[$st] ++; + $current_sum += $st; + } + + // Calculate bars positions and widths + $offset = $bar_start; + $step = $bar_len / count($states); + for ($i = 0 ; $i <= 9; $i++ ) { + $elem = find_by_id($xp, 'bar_' . $i); + $elem->setAttribute('x', $offset); + $elem->setAttribute('width', $step * $progress[$i]); + $offset += $step * $progress[$i]; + } + + // Set percent + $percent = round($current_sum / $full_sum * 100); + find_by_id($xp, 'percent-fg')->nodeValue = $percent . '%'; + + // Set BG color gradient; + $current_bg_scheme = $bg_schemes['middle']; + if ($progress[9] / count($states) > 0.6) { + $current_bg_scheme = $bg_schemes['high']; + } else if ($progress[0] / count($states) > 0.6) { + $current_bg_scheme = $bg_schemes['low']; + } + + find_by_id($xp, 'bg-grd-start')->setAttribute('style', 'stop-color:#' . $current_bg_scheme[0] . ';stop-opacity:1'); + find_by_id($xp, 'bg-grd-stop')->setAttribute('style', 'stop-color:#' . $current_bg_scheme[1] . ';stop-opacity:1'); + + // Save it to file + if (($fd = fopen($svg_output, 'w')) === false) + throw new Exception("Cant open SVG file for saving"); + fwrite($fd, $xdoc->saveXML()); + fclose($fd); + + return $svg_output; +} + +function convert_to_png($svg_input, $base_name) { + global $output_dir; + + $png_output = $output_dir . $base_name . '.png'; + exec("convert $svg_input $png_output"); + + return $png_output; +} + +function find_by_id($xp, $id) { + $item = $xp->query("//*[@id = '$id']")->item(0); + if (empty($item)) + throw new Exception("Cant find element with ID = $id"); + return $item; +} + +?> \ No newline at end of file diff --git a/lib/drawers/progress1.svg b/lib/drawers/progress1.svg new file mode 100644 index 0000000..3de460f --- /dev/null +++ b/lib/drawers/progress1.svg @@ -0,0 +1,521 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 30% + + diff --git a/lib/update_kml.php b/lib/update_kml.php index 7c52023..5eb5e73 100644 --- a/lib/update_kml.php +++ b/lib/update_kml.php @@ -5,6 +5,8 @@ * To Public License, Version 2, as published by Sam Hocevar. See * http://sam.zoy.org/wtfpl/COPYING for more details. */ +$banners_dir = dirname(__FILE__) . '/../static/banner/'; + function update_kml($pie_id) { global $connection; $color = array ("800000ff","800040ff","800060ff","800070ff","800080ff","800090ff","8000b0ff","8000d0ff","8000ffff","8000ff00"); @@ -27,5 +29,9 @@ function update_kml($pie_id) { fwrite($kml, ""); fclose($kml); } + + // Clear banners + global $banners_dir; + exec("rm " . $banners_dir . $pie_id . '-*'); } ?> diff --git a/static/banner/.gitignore b/static/banner/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/static/banner/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/static/img/progress1-demo.png b/static/img/progress1-demo.png new file mode 100644 index 0000000000000000000000000000000000000000..3a33468e42acc9fd753d547212a767bb987f7c18 GIT binary patch literal 12517 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
    Im0UKV~GP;*U%O?}{!$|4@qa;u)AhF zb>Vb$t}y{JD#6ZZ+V=k=9&l-$ih|+~F_J=)9NNMHocdFDzsv;lnom~FsJQXS*q8r+ z0HxP+l5>){G~fvmo1H+VbB$SOiIMmrQjks*PVAE~;L?vrvFBc;{8YkKS}W*!)M)v? zsr?YK`L;M9aTs!ZU058pdMu|tvt~3!bssq%F)|X+tn#|wsPqD(hI(`Hqi}&rBv>vJ>es`2551bM zft1cvX_rmb>{XdkDTPG7Cwd+?K;*pI+|i5ALyE$1`3nMW;Dl78Vj(HP{7k^8^JiIY z%&NI5O9t2mB+q43BgM>}hKIV2W;m^x)0)d$O%g~sx5}jYA|;z3kUmH z?}BO*SAPWI^+6&x7aM{!+rMq(c=ZvK!FCa~N0mk9>8*vl%C=S+YU|D)njewF60l^Mm;qnxqq%h!@5hSpD%bxa=LuDC_6_d4C>`1lrn5$x6XdU=;rv5kw{hB#rR znC|;BH%DiMpCV#cOY2$hH&CTV4a7n0ZFZXXEP`X{p8KNqtdZOWPoIOrcHn9j5gtJB zMlzSbdx1Fwgb0IzOC?O_f%G32Lz{$$L82f34Pw@%2xjA@U${uSv-K;|2V->7IyQ1i zxn4G{d*^}JaTh9ny^lvoG^5W2d0MCcBhVw0FFKwBxTw`0B<_#sJ;k_i#$W;DH2k)| z^Bw_KKc1jF;Pn&pWn<%RF}0K7>9B(f z|DgES>i@3qRR-|}YH{auyn?9kW77Qa1iQsUkRTj3W}^`(CiH@dKd!X2^y(Ud;N#r; zsTY^3GblAI+Du>n4z#lqd5F)t47)VuNeM{>V}Cv~g?e4*kP>Cj%?*)|7n_iy;jLfi z<`)7fptsR2J+eh8>DF^@yeLd5r|_0O&kKPY`6zkNE0EuCi1R|Fa4k+-p6mrZ-7hI$ zo8r=Fjr2^uR7nTq5Ux7WsNuhE|DB5ie%A3lczAS5ZuYP5K{j4hxwqOOu~8#ez3wl@ z9z}tcQ(X|$(OMHG1Ncq&*Z>=*i9#)z33C~LG5uZItOO!+54in7i}?2lSunY(6M8Ee zkl)k$X&0zCE#Pz-9Xstg^PgXMJz;r#m3SSXY4M9#Gw@%B|8R-b-S-^D6&&bey|o_! z>sNehu6;xWdCSZ)pUh)X0ziu%tP z=&o32e8!;sV)1yz<|fe;Z>|RGQizk=t~UIwm_tvOKLhxVlq}2(BTlsKLz%^48bde{ zVJ0(iW3d?-%N|C^_Fe4Z?&8PvXpW0}xiVU%!&D+)wM>`@%p#)yT6J;BZRLrY5_cgg z811%daQTYSjfT~sPMF>Q_W4P59mqY@y%y{6Oi(SjT`j>~Q@jdc;Yk{QBf_s0)Snw1 z{T}V@JdB@bT@?R5)FqZQym8&3HMy_u6HhxQg`+YSpGX4u)w7$fb)26f z(J4qZ6_Y!|I@-p|2Yyq7+0PxhPyP0wdIm4qnF8<%!^}zNG6cd&AMZ_DnEuP=U${Jn z*Y4_6Cg&_)rsrVnM&L(q+iS@ZuH~8G0P5){g zp z=W(gBr}aav`PQ#ISjw1D^LBvXy&mh&@!_w}_^4}gCWlD6cGu~Xh4-j}uqk`je)+5P z>#A7JQ