Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorThomas Steur <thomas.steur@gmail.com>2016-02-14 23:10:26 +0300
committerThomas Steur <thomas.steur@gmail.com>2016-02-14 23:10:26 +0300
commit2bae9d90f860f3ccc5598420eb978cafd598451e (patch)
treeb742afddcfc882de15b9c075522cee4eae680db6 /libs
parent41b579a9d94a05f7c0cb2e42bf7c03c2d374ed95 (diff)
merge master => 3.0
Diffstat (limited to 'libs')
-rw-r--r--libs/README.md1
-rw-r--r--libs/Zend/Session.php13
-rw-r--r--libs/Zend/Validate/Hostname.php118
-rw-r--r--libs/bower_components/angular/angular.js4
-rwxr-xr-xlibs/pChart/class/pData.class.php1576
-rwxr-xr-xlibs/pChart/class/pImage.class.php962
-rwxr-xr-xlibs/pChart/class/pPie.class.php2998
7 files changed, 2882 insertions, 2790 deletions
diff --git a/libs/README.md b/libs/README.md
index f5a061a1dc..083684c962 100644
--- a/libs/README.md
+++ b/libs/README.md
@@ -30,3 +30,4 @@ third-party libraries:
- ZF-10871 - undefined variables when socket support disabled
- fix #6980 ("Array to string conversion") in `Zend/Session/Exception.php`
- fix Zend/Validate using deprecated iconv_set_encoding()
+ - Make sure sessions work when storing notifications
diff --git a/libs/Zend/Session.php b/libs/Zend/Session.php
index b5177c18fd..8b55a17b6d 100644
--- a/libs/Zend/Session.php
+++ b/libs/Zend/Session.php
@@ -491,6 +491,10 @@ class Zend_Session extends Zend_Session_Abstract
self::regenerateId();
}
+ if (isset($_SESSION['data']) && is_string($_SESSION['data'])) {
+ $_SESSION = unserialize(base64_decode($_SESSION['data']));
+ }
+
// run validators if they exist
if (isset($_SESSION['__ZF']['VALID'])) {
self::_processValidators();
@@ -688,8 +692,17 @@ class Zend_Session extends Zend_Session_Abstract
parent::$_writable = false;
}
+ if (isset($_SESSION)) {
+ $sessionBkp = $_SESSION;
+ $_SESSION = array('data' => base64_encode(serialize($_SESSION)));
+ }
+
session_write_close();
self::$_writeClosed = true;
+
+ if (isset($sessionBkp)) {
+ $_SESSION = $sessionBkp;
+ }
}
diff --git a/libs/Zend/Validate/Hostname.php b/libs/Zend/Validate/Hostname.php
index e485a5d546..cd5db5abcb 100644
--- a/libs/Zend/Validate/Hostname.php
+++ b/libs/Zend/Validate/Hostname.php
@@ -115,25 +115,103 @@ class Zend_Validate_Hostname extends Zend_Validate_Abstract
* @var array
*/
protected $_validTlds = array(
- 'ac', 'ad', 'ae', 'aero', 'af', 'ag', 'ai', 'al', 'am', 'an', 'ao', 'aq', 'ar', 'arpa',
- 'as', 'asia', 'at', 'au', 'aw', 'ax', 'az', 'ba', 'bb', 'bd', 'be', 'bf', 'bg', 'bh', 'bi',
- 'biz', 'bj', 'bm', 'bn', 'bo', 'br', 'bs', 'bt', 'bv', 'bw', 'by', 'bz', 'ca', 'cat', 'cc',
- 'cd', 'cf', 'cg', 'ch', 'ci', 'ck', 'cl', 'cm', 'cn', 'co', 'com', 'coop', 'cr', 'cu',
- 'cv', 'cx', 'cy', 'cz', 'de', 'dj', 'dk', 'dm', 'do', 'dz', 'ec', 'edu', 'ee', 'eg', 'er',
- 'es', 'et', 'eu', 'fi', 'fj', 'fk', 'fm', 'fo', 'fr', 'ga', 'gb', 'gd', 'ge', 'gf', 'gg',
- 'gh', 'gi', 'gl', 'gm', 'gn', 'gov', 'gp', 'gq', 'gr', 'gs', 'gt', 'gu', 'gw', 'gy', 'hk',
- 'hm', 'hn', 'hr', 'ht', 'hu', 'id', 'ie', 'il', 'im', 'in', 'info', 'int', 'io', 'iq',
- 'ir', 'is', 'it', 'je', 'jm', 'jo', 'jobs', 'jp', 'ke', 'kg', 'kh', 'ki', 'km', 'kn', 'kp',
- 'kr', 'kw', 'ky', 'kz', 'la', 'lb', 'lc', 'li', 'lk', 'lr', 'ls', 'lt', 'lu', 'lv', 'ly',
- 'ma', 'mc', 'md', 'me', 'mg', 'mh', 'mil', 'mk', 'ml', 'mm', 'mn', 'mo', 'mobi', 'mp',
- 'mq', 'mr', 'ms', 'mt', 'mu', 'museum', 'mv', 'mw', 'mx', 'my', 'mz', 'na', 'name', 'nc',
- 'ne', 'net', 'nf', 'ng', 'ni', 'nl', 'no', 'np', 'nr', 'nu', 'nz', 'om', 'org', 'pa', 'pe',
- 'pf', 'pg', 'ph', 'pk', 'pl', 'pm', 'pn', 'pr', 'pro', 'ps', 'pt', 'pw', 'py', 'qa', 're',
- 'ro', 'rs', 'ru', 'rw', 'sa', 'sb', 'sc', 'sd', 'se', 'sg', 'sh', 'si', 'sj', 'sk', 'sl',
- 'sm', 'sn', 'so', 'sr', 'st', 'su', 'sv', 'sy', 'sz', 'tc', 'td', 'tel', 'tf', 'tg', 'th',
- 'tj', 'tk', 'tl', 'tm', 'tn', 'to', 'tp', 'tr', 'travel', 'tt', 'tv', 'tw', 'tz', 'ua',
- 'ug', 'uk', 'um', 'us', 'uy', 'uz', 'va', 'vc', 've', 'vg', 'vi', 'vn', 'vu', 'wf', 'ws',
- 'ye', 'yt', 'yu', 'za', 'zm', 'zw'
+ 'aaa', 'aarp', 'abb', 'abbott', 'abogado', 'ac', 'academy', 'accenture', 'accountant', 'accountants',
+ 'aco', 'active', 'actor', 'ad', 'ads', 'adult', 'ae', 'aeg', 'aero', 'af', 'afl', 'ag', 'agency', 'ai',
+ 'aig', 'airforce', 'airtel', 'al', 'allfinanz', 'alsace', 'am', 'amica', 'amsterdam', 'analytics',
+ 'android', 'ao', 'apartments', 'app', 'apple', 'aq', 'aquarelle', 'ar', 'aramco', 'archi', 'army', 'arpa',
+ 'arte', 'as', 'asia', 'associates', 'at', 'attorney', 'au', 'auction', 'audi', 'audio', 'author', 'auto',
+ 'autos', 'aw', 'ax', 'axa', 'az', 'azure', 'ba', 'baidu', 'band', 'bank', 'bar', 'barcelona', 'barclaycard',
+ 'barclays', 'bargains', 'bauhaus', 'bayern', 'bb', 'bbc', 'bbva', 'bcn', 'bd', 'be', 'beats', 'beer',
+ 'bentley', 'berlin', 'best', 'bet', 'bf', 'bg', 'bh', 'bharti', 'bi', 'bible', 'bid', 'bike', 'bing',
+ 'bingo', 'bio', 'biz', 'bj', 'black', 'blackfriday', 'bloomberg', 'blue', 'bm', 'bms', 'bmw', 'bn', 'bnl',
+ 'bnpparibas', 'bo', 'boats', 'boehringer', 'bom', 'bond', 'boo', 'book', 'boots', 'bosch', 'bostik', 'bot',
+ 'boutique', 'br', 'bradesco', 'bridgestone', 'broadway', 'broker', 'brother', 'brussels', 'bs', 'bt',
+ 'budapest', 'bugatti', 'build', 'builders', 'business', 'buy', 'buzz', 'bv', 'bw', 'by', 'bz', 'bzh', 'ca',
+ 'cab', 'cafe', 'cal', 'call', 'camera', 'camp', 'cancerresearch', 'canon', 'capetown', 'capital', 'car',
+ 'caravan', 'cards', 'care', 'career', 'careers', 'cars', 'cartier', 'casa', 'cash', 'casino', 'cat',
+ 'catering', 'cba', 'cbn', 'cc', 'cd', 'ceb', 'center', 'ceo', 'cern', 'cf', 'cfa', 'cfd', 'cg', 'ch',
+ 'chanel', 'channel', 'chat', 'cheap', 'chloe', 'christmas', 'chrome', 'church', 'ci', 'cipriani',
+ 'circle', 'cisco', 'citic', 'city', 'cityeats', 'ck', 'cl', 'claims', 'cleaning', 'click', 'clinic',
+ 'clinique', 'clothing', 'cloud', 'club', 'clubmed', 'cm', 'cn', 'co', 'coach', 'codes', 'coffee',
+ 'college', 'cologne', 'com', 'commbank', 'community', 'company', 'computer', 'comsec', 'condos',
+ 'construction', 'consulting', 'contact', 'contractors', 'cooking', 'cool', 'coop', 'corsica', 'country',
+ 'coupons', 'courses', 'cr', 'credit', 'creditcard', 'creditunion', 'cricket', 'crown', 'crs', 'cruises',
+ 'csc', 'cu', 'cuisinella', 'cv', 'cw', 'cx', 'cy', 'cymru', 'cyou', 'cz', 'dabur', 'dad', 'dance', 'date',
+ 'dating', 'datsun', 'day', 'dclk', 'de', 'dealer', 'deals', 'degree', 'delivery', 'dell', 'delta', 'democrat',
+ 'dental', 'dentist', 'desi', 'design', 'dev', 'diamonds', 'diet', 'digital', 'direct', 'directory',
+ 'discount', 'dj', 'dk', 'dm', 'dnp', 'do', 'docs', 'dog', 'doha', 'domains', 'doosan', 'download', 'drive',
+ 'dubai', 'durban', 'dvag', 'dz', 'earth', 'eat', 'ec', 'edu', 'education', 'ee', 'eg', 'email', 'emerck',
+ 'energy', 'engineer', 'engineering', 'enterprises', 'epson', 'equipment', 'er', 'erni', 'es', 'esq',
+ 'estate', 'et', 'eu', 'eurovision', 'eus', 'events', 'everbank', 'exchange', 'expert', 'exposed', 'express',
+ 'fage', 'fail', 'fairwinds', 'faith', 'family', 'fan', 'fans', 'farm', 'fashion', 'fast', 'feedback',
+ 'ferrero', 'fi', 'film', 'final', 'finance', 'financial', 'firestone', 'firmdale', 'fish', 'fishing',
+ 'fit', 'fitness', 'fj', 'fk', 'flights', 'florist', 'flowers', 'flsmidth', 'fly', 'fm', 'fo', 'foo',
+ 'football', 'ford', 'forex', 'forsale', 'forum', 'foundation', 'fox', 'fr', 'frl', 'frogans', 'fund',
+ 'furniture', 'futbol', 'fyi', 'ga', 'gal', 'gallery', 'game', 'garden', 'gb', 'gbiz', 'gd', 'gdn', 'ge',
+ 'gea', 'gent', 'genting', 'gf', 'gg', 'ggee', 'gh', 'gi', 'gift', 'gifts', 'gives', 'giving', 'gl', 'glass',
+ 'gle', 'global', 'globo', 'gm', 'gmail', 'gmo', 'gmx', 'gn', 'gold', 'goldpoint', 'golf', 'goo', 'goog',
+ 'google', 'gop', 'got', 'gov', 'gp', 'gq', 'gr', 'grainger', 'graphics', 'gratis', 'green', 'gripe', 'group',
+ 'gs', 'gt', 'gu', 'gucci', 'guge', 'guide', 'guitars', 'guru', 'gw', 'gy', 'hamburg', 'hangout', 'haus',
+ 'healthcare', 'help', 'here', 'hermes', 'hiphop', 'hitachi', 'hiv', 'hk', 'hm', 'hn', 'hockey', 'holdings',
+ 'holiday', 'homedepot', 'homes', 'honda', 'horse', 'host', 'hosting', 'hoteles', 'hotmail', 'house', 'how',
+ 'hr', 'hsbc', 'ht', 'hu', 'hyundai', 'ibm', 'icbc', 'ice', 'icu', 'id', 'ie', 'ifm', 'iinet', 'il', 'im',
+ 'immo', 'immobilien', 'in', 'industries', 'infiniti', 'info', 'ing', 'ink', 'institute', 'insurance', 'insure',
+ 'int', 'international', 'investments', 'io', 'ipiranga', 'iq', 'ir', 'irish', 'is', 'ist', 'istanbul', 'it',
+ 'itau', 'iwc', 'jaguar', 'java', 'jcb', 'je', 'jetzt', 'jewelry', 'jlc', 'jll', 'jm', 'jmp', 'jo', 'jobs',
+ 'joburg', 'jot', 'joy', 'jp', 'jprs', 'juegos', 'kaufen', 'kddi', 'ke', 'kfh', 'kg', 'kh', 'ki', 'kia', 'kim',
+ 'kinder', 'kitchen', 'kiwi', 'km', 'kn', 'koeln', 'komatsu', 'kp', 'kpn', 'kr', 'krd', 'kred', 'kw', 'ky',
+ 'kyoto', 'kz', 'la', 'lacaixa', 'lamborghini', 'lamer', 'lancaster', 'land', 'landrover', 'lasalle', 'lat',
+ 'latrobe', 'law', 'lawyer', 'lb', 'lc', 'lds', 'lease', 'leclerc', 'legal', 'lexus', 'lgbt', 'li', 'liaison',
+ 'lidl', 'life', 'lifestyle', 'lighting', 'like', 'limited', 'limo', 'lincoln', 'linde', 'link', 'live',
+ 'living', 'lixil', 'lk', 'loan', 'loans', 'lol', 'london', 'lotte', 'lotto', 'love', 'lr', 'ls', 'lt', 'ltd',
+ 'ltda', 'lu', 'lupin', 'luxe', 'luxury', 'lv', 'ly', 'ma', 'madrid', 'maif', 'maison', 'man', 'management',
+ 'mango', 'market', 'marketing', 'markets', 'marriott', 'mba', 'mc', 'md', 'me', 'med', 'media', 'meet',
+ 'melbourne', 'meme', 'memorial', 'men', 'menu', 'meo', 'mg', 'mh', 'miami', 'microsoft', 'mil', 'mini', 'mk',
+ 'ml', 'mm', 'mma', 'mn', 'mo', 'mobi', 'mobily', 'moda', 'moe', 'moi', 'mom', 'monash', 'money', 'montblanc',
+ 'mormon', 'mortgage', 'moscow', 'motorcycles', 'mov', 'movie', 'movistar', 'mp', 'mq', 'mr', 'ms', 'mt',
+ 'mtn', 'mtpc', 'mtr', 'mu', 'museum', 'mutuelle', 'mv', 'mw', 'mx', 'my', 'mz', 'na', 'nadex', 'nagoya',
+ 'name', 'navy', 'nc', 'ne', 'nec', 'net', 'netbank', 'network', 'neustar', 'new', 'news', 'nexus', 'nf',
+ 'ng', 'ngo', 'nhk', 'ni', 'nico', 'ninja', 'nissan', 'nl', 'no', 'nokia', 'norton', 'nowruz', 'np', 'nr',
+ 'nra', 'nrw', 'ntt', 'nu', 'nyc', 'nz', 'obi', 'office', 'okinawa', 'om', 'omega', 'one', 'ong', 'onl',
+ 'online', 'ooo', 'oracle', 'orange', 'org', 'organic', 'origins', 'osaka', 'otsuka', 'ovh', 'pa', 'page',
+ 'panerai', 'paris', 'pars', 'partners', 'parts', 'party', 'pe', 'pet', 'pf', 'pg', 'ph', 'pharmacy',
+ 'philips', 'photo', 'photography', 'photos', 'physio', 'piaget', 'pics', 'pictet', 'pictures', 'pid', 'pin',
+ 'ping', 'pink', 'pizza', 'pk', 'pl', 'place', 'play', 'playstation', 'plumbing', 'plus', 'pm', 'pn', 'pohl',
+ 'poker', 'porn', 'post', 'pr', 'praxi', 'press', 'pro', 'prod', 'productions', 'prof', 'promo', 'properties',
+ 'property', 'protection', 'ps', 'pt', 'pub', 'pw', 'py', 'qa', 'qpon', 'quebec', 'racing', 're', 'read',
+ 'realtor', 'realty', 'recipes', 'red', 'redstone', 'redumbrella', 'rehab', 'reise', 'reisen', 'reit', 'ren',
+ 'rent', 'rentals', 'repair', 'report', 'republican', 'rest', 'restaurant', 'review', 'reviews', 'rexroth',
+ 'rich', 'ricoh', 'rio', 'rip', 'ro', 'rocher', 'rocks', 'rodeo', 'room', 'rs', 'rsvp', 'ru', 'ruhr', 'run',
+ 'rw', 'rwe', 'ryukyu', 'sa', 'saarland', 'safe', 'safety', 'sakura', 'sale', 'salon', 'samsung', 'sandvik',
+ 'sandvikcoromant', 'sanofi', 'sap', 'sapo', 'sarl', 'sas', 'saxo', 'sb', 'sbs', 'sc', 'sca', 'scb',
+ 'schaeffler', 'schmidt', 'scholarships', 'school', 'schule', 'schwarz', 'science', 'scor', 'scot', 'sd',
+ 'se', 'seat', 'security', 'seek', 'sener', 'services', 'seven', 'sew', 'sex', 'sexy', 'sfr', 'sg', 'sh',
+ 'sharp', 'shell', 'shia', 'shiksha', 'shoes', 'show', 'shriram', 'si', 'singles', 'site', 'sj', 'sk', 'ski',
+ 'sky', 'skype', 'sl', 'sm', 'smile', 'sn', 'sncf', 'so', 'soccer', 'social', 'software', 'sohu', 'solar',
+ 'solutions', 'sony', 'soy', 'space', 'spiegel', 'spreadbetting', 'sr', 'srl', 'st', 'stada', 'star', 'starhub',
+ 'statefarm', 'statoil', 'stc', 'stcgroup', 'stockholm', 'storage', 'studio', 'study', 'style', 'su', 'sucks',
+ 'supplies', 'supply', 'support', 'surf', 'surgery', 'suzuki', 'sv', 'swatch', 'swiss', 'sx', 'sy', 'sydney',
+ 'symantec', 'systems', 'sz', 'tab', 'taipei', 'tatamotors', 'tatar', 'tattoo', 'tax', 'taxi', 'tc', 'tci',
+ 'td', 'team', 'tech', 'technology', 'tel', 'telefonica', 'temasek', 'tennis', 'tf', 'tg', 'th', 'thd',
+ 'theater', 'theatre', 'tickets', 'tienda', 'tips', 'tires', 'tirol', 'tj', 'tk', 'tl', 'tm', 'tn', 'to',
+ 'today', 'tokyo', 'tools', 'top', 'toray', 'toshiba', 'tours', 'town', 'toyota', 'toys', 'tr', 'trade',
+ 'trading', 'training', 'travel', 'travelers', 'travelersinsurance', 'trust', 'trv', 'tt', 'tui', 'tushu',
+ 'tv', 'tw', 'tz', 'ua', 'ubs', 'ug', 'uk', 'university', 'uno', 'uol', 'us', 'uy', 'uz', 'va', 'vacations',
+ 'vana', 'vc', 've', 'vegas', 'ventures', 'verisign', 'versicherung', 'vet', 'vg', 'vi', 'viajes', 'video',
+ 'villas', 'vin', 'vip', 'virgin', 'vision', 'vista', 'vistaprint', 'viva', 'vlaanderen', 'vn', 'vodka', 'vote',
+ 'voting', 'voto', 'voyage', 'vu', 'wales', 'walter', 'wang', 'wanggou', 'watch', 'watches', 'webcam', 'weber',
+ 'website', 'wed', 'wedding', 'weir', 'wf', 'whoswho', 'wien', 'wiki', 'williamhill', 'win', 'windows', 'wine',
+ 'wme', 'work', 'works', 'world', 'ws', 'wtc', 'wtf', 'xbox', 'xerox', 'xin', 'कॉम', '佛山', '慈善', '集团',
+ '在线', '한국', '点看', 'คอม', 'ভারত', '八卦', 'موقع', '公益', '公司', '移动', '我爱你', 'москва', 'қаз', 'онлайн',
+ 'сайт', 'срб', 'бел', 'קום', '时尚', '淡马锡', 'орг', 'नेट', '삼성', 'சிங்கப்பூர்', '商标', '商店', '商城', 'дети',
+ 'мкд', 'ポイント', '新闻', '工行', 'كوم', '中文网', '中信', '中国', '中國', '娱乐', '谷歌', 'భారత్', 'ලංකා', 'ભારત',
+ 'भारत', '网店', 'संगठन', '餐厅', '网络', 'ком', 'укр', '香港', '诺基亚', '飞利浦', '台湾', '台灣', '手表', '手机',
+ 'мон', 'الجزائر', 'عمان', 'ارامكو', 'ایران', 'امارات', 'بازار', 'الاردن', 'موبايلي', 'بھارت', 'المغرب',
+ 'السعودية', 'سودان', 'همراه', 'عراق', 'مليسيا', '닷컴', '政府', 'شبكة', 'بيتك', 'გე', '机构', '组织机构',
+ '健康', 'ไทย', 'سورية', 'рус', 'рф', '珠宝', 'تونس', '大拿', 'みんな', 'グーグル', 'ελ', '世界', 'ਭਾਰਤ', '网址',
+ '닷넷', 'コム', '游戏', 'vermögensberater', 'vermögensberatung', '企业', '信息', 'مصر', 'قطر', '广东', 'இலங்கை',
+ 'இந்தியா', 'հայ', '新加坡', 'فلسطين', '政务', 'xperia', 'xxx', 'xyz', 'yachts', 'yamaxun', 'yandex', 'ye',
+ 'yodobashi', 'yoga', 'yokohama', 'youtube', 'yt', 'za', 'zara', 'zero', 'zip', 'zm', 'zone', 'zuerich', 'zw'
);
/**
@@ -557,7 +635,7 @@ class Zend_Validate_Hostname extends Zend_Validate_Abstract
do {
// First check TLD
$matches = array();
- if (preg_match('/([^.]{2,10})$/i', end($domainParts), $matches) ||
+ if (preg_match('/([^.]{2,63})$/i', end($domainParts), $matches) ||
(end($domainParts) == 'ایران') || (end($domainParts) == '中国') ||
(end($domainParts) == '公司') || (end($domainParts) == '网络')) {
diff --git a/libs/bower_components/angular/angular.js b/libs/bower_components/angular/angular.js
index f7442c0b03..7082434896 100644
--- a/libs/bower_components/angular/angular.js
+++ b/libs/bower_components/angular/angular.js
@@ -16429,7 +16429,7 @@ function adjustMatchers(matchers) {
*
* - your app is hosted at url `http://myapp.example.com/`
* - but some of your templates are hosted on other domains you control such as
- * `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.
+ * `http://srv01.assets.example.com/`, `http://srv02.assets.example.com/`, etc.
* - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
*
* Here is what a secure configuration for this scenario might look like:
@@ -28361,4 +28361,4 @@ var minlengthDirective = function() {
})(window, document);
-!window.angular.$$csp() && window.angular.element(document.head).prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng\\:form{display:block;}.ng-animate-shim{visibility:hidden;}.ng-anchor{position:absolute;}</style>'); \ No newline at end of file
+!window.angular.$$csp() && window.angular.element(document.head).prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng\\:form{display:block;}.ng-animate-shim{visibility:hidden;}.ng-anchor{position:absolute;}</style>');
diff --git a/libs/pChart/class/pData.class.php b/libs/pChart/class/pData.class.php
index 49d16a33bd..d29e0d499c 100755
--- a/libs/pChart/class/pData.class.php
+++ b/libs/pChart/class/pData.class.php
@@ -1,789 +1,789 @@
-<?php
- /*
- pDraw - class to manipulate data arrays
-
- Version : 2.1.4
- Made by : Jean-Damien POGOLOTTI
- Last Update : 19/01/2014
-
- This file can be distributed under the license you can find at :
-
- http://www.pchart.net/license
-
- You can find the whole class documentation on the pChart web site.
- */
-
- /* Axis configuration */
- define("AXIS_FORMAT_DEFAULT" , 680001);
- define("AXIS_FORMAT_TIME" , 680002);
- define("AXIS_FORMAT_DATE" , 680003);
- define("AXIS_FORMAT_METRIC" , 680004);
- define("AXIS_FORMAT_CURRENCY" , 680005);
- define("AXIS_FORMAT_TRAFFIC" , 680006);
- define("AXIS_FORMAT_CUSTOM" , 680007);
-
- /* Axis position */
- define("AXIS_POSITION_LEFT" , 681001);
- define("AXIS_POSITION_RIGHT" , 681002);
- define("AXIS_POSITION_TOP" , 681001);
- define("AXIS_POSITION_BOTTOM" , 681002);
-
- /* Families of data points */
- define("SERIE_SHAPE_FILLEDCIRCLE" , 681011);
- define("SERIE_SHAPE_FILLEDTRIANGLE" , 681012);
- define("SERIE_SHAPE_FILLEDSQUARE" , 681013);
- define("SERIE_SHAPE_FILLEDDIAMOND" , 681017);
- define("SERIE_SHAPE_CIRCLE" , 681014);
- define("SERIE_SHAPE_TRIANGLE" , 681015);
- define("SERIE_SHAPE_SQUARE" , 681016);
- define("SERIE_SHAPE_DIAMOND" , 681018);
-
- /* Axis position */
- define("AXIS_X" , 682001);
- define("AXIS_Y" , 682002);
-
- /* Define value limits */
- define("ABSOLUTE_MIN" , -10000000000000);
- define("ABSOLUTE_MAX" , 10000000000000);
-
- /* Replacement to the PHP NULL keyword */
- define("VOID" , 0.123456789);
-
- /* Euro symbol for GD fonts */
- define("EURO_SYMBOL" , utf8_encode("&#8364;"));
-
- /* pData class definition */
- class pData
- {
- var $Data;
-
- var $Palette = array("0"=>array("R"=>188,"G"=>224,"B"=>46,"Alpha"=>100),
- "1"=>array("R"=>224,"G"=>100,"B"=>46,"Alpha"=>100),
- "2"=>array("R"=>224,"G"=>214,"B"=>46,"Alpha"=>100),
- "3"=>array("R"=>46,"G"=>151,"B"=>224,"Alpha"=>100),
- "4"=>array("R"=>176,"G"=>46,"B"=>224,"Alpha"=>100),
- "5"=>array("R"=>224,"G"=>46,"B"=>117,"Alpha"=>100),
- "6"=>array("R"=>92,"G"=>224,"B"=>46,"Alpha"=>100),
- "7"=>array("R"=>224,"G"=>176,"B"=>46,"Alpha"=>100));
-
- /* Class creator */
- function pData()
- {
- $this->Data = "";
- $this->Data["XAxisDisplay"] = AXIS_FORMAT_DEFAULT;
- $this->Data["XAxisFormat"] = NULL;
- $this->Data["XAxisName"] = NULL;
- $this->Data["XAxisUnit"] = NULL;
- $this->Data["Abscissa"] = NULL;
- $this->Data["AbsicssaPosition"] = AXIS_POSITION_BOTTOM;
-
- $this->Data["Axis"][0]["Display"] = AXIS_FORMAT_DEFAULT;
- $this->Data["Axis"][0]["Position"] = AXIS_POSITION_LEFT;
- $this->Data["Axis"][0]["Identity"] = AXIS_Y;
- }
-
- /* Add a single point or an array to the given serie */
- function addPoints($Values,$SerieName="Serie1")
- {
- if (!isset($this->Data["Series"][$SerieName]))
- $this->initialise($SerieName);
-
- if ( is_array($Values) )
- {
- foreach($Values as $Key => $Value)
- { $this->Data["Series"][$SerieName]["Data"][] = $Value; }
- }
- else
- $this->Data["Series"][$SerieName]["Data"][] = $Values;
-
- if ( $Values != VOID )
- {
- $StrippedData = $this->stripVOID($this->Data["Series"][$SerieName]["Data"]);
- if ( empty($StrippedData) ) { $this->Data["Series"][$SerieName]["Max"] = 0; $this->Data["Series"][$SerieName]["Min"] =0; return(0); }
- $this->Data["Series"][$SerieName]["Max"] = max($StrippedData);
- $this->Data["Series"][$SerieName]["Min"] = min($StrippedData);
- }
- }
-
- /* Strip VOID values */
- function stripVOID($Values)
- { if (!is_array($Values)) { return(array()); } $Result = array(); foreach($Values as $Key => $Value) { if ( $Value != VOID ) { $Result[] = $Value; } } return($Result); }
-
- /* Return the number of values contained in a given serie */
- function getSerieCount($Serie)
- { if (isset($this->Data["Series"][$Serie]["Data"])) { return(sizeof($this->Data["Series"][$Serie]["Data"])); } else { return(0); } }
-
- /* Remove a serie from the pData object */
- function removeSerie($Series)
- {
- if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); }
- foreach($Series as $Key => $Serie) { if (isset($this->Data["Series"][$Serie])) { unset($this->Data["Series"][$Serie]); } }
- }
-
- /* Return a value from given serie & index */
- function getValueAt($Serie,$Index=0)
- { if (isset($this->Data["Series"][$Serie]["Data"][$Index])) { return($this->Data["Series"][$Serie]["Data"][$Index]); } else { return(NULL); } }
-
- /* Return the values array */
- function getValues($Serie)
- { if (isset($this->Data["Series"][$Serie]["Data"])) { return($this->Data["Series"][$Serie]["Data"]); } else { return(NULL); } }
-
- /* Reverse the values in the given serie */
- function reverseSerie($Series)
- {
- if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); }
- foreach($Series as $Key => $Serie) { if (isset($this->Data["Series"][$Serie]["Data"])) { $this->Data["Series"][$Serie]["Data"] = array_reverse($this->Data["Series"][$Serie]["Data"]); } }
- }
-
- /* Return the sum of the serie values */
- function getSum($Serie)
- { if (isset($this->Data["Series"][$Serie])) { return(array_sum($this->Data["Series"][$Serie]["Data"])); } else { return(NULL); } }
-
- /* Return the max value of a given serie */
- function getMax($Serie)
- { if (isset($this->Data["Series"][$Serie]["Max"])) { return($this->Data["Series"][$Serie]["Max"]); } else { return(NULL); } }
-
- /* Return the min value of a given serie */
- function getMin($Serie)
- { if (isset($this->Data["Series"][$Serie]["Min"])) { return($this->Data["Series"][$Serie]["Min"]); } else { return(NULL); } }
-
- /* Set the description of a given serie */
- function setSerieShape($Series,$Shape=SERIE_SHAPE_FILLEDCIRCLE)
- {
- if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); }
- foreach($Series as $Key => $Serie) { if (isset($this->Data["Series"][$Serie]) ) { $this->Data["Series"][$Serie]["Shape"] = $Shape; } }
- }
-
- /* Set the description of a given serie */
- function setSerieDescription($Series,$Description="My serie")
- {
- if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); }
- foreach($Series as $Key => $Serie) { if (isset($this->Data["Series"][$Serie]) ) { $this->Data["Series"][$Serie]["Description"] = $Description; } }
- }
-
- /* Set a serie as "drawable" while calling a rendering function */
- function setSerieDrawable($Series,$Drawable=TRUE)
- {
- if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); }
- foreach($Series as $Key => $Serie) { if (isset($this->Data["Series"][$Serie]) ) { $this->Data["Series"][$Serie]["isDrawable"] = $Drawable; } }
- }
-
- /* Set the icon associated to a given serie */
- function setSeriePicture($Series,$Picture=NULL)
- {
- if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); }
- foreach($Series as $Key => $Serie) { if (isset($this->Data["Series"][$Serie]) ) { $this->Data["Series"][$Serie]["Picture"] = $Picture; } }
- }
-
- /* Set the name of the X Axis */
- function setXAxisName($Name)
- { $this->Data["XAxisName"] = $Name; }
-
- /* Set the display mode of the X Axis */
- function setXAxisDisplay($Mode,$Format=NULL)
- { $this->Data["XAxisDisplay"] = $Mode; $this->Data["XAxisFormat"] = $Format; }
-
- /* Set the unit that will be displayed on the X axis */
- function setXAxisUnit($Unit)
- { $this->Data["XAxisUnit"] = $Unit; }
-
- /* Set the serie that will be used as abscissa */
- function setAbscissa($Serie)
- { if (isset($this->Data["Series"][$Serie])) { $this->Data["Abscissa"] = $Serie; } }
-
- function setAbsicssaPosition($Position = AXIS_POSITION_BOTTOM)
- { $this->Data["AbsicssaPosition"] = $Position; }
-
- /* Set the name of the abscissa axis */
- function setAbscissaName($Name)
- { $this->Data["AbscissaName"] = $Name; }
-
- /* Create a scatter group specifyin X and Y data series */
- function setScatterSerie($SerieX,$SerieY,$ID=0)
- { if (isset($this->Data["Series"][$SerieX]) && isset($this->Data["Series"][$SerieY]) ) { $this->initScatterSerie($ID); $this->Data["ScatterSeries"][$ID]["X"] = $SerieX; $this->Data["ScatterSeries"][$ID]["Y"] = $SerieY; } }
-
- /* Set the shape of a given sctatter serie */
- function setScatterSerieShape($ID,$Shape=SERIE_SHAPE_FILLEDCIRCLE)
- { if (isset($this->Data["ScatterSeries"][$ID]) ) { $this->Data["ScatterSeries"][$ID]["Shape"] = $Shape; } }
-
- /* Set the description of a given scatter serie */
- function setScatterSerieDescription($ID,$Description="My serie")
- { if (isset($this->Data["ScatterSeries"][$ID]) ) { $this->Data["ScatterSeries"][$ID]["Description"] = $Description; } }
-
- /* Set the icon associated to a given scatter serie */
- function setScatterSeriePicture($ID,$Picture=NULL)
- { if (isset($this->Data["ScatterSeries"][$ID]) ) { $this->Data["ScatterSeries"][$ID]["Picture"] = $Picture; } }
-
- /* Set a scatter serie as "drawable" while calling a rendering function */
- function setScatterSerieDrawable($ID ,$Drawable=TRUE)
- { if (isset($this->Data["ScatterSeries"][$ID]) ) { $this->Data["ScatterSeries"][$ID]["isDrawable"] = $Drawable; } }
-
- /* Define if a scatter serie should be draw with ticks */
- function setScatterSerieTicks($ID,$Width=0)
- { if ( isset($this->Data["ScatterSeries"][$ID]) ) { $this->Data["ScatterSeries"][$ID]["Ticks"] = $Width; } }
-
- /* Define if a scatter serie should be draw with a special weight */
- function setScatterSerieWeight($ID,$Weight=0)
- { if ( isset($this->Data["ScatterSeries"][$ID]) ) { $this->Data["ScatterSeries"][$ID]["Weight"] = $Weight; } }
-
- /* Associate a color to a scatter serie */
- function setScatterSerieColor($ID,$Format)
- {
- $R = isset($Format["R"]) ? $Format["R"] : 0;
- $G = isset($Format["G"]) ? $Format["G"] : 0;
- $B = isset($Format["B"]) ? $Format["B"] : 0;
- $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;
-
- if ( isset($this->Data["ScatterSeries"][$ID]) )
- {
- $this->Data["ScatterSeries"][$ID]["Color"]["R"] = $R;
- $this->Data["ScatterSeries"][$ID]["Color"]["G"] = $G;
- $this->Data["ScatterSeries"][$ID]["Color"]["B"] = $B;
- $this->Data["ScatterSeries"][$ID]["Color"]["Alpha"] = $Alpha;
- }
- }
-
- /* Compute the series limits for an individual and global point of view */
- function limits()
- {
- $GlobalMin = ABSOLUTE_MAX;
- $GlobalMax = ABSOLUTE_MIN;
-
- foreach($this->Data["Series"] as $Key => $Value)
- {
- if ( $this->Data["Abscissa"] != $Key && $this->Data["Series"][$Key]["isDrawable"] == TRUE)
- {
- if ( $GlobalMin > $this->Data["Series"][$Key]["Min"] ) { $GlobalMin = $this->Data["Series"][$Key]["Min"]; }
- if ( $GlobalMax < $this->Data["Series"][$Key]["Max"] ) { $GlobalMax = $this->Data["Series"][$Key]["Max"]; }
- }
- }
- $this->Data["Min"] = $GlobalMin;
- $this->Data["Max"] = $GlobalMax;
-
- return(array($GlobalMin,$GlobalMax));
- }
-
- /* Mark all series as drawable */
- function drawAll()
- { foreach($this->Data["Series"] as $Key => $Value) { if ( $this->Data["Abscissa"] != $Key ) { $this->Data["Series"][$Key]["isDrawable"]=TRUE; } } }
-
- /* Return the average value of the given serie */
- function getSerieAverage($Serie)
- {
- if ( isset($this->Data["Series"][$Serie]) )
- {
- $SerieData = $this->stripVOID($this->Data["Series"][$Serie]["Data"]);
- return(array_sum($SerieData)/sizeof($SerieData));
- }
- else
- return(NULL);
- }
-
- /* Return the geometric mean of the given serie */
- function getGeometricMean($Serie)
- {
- if ( isset($this->Data["Series"][$Serie]) )
- {
- $SerieData = $this->stripVOID($this->Data["Series"][$Serie]["Data"]);
- $Seriesum = 1; foreach($SerieData as $Key => $Value) { $Seriesum = $Seriesum * $Value; }
- return(pow($Seriesum,1/sizeof($SerieData)));
- }
- else
- return(NULL);
- }
-
- /* Return the harmonic mean of the given serie */
- function getHarmonicMean($Serie)
- {
- if ( isset($this->Data["Series"][$Serie]) )
- {
- $SerieData = $this->stripVOID($this->Data["Series"][$Serie]["Data"]);
- $Seriesum = 0; foreach($SerieData as $Key => $Value) { $Seriesum = $Seriesum + 1/$Value; }
- return(sizeof($SerieData)/$Seriesum);
- }
- else
- return(NULL);
- }
-
- /* Return the standard deviation of the given serie */
- function getStandardDeviation($Serie)
- {
- if ( isset($this->Data["Series"][$Serie]) )
- {
- $Average = $this->getSerieAverage($Serie);
- $SerieData = $this->stripVOID($this->Data["Series"][$Serie]["Data"]);
-
- $DeviationSum = 0;
- foreach($SerieData as $Key => $Value)
- $DeviationSum = $DeviationSum + ($Value-$Average)*($Value-$Average);
-
- $Deviation = sqrt($DeviationSum/count($SerieData));
-
- return($Deviation);
- }
- else
- return(NULL);
- }
-
- /* Return the Coefficient of variation of the given serie */
- function getCoefficientOfVariation($Serie)
- {
- if ( isset($this->Data["Series"][$Serie]) )
- {
- $Average = $this->getSerieAverage($Serie);
- $StandardDeviation = $this->getStandardDeviation($Serie);
-
- if ( $StandardDeviation != 0 )
- return($StandardDeviation/$Average);
- else
- return(NULL);
- }
- else
- return(NULL);
- }
-
- /* Return the median value of the given serie */
- function getSerieMedian($Serie)
- {
- if ( isset($this->Data["Series"][$Serie]) )
- {
- $SerieData = $this->stripVOID($this->Data["Series"][$Serie]["Data"]);
- sort($SerieData);
- $SerieCenter = floor(sizeof($SerieData)/2);
-
- if ( isset($SerieData[$SerieCenter]) )
- return($SerieData[$SerieCenter]);
- else
- return(NULL);
- }
- else
- return(NULL);
- }
-
- /* Return the x th percentil of the given serie */
- function getSeriePercentile($Serie="Serie1",$Percentil=95)
- {
- if (!isset($this->Data["Series"][$Serie]["Data"])) { return(NULL); }
-
- $Values = count($this->Data["Series"][$Serie]["Data"])-1;
- if ( $Values < 0 ) { $Values = 0; }
-
- $PercentilID = floor(($Values/100)*$Percentil+.5);
- $SortedValues = $this->Data["Series"][$Serie]["Data"];
- sort($SortedValues);
-
- if ( is_numeric($SortedValues[$PercentilID]) )
- return($SortedValues[$PercentilID]);
- else
- return(NULL);
- }
-
- /* Add random values to a given serie */
- function addRandomValues($SerieName="Serie1",$Options="")
- {
- $Values = isset($Options["Values"]) ? $Options["Values"] : 20;
- $Min = isset($Options["Min"]) ? $Options["Min"] : 0;
- $Max = isset($Options["Max"]) ? $Options["Max"] : 100;
- $withFloat = isset($Options["withFloat"]) ? $Options["withFloat"] : FALSE;
-
- for ($i=0;$i<=$Values;$i++)
- {
- if ( $withFloat ) { $Value = rand($Min*100,$Max*100)/100; } else { $Value = rand($Min,$Max); }
- $this->addPoints($Value,$SerieName);
- }
- }
-
- /* Test if we have valid data */
- function containsData()
- {
- if (!isset($this->Data["Series"])) { return(FALSE); }
-
- $Result = FALSE;
- foreach($this->Data["Series"] as $Key => $Value)
- { if ( $this->Data["Abscissa"] != $Key && $this->Data["Series"][$Key]["isDrawable"]==TRUE) { $Result=TRUE; } }
- return($Result);
- }
-
- /* Set the display mode of an Axis */
- function setAxisDisplay($AxisID,$Mode=AXIS_FORMAT_DEFAULT,$Format=NULL)
- {
- if ( isset($this->Data["Axis"][$AxisID] ) )
- {
- $this->Data["Axis"][$AxisID]["Display"] = $Mode;
- if ( $Format != NULL ) { $this->Data["Axis"][$AxisID]["Format"] = $Format; }
- }
- }
-
- /* Set the position of an Axis */
- function setAxisPosition($AxisID,$Position=AXIS_POSITION_LEFT)
- { if ( isset($this->Data["Axis"][$AxisID] ) ) { $this->Data["Axis"][$AxisID]["Position"] = $Position; } }
-
- /* Associate an unit to an axis */
- function setAxisUnit($AxisID,$Unit)
- { if ( isset($this->Data["Axis"][$AxisID] ) ) { $this->Data["Axis"][$AxisID]["Unit"] = $Unit; } }
-
- /* Associate a name to an axis */
- function setAxisName($AxisID,$Name)
- { if ( isset($this->Data["Axis"][$AxisID] ) ) { $this->Data["Axis"][$AxisID]["Name"] = $Name; } }
-
- /* Associate a color to an axis */
- function setAxisColor($AxisID,$Format)
- {
- $R = isset($Format["R"]) ? $Format["R"] : 0;
- $G = isset($Format["G"]) ? $Format["G"] : 0;
- $B = isset($Format["B"]) ? $Format["B"] : 0;
- $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;
-
- if ( isset($this->Data["Axis"][$AxisID] ) )
- {
- $this->Data["Axis"][$AxisID]["Color"]["R"] = $R;
- $this->Data["Axis"][$AxisID]["Color"]["G"] = $G;
- $this->Data["Axis"][$AxisID]["Color"]["B"] = $B;
- $this->Data["Axis"][$AxisID]["Color"]["Alpha"] = $Alpha;
- }
- }
-
-
- /* Design an axis as X or Y member */
- function setAxisXY($AxisID,$Identity=AXIS_Y)
- { if ( isset($this->Data["Axis"][$AxisID] ) ) { $this->Data["Axis"][$AxisID]["Identity"] = $Identity; } }
-
- /* Associate one data serie with one axis */
- function setSerieOnAxis($Series,$AxisID)
- {
- if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); }
- foreach($Series as $Key => $Serie)
- {
- $PreviousAxis = $this->Data["Series"][$Serie]["Axis"];
-
- /* Create missing axis */
- if ( !isset($this->Data["Axis"][$AxisID] ) )
- { $this->Data["Axis"][$AxisID]["Position"] = AXIS_POSITION_LEFT; $this->Data["Axis"][$AxisID]["Identity"] = AXIS_Y;}
-
- $this->Data["Series"][$Serie]["Axis"] = $AxisID;
-
- /* Cleanup unused axis */
- $Found = FALSE;
- foreach($this->Data["Series"] as $SerieName => $Values) { if ( $Values["Axis"] == $PreviousAxis ) { $Found = TRUE; } }
- if (!$Found) { unset($this->Data["Axis"][$PreviousAxis]); }
- }
- }
-
- /* Define if a serie should be draw with ticks */
- function setSerieTicks($Series,$Width=0)
- {
- if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); }
- foreach($Series as $Key => $Serie) { if ( isset($this->Data["Series"][$Serie]) ) { $this->Data["Series"][$Serie]["Ticks"] = $Width; } }
- }
-
- /* Define if a serie should be draw with a special weight */
- function setSerieWeight($Series,$Weight=0)
- {
- if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); }
- foreach($Series as $Key => $Serie) { if ( isset($this->Data["Series"][$Serie]) ) { $this->Data["Series"][$Serie]["Weight"] = $Weight; } }
- }
-
- /* Returns the palette of the given serie */
- function getSeriePalette($Serie)
- {
- if ( !isset($this->Data["Series"][$Serie]) ) { return(NULL); }
-
- $Result = "";
- $Result["R"] = $this->Data["Series"][$Serie]["Color"]["R"];
- $Result["G"] = $this->Data["Series"][$Serie]["Color"]["G"];
- $Result["B"] = $this->Data["Series"][$Serie]["Color"]["B"];
- $Result["Alpha"] = $this->Data["Series"][$Serie]["Color"]["Alpha"];
-
- return($Result);
- }
-
- /* Set the color of one serie */
- function setPalette($Series,$Format=NULL)
- {
- if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); }
-
- foreach($Series as $Key => $Serie)
- {
- $R = isset($Format["R"]) ? $Format["R"] : 0;
- $G = isset($Format["G"]) ? $Format["G"] : 0;
- $B = isset($Format["B"]) ? $Format["B"] : 0;
- $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;
-
- if ( isset($this->Data["Series"][$Serie]) )
- {
- $OldR = $this->Data["Series"][$Serie]["Color"]["R"]; $OldG = $this->Data["Series"][$Serie]["Color"]["G"]; $OldB = $this->Data["Series"][$Serie]["Color"]["B"];
- $this->Data["Series"][$Serie]["Color"]["R"] = $R;
- $this->Data["Series"][$Serie]["Color"]["G"] = $G;
- $this->Data["Series"][$Serie]["Color"]["B"] = $B;
- $this->Data["Series"][$Serie]["Color"]["Alpha"] = $Alpha;
-
- /* Do reverse processing on the internal palette array */
- foreach ($this->Palette as $Key => $Value)
- { if ($Value["R"] == $OldR && $Value["G"] == $OldG && $Value["B"] == $OldB) { $this->Palette[$Key]["R"] = $R; $this->Palette[$Key]["G"] = $G; $this->Palette[$Key]["B"] = $B; $this->Palette[$Key]["Alpha"] = $Alpha;} }
- }
- }
- }
-
- /* Load a palette file */
- function loadPalette($FileName,$Overwrite=FALSE)
- {
- if ( !file_exists($FileName) ) { return(-1); }
- if ( $Overwrite ) { $this->Palette = ""; }
-
- $fileHandle = @fopen($FileName, "r");
- if (!$fileHandle) { return(-1); }
- while (!feof($fileHandle))
- {
- $buffer = fgets($fileHandle, 4096);
- if ( preg_match("/,/",$buffer) )
- {
- list($R,$G,$B,$Alpha) = preg_split("/,/",$buffer);
- if ( $this->Palette == "" ) { $ID = 0; } else { $ID = count($this->Palette); }
- $this->Palette[$ID] = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha);
- }
- }
- fclose($fileHandle);
-
- /* Apply changes to current series */
- $ID = 0;
- if ( isset($this->Data["Series"]))
- {
- foreach($this->Data["Series"] as $Key => $Value)
- {
- if ( !isset($this->Palette[$ID]) )
- $this->Data["Series"][$Key]["Color"] = array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>0);
- else
- $this->Data["Series"][$Key]["Color"] = $this->Palette[$ID];
- $ID++;
- }
- }
- }
-
- /* Initialise a given scatter serie */
- function initScatterSerie($ID)
- {
- if ( isset($this->Data["ScatterSeries"][$ID]) ) { return(0); }
-
- $this->Data["ScatterSeries"][$ID]["Description"] = "Scatter ".$ID;
- $this->Data["ScatterSeries"][$ID]["isDrawable"] = TRUE;
- $this->Data["ScatterSeries"][$ID]["Picture"] = NULL;
- $this->Data["ScatterSeries"][$ID]["Ticks"] = 0;
- $this->Data["ScatterSeries"][$ID]["Weight"] = 0;
-
- if ( isset($this->Palette[$ID]) )
- $this->Data["ScatterSeries"][$ID]["Color"] = $this->Palette[$ID];
- else
- {
- $this->Data["ScatterSeries"][$ID]["Color"]["R"] = rand(0,255);
- $this->Data["ScatterSeries"][$ID]["Color"]["G"] = rand(0,255);
- $this->Data["ScatterSeries"][$ID]["Color"]["B"] = rand(0,255);
- $this->Data["ScatterSeries"][$ID]["Color"]["Alpha"] = 100;
- }
- }
-
- /* Initialise a given serie */
- function initialise($Serie)
- {
- if ( isset($this->Data["Series"]) ) { $ID = count($this->Data["Series"]); } else { $ID = 0; }
-
- $this->Data["Series"][$Serie]["Description"] = $Serie;
- $this->Data["Series"][$Serie]["isDrawable"] = TRUE;
- $this->Data["Series"][$Serie]["Picture"] = NULL;
- $this->Data["Series"][$Serie]["Max"] = NULL;
- $this->Data["Series"][$Serie]["Min"] = NULL;
- $this->Data["Series"][$Serie]["Axis"] = 0;
- $this->Data["Series"][$Serie]["Ticks"] = 0;
- $this->Data["Series"][$Serie]["Weight"] = 0;
- $this->Data["Series"][$Serie]["Shape"] = SERIE_SHAPE_FILLEDCIRCLE;
-
- if ( isset($this->Palette[$ID]) )
- $this->Data["Series"][$Serie]["Color"] = $this->Palette[$ID];
- else
- {
- $this->Data["Series"][$Serie]["Color"]["R"] = rand(0,255);
- $this->Data["Series"][$Serie]["Color"]["G"] = rand(0,255);
- $this->Data["Series"][$Serie]["Color"]["B"] = rand(0,255);
- $this->Data["Series"][$Serie]["Color"]["Alpha"] = 100;
- }
- }
-
- function normalize($NormalizationFactor=100,$UnitChange=NULL,$Round=1)
- {
- $Abscissa = $this->Data["Abscissa"];
-
- $SelectedSeries = "";
- $MaxVal = 0;
- foreach($this->Data["Axis"] as $AxisID => $Axis)
- {
- if ( $UnitChange != NULL ) { $this->Data["Axis"][$AxisID]["Unit"] = $UnitChange; }
-
- foreach($this->Data["Series"] as $SerieName => $Serie)
- {
- if ($Serie["Axis"] == $AxisID && $Serie["isDrawable"] == TRUE && $SerieName != $Abscissa)
- {
- $SelectedSeries[$SerieName] = $SerieName;
-
- if ( count($Serie["Data"] ) > $MaxVal ) { $MaxVal = count($Serie["Data"]); }
- }
- }
- }
-
- for($i=0;$i<=$MaxVal-1;$i++)
- {
- $Factor = 0;
- foreach ($SelectedSeries as $Key => $SerieName )
- {
- $Value = $this->Data["Series"][$SerieName]["Data"][$i];
- if ( $Value != VOID )
- $Factor = $Factor + abs($Value);
- }
-
- if ( $Factor != 0 )
- {
- $Factor = $NormalizationFactor / $Factor;
-
- foreach ($SelectedSeries as $Key => $SerieName )
- {
- $Value = $this->Data["Series"][$SerieName]["Data"][$i];
-
- if ( $Value != VOID && $Factor != $NormalizationFactor )
- $this->Data["Series"][$SerieName]["Data"][$i] = round(abs($Value)*$Factor,$Round);
- elseif ( $Value == VOID || $Value == 0 )
- $this->Data["Series"][$SerieName]["Data"][$i] = VOID;
- elseif ( $Factor == $NormalizationFactor )
- $this->Data["Series"][$SerieName]["Data"][$i] = $NormalizationFactor;
- }
- }
- }
-
- foreach ($SelectedSeries as $Key => $SerieName )
- {
- $this->Data["Series"][$SerieName]["Max"] = max($this->stripVOID($this->Data["Series"][$SerieName]["Data"]));
- $this->Data["Series"][$SerieName]["Min"] = min($this->stripVOID($this->Data["Series"][$SerieName]["Data"]));
- }
- }
-
- /* Load data from a CSV (or similar) data source */
- function importFromCSV($FileName,$Options="")
- {
- $Delimiter = isset($Options["Delimiter"]) ? $Options["Delimiter"] : ",";
- $GotHeader = isset($Options["GotHeader"]) ? $Options["GotHeader"] : FALSE;
- $SkipColumns = isset($Options["SkipColumns"]) ? $Options["SkipColumns"] : array(-1);
- $DefaultSerieName = isset($Options["DefaultSerieName"]) ? $Options["DefaultSerieName"] : "Serie";
-
- $Handle = @fopen($FileName,"r");
- if ($Handle)
- {
- $HeaderParsed = FALSE; $SerieNames = "";
- while (!feof($Handle))
- {
- $Buffer = fgets($Handle, 4096);
- $Buffer = str_replace(chr(10),"",$Buffer);
- $Buffer = str_replace(chr(13),"",$Buffer);
- $Values = preg_split("/".$Delimiter."/",$Buffer);
-
- if ( $Buffer != "" )
- {
- if ( $GotHeader && !$HeaderParsed )
- {
- foreach($Values as $Key => $Name) { if ( !in_array($Key,$SkipColumns) ) { $SerieNames[$Key] = $Name; } }
- $HeaderParsed = TRUE;
- }
- else
- {
- if ($SerieNames == "" ) { foreach($Values as $Key => $Name) { if ( !in_array($Key,$SkipColumns) ) { $SerieNames[$Key] = $DefaultSerieName.$Key; } } }
- foreach($Values as $Key => $Value) { if ( !in_array($Key,$SkipColumns) ) { $this->addPoints($Value,$SerieNames[$Key]); } }
- }
- }
- }
- fclose($Handle);
- }
- }
-
- /* Create a dataset based on a formula */
- /* COMMENTED BY PIWIK to avoid eval()
- function createFunctionSerie($SerieName,$Formula="",$Options="")
- {
- $MinX = isset($Options["MinX"]) ? $Options["MinX"] : -10;
- $MaxX = isset($Options["MaxX"]) ? $Options["MaxX"] : 10;
- $XStep = isset($Options["XStep"]) ? $Options["XStep"] : 1;
- $AutoDescription = isset($Options["AutoDescription"]) ? $Options["AutoDescription"] : FALSE;
- $RecordAbscissa = isset($Options["RecordAbscissa"]) ? $Options["RecordAbscissa"] : FALSE;
- $AbscissaSerie = isset($Options["AbscissaSerie"]) ? $Options["AbscissaSerie"] : "Abscissa";
-
- if ( $Formula == "" ) { return(0); }
-
- $Result = ""; $Abscissa = "";
- for($i=$MinX; $i<=$MaxX; $i=$i+$XStep)
- {
- $Expression = "\$return = '!'.(".str_replace("z",$i,$Formula).");";
- if ( @eval($Expression) === FALSE ) { $return = VOID; }
- if ( $return == "!" ) { $return = VOID; } else { $return = $this->right($return,strlen($return)-1); }
- if ( $return == "NAN" ) { $return = VOID; }
- if ( $return == "INF" ) { $return = VOID; }
- if ( $return == "-INF" ) { $return = VOID; }
-
- $Abscissa[] = $i;
- $Result[] = $return;
- }
-
- $this->addPoints($Result,$SerieName);
- if ( $AutoDescription ) { $this->setSerieDescription($SerieName,$Formula); }
- if ( $RecordAbscissa ) { $this->addPoints($Abscissa,$AbscissaSerie); }
- }*/
-
- function negateValues($Series)
- {
- if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); }
- foreach($Series as $Key => $SerieName)
- {
- if (isset($this->Data["Series"][$SerieName]))
- {
- $Data = "";
- foreach($this->Data["Series"][$SerieName]["Data"] as $Key => $Value)
- { if ( $Value == VOID ) { $Data[] = VOID; } else { $Data[] = -$Value; } }
- $this->Data["Series"][$SerieName]["Data"] = $Data;
-
- $this->Data["Series"][$SerieName]["Max"] = max($this->stripVOID($this->Data["Series"][$SerieName]["Data"]));
- $this->Data["Series"][$SerieName]["Min"] = min($this->stripVOID($this->Data["Series"][$SerieName]["Data"]));
- }
- }
- }
-
- /* Return the data & configuration of the series */
- function getData()
- { return($this->Data); }
-
- /* Save a palette element */
- function savePalette($ID,$Color)
- { $this->Palette[$ID] = $Color; }
-
- /* Return the palette of the series */
- function getPalette()
- { return($this->Palette); }
-
- /* Called by the scaling algorithm to save the config */
- function saveAxisConfig($Axis) { $this->Data["Axis"]=$Axis; }
-
- /* Save the Y Margin if set */
- function saveYMargin($Value) { $this->Data["YMargin"]=$Value; }
-
- /* Save extended configuration to the pData object */
- function saveExtendedData($Tag,$Values) { $this->Data["Extended"][$Tag]=$Values; }
-
- /* Called by the scaling algorithm to save the orientation of the scale */
- function saveOrientation($Orientation) { $this->Data["Orientation"]=$Orientation; }
-
- /* Convert a string to a single elements array */
- function convertToArray($Value)
- { $Values = ""; $Values[] = $Value; return($Values); }
-
- /* Class string wrapper */
- function __toString()
- { return("pData object."); }
-
- function left($value,$NbChar) { return substr($value,0,$NbChar); }
- function right($value,$NbChar) { return substr($value,strlen($value)-$NbChar,$NbChar); }
- function mid($value,$Depart,$NbChar) { return substr($value,$Depart-1,$NbChar); }
- }
+<?php
+ /*
+ pDraw - class to manipulate data arrays
+
+ Version : 2.1.4
+ Made by : Jean-Damien POGOLOTTI
+ Last Update : 19/01/2014
+
+ This file can be distributed under the license you can find at :
+
+ http://www.pchart.net/license
+
+ You can find the whole class documentation on the pChart web site.
+ */
+
+ /* Axis configuration */
+ define("AXIS_FORMAT_DEFAULT" , 680001);
+ define("AXIS_FORMAT_TIME" , 680002);
+ define("AXIS_FORMAT_DATE" , 680003);
+ define("AXIS_FORMAT_METRIC" , 680004);
+ define("AXIS_FORMAT_CURRENCY" , 680005);
+ define("AXIS_FORMAT_TRAFFIC" , 680006);
+ define("AXIS_FORMAT_CUSTOM" , 680007);
+
+ /* Axis position */
+ define("AXIS_POSITION_LEFT" , 681001);
+ define("AXIS_POSITION_RIGHT" , 681002);
+ define("AXIS_POSITION_TOP" , 681001);
+ define("AXIS_POSITION_BOTTOM" , 681002);
+
+ /* Families of data points */
+ define("SERIE_SHAPE_FILLEDCIRCLE" , 681011);
+ define("SERIE_SHAPE_FILLEDTRIANGLE" , 681012);
+ define("SERIE_SHAPE_FILLEDSQUARE" , 681013);
+ define("SERIE_SHAPE_FILLEDDIAMOND" , 681017);
+ define("SERIE_SHAPE_CIRCLE" , 681014);
+ define("SERIE_SHAPE_TRIANGLE" , 681015);
+ define("SERIE_SHAPE_SQUARE" , 681016);
+ define("SERIE_SHAPE_DIAMOND" , 681018);
+
+ /* Axis position */
+ define("AXIS_X" , 682001);
+ define("AXIS_Y" , 682002);
+
+ /* Define value limits */
+ define("ABSOLUTE_MIN" , -10000000000000);
+ define("ABSOLUTE_MAX" , 10000000000000);
+
+ /* Replacement to the PHP NULL keyword */
+ define("VOID" , 0.123456789);
+
+ /* Euro symbol for GD fonts */
+ define("EURO_SYMBOL" , utf8_encode("&#8364;"));
+
+ /* pData class definition */
+ class pData
+ {
+ var $Data;
+
+ var $Palette = array("0"=>array("R"=>188,"G"=>224,"B"=>46,"Alpha"=>100),
+ "1"=>array("R"=>224,"G"=>100,"B"=>46,"Alpha"=>100),
+ "2"=>array("R"=>224,"G"=>214,"B"=>46,"Alpha"=>100),
+ "3"=>array("R"=>46,"G"=>151,"B"=>224,"Alpha"=>100),
+ "4"=>array("R"=>176,"G"=>46,"B"=>224,"Alpha"=>100),
+ "5"=>array("R"=>224,"G"=>46,"B"=>117,"Alpha"=>100),
+ "6"=>array("R"=>92,"G"=>224,"B"=>46,"Alpha"=>100),
+ "7"=>array("R"=>224,"G"=>176,"B"=>46,"Alpha"=>100));
+
+ /* Class creator */
+ function __construct()
+ {
+ $this->Data = "";
+ $this->Data["XAxisDisplay"] = AXIS_FORMAT_DEFAULT;
+ $this->Data["XAxisFormat"] = NULL;
+ $this->Data["XAxisName"] = NULL;
+ $this->Data["XAxisUnit"] = NULL;
+ $this->Data["Abscissa"] = NULL;
+ $this->Data["AbsicssaPosition"] = AXIS_POSITION_BOTTOM;
+
+ $this->Data["Axis"][0]["Display"] = AXIS_FORMAT_DEFAULT;
+ $this->Data["Axis"][0]["Position"] = AXIS_POSITION_LEFT;
+ $this->Data["Axis"][0]["Identity"] = AXIS_Y;
+ }
+
+ /* Add a single point or an array to the given serie */
+ function addPoints($Values,$SerieName="Serie1")
+ {
+ if (!isset($this->Data["Series"][$SerieName]))
+ $this->initialise($SerieName);
+
+ if ( is_array($Values) )
+ {
+ foreach($Values as $Key => $Value)
+ { $this->Data["Series"][$SerieName]["Data"][] = $Value; }
+ }
+ else
+ $this->Data["Series"][$SerieName]["Data"][] = $Values;
+
+ if ( $Values != VOID )
+ {
+ $StrippedData = $this->stripVOID($this->Data["Series"][$SerieName]["Data"]);
+ if ( empty($StrippedData) ) { $this->Data["Series"][$SerieName]["Max"] = 0; $this->Data["Series"][$SerieName]["Min"] =0; return(0); }
+ $this->Data["Series"][$SerieName]["Max"] = max($StrippedData);
+ $this->Data["Series"][$SerieName]["Min"] = min($StrippedData);
+ }
+ }
+
+ /* Strip VOID values */
+ function stripVOID($Values)
+ { if (!is_array($Values)) { return(array()); } $Result = array(); foreach($Values as $Key => $Value) { if ( $Value != VOID ) { $Result[] = $Value; } } return($Result); }
+
+ /* Return the number of values contained in a given serie */
+ function getSerieCount($Serie)
+ { if (isset($this->Data["Series"][$Serie]["Data"])) { return(sizeof($this->Data["Series"][$Serie]["Data"])); } else { return(0); } }
+
+ /* Remove a serie from the pData object */
+ function removeSerie($Series)
+ {
+ if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); }
+ foreach($Series as $Key => $Serie) { if (isset($this->Data["Series"][$Serie])) { unset($this->Data["Series"][$Serie]); } }
+ }
+
+ /* Return a value from given serie & index */
+ function getValueAt($Serie,$Index=0)
+ { if (isset($this->Data["Series"][$Serie]["Data"][$Index])) { return($this->Data["Series"][$Serie]["Data"][$Index]); } else { return(NULL); } }
+
+ /* Return the values array */
+ function getValues($Serie)
+ { if (isset($this->Data["Series"][$Serie]["Data"])) { return($this->Data["Series"][$Serie]["Data"]); } else { return(NULL); } }
+
+ /* Reverse the values in the given serie */
+ function reverseSerie($Series)
+ {
+ if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); }
+ foreach($Series as $Key => $Serie) { if (isset($this->Data["Series"][$Serie]["Data"])) { $this->Data["Series"][$Serie]["Data"] = array_reverse($this->Data["Series"][$Serie]["Data"]); } }
+ }
+
+ /* Return the sum of the serie values */
+ function getSum($Serie)
+ { if (isset($this->Data["Series"][$Serie])) { return(array_sum($this->Data["Series"][$Serie]["Data"])); } else { return(NULL); } }
+
+ /* Return the max value of a given serie */
+ function getMax($Serie)
+ { if (isset($this->Data["Series"][$Serie]["Max"])) { return($this->Data["Series"][$Serie]["Max"]); } else { return(NULL); } }
+
+ /* Return the min value of a given serie */
+ function getMin($Serie)
+ { if (isset($this->Data["Series"][$Serie]["Min"])) { return($this->Data["Series"][$Serie]["Min"]); } else { return(NULL); } }
+
+ /* Set the description of a given serie */
+ function setSerieShape($Series,$Shape=SERIE_SHAPE_FILLEDCIRCLE)
+ {
+ if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); }
+ foreach($Series as $Key => $Serie) { if (isset($this->Data["Series"][$Serie]) ) { $this->Data["Series"][$Serie]["Shape"] = $Shape; } }
+ }
+
+ /* Set the description of a given serie */
+ function setSerieDescription($Series,$Description="My serie")
+ {
+ if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); }
+ foreach($Series as $Key => $Serie) { if (isset($this->Data["Series"][$Serie]) ) { $this->Data["Series"][$Serie]["Description"] = $Description; } }
+ }
+
+ /* Set a serie as "drawable" while calling a rendering function */
+ function setSerieDrawable($Series,$Drawable=TRUE)
+ {
+ if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); }
+ foreach($Series as $Key => $Serie) { if (isset($this->Data["Series"][$Serie]) ) { $this->Data["Series"][$Serie]["isDrawable"] = $Drawable; } }
+ }
+
+ /* Set the icon associated to a given serie */
+ function setSeriePicture($Series,$Picture=NULL)
+ {
+ if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); }
+ foreach($Series as $Key => $Serie) { if (isset($this->Data["Series"][$Serie]) ) { $this->Data["Series"][$Serie]["Picture"] = $Picture; } }
+ }
+
+ /* Set the name of the X Axis */
+ function setXAxisName($Name)
+ { $this->Data["XAxisName"] = $Name; }
+
+ /* Set the display mode of the X Axis */
+ function setXAxisDisplay($Mode,$Format=NULL)
+ { $this->Data["XAxisDisplay"] = $Mode; $this->Data["XAxisFormat"] = $Format; }
+
+ /* Set the unit that will be displayed on the X axis */
+ function setXAxisUnit($Unit)
+ { $this->Data["XAxisUnit"] = $Unit; }
+
+ /* Set the serie that will be used as abscissa */
+ function setAbscissa($Serie)
+ { if (isset($this->Data["Series"][$Serie])) { $this->Data["Abscissa"] = $Serie; } }
+
+ function setAbsicssaPosition($Position = AXIS_POSITION_BOTTOM)
+ { $this->Data["AbsicssaPosition"] = $Position; }
+
+ /* Set the name of the abscissa axis */
+ function setAbscissaName($Name)
+ { $this->Data["AbscissaName"] = $Name; }
+
+ /* Create a scatter group specifyin X and Y data series */
+ function setScatterSerie($SerieX,$SerieY,$ID=0)
+ { if (isset($this->Data["Series"][$SerieX]) && isset($this->Data["Series"][$SerieY]) ) { $this->initScatterSerie($ID); $this->Data["ScatterSeries"][$ID]["X"] = $SerieX; $this->Data["ScatterSeries"][$ID]["Y"] = $SerieY; } }
+
+ /* Set the shape of a given sctatter serie */
+ function setScatterSerieShape($ID,$Shape=SERIE_SHAPE_FILLEDCIRCLE)
+ { if (isset($this->Data["ScatterSeries"][$ID]) ) { $this->Data["ScatterSeries"][$ID]["Shape"] = $Shape; } }
+
+ /* Set the description of a given scatter serie */
+ function setScatterSerieDescription($ID,$Description="My serie")
+ { if (isset($this->Data["ScatterSeries"][$ID]) ) { $this->Data["ScatterSeries"][$ID]["Description"] = $Description; } }
+
+ /* Set the icon associated to a given scatter serie */
+ function setScatterSeriePicture($ID,$Picture=NULL)
+ { if (isset($this->Data["ScatterSeries"][$ID]) ) { $this->Data["ScatterSeries"][$ID]["Picture"] = $Picture; } }
+
+ /* Set a scatter serie as "drawable" while calling a rendering function */
+ function setScatterSerieDrawable($ID ,$Drawable=TRUE)
+ { if (isset($this->Data["ScatterSeries"][$ID]) ) { $this->Data["ScatterSeries"][$ID]["isDrawable"] = $Drawable; } }
+
+ /* Define if a scatter serie should be draw with ticks */
+ function setScatterSerieTicks($ID,$Width=0)
+ { if ( isset($this->Data["ScatterSeries"][$ID]) ) { $this->Data["ScatterSeries"][$ID]["Ticks"] = $Width; } }
+
+ /* Define if a scatter serie should be draw with a special weight */
+ function setScatterSerieWeight($ID,$Weight=0)
+ { if ( isset($this->Data["ScatterSeries"][$ID]) ) { $this->Data["ScatterSeries"][$ID]["Weight"] = $Weight; } }
+
+ /* Associate a color to a scatter serie */
+ function setScatterSerieColor($ID,$Format)
+ {
+ $R = isset($Format["R"]) ? $Format["R"] : 0;
+ $G = isset($Format["G"]) ? $Format["G"] : 0;
+ $B = isset($Format["B"]) ? $Format["B"] : 0;
+ $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;
+
+ if ( isset($this->Data["ScatterSeries"][$ID]) )
+ {
+ $this->Data["ScatterSeries"][$ID]["Color"]["R"] = $R;
+ $this->Data["ScatterSeries"][$ID]["Color"]["G"] = $G;
+ $this->Data["ScatterSeries"][$ID]["Color"]["B"] = $B;
+ $this->Data["ScatterSeries"][$ID]["Color"]["Alpha"] = $Alpha;
+ }
+ }
+
+ /* Compute the series limits for an individual and global point of view */
+ function limits()
+ {
+ $GlobalMin = ABSOLUTE_MAX;
+ $GlobalMax = ABSOLUTE_MIN;
+
+ foreach($this->Data["Series"] as $Key => $Value)
+ {
+ if ( $this->Data["Abscissa"] != $Key && $this->Data["Series"][$Key]["isDrawable"] == TRUE)
+ {
+ if ( $GlobalMin > $this->Data["Series"][$Key]["Min"] ) { $GlobalMin = $this->Data["Series"][$Key]["Min"]; }
+ if ( $GlobalMax < $this->Data["Series"][$Key]["Max"] ) { $GlobalMax = $this->Data["Series"][$Key]["Max"]; }
+ }
+ }
+ $this->Data["Min"] = $GlobalMin;
+ $this->Data["Max"] = $GlobalMax;
+
+ return(array($GlobalMin,$GlobalMax));
+ }
+
+ /* Mark all series as drawable */
+ function drawAll()
+ { foreach($this->Data["Series"] as $Key => $Value) { if ( $this->Data["Abscissa"] != $Key ) { $this->Data["Series"][$Key]["isDrawable"]=TRUE; } } }
+
+ /* Return the average value of the given serie */
+ function getSerieAverage($Serie)
+ {
+ if ( isset($this->Data["Series"][$Serie]) )
+ {
+ $SerieData = $this->stripVOID($this->Data["Series"][$Serie]["Data"]);
+ return(array_sum($SerieData)/sizeof($SerieData));
+ }
+ else
+ return(NULL);
+ }
+
+ /* Return the geometric mean of the given serie */
+ function getGeometricMean($Serie)
+ {
+ if ( isset($this->Data["Series"][$Serie]) )
+ {
+ $SerieData = $this->stripVOID($this->Data["Series"][$Serie]["Data"]);
+ $Seriesum = 1; foreach($SerieData as $Key => $Value) { $Seriesum = $Seriesum * $Value; }
+ return(pow($Seriesum,1/sizeof($SerieData)));
+ }
+ else
+ return(NULL);
+ }
+
+ /* Return the harmonic mean of the given serie */
+ function getHarmonicMean($Serie)
+ {
+ if ( isset($this->Data["Series"][$Serie]) )
+ {
+ $SerieData = $this->stripVOID($this->Data["Series"][$Serie]["Data"]);
+ $Seriesum = 0; foreach($SerieData as $Key => $Value) { $Seriesum = $Seriesum + 1/$Value; }
+ return(sizeof($SerieData)/$Seriesum);
+ }
+ else
+ return(NULL);
+ }
+
+ /* Return the standard deviation of the given serie */
+ function getStandardDeviation($Serie)
+ {
+ if ( isset($this->Data["Series"][$Serie]) )
+ {
+ $Average = $this->getSerieAverage($Serie);
+ $SerieData = $this->stripVOID($this->Data["Series"][$Serie]["Data"]);
+
+ $DeviationSum = 0;
+ foreach($SerieData as $Key => $Value)
+ $DeviationSum = $DeviationSum + ($Value-$Average)*($Value-$Average);
+
+ $Deviation = sqrt($DeviationSum/count($SerieData));
+
+ return($Deviation);
+ }
+ else
+ return(NULL);
+ }
+
+ /* Return the Coefficient of variation of the given serie */
+ function getCoefficientOfVariation($Serie)
+ {
+ if ( isset($this->Data["Series"][$Serie]) )
+ {
+ $Average = $this->getSerieAverage($Serie);
+ $StandardDeviation = $this->getStandardDeviation($Serie);
+
+ if ( $StandardDeviation != 0 )
+ return($StandardDeviation/$Average);
+ else
+ return(NULL);
+ }
+ else
+ return(NULL);
+ }
+
+ /* Return the median value of the given serie */
+ function getSerieMedian($Serie)
+ {
+ if ( isset($this->Data["Series"][$Serie]) )
+ {
+ $SerieData = $this->stripVOID($this->Data["Series"][$Serie]["Data"]);
+ sort($SerieData);
+ $SerieCenter = floor(sizeof($SerieData)/2);
+
+ if ( isset($SerieData[$SerieCenter]) )
+ return($SerieData[$SerieCenter]);
+ else
+ return(NULL);
+ }
+ else
+ return(NULL);
+ }
+
+ /* Return the x th percentil of the given serie */
+ function getSeriePercentile($Serie="Serie1",$Percentil=95)
+ {
+ if (!isset($this->Data["Series"][$Serie]["Data"])) { return(NULL); }
+
+ $Values = count($this->Data["Series"][$Serie]["Data"])-1;
+ if ( $Values < 0 ) { $Values = 0; }
+
+ $PercentilID = floor(($Values/100)*$Percentil+.5);
+ $SortedValues = $this->Data["Series"][$Serie]["Data"];
+ sort($SortedValues);
+
+ if ( is_numeric($SortedValues[$PercentilID]) )
+ return($SortedValues[$PercentilID]);
+ else
+ return(NULL);
+ }
+
+ /* Add random values to a given serie */
+ function addRandomValues($SerieName="Serie1",$Options="")
+ {
+ $Values = isset($Options["Values"]) ? $Options["Values"] : 20;
+ $Min = isset($Options["Min"]) ? $Options["Min"] : 0;
+ $Max = isset($Options["Max"]) ? $Options["Max"] : 100;
+ $withFloat = isset($Options["withFloat"]) ? $Options["withFloat"] : FALSE;
+
+ for ($i=0;$i<=$Values;$i++)
+ {
+ if ( $withFloat ) { $Value = rand($Min*100,$Max*100)/100; } else { $Value = rand($Min,$Max); }
+ $this->addPoints($Value,$SerieName);
+ }
+ }
+
+ /* Test if we have valid data */
+ function containsData()
+ {
+ if (!isset($this->Data["Series"])) { return(FALSE); }
+
+ $Result = FALSE;
+ foreach($this->Data["Series"] as $Key => $Value)
+ { if ( $this->Data["Abscissa"] != $Key && $this->Data["Series"][$Key]["isDrawable"]==TRUE) { $Result=TRUE; } }
+ return($Result);
+ }
+
+ /* Set the display mode of an Axis */
+ function setAxisDisplay($AxisID,$Mode=AXIS_FORMAT_DEFAULT,$Format=NULL)
+ {
+ if ( isset($this->Data["Axis"][$AxisID] ) )
+ {
+ $this->Data["Axis"][$AxisID]["Display"] = $Mode;
+ if ( $Format != NULL ) { $this->Data["Axis"][$AxisID]["Format"] = $Format; }
+ }
+ }
+
+ /* Set the position of an Axis */
+ function setAxisPosition($AxisID,$Position=AXIS_POSITION_LEFT)
+ { if ( isset($this->Data["Axis"][$AxisID] ) ) { $this->Data["Axis"][$AxisID]["Position"] = $Position; } }
+
+ /* Associate an unit to an axis */
+ function setAxisUnit($AxisID,$Unit)
+ { if ( isset($this->Data["Axis"][$AxisID] ) ) { $this->Data["Axis"][$AxisID]["Unit"] = $Unit; } }
+
+ /* Associate a name to an axis */
+ function setAxisName($AxisID,$Name)
+ { if ( isset($this->Data["Axis"][$AxisID] ) ) { $this->Data["Axis"][$AxisID]["Name"] = $Name; } }
+
+ /* Associate a color to an axis */
+ function setAxisColor($AxisID,$Format)
+ {
+ $R = isset($Format["R"]) ? $Format["R"] : 0;
+ $G = isset($Format["G"]) ? $Format["G"] : 0;
+ $B = isset($Format["B"]) ? $Format["B"] : 0;
+ $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;
+
+ if ( isset($this->Data["Axis"][$AxisID] ) )
+ {
+ $this->Data["Axis"][$AxisID]["Color"]["R"] = $R;
+ $this->Data["Axis"][$AxisID]["Color"]["G"] = $G;
+ $this->Data["Axis"][$AxisID]["Color"]["B"] = $B;
+ $this->Data["Axis"][$AxisID]["Color"]["Alpha"] = $Alpha;
+ }
+ }
+
+
+ /* Design an axis as X or Y member */
+ function setAxisXY($AxisID,$Identity=AXIS_Y)
+ { if ( isset($this->Data["Axis"][$AxisID] ) ) { $this->Data["Axis"][$AxisID]["Identity"] = $Identity; } }
+
+ /* Associate one data serie with one axis */
+ function setSerieOnAxis($Series,$AxisID)
+ {
+ if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); }
+ foreach($Series as $Key => $Serie)
+ {
+ $PreviousAxis = $this->Data["Series"][$Serie]["Axis"];
+
+ /* Create missing axis */
+ if ( !isset($this->Data["Axis"][$AxisID] ) )
+ { $this->Data["Axis"][$AxisID]["Position"] = AXIS_POSITION_LEFT; $this->Data["Axis"][$AxisID]["Identity"] = AXIS_Y;}
+
+ $this->Data["Series"][$Serie]["Axis"] = $AxisID;
+
+ /* Cleanup unused axis */
+ $Found = FALSE;
+ foreach($this->Data["Series"] as $SerieName => $Values) { if ( $Values["Axis"] == $PreviousAxis ) { $Found = TRUE; } }
+ if (!$Found) { unset($this->Data["Axis"][$PreviousAxis]); }
+ }
+ }
+
+ /* Define if a serie should be draw with ticks */
+ function setSerieTicks($Series,$Width=0)
+ {
+ if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); }
+ foreach($Series as $Key => $Serie) { if ( isset($this->Data["Series"][$Serie]) ) { $this->Data["Series"][$Serie]["Ticks"] = $Width; } }
+ }
+
+ /* Define if a serie should be draw with a special weight */
+ function setSerieWeight($Series,$Weight=0)
+ {
+ if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); }
+ foreach($Series as $Key => $Serie) { if ( isset($this->Data["Series"][$Serie]) ) { $this->Data["Series"][$Serie]["Weight"] = $Weight; } }
+ }
+
+ /* Returns the palette of the given serie */
+ function getSeriePalette($Serie)
+ {
+ if ( !isset($this->Data["Series"][$Serie]) ) { return(NULL); }
+
+ $Result = "";
+ $Result["R"] = $this->Data["Series"][$Serie]["Color"]["R"];
+ $Result["G"] = $this->Data["Series"][$Serie]["Color"]["G"];
+ $Result["B"] = $this->Data["Series"][$Serie]["Color"]["B"];
+ $Result["Alpha"] = $this->Data["Series"][$Serie]["Color"]["Alpha"];
+
+ return($Result);
+ }
+
+ /* Set the color of one serie */
+ function setPalette($Series,$Format=NULL)
+ {
+ if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); }
+
+ foreach($Series as $Key => $Serie)
+ {
+ $R = isset($Format["R"]) ? $Format["R"] : 0;
+ $G = isset($Format["G"]) ? $Format["G"] : 0;
+ $B = isset($Format["B"]) ? $Format["B"] : 0;
+ $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;
+
+ if ( isset($this->Data["Series"][$Serie]) )
+ {
+ $OldR = $this->Data["Series"][$Serie]["Color"]["R"]; $OldG = $this->Data["Series"][$Serie]["Color"]["G"]; $OldB = $this->Data["Series"][$Serie]["Color"]["B"];
+ $this->Data["Series"][$Serie]["Color"]["R"] = $R;
+ $this->Data["Series"][$Serie]["Color"]["G"] = $G;
+ $this->Data["Series"][$Serie]["Color"]["B"] = $B;
+ $this->Data["Series"][$Serie]["Color"]["Alpha"] = $Alpha;
+
+ /* Do reverse processing on the internal palette array */
+ foreach ($this->Palette as $Key => $Value)
+ { if ($Value["R"] == $OldR && $Value["G"] == $OldG && $Value["B"] == $OldB) { $this->Palette[$Key]["R"] = $R; $this->Palette[$Key]["G"] = $G; $this->Palette[$Key]["B"] = $B; $this->Palette[$Key]["Alpha"] = $Alpha;} }
+ }
+ }
+ }
+
+ /* Load a palette file */
+ function loadPalette($FileName,$Overwrite=FALSE)
+ {
+ if ( !file_exists($FileName) ) { return(-1); }
+ if ( $Overwrite ) { $this->Palette = ""; }
+
+ $fileHandle = @fopen($FileName, "r");
+ if (!$fileHandle) { return(-1); }
+ while (!feof($fileHandle))
+ {
+ $buffer = fgets($fileHandle, 4096);
+ if ( preg_match("/,/",$buffer) )
+ {
+ list($R,$G,$B,$Alpha) = preg_split("/,/",$buffer);
+ if ( $this->Palette == "" ) { $ID = 0; } else { $ID = count($this->Palette); }
+ $this->Palette[$ID] = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha);
+ }
+ }
+ fclose($fileHandle);
+
+ /* Apply changes to current series */
+ $ID = 0;
+ if ( isset($this->Data["Series"]))
+ {
+ foreach($this->Data["Series"] as $Key => $Value)
+ {
+ if ( !isset($this->Palette[$ID]) )
+ $this->Data["Series"][$Key]["Color"] = array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>0);
+ else
+ $this->Data["Series"][$Key]["Color"] = $this->Palette[$ID];
+ $ID++;
+ }
+ }
+ }
+
+ /* Initialise a given scatter serie */
+ function initScatterSerie($ID)
+ {
+ if ( isset($this->Data["ScatterSeries"][$ID]) ) { return(0); }
+
+ $this->Data["ScatterSeries"][$ID]["Description"] = "Scatter ".$ID;
+ $this->Data["ScatterSeries"][$ID]["isDrawable"] = TRUE;
+ $this->Data["ScatterSeries"][$ID]["Picture"] = NULL;
+ $this->Data["ScatterSeries"][$ID]["Ticks"] = 0;
+ $this->Data["ScatterSeries"][$ID]["Weight"] = 0;
+
+ if ( isset($this->Palette[$ID]) )
+ $this->Data["ScatterSeries"][$ID]["Color"] = $this->Palette[$ID];
+ else
+ {
+ $this->Data["ScatterSeries"][$ID]["Color"]["R"] = rand(0,255);
+ $this->Data["ScatterSeries"][$ID]["Color"]["G"] = rand(0,255);
+ $this->Data["ScatterSeries"][$ID]["Color"]["B"] = rand(0,255);
+ $this->Data["ScatterSeries"][$ID]["Color"]["Alpha"] = 100;
+ }
+ }
+
+ /* Initialise a given serie */
+ function initialise($Serie)
+ {
+ if ( isset($this->Data["Series"]) ) { $ID = count($this->Data["Series"]); } else { $ID = 0; }
+
+ $this->Data["Series"][$Serie]["Description"] = $Serie;
+ $this->Data["Series"][$Serie]["isDrawable"] = TRUE;
+ $this->Data["Series"][$Serie]["Picture"] = NULL;
+ $this->Data["Series"][$Serie]["Max"] = NULL;
+ $this->Data["Series"][$Serie]["Min"] = NULL;
+ $this->Data["Series"][$Serie]["Axis"] = 0;
+ $this->Data["Series"][$Serie]["Ticks"] = 0;
+ $this->Data["Series"][$Serie]["Weight"] = 0;
+ $this->Data["Series"][$Serie]["Shape"] = SERIE_SHAPE_FILLEDCIRCLE;
+
+ if ( isset($this->Palette[$ID]) )
+ $this->Data["Series"][$Serie]["Color"] = $this->Palette[$ID];
+ else
+ {
+ $this->Data["Series"][$Serie]["Color"]["R"] = rand(0,255);
+ $this->Data["Series"][$Serie]["Color"]["G"] = rand(0,255);
+ $this->Data["Series"][$Serie]["Color"]["B"] = rand(0,255);
+ $this->Data["Series"][$Serie]["Color"]["Alpha"] = 100;
+ }
+ }
+
+ function normalize($NormalizationFactor=100,$UnitChange=NULL,$Round=1)
+ {
+ $Abscissa = $this->Data["Abscissa"];
+
+ $SelectedSeries = "";
+ $MaxVal = 0;
+ foreach($this->Data["Axis"] as $AxisID => $Axis)
+ {
+ if ( $UnitChange != NULL ) { $this->Data["Axis"][$AxisID]["Unit"] = $UnitChange; }
+
+ foreach($this->Data["Series"] as $SerieName => $Serie)
+ {
+ if ($Serie["Axis"] == $AxisID && $Serie["isDrawable"] == TRUE && $SerieName != $Abscissa)
+ {
+ $SelectedSeries[$SerieName] = $SerieName;
+
+ if ( count($Serie["Data"] ) > $MaxVal ) { $MaxVal = count($Serie["Data"]); }
+ }
+ }
+ }
+
+ for($i=0;$i<=$MaxVal-1;$i++)
+ {
+ $Factor = 0;
+ foreach ($SelectedSeries as $Key => $SerieName )
+ {
+ $Value = $this->Data["Series"][$SerieName]["Data"][$i];
+ if ( $Value != VOID )
+ $Factor = $Factor + abs($Value);
+ }
+
+ if ( $Factor != 0 )
+ {
+ $Factor = $NormalizationFactor / $Factor;
+
+ foreach ($SelectedSeries as $Key => $SerieName )
+ {
+ $Value = $this->Data["Series"][$SerieName]["Data"][$i];
+
+ if ( $Value != VOID && $Factor != $NormalizationFactor )
+ $this->Data["Series"][$SerieName]["Data"][$i] = round(abs($Value)*$Factor,$Round);
+ elseif ( $Value == VOID || $Value == 0 )
+ $this->Data["Series"][$SerieName]["Data"][$i] = VOID;
+ elseif ( $Factor == $NormalizationFactor )
+ $this->Data["Series"][$SerieName]["Data"][$i] = $NormalizationFactor;
+ }
+ }
+ }
+
+ foreach ($SelectedSeries as $Key => $SerieName )
+ {
+ $this->Data["Series"][$SerieName]["Max"] = max($this->stripVOID($this->Data["Series"][$SerieName]["Data"]));
+ $this->Data["Series"][$SerieName]["Min"] = min($this->stripVOID($this->Data["Series"][$SerieName]["Data"]));
+ }
+ }
+
+ /* Load data from a CSV (or similar) data source */
+ function importFromCSV($FileName,$Options="")
+ {
+ $Delimiter = isset($Options["Delimiter"]) ? $Options["Delimiter"] : ",";
+ $GotHeader = isset($Options["GotHeader"]) ? $Options["GotHeader"] : FALSE;
+ $SkipColumns = isset($Options["SkipColumns"]) ? $Options["SkipColumns"] : array(-1);
+ $DefaultSerieName = isset($Options["DefaultSerieName"]) ? $Options["DefaultSerieName"] : "Serie";
+
+ $Handle = @fopen($FileName,"r");
+ if ($Handle)
+ {
+ $HeaderParsed = FALSE; $SerieNames = "";
+ while (!feof($Handle))
+ {
+ $Buffer = fgets($Handle, 4096);
+ $Buffer = str_replace(chr(10),"",$Buffer);
+ $Buffer = str_replace(chr(13),"",$Buffer);
+ $Values = preg_split("/".$Delimiter."/",$Buffer);
+
+ if ( $Buffer != "" )
+ {
+ if ( $GotHeader && !$HeaderParsed )
+ {
+ foreach($Values as $Key => $Name) { if ( !in_array($Key,$SkipColumns) ) { $SerieNames[$Key] = $Name; } }
+ $HeaderParsed = TRUE;
+ }
+ else
+ {
+ if ($SerieNames == "" ) { foreach($Values as $Key => $Name) { if ( !in_array($Key,$SkipColumns) ) { $SerieNames[$Key] = $DefaultSerieName.$Key; } } }
+ foreach($Values as $Key => $Value) { if ( !in_array($Key,$SkipColumns) ) { $this->addPoints($Value,$SerieNames[$Key]); } }
+ }
+ }
+ }
+ fclose($Handle);
+ }
+ }
+
+ /* Create a dataset based on a formula */
+ /* COMMENTED BY PIWIK to avoid eval()
+ function createFunctionSerie($SerieName,$Formula="",$Options="")
+ {
+ $MinX = isset($Options["MinX"]) ? $Options["MinX"] : -10;
+ $MaxX = isset($Options["MaxX"]) ? $Options["MaxX"] : 10;
+ $XStep = isset($Options["XStep"]) ? $Options["XStep"] : 1;
+ $AutoDescription = isset($Options["AutoDescription"]) ? $Options["AutoDescription"] : FALSE;
+ $RecordAbscissa = isset($Options["RecordAbscissa"]) ? $Options["RecordAbscissa"] : FALSE;
+ $AbscissaSerie = isset($Options["AbscissaSerie"]) ? $Options["AbscissaSerie"] : "Abscissa";
+
+ if ( $Formula == "" ) { return(0); }
+
+ $Result = ""; $Abscissa = "";
+ for($i=$MinX; $i<=$MaxX; $i=$i+$XStep)
+ {
+ $Expression = "\$return = '!'.(".str_replace("z",$i,$Formula).");";
+ if ( @eval($Expression) === FALSE ) { $return = VOID; }
+ if ( $return == "!" ) { $return = VOID; } else { $return = $this->right($return,strlen($return)-1); }
+ if ( $return == "NAN" ) { $return = VOID; }
+ if ( $return == "INF" ) { $return = VOID; }
+ if ( $return == "-INF" ) { $return = VOID; }
+
+ $Abscissa[] = $i;
+ $Result[] = $return;
+ }
+
+ $this->addPoints($Result,$SerieName);
+ if ( $AutoDescription ) { $this->setSerieDescription($SerieName,$Formula); }
+ if ( $RecordAbscissa ) { $this->addPoints($Abscissa,$AbscissaSerie); }
+ }*/
+
+ function negateValues($Series)
+ {
+ if ( !is_array($Series) ) { $Series = $this->convertToArray($Series); }
+ foreach($Series as $Key => $SerieName)
+ {
+ if (isset($this->Data["Series"][$SerieName]))
+ {
+ $Data = "";
+ foreach($this->Data["Series"][$SerieName]["Data"] as $Key => $Value)
+ { if ( $Value == VOID ) { $Data[] = VOID; } else { $Data[] = -$Value; } }
+ $this->Data["Series"][$SerieName]["Data"] = $Data;
+
+ $this->Data["Series"][$SerieName]["Max"] = max($this->stripVOID($this->Data["Series"][$SerieName]["Data"]));
+ $this->Data["Series"][$SerieName]["Min"] = min($this->stripVOID($this->Data["Series"][$SerieName]["Data"]));
+ }
+ }
+ }
+
+ /* Return the data & configuration of the series */
+ function getData()
+ { return($this->Data); }
+
+ /* Save a palette element */
+ function savePalette($ID,$Color)
+ { $this->Palette[$ID] = $Color; }
+
+ /* Return the palette of the series */
+ function getPalette()
+ { return($this->Palette); }
+
+ /* Called by the scaling algorithm to save the config */
+ function saveAxisConfig($Axis) { $this->Data["Axis"]=$Axis; }
+
+ /* Save the Y Margin if set */
+ function saveYMargin($Value) { $this->Data["YMargin"]=$Value; }
+
+ /* Save extended configuration to the pData object */
+ function saveExtendedData($Tag,$Values) { $this->Data["Extended"][$Tag]=$Values; }
+
+ /* Called by the scaling algorithm to save the orientation of the scale */
+ function saveOrientation($Orientation) { $this->Data["Orientation"]=$Orientation; }
+
+ /* Convert a string to a single elements array */
+ function convertToArray($Value)
+ { $Values = ""; $Values[] = $Value; return($Values); }
+
+ /* Class string wrapper */
+ function __toString()
+ { return("pData object."); }
+
+ function left($value,$NbChar) { return substr($value,0,$NbChar); }
+ function right($value,$NbChar) { return substr($value,strlen($value)-$NbChar,$NbChar); }
+ function mid($value,$Depart,$NbChar) { return substr($value,$Depart-1,$NbChar); }
+ }
?> \ No newline at end of file
diff --git a/libs/pChart/class/pImage.class.php b/libs/pChart/class/pImage.class.php
index 900174d720..562dd08922 100755
--- a/libs/pChart/class/pImage.class.php
+++ b/libs/pChart/class/pImage.class.php
@@ -1,482 +1,482 @@
-<?php
- /*
- pDraw - pChart core class
-
- Version : 2.1.4
- Made by : Jean-Damien POGOLOTTI
- Last Update : 19/01/2014
-
- This file can be distributed under the license you can find at :
-
- http://www.pchart.net/license
-
- You can find the whole class documentation on the pChart web site.
- */
-
- /* The GD extension is mandatory */
- if (!extension_loaded('gd') && !extension_loaded('gd2'))
- {
- echo "GD extension must be loaded. \r\n";
- exit();
- }
-
- /* Image map handling */
- define("IMAGE_MAP_STORAGE_FILE" , 680001);
- define("IMAGE_MAP_STORAGE_SESSION" , 680002);
-
- /* Last generated chart layout */
- define("CHART_LAST_LAYOUT_REGULAR" , 680011);
- define("CHART_LAST_LAYOUT_STACKED" , 680012);
-
- /* ImageMap string delimiter */
- define("IMAGE_MAP_DELIMITER" , chr(1));
-
- class pImage extends pDraw
- {
- /* Image settings, size, quality, .. */
- var $XSize = NULL; // Width of the picture
- var $YSize = NULL; // Height of the picture
- var $Picture = NULL; // GD picture object
- var $Antialias = TRUE; // Turn antialias on or off
- var $AntialiasQuality = 0; // Quality of the antialiasing implementation (0-1)
- var $Mask = ""; // Already drawn pixels mask (Filled circle implementation)
- var $TransparentBackground = FALSE; // Just to know if we need to flush the alpha channels when rendering
-
- /* Graph area settings */
- var $GraphAreaX1 = NULL; // Graph area X origin
- var $GraphAreaY1 = NULL; // Graph area Y origin
- var $GraphAreaX2 = NULL; // Graph area bottom right X position
- var $GraphAreaY2 = NULL; // Graph area bottom right Y position
-
- /* Scale settings */
- var $ScaleMinDivHeight = 20; // Minimum height for scame divs
-
- /* Font properties */
- var $FontName = "fonts/GeosansLight.ttf"; // Default font file
- var $FontSize = 12; // Default font size
- var $FontBox = NULL; // Return the bounding box of the last written string
- var $FontColorR = 0; // Default color settings
- var $FontColorG = 0; // Default color settings
- var $FontColorB = 0; // Default color settings
- var $FontColorA = 100; // Default transparency
-
- /* Shadow properties */
- var $Shadow = FALSE; // Turn shadows on or off
- var $ShadowX = NULL; // X Offset of the shadow
- var $ShadowY = NULL; // Y Offset of the shadow
- var $ShadowR = NULL; // R component of the shadow
- var $ShadowG = NULL; // G component of the shadow
- var $ShadowB = NULL; // B component of the shadow
- var $Shadowa = NULL; // Alpha level of the shadow
-
- /* Image map */
- var $ImageMap = NULL; // Aray containing the image map
- var $ImageMapIndex = "pChart"; // Name of the session array
- var $ImageMapStorageMode = NULL; // Save the current imagemap storage mode
- var $ImageMapAutoDelete = TRUE; // Automatic deletion of the image map temp files
-
- /* Data Set */
- var $DataSet = NULL; // Attached dataset
-
- /* Last generated chart info */
- var $LastChartLayout = CHART_LAST_LAYOUT_REGULAR; // Last layout : regular or stacked
-
- /* Class constructor */
- function pImage($XSize,$YSize,$DataSet=NULL,$TransparentBackground=FALSE)
- {
- $this->TransparentBackground = $TransparentBackground;
-
- if ( $DataSet != NULL ) { $this->DataSet = $DataSet; }
-
- $this->XSize = $XSize;
- $this->YSize = $YSize;
- $this->Picture = imagecreatetruecolor($XSize,$YSize);
-
- if ( $this->TransparentBackground )
- {
- imagealphablending($this->Picture,FALSE);
- imagefilledrectangle($this->Picture, 0,0,$XSize, $YSize, imagecolorallocatealpha($this->Picture, 255, 255, 255, 127));
- imagealphablending($this->Picture,TRUE);
- imagesavealpha($this->Picture,true);
- }
- else
- {
- $C_White = $this->AllocateColor($this->Picture,255,255,255);
- imagefilledrectangle($this->Picture,0,0,$XSize,$YSize,$C_White);
- }
- }
-
- /* Enable / Disable and set shadow properties */
- function setShadow($Enabled=TRUE,$Format="")
- {
- $X = isset($Format["X"]) ? $Format["X"] : 2;
- $Y = isset($Format["Y"]) ? $Format["Y"] : 2;
- $R = isset($Format["R"]) ? $Format["R"] : 0;
- $G = isset($Format["G"]) ? $Format["G"] : 0;
- $B = isset($Format["B"]) ? $Format["B"] : 0;
- $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 10;
-
- $this->Shadow = $Enabled;
- $this->ShadowX = $X;
- $this->ShadowY = $Y;
- $this->ShadowR = $R;
- $this->ShadowG = $G;
- $this->ShadowB = $B;
- $this->Shadowa = $Alpha;
- }
-
- /* Set the graph area position */
- function setGraphArea($X1,$Y1,$X2,$Y2)
- {
- if ( $X2 < $X1 || $X1 == $X2 || $Y2 < $Y1 || $Y1 == $Y2 ) { return(-1); }
-
- $this->GraphAreaX1 = $X1; $this->DataSet->Data["GraphArea"]["X1"] = $X1;
- $this->GraphAreaY1 = $Y1; $this->DataSet->Data["GraphArea"]["Y1"] = $Y1;
- $this->GraphAreaX2 = $X2; $this->DataSet->Data["GraphArea"]["X2"] = $X2;
- $this->GraphAreaY2 = $Y2; $this->DataSet->Data["GraphArea"]["Y2"] = $Y2;
- }
-
- /* Return the width of the picture */
- function getWidth()
- { return($this->XSize); }
-
- /* Return the heigth of the picture */
- function getHeight()
- { return($this->YSize); }
-
- /* Render the picture to a file */
- function render($FileName)
- {
- if ( $this->TransparentBackground ) { imagealphablending($this->Picture,false); imagesavealpha($this->Picture,true); }
- imagepng($this->Picture,$FileName);
- }
-
- /* Render the picture to a web browser stream */
- function stroke($BrowserExpire=FALSE)
- {
- if ( $this->TransparentBackground ) { imagealphablending($this->Picture,false); imagesavealpha($this->Picture,true); }
-
- if ( $BrowserExpire )
- {
- header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
- header("Cache-Control: no-cache");
- header("Pragma: no-cache");
- }
-
- header('Content-type: image/png');
- imagepng($this->Picture);
- }
-
- /* Automatic output method based on the calling interface */
- function autoOutput($FileName="output.png")
- {
- if (php_sapi_name() == "cli")
- $this->Render($FileName);
- else
- $this->Stroke();
- }
-
- /* Return the length between two points */
- function getLength($X1,$Y1,$X2,$Y2)
- { return(sqrt(pow(max($X1,$X2)-min($X1,$X2),2)+pow(max($Y1,$Y2)-min($Y1,$Y2),2))); }
-
- /* Return the orientation of a line */
- function getAngle($X1,$Y1,$X2,$Y2)
- {
- $Opposite = $Y2 - $Y1; $Adjacent = $X2 - $X1;$Angle = rad2deg(atan2($Opposite,$Adjacent));
- if ($Angle > 0) { return($Angle); } else { return(360-abs($Angle)); }
- }
-
- /* Return the surrounding box of text area */
- function getTextBox_deprecated($X,$Y,$FontName,$FontSize,$Angle,$Text)
- {
- $Size = imagettfbbox($FontSize,$Angle,$FontName,$this->getEncodedText($Text));
- $Width = $this->getLength($Size[0],$Size[1],$Size[2],$Size[3])+1;
- $Height = $this->getLength($Size[2],$Size[3],$Size[4],$Size[5])+1;
-
- $RealPos[0]["X"] = $X; $RealPos[0]["Y"] = $Y;
- $RealPos[1]["X"] = cos((360-$Angle)*PI/180)*$Width + $RealPos[0]["X"]; $RealPos[1]["Y"] = sin((360-$Angle)*PI/180)*$Width + $RealPos[0]["Y"];
- $RealPos[2]["X"] = cos((270-$Angle)*PI/180)*$Height + $RealPos[1]["X"]; $RealPos[2]["Y"] = sin((270-$Angle)*PI/180)*$Height + $RealPos[1]["Y"];
- $RealPos[3]["X"] = cos((180-$Angle)*PI/180)*$Width + $RealPos[2]["X"]; $RealPos[3]["Y"] = sin((180-$Angle)*PI/180)*$Width + $RealPos[2]["Y"];
-
- $RealPos[TEXT_ALIGN_BOTTOMLEFT]["X"] = $RealPos[0]["X"]; $RealPos[TEXT_ALIGN_BOTTOMLEFT]["Y"] = $RealPos[0]["Y"];
- $RealPos[TEXT_ALIGN_BOTTOMRIGHT]["X"] = $RealPos[1]["X"]; $RealPos[TEXT_ALIGN_BOTTOMRIGHT]["Y"] = $RealPos[1]["Y"];
-
- return($RealPos);
- }
-
- function getEncodedText($text)
- {
- $gdinfo = gd_info();
- if (!empty($gdinfo['JIS-mapped Japanese Font Support'])) {
- return mb_convert_encoding($text, "SJIS", "UTF-8");
- }
-
- return $text;
- }
-
- /* Return the surrounding box of text area */
- function getTextBox($X,$Y,$FontName,$FontSize,$Angle,$Text)
- {
- $coords = imagettfbbox($FontSize, 0, $FontName, $this->getEncodedText($Text));
-
- $a = deg2rad($Angle); $ca = cos($a); $sa = sin($a); $RealPos = array();
- for($i = 0; $i < 7; $i += 2)
- {
- $RealPos[$i/2]["X"] = $X + round($coords[$i] * $ca + $coords[$i+1] * $sa);
- $RealPos[$i/2]["Y"] = $Y + round($coords[$i+1] * $ca - $coords[$i] * $sa);
- }
-
- $RealPos[TEXT_ALIGN_BOTTOMLEFT]["X"] = $RealPos[0]["X"]; $RealPos[TEXT_ALIGN_BOTTOMLEFT]["Y"] = $RealPos[0]["Y"];
- $RealPos[TEXT_ALIGN_BOTTOMRIGHT]["X"] = $RealPos[1]["X"]; $RealPos[TEXT_ALIGN_BOTTOMRIGHT]["Y"] = $RealPos[1]["Y"];
- $RealPos[TEXT_ALIGN_TOPLEFT]["X"] = $RealPos[3]["X"]; $RealPos[TEXT_ALIGN_TOPLEFT]["Y"] = $RealPos[3]["Y"];
- $RealPos[TEXT_ALIGN_TOPRIGHT]["X"] = $RealPos[2]["X"]; $RealPos[TEXT_ALIGN_TOPRIGHT]["Y"] = $RealPos[2]["Y"];
- $RealPos[TEXT_ALIGN_BOTTOMMIDDLE]["X"] = ($RealPos[1]["X"]-$RealPos[0]["X"])/2+$RealPos[0]["X"]; $RealPos[TEXT_ALIGN_BOTTOMMIDDLE]["Y"] = ($RealPos[0]["Y"]-$RealPos[1]["Y"])/2+$RealPos[1]["Y"];
- $RealPos[TEXT_ALIGN_TOPMIDDLE]["X"] = ($RealPos[2]["X"]-$RealPos[3]["X"])/2+$RealPos[3]["X"]; $RealPos[TEXT_ALIGN_TOPMIDDLE]["Y"] = ($RealPos[3]["Y"]-$RealPos[2]["Y"])/2+$RealPos[2]["Y"];
- $RealPos[TEXT_ALIGN_MIDDLELEFT]["X"] = ($RealPos[0]["X"]-$RealPos[3]["X"])/2+$RealPos[3]["X"]; $RealPos[TEXT_ALIGN_MIDDLELEFT]["Y"] = ($RealPos[0]["Y"]-$RealPos[3]["Y"])/2+$RealPos[3]["Y"];
- $RealPos[TEXT_ALIGN_MIDDLERIGHT]["X"] = ($RealPos[1]["X"]-$RealPos[2]["X"])/2+$RealPos[2]["X"]; $RealPos[TEXT_ALIGN_MIDDLERIGHT]["Y"] = ($RealPos[1]["Y"]-$RealPos[2]["Y"])/2+$RealPos[2]["Y"];
- $RealPos[TEXT_ALIGN_MIDDLEMIDDLE]["X"] = ($RealPos[1]["X"]-$RealPos[3]["X"])/2+$RealPos[3]["X"]; $RealPos[TEXT_ALIGN_MIDDLEMIDDLE]["Y"] = ($RealPos[0]["Y"]-$RealPos[2]["Y"])/2+$RealPos[2]["Y"];
-
- return($RealPos);
- }
-
- /* Set current font properties */
- function setFontProperties($Format="")
- {
- $R = isset($Format["R"]) ? $Format["R"] : -1;
- $G = isset($Format["G"]) ? $Format["G"] : -1;
- $B = isset($Format["B"]) ? $Format["B"] : -1;
- $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;
- $FontName = isset($Format["FontName"]) ? $Format["FontName"] : NULL;
- $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : NULL;
-
- if ( $R != -1) { $this->FontColorR = $R; }
- if ( $G != -1) { $this->FontColorG = $G; }
- if ( $B != -1) { $this->FontColorB = $B; }
- if ( $Alpha != NULL) { $this->FontColorA = $Alpha; }
-
- if ( $FontName != NULL )
- $this->FontName = $FontName;
-
- if ( $FontSize != NULL )
- $this->FontSize = $FontSize;
- }
-
- /* Returns the 1st decimal values (used to correct AA bugs) */
- function getFirstDecimal($Value)
- {
- $Values = preg_split("/\./",$Value);
- if ( isset($Values[1]) ) { return(substr($Values[1],0,1)); } else { return(0); }
- }
-
- /* Attach a dataset to your pChart Object */
- function setDataSet(&$DataSet)
- { $this->DataSet = $DataSet; }
-
- /* Print attached dataset contents to STDOUT */
- function printDataSet()
- { print_r($this->DataSet); }
-
- /* Initialise the image map methods */
- function initialiseImageMap($Name="pChart",$StorageMode=IMAGE_MAP_STORAGE_SESSION,$UniqueID="imageMap",$StorageFolder="tmp")
- {
- $this->ImageMapIndex = $Name;
- $this->ImageMapStorageMode = $StorageMode;
-
- if ($StorageMode == IMAGE_MAP_STORAGE_SESSION)
- {
- if(!isset($_SESSION)) { session_start(); }
- $_SESSION[$this->ImageMapIndex] = NULL;
- }
- elseif($StorageMode == IMAGE_MAP_STORAGE_FILE)
- {
- $this->ImageMapFileName = $UniqueID;
- $this->ImageMapStorageFolder = $StorageFolder;
-
- if (file_exists($StorageFolder."/".$UniqueID.".map")) { unlink($StorageFolder."/".$UniqueID.".map"); }
- }
- }
-
- /* Add a zone to the image map */
- function addToImageMap($Type,$Plots,$Color=NULL,$Title=NULL,$Message=NULL,$HTMLEncode=FALSE)
- {
- if ( $this->ImageMapStorageMode == NULL ) { $this->initialiseImageMap(); }
-
- /* Encode the characters in the imagemap in HTML standards */
- $Title = str_replace("&#8364;","\u20AC",$Title);
- $Title = htmlentities($Title,ENT_QUOTES,"ISO-8859-15");
- if ( $HTMLEncode )
- {
- $Message = htmlentities($Message,ENT_QUOTES,"ISO-8859-15");
- $Message = str_replace("&lt;","<",$Message);
- $Message = str_replace("&gt;",">",$Message);
- }
-
- if ( $this->ImageMapStorageMode == IMAGE_MAP_STORAGE_SESSION )
- {
- if(!isset($_SESSION)) { $this->initialiseImageMap(); }
- $_SESSION[$this->ImageMapIndex][] = array($Type,$Plots,$Color,$Title,$Message);
- }
- elseif($this->ImageMapStorageMode == IMAGE_MAP_STORAGE_FILE)
- {
- $Handle = fopen($this->ImageMapStorageFolder."/".$this->ImageMapFileName.".map", 'a');
- fwrite($Handle, $Type.IMAGE_MAP_DELIMITER.$Plots.IMAGE_MAP_DELIMITER.$Color.IMAGE_MAP_DELIMITER.$Title.IMAGE_MAP_DELIMITER.$Message."\r\n");
- fclose($Handle);
- }
- }
-
- /* Remove VOID values from an imagemap custom values array */
- function removeVOIDFromArray($SerieName, $Values)
- {
- if ( !isset($this->DataSet->Data["Series"][$SerieName]) ) { return(-1); }
-
- $Result = "";
- foreach($this->DataSet->Data["Series"][$SerieName]["Data"] as $Key => $Value)
- { if ( $Value != VOID && isset($Values[$Key]) ) { $Result[] = $Values[$Key]; } }
- return($Result);
- }
-
- /* Replace the title of one image map serie */
- function replaceImageMapTitle($OldTitle, $NewTitle)
- {
- if ( $this->ImageMapStorageMode == NULL ) { return(-1); }
-
- if ( is_array($NewTitle) ) { $NewTitle = $this->removeVOIDFromArray($OldTitle, $NewTitle); }
-
- if ( $this->ImageMapStorageMode == IMAGE_MAP_STORAGE_SESSION )
- {
- if(!isset($_SESSION)) { return(-1); }
- if ( is_array($NewTitle) )
- { $ID = 0; foreach($_SESSION[$this->ImageMapIndex] as $Key => $Settings) { if ( $Settings[3] == $OldTitle && isset($NewTitle[$ID])) { $_SESSION[$this->ImageMapIndex][$Key][3] = $NewTitle[$ID]; $ID++; } } }
- else
- { foreach($_SESSION[$this->ImageMapIndex] as $Key => $Settings) { if ( $Settings[3] == $OldTitle ) { $_SESSION[$this->ImageMapIndex][$Key][3] = $NewTitle; } } }
- }
- elseif( $this->ImageMapStorageMode == IMAGE_MAP_STORAGE_FILE )
- {
- $TempArray = "";
- $Handle = @fopen($this->ImageMapStorageFolder."/".$this->ImageMapFileName.".map", "r");
- if ($Handle)
- {
- while (($Buffer = fgets($Handle, 4096)) !== false)
- {
- $Fields = preg_split("/".IMAGE_MAP_DELIMITER."/",str_replace(array(chr(10),chr(13)),"",$Buffer));
- $TempArray[] = array($Fields[0],$Fields[1],$Fields[2],$Fields[3],$Fields[4]);
- }
- fclose($Handle);
-
- if ( is_array($NewTitle) )
- { $ID = 0; foreach($TempArray as $Key => $Settings) { if ( $Settings[3] == $OldTitle && isset($NewTitle[$ID]) ) { $TempArray[$Key][3] = $NewTitle[$ID]; $ID++; } } }
- else
- { foreach($TempArray as $Key => $Settings) { if ( $Settings[3] == $OldTitle ) { $TempArray[$Key][3] = $NewTitle; } } }
-
- $Handle = fopen($this->ImageMapStorageFolder."/".$this->ImageMapFileName.".map", 'w');
- foreach($TempArray as $Key => $Settings)
- { fwrite($Handle, $Settings[0].IMAGE_MAP_DELIMITER.$Settings[1].IMAGE_MAP_DELIMITER.$Settings[2].IMAGE_MAP_DELIMITER.$Settings[3].IMAGE_MAP_DELIMITER.$Settings[4]."\r\n"); }
- fclose($Handle);
- }
- }
- }
-
- /* Replace the values of the image map contents */
- function replaceImageMapValues($Title, $Values)
- {
- if ( $this->ImageMapStorageMode == NULL ) { return(-1); }
-
- $Values = $this->removeVOIDFromArray($Title, $Values);
- $ID = 0;
- if ( $this->ImageMapStorageMode == IMAGE_MAP_STORAGE_SESSION )
- {
- if(!isset($_SESSION)) { return(-1); }
- foreach($_SESSION[$this->ImageMapIndex] as $Key => $Settings) { if ( $Settings[3] == $Title ) { if ( isset($Values[$ID]) ) { $_SESSION[$this->ImageMapIndex][$Key][4] = $Values[$ID]; } $ID++; } }
- }
- elseif( $this->ImageMapStorageMode == IMAGE_MAP_STORAGE_FILE )
- {
- $TempArray = "";
- $Handle = @fopen($this->ImageMapStorageFolder."/".$this->ImageMapFileName.".map", "r");
- if ($Handle)
- {
- while (($Buffer = fgets($Handle, 4096)) !== false)
- {
- $Fields = preg_split("/".IMAGE_MAP_DELIMITER."/",str_replace(array(chr(10),chr(13)),"",$Buffer));
- $TempArray[] = array($Fields[0],$Fields[1],$Fields[2],$Fields[3],$Fields[4]);
- }
- fclose($Handle);
-
- foreach($TempArray as $Key => $Settings) { if ( $Settings[3] == $Title ) { if ( isset($Values[$ID]) ) { $TempArray[$Key][4] = $Values[$ID]; } $ID++; } }
-
- $Handle = fopen($this->ImageMapStorageFolder."/".$this->ImageMapFileName.".map", 'w');
- foreach($TempArray as $Key => $Settings)
- { fwrite($Handle, $Settings[0].IMAGE_MAP_DELIMITER.$Settings[1].IMAGE_MAP_DELIMITER.$Settings[2].IMAGE_MAP_DELIMITER.$Settings[3].IMAGE_MAP_DELIMITER.$Settings[4]."\r\n"); }
- fclose($Handle);
- }
- }
- }
-
- /* Dump the image map */
- function dumpImageMap($Name="pChart",$StorageMode=IMAGE_MAP_STORAGE_SESSION,$UniqueID="imageMap",$StorageFolder="tmp")
- {
- $this->ImageMapIndex = $Name;
- $this->ImageMapStorageMode = $StorageMode;
-
- if ( $this->ImageMapStorageMode == IMAGE_MAP_STORAGE_SESSION )
- {
- if(!isset($_SESSION)) { session_start(); }
- if ( $_SESSION[$Name] != NULL )
- {
- foreach($_SESSION[$Name] as $Key => $Params)
- { echo $Params[0].IMAGE_MAP_DELIMITER.$Params[1].IMAGE_MAP_DELIMITER.$Params[2].IMAGE_MAP_DELIMITER.$Params[3].IMAGE_MAP_DELIMITER.$Params[4]."\r\n"; }
- }
- }
- elseif( $this->ImageMapStorageMode == IMAGE_MAP_STORAGE_FILE )
- {
- if (file_exists($StorageFolder."/".$UniqueID.".map"))
- {
- $Handle = @fopen($StorageFolder."/".$UniqueID.".map", "r");
- if ($Handle) { while (($Buffer = fgets($Handle, 4096)) !== false) { echo $Buffer; } }
- fclose($Handle);
-
- if ( $this->ImageMapAutoDelete ) { unlink($StorageFolder."/".$UniqueID.".map"); }
- }
- }
-
- /* When the image map is returned to the client, the script ends */
- exit();
- }
-
- /* Return the HTML converted color from the RGB composite values */
- function toHTMLColor($R,$G,$B)
- {
- $R=intval($R); $G=intval($G); $B=intval($B);
- $R=dechex($R<0?0:($R>255?255:$R)); $G=dechex($G<0?0:($G>255?255:$G));$B=dechex($B<0?0:($B>255?255:$B));
- $Color="#".(strlen($R) < 2?'0':'').$R; $Color.=(strlen($G) < 2?'0':'').$G; $Color.= (strlen($B) < 2?'0':'').$B;
- return($Color);
- }
-
- /* Reverse an array of points */
- function reversePlots($Plots)
- {
- $Result = "";
- for($i=count($Plots)-2;$i>=0;$i=$i-2) { $Result[] = $Plots[$i]; $Result[] = $Plots[$i+1]; }
- return($Result);
- }
-
- /* Mirror Effect */
- function drawAreaMirror($X,$Y,$Width,$Height,$Format="")
- {
- $StartAlpha = isset($Format["StartAlpha"]) ? $Format["StartAlpha"] : 80;
- $EndAlpha = isset($Format["EndAlpha"]) ? $Format["EndAlpha"] : 0;
-
- $AlphaStep = ($StartAlpha-$EndAlpha)/$Height;
-
- $Picture = imagecreatetruecolor($this->XSize,$this->YSize);
- imagecopy($Picture,$this->Picture,0,0,0,0,$this->XSize,$this->YSize);
-
- for($i=1;$i<=$Height;$i++)
- {
- if ( $Y+($i-1) < $this->YSize && $Y-$i > 0 ) { imagecopymerge($Picture,$this->Picture,$X,$Y+($i-1),$X,$Y-$i,$Width,1,$StartAlpha-$AlphaStep*$i); }
- }
-
- imagecopy($this->Picture,$Picture,0,0,0,0,$this->XSize,$this->YSize);
- }
- }
+<?php
+ /*
+ pDraw - pChart core class
+
+ Version : 2.1.4
+ Made by : Jean-Damien POGOLOTTI
+ Last Update : 19/01/2014
+
+ This file can be distributed under the license you can find at :
+
+ http://www.pchart.net/license
+
+ You can find the whole class documentation on the pChart web site.
+ */
+
+ /* The GD extension is mandatory */
+ if (!extension_loaded('gd') && !extension_loaded('gd2'))
+ {
+ echo "GD extension must be loaded. \r\n";
+ exit();
+ }
+
+ /* Image map handling */
+ define("IMAGE_MAP_STORAGE_FILE" , 680001);
+ define("IMAGE_MAP_STORAGE_SESSION" , 680002);
+
+ /* Last generated chart layout */
+ define("CHART_LAST_LAYOUT_REGULAR" , 680011);
+ define("CHART_LAST_LAYOUT_STACKED" , 680012);
+
+ /* ImageMap string delimiter */
+ define("IMAGE_MAP_DELIMITER" , chr(1));
+
+ class pImage extends pDraw
+ {
+ /* Image settings, size, quality, .. */
+ var $XSize = NULL; // Width of the picture
+ var $YSize = NULL; // Height of the picture
+ var $Picture = NULL; // GD picture object
+ var $Antialias = TRUE; // Turn antialias on or off
+ var $AntialiasQuality = 0; // Quality of the antialiasing implementation (0-1)
+ var $Mask = ""; // Already drawn pixels mask (Filled circle implementation)
+ var $TransparentBackground = FALSE; // Just to know if we need to flush the alpha channels when rendering
+
+ /* Graph area settings */
+ var $GraphAreaX1 = NULL; // Graph area X origin
+ var $GraphAreaY1 = NULL; // Graph area Y origin
+ var $GraphAreaX2 = NULL; // Graph area bottom right X position
+ var $GraphAreaY2 = NULL; // Graph area bottom right Y position
+
+ /* Scale settings */
+ var $ScaleMinDivHeight = 20; // Minimum height for scame divs
+
+ /* Font properties */
+ var $FontName = "fonts/GeosansLight.ttf"; // Default font file
+ var $FontSize = 12; // Default font size
+ var $FontBox = NULL; // Return the bounding box of the last written string
+ var $FontColorR = 0; // Default color settings
+ var $FontColorG = 0; // Default color settings
+ var $FontColorB = 0; // Default color settings
+ var $FontColorA = 100; // Default transparency
+
+ /* Shadow properties */
+ var $Shadow = FALSE; // Turn shadows on or off
+ var $ShadowX = NULL; // X Offset of the shadow
+ var $ShadowY = NULL; // Y Offset of the shadow
+ var $ShadowR = NULL; // R component of the shadow
+ var $ShadowG = NULL; // G component of the shadow
+ var $ShadowB = NULL; // B component of the shadow
+ var $Shadowa = NULL; // Alpha level of the shadow
+
+ /* Image map */
+ var $ImageMap = NULL; // Aray containing the image map
+ var $ImageMapIndex = "pChart"; // Name of the session array
+ var $ImageMapStorageMode = NULL; // Save the current imagemap storage mode
+ var $ImageMapAutoDelete = TRUE; // Automatic deletion of the image map temp files
+
+ /* Data Set */
+ var $DataSet = NULL; // Attached dataset
+
+ /* Last generated chart info */
+ var $LastChartLayout = CHART_LAST_LAYOUT_REGULAR; // Last layout : regular or stacked
+
+ /* Class constructor */
+ function __construct($XSize,$YSize,$DataSet=NULL,$TransparentBackground=FALSE)
+ {
+ $this->TransparentBackground = $TransparentBackground;
+
+ if ( $DataSet != NULL ) { $this->DataSet = $DataSet; }
+
+ $this->XSize = $XSize;
+ $this->YSize = $YSize;
+ $this->Picture = imagecreatetruecolor($XSize,$YSize);
+
+ if ( $this->TransparentBackground )
+ {
+ imagealphablending($this->Picture,FALSE);
+ imagefilledrectangle($this->Picture, 0,0,$XSize, $YSize, imagecolorallocatealpha($this->Picture, 255, 255, 255, 127));
+ imagealphablending($this->Picture,TRUE);
+ imagesavealpha($this->Picture,true);
+ }
+ else
+ {
+ $C_White = $this->AllocateColor($this->Picture,255,255,255);
+ imagefilledrectangle($this->Picture,0,0,$XSize,$YSize,$C_White);
+ }
+ }
+
+ /* Enable / Disable and set shadow properties */
+ function setShadow($Enabled=TRUE,$Format="")
+ {
+ $X = isset($Format["X"]) ? $Format["X"] : 2;
+ $Y = isset($Format["Y"]) ? $Format["Y"] : 2;
+ $R = isset($Format["R"]) ? $Format["R"] : 0;
+ $G = isset($Format["G"]) ? $Format["G"] : 0;
+ $B = isset($Format["B"]) ? $Format["B"] : 0;
+ $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 10;
+
+ $this->Shadow = $Enabled;
+ $this->ShadowX = $X;
+ $this->ShadowY = $Y;
+ $this->ShadowR = $R;
+ $this->ShadowG = $G;
+ $this->ShadowB = $B;
+ $this->Shadowa = $Alpha;
+ }
+
+ /* Set the graph area position */
+ function setGraphArea($X1,$Y1,$X2,$Y2)
+ {
+ if ( $X2 < $X1 || $X1 == $X2 || $Y2 < $Y1 || $Y1 == $Y2 ) { return(-1); }
+
+ $this->GraphAreaX1 = $X1; $this->DataSet->Data["GraphArea"]["X1"] = $X1;
+ $this->GraphAreaY1 = $Y1; $this->DataSet->Data["GraphArea"]["Y1"] = $Y1;
+ $this->GraphAreaX2 = $X2; $this->DataSet->Data["GraphArea"]["X2"] = $X2;
+ $this->GraphAreaY2 = $Y2; $this->DataSet->Data["GraphArea"]["Y2"] = $Y2;
+ }
+
+ /* Return the width of the picture */
+ function getWidth()
+ { return($this->XSize); }
+
+ /* Return the heigth of the picture */
+ function getHeight()
+ { return($this->YSize); }
+
+ /* Render the picture to a file */
+ function render($FileName)
+ {
+ if ( $this->TransparentBackground ) { imagealphablending($this->Picture,false); imagesavealpha($this->Picture,true); }
+ imagepng($this->Picture,$FileName);
+ }
+
+ /* Render the picture to a web browser stream */
+ function stroke($BrowserExpire=FALSE)
+ {
+ if ( $this->TransparentBackground ) { imagealphablending($this->Picture,false); imagesavealpha($this->Picture,true); }
+
+ if ( $BrowserExpire )
+ {
+ header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
+ header("Cache-Control: no-cache");
+ header("Pragma: no-cache");
+ }
+
+ header('Content-type: image/png');
+ imagepng($this->Picture);
+ }
+
+ /* Automatic output method based on the calling interface */
+ function autoOutput($FileName="output.png")
+ {
+ if (php_sapi_name() == "cli")
+ $this->Render($FileName);
+ else
+ $this->Stroke();
+ }
+
+ /* Return the length between two points */
+ function getLength($X1,$Y1,$X2,$Y2)
+ { return(sqrt(pow(max($X1,$X2)-min($X1,$X2),2)+pow(max($Y1,$Y2)-min($Y1,$Y2),2))); }
+
+ /* Return the orientation of a line */
+ function getAngle($X1,$Y1,$X2,$Y2)
+ {
+ $Opposite = $Y2 - $Y1; $Adjacent = $X2 - $X1;$Angle = rad2deg(atan2($Opposite,$Adjacent));
+ if ($Angle > 0) { return($Angle); } else { return(360-abs($Angle)); }
+ }
+
+ /* Return the surrounding box of text area */
+ function getTextBox_deprecated($X,$Y,$FontName,$FontSize,$Angle,$Text)
+ {
+ $Size = imagettfbbox($FontSize,$Angle,$FontName,$this->getEncodedText($Text));
+ $Width = $this->getLength($Size[0],$Size[1],$Size[2],$Size[3])+1;
+ $Height = $this->getLength($Size[2],$Size[3],$Size[4],$Size[5])+1;
+
+ $RealPos[0]["X"] = $X; $RealPos[0]["Y"] = $Y;
+ $RealPos[1]["X"] = cos((360-$Angle)*PI/180)*$Width + $RealPos[0]["X"]; $RealPos[1]["Y"] = sin((360-$Angle)*PI/180)*$Width + $RealPos[0]["Y"];
+ $RealPos[2]["X"] = cos((270-$Angle)*PI/180)*$Height + $RealPos[1]["X"]; $RealPos[2]["Y"] = sin((270-$Angle)*PI/180)*$Height + $RealPos[1]["Y"];
+ $RealPos[3]["X"] = cos((180-$Angle)*PI/180)*$Width + $RealPos[2]["X"]; $RealPos[3]["Y"] = sin((180-$Angle)*PI/180)*$Width + $RealPos[2]["Y"];
+
+ $RealPos[TEXT_ALIGN_BOTTOMLEFT]["X"] = $RealPos[0]["X"]; $RealPos[TEXT_ALIGN_BOTTOMLEFT]["Y"] = $RealPos[0]["Y"];
+ $RealPos[TEXT_ALIGN_BOTTOMRIGHT]["X"] = $RealPos[1]["X"]; $RealPos[TEXT_ALIGN_BOTTOMRIGHT]["Y"] = $RealPos[1]["Y"];
+
+ return($RealPos);
+ }
+
+ function getEncodedText($text)
+ {
+ $gdinfo = gd_info();
+ if (!empty($gdinfo['JIS-mapped Japanese Font Support'])) {
+ return mb_convert_encoding($text, "SJIS", "UTF-8");
+ }
+
+ return $text;
+ }
+
+ /* Return the surrounding box of text area */
+ function getTextBox($X,$Y,$FontName,$FontSize,$Angle,$Text)
+ {
+ $coords = imagettfbbox($FontSize, 0, $FontName, $this->getEncodedText($Text));
+
+ $a = deg2rad($Angle); $ca = cos($a); $sa = sin($a); $RealPos = array();
+ for($i = 0; $i < 7; $i += 2)
+ {
+ $RealPos[$i/2]["X"] = $X + round($coords[$i] * $ca + $coords[$i+1] * $sa);
+ $RealPos[$i/2]["Y"] = $Y + round($coords[$i+1] * $ca - $coords[$i] * $sa);
+ }
+
+ $RealPos[TEXT_ALIGN_BOTTOMLEFT]["X"] = $RealPos[0]["X"]; $RealPos[TEXT_ALIGN_BOTTOMLEFT]["Y"] = $RealPos[0]["Y"];
+ $RealPos[TEXT_ALIGN_BOTTOMRIGHT]["X"] = $RealPos[1]["X"]; $RealPos[TEXT_ALIGN_BOTTOMRIGHT]["Y"] = $RealPos[1]["Y"];
+ $RealPos[TEXT_ALIGN_TOPLEFT]["X"] = $RealPos[3]["X"]; $RealPos[TEXT_ALIGN_TOPLEFT]["Y"] = $RealPos[3]["Y"];
+ $RealPos[TEXT_ALIGN_TOPRIGHT]["X"] = $RealPos[2]["X"]; $RealPos[TEXT_ALIGN_TOPRIGHT]["Y"] = $RealPos[2]["Y"];
+ $RealPos[TEXT_ALIGN_BOTTOMMIDDLE]["X"] = ($RealPos[1]["X"]-$RealPos[0]["X"])/2+$RealPos[0]["X"]; $RealPos[TEXT_ALIGN_BOTTOMMIDDLE]["Y"] = ($RealPos[0]["Y"]-$RealPos[1]["Y"])/2+$RealPos[1]["Y"];
+ $RealPos[TEXT_ALIGN_TOPMIDDLE]["X"] = ($RealPos[2]["X"]-$RealPos[3]["X"])/2+$RealPos[3]["X"]; $RealPos[TEXT_ALIGN_TOPMIDDLE]["Y"] = ($RealPos[3]["Y"]-$RealPos[2]["Y"])/2+$RealPos[2]["Y"];
+ $RealPos[TEXT_ALIGN_MIDDLELEFT]["X"] = ($RealPos[0]["X"]-$RealPos[3]["X"])/2+$RealPos[3]["X"]; $RealPos[TEXT_ALIGN_MIDDLELEFT]["Y"] = ($RealPos[0]["Y"]-$RealPos[3]["Y"])/2+$RealPos[3]["Y"];
+ $RealPos[TEXT_ALIGN_MIDDLERIGHT]["X"] = ($RealPos[1]["X"]-$RealPos[2]["X"])/2+$RealPos[2]["X"]; $RealPos[TEXT_ALIGN_MIDDLERIGHT]["Y"] = ($RealPos[1]["Y"]-$RealPos[2]["Y"])/2+$RealPos[2]["Y"];
+ $RealPos[TEXT_ALIGN_MIDDLEMIDDLE]["X"] = ($RealPos[1]["X"]-$RealPos[3]["X"])/2+$RealPos[3]["X"]; $RealPos[TEXT_ALIGN_MIDDLEMIDDLE]["Y"] = ($RealPos[0]["Y"]-$RealPos[2]["Y"])/2+$RealPos[2]["Y"];
+
+ return($RealPos);
+ }
+
+ /* Set current font properties */
+ function setFontProperties($Format="")
+ {
+ $R = isset($Format["R"]) ? $Format["R"] : -1;
+ $G = isset($Format["G"]) ? $Format["G"] : -1;
+ $B = isset($Format["B"]) ? $Format["B"] : -1;
+ $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;
+ $FontName = isset($Format["FontName"]) ? $Format["FontName"] : NULL;
+ $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : NULL;
+
+ if ( $R != -1) { $this->FontColorR = $R; }
+ if ( $G != -1) { $this->FontColorG = $G; }
+ if ( $B != -1) { $this->FontColorB = $B; }
+ if ( $Alpha != NULL) { $this->FontColorA = $Alpha; }
+
+ if ( $FontName != NULL )
+ $this->FontName = $FontName;
+
+ if ( $FontSize != NULL )
+ $this->FontSize = $FontSize;
+ }
+
+ /* Returns the 1st decimal values (used to correct AA bugs) */
+ function getFirstDecimal($Value)
+ {
+ $Values = preg_split("/\./",$Value);
+ if ( isset($Values[1]) ) { return(substr($Values[1],0,1)); } else { return(0); }
+ }
+
+ /* Attach a dataset to your pChart Object */
+ function setDataSet(&$DataSet)
+ { $this->DataSet = $DataSet; }
+
+ /* Print attached dataset contents to STDOUT */
+ function printDataSet()
+ { print_r($this->DataSet); }
+
+ /* Initialise the image map methods */
+ function initialiseImageMap($Name="pChart",$StorageMode=IMAGE_MAP_STORAGE_SESSION,$UniqueID="imageMap",$StorageFolder="tmp")
+ {
+ $this->ImageMapIndex = $Name;
+ $this->ImageMapStorageMode = $StorageMode;
+
+ if ($StorageMode == IMAGE_MAP_STORAGE_SESSION)
+ {
+ if(!isset($_SESSION)) { session_start(); }
+ $_SESSION[$this->ImageMapIndex] = NULL;
+ }
+ elseif($StorageMode == IMAGE_MAP_STORAGE_FILE)
+ {
+ $this->ImageMapFileName = $UniqueID;
+ $this->ImageMapStorageFolder = $StorageFolder;
+
+ if (file_exists($StorageFolder."/".$UniqueID.".map")) { unlink($StorageFolder."/".$UniqueID.".map"); }
+ }
+ }
+
+ /* Add a zone to the image map */
+ function addToImageMap($Type,$Plots,$Color=NULL,$Title=NULL,$Message=NULL,$HTMLEncode=FALSE)
+ {
+ if ( $this->ImageMapStorageMode == NULL ) { $this->initialiseImageMap(); }
+
+ /* Encode the characters in the imagemap in HTML standards */
+ $Title = str_replace("&#8364;","\u20AC",$Title);
+ $Title = htmlentities($Title,ENT_QUOTES,"ISO-8859-15");
+ if ( $HTMLEncode )
+ {
+ $Message = htmlentities($Message,ENT_QUOTES,"ISO-8859-15");
+ $Message = str_replace("&lt;","<",$Message);
+ $Message = str_replace("&gt;",">",$Message);
+ }
+
+ if ( $this->ImageMapStorageMode == IMAGE_MAP_STORAGE_SESSION )
+ {
+ if(!isset($_SESSION)) { $this->initialiseImageMap(); }
+ $_SESSION[$this->ImageMapIndex][] = array($Type,$Plots,$Color,$Title,$Message);
+ }
+ elseif($this->ImageMapStorageMode == IMAGE_MAP_STORAGE_FILE)
+ {
+ $Handle = fopen($this->ImageMapStorageFolder."/".$this->ImageMapFileName.".map", 'a');
+ fwrite($Handle, $Type.IMAGE_MAP_DELIMITER.$Plots.IMAGE_MAP_DELIMITER.$Color.IMAGE_MAP_DELIMITER.$Title.IMAGE_MAP_DELIMITER.$Message."\r\n");
+ fclose($Handle);
+ }
+ }
+
+ /* Remove VOID values from an imagemap custom values array */
+ function removeVOIDFromArray($SerieName, $Values)
+ {
+ if ( !isset($this->DataSet->Data["Series"][$SerieName]) ) { return(-1); }
+
+ $Result = "";
+ foreach($this->DataSet->Data["Series"][$SerieName]["Data"] as $Key => $Value)
+ { if ( $Value != VOID && isset($Values[$Key]) ) { $Result[] = $Values[$Key]; } }
+ return($Result);
+ }
+
+ /* Replace the title of one image map serie */
+ function replaceImageMapTitle($OldTitle, $NewTitle)
+ {
+ if ( $this->ImageMapStorageMode == NULL ) { return(-1); }
+
+ if ( is_array($NewTitle) ) { $NewTitle = $this->removeVOIDFromArray($OldTitle, $NewTitle); }
+
+ if ( $this->ImageMapStorageMode == IMAGE_MAP_STORAGE_SESSION )
+ {
+ if(!isset($_SESSION)) { return(-1); }
+ if ( is_array($NewTitle) )
+ { $ID = 0; foreach($_SESSION[$this->ImageMapIndex] as $Key => $Settings) { if ( $Settings[3] == $OldTitle && isset($NewTitle[$ID])) { $_SESSION[$this->ImageMapIndex][$Key][3] = $NewTitle[$ID]; $ID++; } } }
+ else
+ { foreach($_SESSION[$this->ImageMapIndex] as $Key => $Settings) { if ( $Settings[3] == $OldTitle ) { $_SESSION[$this->ImageMapIndex][$Key][3] = $NewTitle; } } }
+ }
+ elseif( $this->ImageMapStorageMode == IMAGE_MAP_STORAGE_FILE )
+ {
+ $TempArray = "";
+ $Handle = @fopen($this->ImageMapStorageFolder."/".$this->ImageMapFileName.".map", "r");
+ if ($Handle)
+ {
+ while (($Buffer = fgets($Handle, 4096)) !== false)
+ {
+ $Fields = preg_split("/".IMAGE_MAP_DELIMITER."/",str_replace(array(chr(10),chr(13)),"",$Buffer));
+ $TempArray[] = array($Fields[0],$Fields[1],$Fields[2],$Fields[3],$Fields[4]);
+ }
+ fclose($Handle);
+
+ if ( is_array($NewTitle) )
+ { $ID = 0; foreach($TempArray as $Key => $Settings) { if ( $Settings[3] == $OldTitle && isset($NewTitle[$ID]) ) { $TempArray[$Key][3] = $NewTitle[$ID]; $ID++; } } }
+ else
+ { foreach($TempArray as $Key => $Settings) { if ( $Settings[3] == $OldTitle ) { $TempArray[$Key][3] = $NewTitle; } } }
+
+ $Handle = fopen($this->ImageMapStorageFolder."/".$this->ImageMapFileName.".map", 'w');
+ foreach($TempArray as $Key => $Settings)
+ { fwrite($Handle, $Settings[0].IMAGE_MAP_DELIMITER.$Settings[1].IMAGE_MAP_DELIMITER.$Settings[2].IMAGE_MAP_DELIMITER.$Settings[3].IMAGE_MAP_DELIMITER.$Settings[4]."\r\n"); }
+ fclose($Handle);
+ }
+ }
+ }
+
+ /* Replace the values of the image map contents */
+ function replaceImageMapValues($Title, $Values)
+ {
+ if ( $this->ImageMapStorageMode == NULL ) { return(-1); }
+
+ $Values = $this->removeVOIDFromArray($Title, $Values);
+ $ID = 0;
+ if ( $this->ImageMapStorageMode == IMAGE_MAP_STORAGE_SESSION )
+ {
+ if(!isset($_SESSION)) { return(-1); }
+ foreach($_SESSION[$this->ImageMapIndex] as $Key => $Settings) { if ( $Settings[3] == $Title ) { if ( isset($Values[$ID]) ) { $_SESSION[$this->ImageMapIndex][$Key][4] = $Values[$ID]; } $ID++; } }
+ }
+ elseif( $this->ImageMapStorageMode == IMAGE_MAP_STORAGE_FILE )
+ {
+ $TempArray = "";
+ $Handle = @fopen($this->ImageMapStorageFolder."/".$this->ImageMapFileName.".map", "r");
+ if ($Handle)
+ {
+ while (($Buffer = fgets($Handle, 4096)) !== false)
+ {
+ $Fields = preg_split("/".IMAGE_MAP_DELIMITER."/",str_replace(array(chr(10),chr(13)),"",$Buffer));
+ $TempArray[] = array($Fields[0],$Fields[1],$Fields[2],$Fields[3],$Fields[4]);
+ }
+ fclose($Handle);
+
+ foreach($TempArray as $Key => $Settings) { if ( $Settings[3] == $Title ) { if ( isset($Values[$ID]) ) { $TempArray[$Key][4] = $Values[$ID]; } $ID++; } }
+
+ $Handle = fopen($this->ImageMapStorageFolder."/".$this->ImageMapFileName.".map", 'w');
+ foreach($TempArray as $Key => $Settings)
+ { fwrite($Handle, $Settings[0].IMAGE_MAP_DELIMITER.$Settings[1].IMAGE_MAP_DELIMITER.$Settings[2].IMAGE_MAP_DELIMITER.$Settings[3].IMAGE_MAP_DELIMITER.$Settings[4]."\r\n"); }
+ fclose($Handle);
+ }
+ }
+ }
+
+ /* Dump the image map */
+ function dumpImageMap($Name="pChart",$StorageMode=IMAGE_MAP_STORAGE_SESSION,$UniqueID="imageMap",$StorageFolder="tmp")
+ {
+ $this->ImageMapIndex = $Name;
+ $this->ImageMapStorageMode = $StorageMode;
+
+ if ( $this->ImageMapStorageMode == IMAGE_MAP_STORAGE_SESSION )
+ {
+ if(!isset($_SESSION)) { session_start(); }
+ if ( $_SESSION[$Name] != NULL )
+ {
+ foreach($_SESSION[$Name] as $Key => $Params)
+ { echo $Params[0].IMAGE_MAP_DELIMITER.$Params[1].IMAGE_MAP_DELIMITER.$Params[2].IMAGE_MAP_DELIMITER.$Params[3].IMAGE_MAP_DELIMITER.$Params[4]."\r\n"; }
+ }
+ }
+ elseif( $this->ImageMapStorageMode == IMAGE_MAP_STORAGE_FILE )
+ {
+ if (file_exists($StorageFolder."/".$UniqueID.".map"))
+ {
+ $Handle = @fopen($StorageFolder."/".$UniqueID.".map", "r");
+ if ($Handle) { while (($Buffer = fgets($Handle, 4096)) !== false) { echo $Buffer; } }
+ fclose($Handle);
+
+ if ( $this->ImageMapAutoDelete ) { unlink($StorageFolder."/".$UniqueID.".map"); }
+ }
+ }
+
+ /* When the image map is returned to the client, the script ends */
+ exit();
+ }
+
+ /* Return the HTML converted color from the RGB composite values */
+ function toHTMLColor($R,$G,$B)
+ {
+ $R=intval($R); $G=intval($G); $B=intval($B);
+ $R=dechex($R<0?0:($R>255?255:$R)); $G=dechex($G<0?0:($G>255?255:$G));$B=dechex($B<0?0:($B>255?255:$B));
+ $Color="#".(strlen($R) < 2?'0':'').$R; $Color.=(strlen($G) < 2?'0':'').$G; $Color.= (strlen($B) < 2?'0':'').$B;
+ return($Color);
+ }
+
+ /* Reverse an array of points */
+ function reversePlots($Plots)
+ {
+ $Result = "";
+ for($i=count($Plots)-2;$i>=0;$i=$i-2) { $Result[] = $Plots[$i]; $Result[] = $Plots[$i+1]; }
+ return($Result);
+ }
+
+ /* Mirror Effect */
+ function drawAreaMirror($X,$Y,$Width,$Height,$Format="")
+ {
+ $StartAlpha = isset($Format["StartAlpha"]) ? $Format["StartAlpha"] : 80;
+ $EndAlpha = isset($Format["EndAlpha"]) ? $Format["EndAlpha"] : 0;
+
+ $AlphaStep = ($StartAlpha-$EndAlpha)/$Height;
+
+ $Picture = imagecreatetruecolor($this->XSize,$this->YSize);
+ imagecopy($Picture,$this->Picture,0,0,0,0,$this->XSize,$this->YSize);
+
+ for($i=1;$i<=$Height;$i++)
+ {
+ if ( $Y+($i-1) < $this->YSize && $Y-$i > 0 ) { imagecopymerge($Picture,$this->Picture,$X,$Y+($i-1),$X,$Y-$i,$Width,1,$StartAlpha-$AlphaStep*$i); }
+ }
+
+ imagecopy($this->Picture,$Picture,0,0,0,0,$this->XSize,$this->YSize);
+ }
+ }
?> \ No newline at end of file
diff --git a/libs/pChart/class/pPie.class.php b/libs/pChart/class/pPie.class.php
index 209b74979e..845f81ca98 100755
--- a/libs/pChart/class/pPie.class.php
+++ b/libs/pChart/class/pPie.class.php
@@ -1,1500 +1,1500 @@
-<?php
- /*
- pPie - class to draw pie charts
-
- Version : 2.1.4
- Made by : Jean-Damien POGOLOTTI
- Last Update : 19/01/2014
-
- This file can be distributed under the license you can find at :
-
- http://www.pchart.net/license
-
- You can find the whole class documentation on the pChart web site.
- */
-
- /* Class return codes */
- define("PIE_NO_ABSCISSA" , 140001);
- define("PIE_NO_DATASERIE" , 140002);
- define("PIE_SUMISNULL" , 140003);
- define("PIE_RENDERED" , 140000);
-
- define("PIE_LABEL_COLOR_AUTO" , 140010);
- define("PIE_LABEL_COLOR_MANUAL", 140011);
-
- define("PIE_VALUE_NATURAL" , 140020);
- define("PIE_VALUE_PERCENTAGE" , 140021);
-
- define("PIE_VALUE_INSIDE" , 140030);
- define("PIE_VALUE_OUTSIDE" , 140031);
-
- /* pPie class definition */
- class pPie
- {
- var $pChartObject;
- var $pDataObject;
- var $LabelPos = "" ;
-
- /* Class creator */
- function pPie($Object,$pDataObject)
- {
- /* Cache the pChart object reference */
- $this->pChartObject = $Object;
-
- /* Cache the pData object reference */
- $this->pDataObject = $pDataObject;
- }
-
- /* Draw a pie chart */
- function draw2DPie($X,$Y,$Format="")
- {
- $Radius = isset($Format["Radius"]) ? $Format["Radius"] : 60;
- $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0;
- $DataGapAngle = isset($Format["DataGapAngle"]) ? $Format["DataGapAngle"] : 0;
- $DataGapRadius = isset($Format["DataGapRadius"]) ? $Format["DataGapRadius"] : 0;
- $SecondPass = isset($Format["SecondPass"]) ? $Format["SecondPass"] : TRUE;
- $Border = isset($Format["Border"]) ? $Format["Border"] : FALSE;
- $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 255;
- $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 255;
- $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 255;
- $Shadow = isset($Format["Shadow"]) ? $Format["Shadow"] : FALSE;
- $DrawLabels = isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : FALSE;
- $LabelStacked = isset($Format["LabelStacked"]) ? $Format["LabelStacked"] : FALSE;
- $LabelColor = isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL;
- $LabelR = isset($Format["LabelR"]) ? $Format["LabelR"] : 0;
- $LabelG = isset($Format["LabelG"]) ? $Format["LabelG"] : 0;
- $LabelB = isset($Format["LabelB"]) ? $Format["LabelB"] : 0;
- $LabelAlpha = isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100;
- $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : NULL;
- $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_OUTSIDE;
- $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : 15;
- $ValueSuffix = isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : "";
- $ValueR = isset($Format["ValueR"]) ? $Format["ValueR"] : 255;
- $ValueG = isset($Format["ValueG"]) ? $Format["ValueG"] : 255;
- $ValueB = isset($Format["ValueB"]) ? $Format["ValueB"] : 255;
- $ValueAlpha = isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100;
- $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE;
-
- /* Data Processing */
- $Data = $this->pDataObject->getData();
- $Palette = $this->pDataObject->getPalette();
-
- /* Do we have an abscissa serie defined? */
- if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); }
-
- /* Try to find the data serie */
- $DataSerie = "";
- foreach ($Data["Series"] as $SerieName => $SerieData)
- { if ( $SerieName != $Data["Abscissa"]) { $DataSerie = $SerieName; } }
-
- /* Do we have data to compute? */
- if ( $DataSerie == "" ) { return(PIE_NO_DATASERIE); }
-
- /* Remove unused data */
- list($Data,$Palette) = $this->clean0Values($Data,$Palette,$DataSerie,$Data["Abscissa"]);
-
- /* Compute the pie sum */
- $SerieSum = $this->pDataObject->getSum($DataSerie);
-
- /* Do we have data to draw? */
- if ( $SerieSum == 0 ) { return(PIE_SUMISNULL); }
-
- /* Dump the real number of data to draw */
- $Values = "";
- foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value)
- { if ($Value != 0) { $Values[] = $Value; } }
-
- /* Compute the wasted angular space between series */
- if (count($Values)==1) { $WastedAngular = 0; } else { $WastedAngular = count($Values) * $DataGapAngle; }
-
- /* Compute the scale */
- $ScaleFactor = (360 - $WastedAngular) / $SerieSum;
-
- $RestoreShadow = $this->pChartObject->Shadow;
- if ( $this->pChartObject->Shadow )
- {
- $this->pChartObject->Shadow = FALSE;
-
- $ShadowFormat = $Format; $ShadowFormat["Shadow"] = TRUE;
- $this->draw2DPie($X+$this->pChartObject->ShadowX,$Y+$this->pChartObject->ShadowY,$ShadowFormat);
- }
-
- /* Draw the polygon pie elements */
- $Step = 360 / (2 * PI * $Radius);
- $Offset = 0; $ID = 0;
- foreach($Values as $Key => $Value)
- {
- if ( $Shadow )
- $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa);
- else
- {
- if ( !isset($Palette[$ID]["R"]) ) { $Color = $this->pChartObject->getRandomColor(); $Palette[$ID] = $Color; $this->pDataObject->savePalette($ID,$Color); }
- $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);
- }
-
- if ( !$SecondPass && !$Shadow )
- {
- if ( !$Border )
- $Settings["Surrounding"] = 10;
- else
- { $Settings["BorderR"] = $BorderR; $Settings["BorderG"] = $BorderG; $Settings["BorderB"] = $BorderB; }
- }
-
- $Plots = "";
- $EndAngle = $Offset+($Value*$ScaleFactor); if ( $EndAngle > 360 ) { $EndAngle = 360; }
-
- $Angle = ($EndAngle - $Offset)/2 + $Offset;
- if ($DataGapAngle == 0)
- { $X0 = $X; $Y0 = $Y; }
- else
- {
- $X0 = cos(($Angle-90)*PI/180) * $DataGapRadius + $X;
- $Y0 = sin(($Angle-90)*PI/180) * $DataGapRadius + $Y;
- }
-
- $Plots[] = $X0; $Plots[] = $Y0;
-
-
- for($i=$Offset;$i<=$EndAngle;$i=$i+$Step)
- {
- $Xc = cos(($i-90)*PI/180) * $Radius + $X;
- $Yc = sin(($i-90)*PI/180) * $Radius + $Y;
-
- if ( $SecondPass && ( $i<90 )) { $Yc++; }
- if ( $SecondPass && ( $i>180 && $i<270 )) { $Xc++; }
- if ( $SecondPass && ( $i>=270 )) { $Xc++; $Yc++; }
-
- $Plots[] = $Xc; $Plots[] = $Yc;
- }
-
- $this->pChartObject->drawPolygon($Plots,$Settings);
- if ( $RecordImageMap && !$Shadow ) { $this->pChartObject->addToImageMap("POLY",$this->arraySerialize($Plots),$this->pChartObject->toHTMLColor($Palette[$ID]["R"],$Palette[$ID]["G"],$Palette[$ID]["B"]),$Data["Series"][$Data["Abscissa"]]["Data"][$Key],$Value); }
-
- if ( $DrawLabels && !$Shadow && !$SecondPass )
- {
- if ( $LabelColor == PIE_LABEL_COLOR_AUTO )
- { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);}
- else
- { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); }
-
- $Angle = ($EndAngle - $Offset)/2 + $Offset;
- $Xc = cos(($Angle-90)*PI/180) * $Radius + $X;
- $Yc = sin(($Angle-90)*PI/180) * $Radius + $Y;
-
- $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key];
-
- if ( $LabelStacked )
- $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,TRUE,$X,$Y,$Radius);
- else
- $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,FALSE);
- }
-
- $Offset = $i + $DataGapAngle; $ID++;
- }
-
- /* Second pass to smooth the angles */
- if ( $SecondPass )
- {
- $Step = 360 / (2 * PI * $Radius);
- $Offset = 0; $ID = 0;
- foreach($Values as $Key => $Value)
- {
- $FirstPoint = TRUE;
- if ( $Shadow )
- $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa);
- else
- {
- if ( $Border )
- $Settings = array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB);
- else
- $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);
- }
-
- $EndAngle = $Offset+($Value*$ScaleFactor); if ( $EndAngle > 360 ) { $EndAngle = 360; }
-
- if ($DataGapAngle == 0)
- { $X0 = $X; $Y0 = $Y; }
- else
- {
- $Angle = ($EndAngle - $Offset)/2 + $Offset;
- $X0 = cos(($Angle-90)*PI/180) * $DataGapRadius + $X;
- $Y0 = sin(($Angle-90)*PI/180) * $DataGapRadius + $Y;
- }
- $Plots[] = $X0; $Plots[] = $Y0;
-
- for($i=$Offset;$i<=$EndAngle;$i=$i+$Step)
- {
- $Xc = cos(($i-90)*PI/180) * $Radius + $X;
- $Yc = sin(($i-90)*PI/180) * $Radius + $Y;
-
- if ( $FirstPoint ) { $this->pChartObject->drawLine($Xc,$Yc,$X0,$Y0,$Settings); } { $FirstPoint = FALSE; }
-
- $this->pChartObject->drawAntialiasPixel($Xc,$Yc,$Settings);
- }
- $this->pChartObject->drawLine($Xc,$Yc,$X0,$Y0,$Settings);
-
- if ( $DrawLabels && !$Shadow )
- {
- if ( $LabelColor == PIE_LABEL_COLOR_AUTO )
- { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);}
- else
- { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); }
-
- $Angle = ($EndAngle - $Offset)/2 + $Offset;
- $Xc = cos(($Angle-90)*PI/180) * $Radius + $X;
- $Yc = sin(($Angle-90)*PI/180) * $Radius + $Y;
-
- $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key];
-
- if ( $LabelStacked )
- $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,TRUE,$X,$Y,$Radius);
- else
- $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,FALSE);
- }
-
- $Offset = $i + $DataGapAngle; $ID++;
- }
- }
-
- if ( $WriteValues != NULL && !$Shadow )
- {
- $Step = 360 / (2 * PI * $Radius);
- $Offset = 0; $ID = count($Values)-1;
- $Settings = array("Align"=>TEXT_ALIGN_MIDDLEMIDDLE,"R"=>$ValueR,"G"=>$ValueG,"B"=>$ValueB,"Alpha"=>$ValueAlpha);
- foreach($Values as $Key => $Value)
- {
- $EndAngle = ($Value*$ScaleFactor) + $Offset; if ( (int)$EndAngle > 360 ) { $EndAngle = 0; }
- $Angle = ($EndAngle - $Offset)/2 + $Offset;
-
- if ( $ValuePosition == PIE_VALUE_OUTSIDE )
- {
- $Xc = cos(($Angle-90)*PI/180) * ($Radius+$ValuePadding) + $X;
- $Yc = sin(($Angle-90)*PI/180) * ($Radius+$ValuePadding) + $Y;
- }
- else
- {
- $Xc = cos(($Angle-90)*PI/180) * ($Radius)/2 + $X;
- $Yc = sin(($Angle-90)*PI/180) * ($Radius)/2 + $Y;
- }
-
- if ( $WriteValues == PIE_VALUE_PERCENTAGE )
- $Display = round(( 100 / $SerieSum ) * $Value,$Precision)."%";
- elseif ( $WriteValues == PIE_VALUE_NATURAL )
- $Display = $Value.$ValueSuffix;
-
- $this->pChartObject->drawText($Xc,$Yc,$Display,$Settings);
-
- $Offset = $EndAngle + $DataGapAngle; $ID--;
- }
- }
-
- if ( $DrawLabels && $LabelStacked ) { $this->writeShiftedLabels(); }
-
- $this->pChartObject->Shadow = $RestoreShadow;
-
- return(PIE_RENDERED);
- }
-
- /* Draw a 3D pie chart */
- function draw3DPie($X,$Y,$Format="")
- {
- /* Rendering layout */
- $Radius = isset($Format["Radius"]) ? $Format["Radius"] : 80;
- $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0;
- $SkewFactor = isset($Format["SkewFactor"]) ? $Format["SkewFactor"] : .5;
- $SliceHeight = isset($Format["SliceHeight"]) ? $Format["SliceHeight"] : 20;
- $DataGapAngle = isset($Format["DataGapAngle"]) ? $Format["DataGapAngle"] : 0;
- $DataGapRadius = isset($Format["DataGapRadius"]) ? $Format["DataGapRadius"] : 0;
- $SecondPass = isset($Format["SecondPass"]) ? $Format["SecondPass"] : TRUE;
- $Border = isset($Format["Border"]) ? $Format["Border"] : FALSE;
- $Shadow = isset($Format["Shadow"]) ? $Format["Shadow"] : FALSE;
- $DrawLabels = isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : FALSE;
- $LabelStacked = isset($Format["LabelStacked"]) ? $Format["LabelStacked"] : FALSE;
- $LabelColor = isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL;
- $LabelR = isset($Format["LabelR"]) ? $Format["LabelR"] : 0;
- $LabelG = isset($Format["LabelG"]) ? $Format["LabelG"] : 0;
- $LabelB = isset($Format["LabelB"]) ? $Format["LabelB"] : 0;
- $LabelAlpha = isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100;
- $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : NULL; //PIE_VALUE_PERCENTAGE
- $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_INSIDE;
- $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : 15;
- $ValueSuffix = isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : "";
- $ValueR = isset($Format["ValueR"]) ? $Format["ValueR"] : 255;
- $ValueG = isset($Format["ValueG"]) ? $Format["ValueG"] : 255;
- $ValueB = isset($Format["ValueB"]) ? $Format["ValueB"] : 255;
- $ValueAlpha = isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100;
- $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE;
-
- /* Error correction for overlaying rounded corners */
- if ( $SkewFactor < .5 ) { $SkewFactor = .5; }
-
- /* Data Processing */
- $Data = $this->pDataObject->getData();
- $Palette = $this->pDataObject->getPalette();
-
- /* Do we have an abscissa serie defined? */
- if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); }
-
- /* Try to find the data serie */
- $DataSerie = "";
- foreach ($Data["Series"] as $SerieName => $SerieData)
- { if ( $SerieName != $Data["Abscissa"]) { $DataSerie = $SerieName; } }
-
- /* Do we have data to compute? */
- if ( $DataSerie == "" ) { return(PIE_NO_DATASERIE); }
-
- /* Remove unused data */
- list($Data,$Palette) = $this->clean0Values($Data,$Palette,$DataSerie,$Data["Abscissa"]);
-
- /* Compute the pie sum */
- $SerieSum = $this->pDataObject->getSum($DataSerie);
-
- /* Do we have data to draw? */
- if ( $SerieSum == 0 ) { return(PIE_SUMISNULL); }
-
- /* Dump the real number of data to draw */
- $Values = "";
- foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value)
- { if ($Value != 0) { $Values[] = $Value; } }
-
- /* Compute the wasted angular space between series */
- if (count($Values)==1) { $WastedAngular = 0; } else { $WastedAngular = count($Values) * $DataGapAngle; }
-
- /* Compute the scale */
- $ScaleFactor = (360 - $WastedAngular) / $SerieSum;
-
- $RestoreShadow = $this->pChartObject->Shadow;
- if ( $this->pChartObject->Shadow ) { $this->pChartObject->Shadow = FALSE; }
-
- /* Draw the polygon pie elements */
- $Step = 360 / (2 * PI * $Radius);
- $Offset = 360; $ID = count($Values)-1;
- $Values = array_reverse($Values);
- $Slice = 0; $Slices = ""; $SliceColors = ""; $Visible = ""; $SliceAngle = "";
- foreach($Values as $Key => $Value)
- {
- if ( !isset($Palette[$ID]["R"]) ) { $Color = $this->pChartObject->getRandomColor(); $Palette[$ID] = $Color; $this->pDataObject->savePalette($ID,$Color); }
- $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);
-
- $SliceColors[$Slice] = $Settings;
-
- $StartAngle = $Offset;
- $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; }
-
- if ( $StartAngle > 180 ) { $Visible[$Slice]["Start"] = TRUE; } else { $Visible[$Slice]["Start"] = TRUE; }
- if ( $EndAngle < 180 ) { $Visible[$Slice]["End"] = FALSE; } else { $Visible[$Slice]["End"] = TRUE; }
-
- if ($DataGapAngle == 0)
- { $X0 = $X; $Y0 = $Y; }
- else
- {
- $Angle = ($EndAngle - $Offset)/2 + $Offset;
- $X0 = cos(($Angle-90)*PI/180) * $DataGapRadius + $X;
- $Y0 = sin(($Angle-90)*PI/180) * $DataGapRadius*$SkewFactor + $Y;
- }
- $Slices[$Slice][] = $X0; $Slices[$Slice][] = $Y0; $SliceAngle[$Slice][] = 0;
-
- for($i=$Offset;$i>=$EndAngle;$i=$i-$Step)
- {
- $Xc = cos(($i-90)*PI/180) * $Radius + $X;
- $Yc = sin(($i-90)*PI/180) * $Radius*$SkewFactor + $Y;
-
- if ( ($SecondPass || $RestoreShadow ) && ( $i<90 )) { $Yc++; }
- if ( ($SecondPass || $RestoreShadow ) && ( $i>90 && $i<180 )) { $Xc++; }
- if ( ($SecondPass || $RestoreShadow ) && ( $i>180 && $i<270 )) { $Xc++; }
- if ( ($SecondPass || $RestoreShadow ) && ( $i>=270 )) { $Xc++; $Yc++; }
-
- $Slices[$Slice][] = $Xc; $Slices[$Slice][] = $Yc; $SliceAngle[$Slice][] = $i;
- }
-
- $Offset = $i - $DataGapAngle; $ID--; $Slice++;
- }
-
- /* Draw the bottom shadow if needed */
- if ( $RestoreShadow && ($this->pChartObject->ShadowX != 0 || $this->pChartObject->ShadowY !=0 ))
- {
- foreach($Slices as $SliceID => $Plots)
- {
- $ShadowPie = "";
- for($i=0;$i<count($Plots);$i=$i+2)
- { $ShadowPie[] = $Plots[$i]+$this->pChartObject->ShadowX; $ShadowPie[] = $Plots[$i+1]+$this->pChartObject->ShadowY; }
-
- $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa,"NoBorder"=>TRUE);
- $this->pChartObject->drawPolygon($ShadowPie,$Settings);
- }
-
- $Step = 360 / (2 * PI * $Radius);
- $Offset = 360;
- foreach($Values as $Key => $Value)
- {
- $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; }
-
- for($i=$Offset;$i>=$EndAngle;$i=$i-$Step)
- {
- $Xc = cos(($i-90)*PI/180) * $Radius + $X + $this->pChartObject->ShadowX;
- $Yc = sin(($i-90)*PI/180) * $Radius*$SkewFactor + $Y + $this->pChartObject->ShadowY;
-
- $this->pChartObject->drawAntialiasPixel($Xc,$Yc,$Settings);
- }
-
- $Offset = $i - $DataGapAngle; $ID--;
- }
- }
-
- /* Draw the bottom pie splice */
- foreach($Slices as $SliceID => $Plots)
- {
- $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE;
- $this->pChartObject->drawPolygon($Plots,$Settings);
-
- if ( $SecondPass )
- {
- $Settings = $SliceColors[$SliceID];
- if ( $Border )
- { $Settings["R"]+= 30; $Settings["G"]+= 30; $Settings["B"]+= 30;; }
-
- if ( isset($SliceAngle[$SliceID][1]) ) /* Empty error handling */
- {
- $Angle = $SliceAngle[$SliceID][1];
- $Xc = cos(($Angle-90)*PI/180) * $Radius + $X;
- $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y;
- $this->pChartObject->drawLine($Plots[0],$Plots[1],$Xc,$Yc,$Settings);
-
- $Angle = $SliceAngle[$SliceID][count($SliceAngle[$SliceID])-1];
- $Xc = cos(($Angle-90)*PI/180) * $Radius + $X;
- $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y;
- $this->pChartObject->drawLine($Plots[0],$Plots[1],$Xc,$Yc,$Settings);
- }
- }
- }
-
- /* Draw the two vertical edges */
- $Slices = array_reverse($Slices);
- $SliceColors = array_reverse($SliceColors);
- foreach($Slices as $SliceID => $Plots)
- {
- $Settings = $SliceColors[$SliceID];
- $Settings["R"]+= 10; $Settings["G"]+= 10; $Settings["B"]+= 10; $Settings["NoBorder"] = TRUE;
-
- if ( $Visible[$SliceID]["Start"] && isset($Plots[2])) /* Empty error handling */
- {
- $this->pChartObject->drawLine($Plots[2],$Plots[3],$Plots[2],$Plots[3]- $SliceHeight,array("R"=>$Settings["R"],"G"=>$Settings["G"],"B"=>$Settings["B"]));
- $Border = "";
- $Border[] = $Plots[0]; $Border[] = $Plots[1]; $Border[] = $Plots[0]; $Border[] = $Plots[1] - $SliceHeight;
- $Border[] = $Plots[2]; $Border[] = $Plots[3] - $SliceHeight; $Border[] = $Plots[2]; $Border[] = $Plots[3];
- $this->pChartObject->drawPolygon($Border,$Settings);
- }
- }
-
- $Slices = array_reverse($Slices);
- $SliceColors = array_reverse($SliceColors);
- foreach($Slices as $SliceID => $Plots)
- {
- $Settings = $SliceColors[$SliceID];
- $Settings["R"]+= 10; $Settings["G"]+= 10; $Settings["B"]+= 10; $Settings["NoBorder"] = TRUE;
- if ( $Visible[$SliceID]["End"] )
- {
- $this->pChartObject->drawLine($Plots[count($Plots)-2],$Plots[count($Plots)-1],$Plots[count($Plots)-2],$Plots[count($Plots)-1]- $SliceHeight,array("R"=>$Settings["R"],"G"=>$Settings["G"],"B"=>$Settings["B"]));
-
- $Border = "";
- $Border[] = $Plots[0]; $Border[] = $Plots[1]; $Border[] = $Plots[0]; $Border[] = $Plots[1] - $SliceHeight;
- $Border[] = $Plots[count($Plots)-2]; $Border[] = $Plots[count($Plots)-1] - $SliceHeight; $Border[] = $Plots[count($Plots)-2]; $Border[] = $Plots[count($Plots)-1];
- $this->pChartObject->drawPolygon($Border,$Settings);
- }
- }
-
- /* Draw the rounded edges */
- foreach($Slices as $SliceID => $Plots)
- {
- $Settings = $SliceColors[$SliceID];
- $Settings["R"]+= 10; $Settings["G"]+= 10; $Settings["B"]+= 10; $Settings["NoBorder"] = TRUE;
-
- for ($j=2;$j<count($Plots)-2;$j=$j+2)
- {
- $Angle = $SliceAngle[$SliceID][$j/2];
- if ( $Angle < 270 && $Angle > 90 )
- {
- $Border = "";
- $Border[] = $Plots[$j]; $Border[] = $Plots[$j+1];
- $Border[] = $Plots[$j+2]; $Border[] = $Plots[$j+3];
- $Border[] = $Plots[$j+2]; $Border[] = $Plots[$j+3] - $SliceHeight;
- $Border[] = $Plots[$j]; $Border[] = $Plots[$j+1] - $SliceHeight;
- $this->pChartObject->drawPolygon($Border,$Settings);
- }
- }
-
- if ( $SecondPass )
- {
- $Settings = $SliceColors[$SliceID];
- if ( $Border )
- { $Settings["R"]+= 30; $Settings["G"]+= 30; $Settings["B"]+= 30; }
-
- if ( isset($SliceAngle[$SliceID][1]) ) /* Empty error handling */
- {
- $Angle = $SliceAngle[$SliceID][1];
- if ( $Angle < 270 && $Angle > 90 )
- {
- $Xc = cos(($Angle-90)*PI/180) * $Radius + $X;
- $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y;
- $this->pChartObject->drawLine($Xc,$Yc,$Xc,$Yc-$SliceHeight,$Settings);
- }
- }
-
- $Angle = $SliceAngle[$SliceID][count($SliceAngle[$SliceID])-1];
- if ( $Angle < 270 && $Angle > 90 )
- {
- $Xc = cos(($Angle-90)*PI/180) * $Radius + $X;
- $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y;
- $this->pChartObject->drawLine($Xc,$Yc,$Xc,$Yc-$SliceHeight,$Settings);
- }
-
- if ( isset($SliceAngle[$SliceID][1]) && $SliceAngle[$SliceID][1] > 270 && $SliceAngle[$SliceID][count($SliceAngle[$SliceID])-1] < 270 )
- {
- $Xc = cos((270-90)*PI/180) * $Radius + $X;
- $Yc = sin((270-90)*PI/180) * $Radius*$SkewFactor + $Y;
- $this->pChartObject->drawLine($Xc,$Yc,$Xc,$Yc-$SliceHeight,$Settings);
- }
-
- if ( isset($SliceAngle[$SliceID][1]) && $SliceAngle[$SliceID][1] > 90 && $SliceAngle[$SliceID][count($SliceAngle[$SliceID])-1] < 90 )
- {
- $Xc = cos((0)*PI/180) * $Radius + $X;
- $Yc = sin((0)*PI/180) * $Radius*$SkewFactor + $Y;
- $this->pChartObject->drawLine($Xc,$Yc,$Xc,$Yc-$SliceHeight,$Settings);
- }
-
- }
- }
-
- /* Draw the top splice */
- foreach($Slices as $SliceID => $Plots)
- {
- $Settings = $SliceColors[$SliceID];
- $Settings["R"]+= 20; $Settings["G"]+= 20; $Settings["B"]+= 20;
-
- $Top = "";
- for($j=0;$j<count($Plots);$j=$j+2) { $Top[] = $Plots[$j]; $Top[] = $Plots[$j+1]- $SliceHeight; }
- $this->pChartObject->drawPolygon($Top,$Settings);
-
- if ( $RecordImageMap && !$Shadow ) { $this->pChartObject->addToImageMap("POLY",$this->arraySerialize($Top),$this->pChartObject->toHTMLColor($Settings["R"],$Settings["G"],$Settings["B"]),$Data["Series"][$Data["Abscissa"]]["Data"][count($Slices)-$SliceID-1],$Values[$SliceID]); }
- }
-
-
- /* Second pass to smooth the angles */
- if ( $SecondPass )
- {
- $Step = 360 / (2 * PI * $Radius);
- $Offset = 360; $ID = count($Values)-1;
- foreach($Values as $Key => $Value)
- {
- $FirstPoint = TRUE;
- if ( $Shadow )
- $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa);
- else
- {
- if ( $Border )
- { $Settings = array("R"=>$Palette[$ID]["R"]+30,"G"=>$Palette[$ID]["G"]+30,"B"=>$Palette[$ID]["B"]+30,"Alpha"=>$Palette[$ID]["Alpha"]); }
- else
- $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);
- }
-
- $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; }
-
- if ($DataGapAngle == 0)
- { $X0 = $X; $Y0 = $Y- $SliceHeight; }
- else
- {
- $Angle = ($EndAngle - $Offset)/2 + $Offset;
- $X0 = cos(($Angle-90)*PI/180) * $DataGapRadius + $X;
- $Y0 = sin(($Angle-90)*PI/180) * $DataGapRadius*$SkewFactor + $Y - $SliceHeight;
- }
- $Plots[] = $X0; $Plots[] = $Y0;
-
- for($i=$Offset;$i>=$EndAngle;$i=$i-$Step)
- {
- $Xc = cos(($i-90)*PI/180) * $Radius + $X;
- $Yc = sin(($i-90)*PI/180) * $Radius*$SkewFactor + $Y - $SliceHeight;
-
- if ( $FirstPoint ) { $this->pChartObject->drawLine($Xc,$Yc,$X0,$Y0,$Settings); } { $FirstPoint = FALSE; }
-
- $this->pChartObject->drawAntialiasPixel($Xc,$Yc,$Settings);
- if ($i < 270 && $i > 90 ) { $this->pChartObject->drawAntialiasPixel($Xc,$Yc+$SliceHeight,$Settings); }
- }
- $this->pChartObject->drawLine($Xc,$Yc,$X0,$Y0,$Settings);
-
- $Offset = $i - $DataGapAngle; $ID--;
- }
- }
-
- if ( $WriteValues != NULL )
- {
- $Step = 360 / (2 * PI * $Radius);
- $Offset = 360; $ID = count($Values)-1;
- $Settings = array("Align"=>TEXT_ALIGN_MIDDLEMIDDLE,"R"=>$ValueR,"G"=>$ValueG,"B"=>$ValueB,"Alpha"=>$ValueAlpha);
- foreach($Values as $Key => $Value)
- {
- $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; }
-
- $Angle = ($EndAngle - $Offset)/2 + $Offset;
-
- if ( $ValuePosition == PIE_VALUE_OUTSIDE )
- {
- $Xc = cos(($Angle-90)*PI/180) * ($Radius+$ValuePadding) + $X;
- $Yc = sin(($Angle-90)*PI/180) * (($Radius*$SkewFactor)+$ValuePadding) + $Y - $SliceHeight;
- }
- else
- {
- $Xc = cos(($Angle-90)*PI/180) * ($Radius)/2 + $X;
- $Yc = sin(($Angle-90)*PI/180) * ($Radius*$SkewFactor)/2 + $Y - $SliceHeight;
- }
-
- if ( $WriteValues == PIE_VALUE_PERCENTAGE )
- $Display = round(( 100 / $SerieSum ) * $Value,$Precision)."%";
- elseif ( $WriteValues == PIE_VALUE_NATURAL )
- $Display = $Value.$ValueSuffix;
-
- $this->pChartObject->drawText($Xc,$Yc,$Display,$Settings);
-
- $Offset = $EndAngle - $DataGapAngle; $ID--;
- }
- }
-
- if ( $DrawLabels )
- {
- $Step = 360 / (2 * PI * $Radius);
- $Offset = 360; $ID = count($Values)-1;
- foreach($Values as $Key => $Value)
- {
- if ( $LabelColor == PIE_LABEL_COLOR_AUTO )
- { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);}
- else
- { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); }
-
- $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; }
-
- $Angle = ($EndAngle - $Offset)/2 + $Offset;
- $Xc = cos(($Angle-90)*PI/180) * $Radius + $X;
- $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y - $SliceHeight;
-
- if ( isset($Data["Series"][$Data["Abscissa"]]["Data"][$ID]) )
- {
- $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$ID];
-
- if ( $LabelStacked )
- $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,TRUE,$X,$Y,$Radius,TRUE);
- else
- $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,FALSE);
- }
-
- $Offset = $EndAngle - $DataGapAngle; $ID--;
- }
- }
-
- if ( $DrawLabels && $LabelStacked ) { $this->writeShiftedLabels(); }
-
- $this->pChartObject->Shadow = $RestoreShadow;
-
- return(PIE_RENDERED);
- }
-
- /* Draw the legend of pie chart */
- function drawPieLegend($X,$Y,$Format="")
- {
- $FontName = isset($Format["FontName"]) ? $Format["FontName"] : $this->pChartObject->FontName;
- $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->pChartObject->FontSize;
- $FontR = isset($Format["FontR"]) ? $Format["FontR"] : $this->pChartObject->FontColorR;
- $FontG = isset($Format["FontG"]) ? $Format["FontG"] : $this->pChartObject->FontColorG;
- $FontB = isset($Format["FontB"]) ? $Format["FontB"] : $this->pChartObject->FontColorB;
- $BoxSize = isset($Format["BoxSize"]) ? $Format["BoxSize"] : 5;
- $Margin = isset($Format["Margin"]) ? $Format["Margin"] : 5;
- $R = isset($Format["R"]) ? $Format["R"] : 200;
- $G = isset($Format["G"]) ? $Format["G"] : 200;
- $B = isset($Format["B"]) ? $Format["B"] : 200;
- $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;
- $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 255;
- $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 255;
- $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 255;
- $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL;
- $Style = isset($Format["Style"]) ? $Format["Style"] : LEGEND_ROUND;
- $Mode = isset($Format["Mode"]) ? $Format["Mode"] : LEGEND_VERTICAL;
-
- if ( $Surrounding != NULL ) { $BorderR = $R + $Surrounding; $BorderG = $G + $Surrounding; $BorderB = $B + $Surrounding; }
-
- $YStep = max($this->pChartObject->FontSize,$BoxSize) + 5;
- $XStep = $BoxSize + 5;
-
- /* Data Processing */
- $Data = $this->pDataObject->getData();
- $Palette = $this->pDataObject->getPalette();
-
- /* Do we have an abscissa serie defined? */
- if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); }
-
- $Boundaries = ""; $Boundaries["L"] = $X; $Boundaries["T"] = $Y; $Boundaries["R"] = 0; $Boundaries["B"] = 0; $vY = $Y; $vX = $X;
- foreach($Data["Series"][$Data["Abscissa"]]["Data"] as $Key => $Value)
- {
- $BoxArray = $this->pChartObject->getTextBox($vX+$BoxSize+4,$vY+$BoxSize/2,$FontName,$FontSize,0,$Value);
-
- if ( $Mode == LEGEND_VERTICAL )
- {
- if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$BoxSize/2 ) { $Boundaries["T"] = $BoxArray[2]["Y"]+$BoxSize/2; }
- if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { $Boundaries["R"] = $BoxArray[1]["X"]+2; }
- if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$BoxSize/2 ) { $Boundaries["B"] = $BoxArray[1]["Y"]+2+$BoxSize/2; }
- $vY=$vY+$YStep;
- }
- elseif ( $Mode == LEGEND_HORIZONTAL )
- {
- if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$BoxSize/2 ) { $Boundaries["T"] = $BoxArray[2]["Y"]+$BoxSize/2; }
- if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { $Boundaries["R"] = $BoxArray[1]["X"]+2; }
- if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$BoxSize/2 ) { $Boundaries["B"] = $BoxArray[1]["Y"]+2+$BoxSize/2; }
- $vX=$Boundaries["R"]+$XStep;
- }
- }
- $vY=$vY-$YStep; $vX=$vX-$XStep;
-
- $TopOffset = $Y - $Boundaries["T"];
- if ( $Boundaries["B"]-($vY+$BoxSize) < $TopOffset ) { $Boundaries["B"] = $vY+$BoxSize+$TopOffset; }
-
- if ( $Style == LEGEND_ROUND )
- $this->pChartObject->drawRoundedFilledRectangle($Boundaries["L"]-$Margin,$Boundaries["T"]-$Margin,$Boundaries["R"]+$Margin,$Boundaries["B"]+$Margin,$Margin,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"BorderR"=>$BorderR,"BorderG"=>$BorderG,"BorderB"=>$BorderB));
- elseif ( $Style == LEGEND_BOX )
- $this->pChartObject->drawFilledRectangle($Boundaries["L"]-$Margin,$Boundaries["T"]-$Margin,$Boundaries["R"]+$Margin,$Boundaries["B"]+$Margin,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"BorderR"=>$BorderR,"BorderG"=>$BorderG,"BorderB"=>$BorderB));
-
- $RestoreShadow = $this->pChartObject->Shadow; $this->pChartObject->Shadow = FALSE;
- foreach($Data["Series"][$Data["Abscissa"]]["Data"] as $Key => $Value)
- {
- $R = $Palette[$Key]["R"]; $G = $Palette[$Key]["G"]; $B = $Palette[$Key]["B"];
-
- $this->pChartObject->drawFilledRectangle($X+1,$Y+1,$X+$BoxSize+1,$Y+$BoxSize+1,array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>20));
- $this->pChartObject->drawFilledRectangle($X,$Y,$X+$BoxSize,$Y+$BoxSize,array("R"=>$R,"G"=>$G,"B"=>$B,"Surrounding"=>20));
- if ( $Mode == LEGEND_VERTICAL )
- {
- $this->pChartObject->drawText($X+$BoxSize+4,$Y+$BoxSize/2,$Value,array("R"=>$FontR,"G"=>$FontG,"B"=>$FontB,"Align"=>TEXT_ALIGN_MIDDLELEFT,"FontName"=>$FontName,"FontSize"=>$FontSize));
- $Y=$Y+$YStep;
- }
- elseif ( $Mode == LEGEND_HORIZONTAL )
- {
- $BoxArray = $this->pChartObject->drawText($X+$BoxSize+4,$Y+$BoxSize/2,$Value,array("R"=>$FontR,"G"=>$FontG,"B"=>$FontB,"Align"=>TEXT_ALIGN_MIDDLELEFT,"FontName"=>$FontName,"FontSize"=>$FontSize));
- $X=$BoxArray[1]["X"]+2+$XStep;
- }
- }
-
- $this->Shadow = $RestoreShadow;
- }
-
- /* Set the color of the specified slice */
- function setSliceColor($SliceID,$Format="")
- {
- $R = isset($Format["R"]) ? $Format["R"] : 0;
- $G = isset($Format["G"]) ? $Format["G"] : 0;
- $B = isset($Format["B"]) ? $Format["B"] : 0;
- $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;
-
- $this->pDataObject->Palette[$SliceID]["R"] = $R;
- $this->pDataObject->Palette[$SliceID]["G"] = $G;
- $this->pDataObject->Palette[$SliceID]["B"] = $B;
- $this->pDataObject->Palette[$SliceID]["Alpha"] = $Alpha;
- }
-
- /* Internally used compute the label positions */
- function writePieLabel($X,$Y,$Label,$Angle,$Settings,$Stacked,$Xc=0,$Yc=0,$Radius=0,$Reversed=FALSE)
- {
- $LabelOffset = 30;
- $FontName = $this->pChartObject->FontName;
- $FontSize = $this->pChartObject->FontSize;
-
- if ( !$Stacked )
- {
- $Settings["Angle"] = 360-$Angle;
- $Settings["Length"] = 25;
- $Settings["Size"] = 8;
-
- $this->pChartObject->drawArrowLabel($X,$Y," ".$Label." ",$Settings);
- }
- else
- {
- $X2 = cos(deg2rad($Angle-90))*20+$X;
- $Y2 = sin(deg2rad($Angle-90))*20+$Y;
-
- $TxtPos = $this->pChartObject->getTextBox($X,$Y,$FontName,$FontSize,0,$Label);
- $Height = $TxtPos[0]["Y"] - $TxtPos[2]["Y"];
- $YTop = $Y2 - $Height/2 - 2;
- $YBottom = $Y2 + $Height/2 + 2;
-
- if ( $this->LabelPos != "" )
- {
- $Done = FALSE;
- foreach($this->LabelPos as $Key => $Settings)
- {
- if ( !$Done )
- {
- if ( $Angle <= 90 && (($YTop >= $Settings["YTop"] && $YTop <= $Settings["YBottom"]) || ($YBottom >= $Settings["YTop"] && $YBottom <= $Settings["YBottom"])))
- { $this->shift(0,180,-($Height+2),$Reversed); $Done = TRUE; }
- if ( $Angle > 90 && $Angle <= 180 && (($YTop >= $Settings["YTop"] && $YTop <= $Settings["YBottom"]) || ($YBottom >= $Settings["YTop"] && $YBottom <= $Settings["YBottom"])))
- { $this->shift(0,180,-($Height+2),$Reversed); $Done = TRUE; }
- if ( $Angle > 180 && $Angle <= 270 && (($YTop >= $Settings["YTop"] && $YTop <= $Settings["YBottom"]) || ($YBottom >= $Settings["YTop"] && $YBottom <= $Settings["YBottom"])))
- { $this->shift(180,360,($Height+2),$Reversed); $Done = TRUE; }
- if ( $Angle > 270 && $Angle <= 360 && (($YTop >= $Settings["YTop"] && $YTop <= $Settings["YBottom"]) || ($YBottom >= $Settings["YTop"] && $YBottom <= $Settings["YBottom"])))
- { $this->shift(180,360,($Height+2),$Reversed); $Done = TRUE; }
- }
- }
- }
-
- $LabelSettings = array("YTop"=>$YTop,"YBottom"=>$YBottom,"Label"=>$Label,"Angle"=>$Angle,"X1"=>$X,"Y1"=>$Y,"X2"=>$X2,"Y2"=>$Y2);
- if ( $Angle <= 180 ) { $LabelSettings["X3"] = $Xc+$Radius+$LabelOffset; }
- if ( $Angle > 180 ) { $LabelSettings["X3"] = $Xc-$Radius-$LabelOffset; }
- $this->LabelPos[] = $LabelSettings;
- }
- }
-
- /* Internally used to shift label positions */
- function shift($StartAngle,$EndAngle,$Offset,$Reversed)
- {
- if ( $Reversed ) { $Offset = -$Offset; }
- foreach($this->LabelPos as $Key => $Settings)
- {
- if ( $Settings["Angle"] > $StartAngle && $Settings["Angle"] <= $EndAngle ) { $this->LabelPos[$Key]["YTop"] = $Settings["YTop"] + $Offset; $this->LabelPos[$Key]["YBottom"] = $Settings["YBottom"] + $Offset; $this->LabelPos[$Key]["Y2"] = $Settings["Y2"] + $Offset; }
- }
- }
-
- /* Internally used to write the re-computed labels */
- function writeShiftedLabels()
- {
- if ( $this->LabelPos == "" ) { return(0); }
- foreach($this->LabelPos as $Key => $Settings)
- {
- $X1 = $Settings["X1"]; $Y1 = $Settings["Y1"];
- $X2 = $Settings["X2"]; $Y2 = $Settings["Y2"];
- $X3 = $Settings["X3"];
- $Angle = $Settings["Angle"];
- $Label = $Settings["Label"];
-
- $this->pChartObject->drawArrow($X2,$Y2,$X1,$Y1,array("Size"=>8));
- if ( $Angle <= 180 )
- {
- $this->pChartObject->drawLine($X2,$Y2,$X3,$Y2);
- $this->pChartObject->drawText($X3+2,$Y2,$Label,array("Align"=>TEXT_ALIGN_MIDDLELEFT));
- }
- else
- {
- $this->pChartObject->drawLine($X2,$Y2,$X3,$Y2);
- $this->pChartObject->drawText($X3-2,$Y2,$Label,array("Align"=>TEXT_ALIGN_MIDDLERIGHT));
- }
- }
- }
-
- /* Draw a ring chart */
- function draw2DRing($X,$Y,$Format="")
- {
- $OuterRadius = isset($Format["Radius"]) ? $Format["Radius"] : 60;
- $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0;
- $InnerRadius = isset($Format["Radius"]) ? $Format["Radius"] : 30;
- $Border = isset($Format["Border"]) ? $Format["Border"] : FALSE;
- $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 255;
- $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 255;
- $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 255;
- $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : 100;
- $Shadow = isset($Format["Shadow"]) ? $Format["Shadow"] : FALSE;
- $DrawLabels = isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : FALSE;
- $LabelStacked = isset($Format["LabelStacked"]) ? $Format["LabelStacked"] : FALSE;
- $LabelColor = isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL;
- $LabelR = isset($Format["LabelR"]) ? $Format["LabelR"] : 0;
- $LabelG = isset($Format["LabelG"]) ? $Format["LabelG"] : 0;
- $LabelB = isset($Format["LabelB"]) ? $Format["LabelB"] : 0;
- $LabelAlpha = isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100;
- $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : NULL; //PIE_VALUE_PERCENTAGE
- $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : 5;
- $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_OUTSIDE;
- $ValueSuffix = isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : "";
- $ValueR = isset($Format["ValueR"]) ? $Format["ValueR"] : 255;
- $ValueG = isset($Format["ValueG"]) ? $Format["ValueG"] : 255;
- $ValueB = isset($Format["ValueB"]) ? $Format["ValueB"] : 255;
- $ValueAlpha = isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100;
- $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE;
-
- /* Data Processing */
- $Data = $this->pDataObject->getData();
- $Palette = $this->pDataObject->getPalette();
-
- /* Do we have an abscissa serie defined? */
- if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); }
-
- /* Try to find the data serie */
- $DataSerie = "";
- foreach ($Data["Series"] as $SerieName => $SerieData)
- { if ( $SerieName != $Data["Abscissa"]) { $DataSerie = $SerieName; } }
-
- /* Do we have data to compute? */
- if ( $DataSerie == "" ) { return(PIE_NO_DATASERIE); }
-
- /* Remove unused data */
- list($Data,$Palette) = $this->clean0Values($Data,$Palette,$DataSerie,$Data["Abscissa"]);
-
- /* Compute the pie sum */
- $SerieSum = $this->pDataObject->getSum($DataSerie);
-
- /* Do we have data to draw? */
- if ( $SerieSum == 0 ) { return(PIE_SUMISNULL); }
-
- /* Dump the real number of data to draw */
- $Values = "";
- foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value)
- { if ($Value != 0) { $Values[] = $Value; } }
-
- /* Compute the wasted angular space between series */
- if (count($Values)==1) { $WastedAngular = 0; } else { $WastedAngular = 0; } // count($Values)
-
- /* Compute the scale */
- $ScaleFactor = (360 - $WastedAngular) / $SerieSum;
-
- $RestoreShadow = $this->pChartObject->Shadow;
- if ( $this->pChartObject->Shadow )
- {
- $this->pChartObject->Shadow = FALSE;
-
- $ShadowFormat = $Format; $ShadowFormat["Shadow"] = TRUE;
- $this->draw2DRing($X+$this->pChartObject->ShadowX,$Y+$this->pChartObject->ShadowY,$ShadowFormat);
- }
-
- /* Draw the polygon pie elements */
- $Step = 360 / (2 * PI * $OuterRadius);
- $Offset = 0; $ID = 0;
- foreach($Values as $Key => $Value)
- {
- if ( $Shadow )
- {
- $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa);
- $BorderColor = $Settings;
- }
- else
- {
- if ( !isset($Palette[$ID]["R"]) ) { $Color = $this->pChartObject->getRandomColor(); $Palette[$ID] = $Color; $this->pDataObject->savePalette($ID,$Color); }
- $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);
-
- if ( $Border )
- $BorderColor = array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha);
- else
- $BorderColor = $Settings;
- }
-
- $Plots = ""; $Boundaries = ""; $AAPixels = "";
- $EndAngle = $Offset+($Value*$ScaleFactor); if ( $EndAngle > 360 ) { $EndAngle = 360; }
- for($i=$Offset;$i<=$EndAngle;$i=$i+$Step)
- {
- $Xc = cos(($i-90)*PI/180) * $OuterRadius + $X;
- $Yc = sin(($i-90)*PI/180) * $OuterRadius + $Y;
-
- if ( !isset($Boundaries[0]["X1"]) ) { $Boundaries[0]["X1"] = $Xc; $Boundaries[0]["Y1"] = $Yc; }
- $AAPixels[] = array($Xc,$Yc);
-
- if ( $i<90 ) { $Yc++; }
- if ( $i>180 && $i<270 ) { $Xc++; }
- if ( $i>=270 ) { $Xc++; $Yc++; }
-
- $Plots[] = $Xc; $Plots[] = $Yc;
- }
- $Boundaries[1]["X1"] = $Xc; $Boundaries[1]["Y1"] = $Yc;
- $Lasti = $EndAngle;
-
- for($i=$EndAngle;$i>=$Offset;$i=$i-$Step)
- {
- $Xc = cos(($i-90)*PI/180) * ($InnerRadius-1) + $X;
- $Yc = sin(($i-90)*PI/180) * ($InnerRadius-1) + $Y;
-
- if ( !isset($Boundaries[1]["X2"]) ) { $Boundaries[1]["X2"] = $Xc; $Boundaries[1]["Y2"] = $Yc; }
- $AAPixels[] = array($Xc,$Yc);
-
- $Xc = cos(($i-90)*PI/180) * $InnerRadius + $X;
- $Yc = sin(($i-90)*PI/180) * $InnerRadius + $Y;
-
- if ( $i<90 ) { $Yc++; }
- if ( $i>180 && $i<270 ) { $Xc++; }
- if ( $i>=270 ) { $Xc++; $Yc++; }
-
- $Plots[] = $Xc; $Plots[] = $Yc;
- }
- $Boundaries[0]["X2"] = $Xc; $Boundaries[0]["Y2"] = $Yc;
-
- /* Draw the polygon */
- $this->pChartObject->drawPolygon($Plots,$Settings);
- if ( $RecordImageMap && !$Shadow ) { $this->pChartObject->addToImageMap("POLY",$this->arraySerialize($Plots),$this->pChartObject->toHTMLColor($Palette[$ID]["R"],$Palette[$ID]["G"],$Palette[$ID]["B"]),$Data["Series"][$Data["Abscissa"]]["Data"][$Key],$Value); }
-
- /* Smooth the edges using AA */
- foreach($AAPixels as $iKey => $Pos ) { $this->pChartObject->drawAntialiasPixel($Pos[0],$Pos[1],$BorderColor); }
- $this->pChartObject->drawLine($Boundaries[0]["X1"],$Boundaries[0]["Y1"],$Boundaries[0]["X2"],$Boundaries[0]["Y2"],$BorderColor);
- $this->pChartObject->drawLine($Boundaries[1]["X1"],$Boundaries[1]["Y1"],$Boundaries[1]["X2"],$Boundaries[1]["Y2"],$BorderColor);
-
- if ( $DrawLabels && !$Shadow )
- {
- if ( $LabelColor == PIE_LABEL_COLOR_AUTO )
- { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);}
- else
- { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); }
-
- $Angle = ($EndAngle - $Offset)/2 + $Offset;
- $Xc = cos(($Angle-90)*PI/180) * $OuterRadius + $X;
- $Yc = sin(($Angle-90)*PI/180) * $OuterRadius + $Y;
-
- $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key];
-
- if ( $LabelStacked )
- $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,TRUE,$X,$Y,$OuterRadius);
- else
- $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,FALSE);
- }
-
- $Offset = $Lasti; $ID++;
- }
-
- if ( $DrawLabels && $LabelStacked ) { $this->writeShiftedLabels(); }
-
- if ( $WriteValues && !$Shadow )
- {
- $Step = 360 / (2 * PI * $OuterRadius);
- $Offset = 0;
- foreach($Values as $Key => $Value)
- {
- $EndAngle = $Offset+($Value*$ScaleFactor);
- if ( $EndAngle > 360 ) { $EndAngle = 360; }
-
- $Angle = $Offset+($Value*$ScaleFactor)/2;
- if ( $ValuePosition == PIE_VALUE_OUTSIDE )
- {
- $Xc = cos(($Angle-90)*PI/180) * ($OuterRadius+$ValuePadding) + $X;
- $Yc = sin(($Angle-90)*PI/180) * ($OuterRadius+$ValuePadding) + $Y;
- if ( $Angle >=0 && $Angle <= 90 ) { $Align = TEXT_ALIGN_BOTTOMLEFT; }
- if ( $Angle > 90 && $Angle <= 180 ) { $Align = TEXT_ALIGN_TOPLEFT; }
- if ( $Angle > 180 && $Angle <= 270 ) { $Align = TEXT_ALIGN_TOPRIGHT; }
- if ( $Angle > 270 ) { $Align = TEXT_ALIGN_BOTTOMRIGHT; }
- }
- else
- {
- $Xc = cos(($Angle-90)*PI/180) * (($OuterRadius-$InnerRadius)/2+$InnerRadius) + $X;
- $Yc = sin(($Angle-90)*PI/180) * (($OuterRadius-$InnerRadius)/2+$InnerRadius) + $Y;
- $Align = TEXT_ALIGN_MIDDLEMIDDLE;
- }
-
- if ( $WriteValues == PIE_VALUE_PERCENTAGE )
- $Display = round(( 100 / $SerieSum ) * $Value,$Precision)."%";
- elseif ( $WriteValues == PIE_VALUE_NATURAL )
- $Display = $Value.$ValueSuffix;
- else
- $Label = "";
-
- $this->pChartObject->drawText($Xc,$Yc,$Display,array("Align"=>$Align,"R"=>$ValueR,"G"=>$ValueG,"B"=>$ValueB));
- $Offset = $EndAngle;
- }
- }
-
- $this->pChartObject->Shadow = $RestoreShadow;
-
- return(PIE_RENDERED);
- }
-
- /* Draw a 3D ring chart */
- function draw3DRing($X,$Y,$Format="")
- {
- $OuterRadius = isset($Format["OuterRadius"]) ? $Format["OuterRadius"] : 100;
- $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0;
- $InnerRadius = isset($Format["InnerRadius"]) ? $Format["InnerRadius"] : 30;
- $SkewFactor = isset($Format["SkewFactor"]) ? $Format["SkewFactor"] : .6;
- $SliceHeight = isset($Format["SliceHeight"]) ? $Format["SliceHeight"] : 10;
- $DataGapAngle = isset($Format["DataGapAngle"]) ? $Format["DataGapAngle"] : 10;
- $DataGapRadius = isset($Format["DataGapRadius"]) ? $Format["DataGapRadius"] : 10;
- $Border = isset($Format["Border"]) ? $Format["Border"] : FALSE;
- $Shadow = isset($Format["Shadow"]) ? $Format["Shadow"] : FALSE;
- $DrawLabels = isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : FALSE;
- $LabelStacked = isset($Format["LabelStacked"]) ? $Format["LabelStacked"] : FALSE;
- $LabelColor = isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL;
- $LabelR = isset($Format["LabelR"]) ? $Format["LabelR"] : 0;
- $LabelG = isset($Format["LabelG"]) ? $Format["LabelG"] : 0;
- $LabelB = isset($Format["LabelB"]) ? $Format["LabelB"] : 0;
- $LabelAlpha = isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100;
- $Cf = isset($Format["Cf"]) ? $Format["Cf"] : 20;
- $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : PIE_VALUE_NATURAL;
- $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : $SliceHeight + 15;
- $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_OUTSIDE;
- $ValueSuffix = isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : "";
- $ValueR = isset($Format["ValueR"]) ? $Format["ValueR"] : 255;
- $ValueG = isset($Format["ValueG"]) ? $Format["ValueG"] : 255;
- $ValueB = isset($Format["ValueB"]) ? $Format["ValueB"] : 255;
- $ValueAlpha = isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100;
- $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE;
-
- /* Error correction for overlaying rounded corners */
- if ( $SkewFactor < .5 ) { $SkewFactor = .5; }
-
- /* Data Processing */
- $Data = $this->pDataObject->getData();
- $Palette = $this->pDataObject->getPalette();
-
- /* Do we have an abscissa serie defined? */
- if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); }
-
- /* Try to find the data serie */
- $DataSerie = "";
- foreach ($Data["Series"] as $SerieName => $SerieData)
- { if ( $SerieName != $Data["Abscissa"]) { $DataSerie = $SerieName; } }
-
- /* Do we have data to compute? */
- if ( $DataSerie == "" ) { return(PIE_NO_DATASERIE); }
-
- /* Remove unused data */
- list($Data,$Palette) = $this->clean0Values($Data,$Palette,$DataSerie,$Data["Abscissa"]);
-
- /* Compute the pie sum */
- $SerieSum = $this->pDataObject->getSum($DataSerie);
-
- /* Do we have data to draw? */
- if ( $SerieSum == 0 ) { return(PIE_SUMISNULL); }
-
- /* Dump the real number of data to draw */
- $Values = "";
- foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value)
- { if ($Value != 0) { $Values[] = $Value; } }
-
- /* Compute the wasted angular space between series */
- if (count($Values)==1) { $WastedAngular = 0; } else { $WastedAngular = count($Values) * $DataGapAngle; }
-
- /* Compute the scale */
- $ScaleFactor = (360 - $WastedAngular) / $SerieSum;
-
- $RestoreShadow = $this->pChartObject->Shadow;
- if ( $this->pChartObject->Shadow ) { $this->pChartObject->Shadow = FALSE; }
-
- /* Draw the polygon ring elements */
- $Offset = 360; $ID = count($Values)-1;
- $Values = array_reverse($Values);
- $Slice = 0; $Slices = ""; $SliceColors = ""; $Visible = ""; $SliceAngle = "";
- foreach($Values as $Key => $Value)
- {
- if ( !isset($Palette[$ID]["R"]) ) { $Color = $this->pChartObject->getRandomColor(); $Palette[$ID] = $Color; $this->pDataObject->savePalette($ID,$Color); }
- $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);
-
- $SliceColors[$Slice] = $Settings;
-
- $StartAngle = $Offset;
- $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; }
-
- if ( $StartAngle > 180 ) { $Visible[$Slice]["Start"] = TRUE; } else { $Visible[$Slice]["Start"] = TRUE; }
- if ( $EndAngle < 180 ) { $Visible[$Slice]["End"] = FALSE; } else { $Visible[$Slice]["End"] = TRUE; }
-
- $Step = (360 / (2 * PI * $OuterRadius))/2;
- $OutX1 = VOID; $OutY1 = VOID;
- for($i=$Offset;$i>=$EndAngle;$i=$i-$Step)
- {
- $Xc = cos(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius-2) + $X;
- $Yc = sin(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius-2)*$SkewFactor + $Y;
- $Slices[$Slice]["AA"][] = array($Xc,$Yc);
-
- $Xc = cos(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius-1) + $X;
- $Yc = sin(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius-1)*$SkewFactor + $Y;
- $Slices[$Slice]["AA"][] = array($Xc,$Yc);
-
- $Xc = cos(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius) + $X;
- $Yc = sin(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius)*$SkewFactor + $Y;
- $this->pChartObject->drawAntialiasPixel($Xc,$Yc,$Settings);
-
- if ( $OutX1 == VOID ) { $OutX1 = $Xc; $OutY1 = $Yc; }
-
- if ( $i<90 ) { $Yc++; }
- if ( $i>90 && $i<180 ) { $Xc++; }
- if ( $i>180 && $i<270 ) { $Xc++; }
- if ( $i>=270 ) { $Xc++; $Yc++; }
-
- $Slices[$Slice]["BottomPoly"][] = floor($Xc); $Slices[$Slice]["BottomPoly"][] = floor($Yc);
- $Slices[$Slice]["TopPoly"][] = floor($Xc); $Slices[$Slice]["TopPoly"][] = floor($Yc)-$SliceHeight;
- $Slices[$Slice]["Angle"][] = $i;
- }
- $OutX2 = $Xc; $OutY2 = $Yc;
-
- $Slices[$Slice]["Angle"][] = VOID;
- $Lasti = $i;
-
- $Step = (360 / (2 * PI * $InnerRadius))/2;
- $InX1 = VOID; $InY1 = VOID;
- for($i=$EndAngle;$i<=$Offset;$i=$i+$Step)
- {
- $Xc = cos(($i-90)*PI/180) * ($InnerRadius+$DataGapRadius-1) + $X;
- $Yc = sin(($i-90)*PI/180) * ($InnerRadius+$DataGapRadius-1)*$SkewFactor + $Y;
- $Slices[$Slice]["AA"][] = array($Xc,$Yc);
-
- $Xc = cos(($i-90)*PI/180) * ($InnerRadius+$DataGapRadius) + $X;
- $Yc = sin(($i-90)*PI/180) * ($InnerRadius+$DataGapRadius)*$SkewFactor + $Y;
- $Slices[$Slice]["AA"][] = array($Xc,$Yc);
-
- if ( $InX1 == VOID ) { $InX1 = $Xc; $InY1 = $Yc; }
-
- if ( $i<90 ) { $Yc++; }
- if ( $i>90 && $i<180 ) { $Xc++; }
- if ( $i>180 && $i<270 ) { $Xc++; }
- if ( $i>=270 ) { $Xc++; $Yc++; }
-
- $Slices[$Slice]["BottomPoly"][] = floor($Xc); $Slices[$Slice]["BottomPoly"][] = floor($Yc);
- $Slices[$Slice]["TopPoly"][] = floor($Xc); $Slices[$Slice]["TopPoly"][] = floor($Yc)-$SliceHeight;
- $Slices[$Slice]["Angle"][] = $i;
- }
- $InX2 = $Xc; $InY2 = $Yc;
-
- $Slices[$Slice]["InX1"] = $InX1; $Slices[$Slice]["InY1"] = $InY1;
- $Slices[$Slice]["InX2"] = $InX2; $Slices[$Slice]["InY2"] = $InY2;
- $Slices[$Slice]["OutX1"] = $OutX1; $Slices[$Slice]["OutY1"] = $OutY1;
- $Slices[$Slice]["OutX2"] = $OutX2; $Slices[$Slice]["OutY2"] = $OutY2;
-
- $Offset = $Lasti - $DataGapAngle; $ID--; $Slice++;
- }
-
- /* Draw the bottom pie splice */
- foreach($Slices as $SliceID => $Plots)
- {
- $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE;
- $this->pChartObject->drawPolygon($Plots["BottomPoly"],$Settings);
-
- foreach($Plots["AA"] as $Key => $Pos)
- $this->pChartObject->drawAntialiasPixel($Pos[0],$Pos[1],$Settings);
-
- $this->pChartObject->drawLine($Plots["InX1"],$Plots["InY1"],$Plots["OutX2"],$Plots["OutY2"],$Settings);
- $this->pChartObject->drawLine($Plots["InX2"],$Plots["InY2"],$Plots["OutX1"],$Plots["OutY1"],$Settings);
- }
-
- $Slices = array_reverse($Slices);
- $SliceColors = array_reverse($SliceColors);
-
- /* Draw the vertical edges (semi-visible) */
- foreach($Slices as $SliceID => $Plots)
- {
- $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE;
- $Settings["R"] = $Settings["R"]+$Cf; $Settings["G"] = $Settings["G"]+$Cf; $Settings["B"] = $Settings["B"]+$Cf;
-
- $StartAngle = $Plots["Angle"][0];
- foreach($Plots["Angle"] as $Key =>$Angle) { if ($Angle == VOID) { $EndAngle = $Plots["Angle"][$Key-1]; } }
-
- if ( $StartAngle >= 270 || $StartAngle <= 90 )
- $this->pChartObject->drawLine($Plots["OutX1"],$Plots["OutY1"],$Plots["OutX1"],$Plots["OutY1"]-$SliceHeight,$Settings);
- if ( $StartAngle >= 270 || $StartAngle <= 90 )
- $this->pChartObject->drawLine($Plots["OutX2"],$Plots["OutY2"],$Plots["OutX2"],$Plots["OutY2"]-$SliceHeight,$Settings);
-
- $this->pChartObject->drawLine($Plots["InX1"],$Plots["InY1"],$Plots["InX1"],$Plots["InY1"]-$SliceHeight,$Settings);
- $this->pChartObject->drawLine($Plots["InX2"],$Plots["InY2"],$Plots["InX2"],$Plots["InY2"]-$SliceHeight,$Settings);
- }
-
- /* Draw the inner vertical slices */
- foreach($Slices as $SliceID => $Plots)
- {
- $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE;
- $Settings["R"] = $Settings["R"]+$Cf; $Settings["G"] = $Settings["G"]+$Cf; $Settings["B"] = $Settings["B"]+$Cf;
-
- $Outer = TRUE; $Inner = FALSE;
- $InnerPlotsA = ""; $InnerPlotsB = "";
- foreach($Plots["Angle"] as $ID => $Angle)
- {
- if ( $Angle == VOID )
- { $Outer = FALSE; $Inner = TRUE; }
- elseif( $Inner )
- {
- if (( $Angle < 90 || $Angle > 270 ) && isset($Plots["BottomPoly"][$ID*2]) )
- {
- $Xo = $Plots["BottomPoly"][$ID*2];
- $Yo = $Plots["BottomPoly"][$ID*2+1];
-
- $InnerPlotsA[] = $Xo; $InnerPlotsA[] = $Yo;
- $InnerPlotsB[] = $Xo; $InnerPlotsB[] = $Yo-$SliceHeight;
- }
- }
- }
-
- if ( $InnerPlotsA != "" )
- { $InnerPlots = array_merge($InnerPlotsA,$this->arrayReverse($InnerPlotsB)); $this->pChartObject->drawPolygon($InnerPlots,$Settings); }
- }
-
- /* Draw the splice top and left poly */
- foreach($Slices as $SliceID => $Plots)
- {
- $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE;
- $Settings["R"] = $Settings["R"]+$Cf*1.5; $Settings["G"] = $Settings["G"]+$Cf*1.5; $Settings["B"] = $Settings["B"]+$Cf*1.5;
-
- $StartAngle = $Plots["Angle"][0];
- foreach($Plots["Angle"] as $Key =>$Angle) { if ($Angle == VOID) { $EndAngle = $Plots["Angle"][$Key-1]; } }
-
- if ( $StartAngle < 180 )
- {
- $Points = "";
- $Points[] = $Plots["InX2"];
- $Points[] = $Plots["InY2"];
- $Points[] = $Plots["InX2"];
- $Points[] = $Plots["InY2"]-$SliceHeight;
- $Points[] = $Plots["OutX1"];
- $Points[] = $Plots["OutY1"]-$SliceHeight;
- $Points[] = $Plots["OutX1"];
- $Points[] = $Plots["OutY1"];
-
- $this->pChartObject->drawPolygon($Points,$Settings);
- }
-
- if ( $EndAngle > 180 )
- {
- $Points = "";
- $Points[] = $Plots["InX1"];
- $Points[] = $Plots["InY1"];
- $Points[] = $Plots["InX1"];
- $Points[] = $Plots["InY1"]-$SliceHeight;
- $Points[] = $Plots["OutX2"];
- $Points[] = $Plots["OutY2"]-$SliceHeight;
- $Points[] = $Plots["OutX2"];
- $Points[] = $Plots["OutY2"];
-
- $this->pChartObject->drawPolygon($Points,$Settings);
- }
- }
-
-
- /* Draw the vertical edges (visible) */
- foreach($Slices as $SliceID => $Plots)
- {
- $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE;
- $Settings["R"] = $Settings["R"]+$Cf; $Settings["G"] = $Settings["G"]+$Cf; $Settings["B"] = $Settings["B"]+$Cf;
-
- $StartAngle = $Plots["Angle"][0];
- foreach($Plots["Angle"] as $Key =>$Angle) { if ($Angle == VOID) { $EndAngle = $Plots["Angle"][$Key-1]; } }
-
- if ( $StartAngle <= 270 && $StartAngle >= 90 )
- $this->pChartObject->drawLine($Plots["OutX1"],$Plots["OutY1"],$Plots["OutX1"],$Plots["OutY1"]-$SliceHeight,$Settings);
- if ( $EndAngle <= 270 && $EndAngle >= 90 )
- $this->pChartObject->drawLine($Plots["OutX2"],$Plots["OutY2"],$Plots["OutX2"],$Plots["OutY2"]-$SliceHeight,$Settings);
- }
-
-
- /* Draw the outer vertical slices */
- foreach($Slices as $SliceID => $Plots)
- {
- $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE;
- $Settings["R"] = $Settings["R"]+$Cf; $Settings["G"] = $Settings["G"]+$Cf; $Settings["B"] = $Settings["B"]+$Cf;
-
- $Outer = TRUE; $Inner = FALSE;
- $OuterPlotsA = ""; $OuterPlotsB = ""; $InnerPlotsA = ""; $InnerPlotsB = "";
- foreach($Plots["Angle"] as $ID => $Angle)
- {
- if ( $Angle == VOID )
- { $Outer = FALSE; $Inner = TRUE; }
- elseif( $Outer )
- {
- if ( ( $Angle > 90 && $Angle < 270 ) && isset($Plots["BottomPoly"][$ID*2]) )
- {
- $Xo = $Plots["BottomPoly"][$ID*2];
- $Yo = $Plots["BottomPoly"][$ID*2+1];
-
- $OuterPlotsA[] = $Xo; $OuterPlotsA[] = $Yo;
- $OuterPlotsB[] = $Xo; $OuterPlotsB[] = $Yo-$SliceHeight;
- }
- }
- }
- if ( $OuterPlotsA != "" )
- { $OuterPlots = array_merge($OuterPlotsA,$this->arrayReverse($OuterPlotsB)); $this->pChartObject->drawPolygon($OuterPlots,$Settings); }
- }
-
- $Slices = array_reverse($Slices);
- $SliceColors = array_reverse($SliceColors);
-
-
- /* Draw the top pie splice */
- foreach($Slices as $SliceID => $Plots)
- {
- $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE;
- $Settings["R"] = $Settings["R"]+$Cf*2; $Settings["G"] = $Settings["G"]+$Cf*2; $Settings["B"] = $Settings["B"]+$Cf*2;
-
- $this->pChartObject->drawPolygon($Plots["TopPoly"],$Settings);
-
- if ( $RecordImageMap ) { $this->pChartObject->addToImageMap("POLY",$this->arraySerialize($Plots["TopPoly"]),$this->pChartObject->toHTMLColor($Settings["R"],$Settings["G"],$Settings["B"]),$Data["Series"][$Data["Abscissa"]]["Data"][$SliceID],$Data["Series"][$DataSerie]["Data"][count($Slices)-$SliceID-1]); }
-
- foreach($Plots["AA"] as $Key => $Pos)
- $this->pChartObject->drawAntialiasPixel($Pos[0],$Pos[1]-$SliceHeight,$Settings);
-
- $this->pChartObject->drawLine($Plots["InX1"],$Plots["InY1"]-$SliceHeight,$Plots["OutX2"],$Plots["OutY2"]-$SliceHeight,$Settings);
- $this->pChartObject->drawLine($Plots["InX2"],$Plots["InY2"]-$SliceHeight,$Plots["OutX1"],$Plots["OutY1"]-$SliceHeight,$Settings);
- }
-
- if ( $DrawLabels )
- {
- $Offset = 360;
- foreach($Values as $Key => $Value)
- {
- $StartAngle = $Offset;
- $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; }
-
- if ( $LabelColor == PIE_LABEL_COLOR_AUTO )
- { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);}
- else
- { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); }
-
- $Angle = ($EndAngle - $Offset)/2 + $Offset;
- $Xc = cos(($Angle-90)*PI/180) * ($OuterRadius+$DataGapRadius) + $X;
- $Yc = sin(($Angle-90)*PI/180) * ($OuterRadius+$DataGapRadius)*$SkewFactor + $Y;
-
- if ( $WriteValues == PIE_VALUE_PERCENTAGE )
- $Label = $Display = round(( 100 / $SerieSum ) * $Value,$Precision)."%";
- elseif ( $WriteValues == PIE_VALUE_NATURAL )
- $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key];
- else
- $Label = "";
-
- if ( $LabelStacked )
- $this->writePieLabel($Xc,$Yc-$SliceHeight,$Label,$Angle,$Settings,TRUE,$X,$Y,$OuterRadius);
- else
- $this->writePieLabel($Xc,$Yc-$SliceHeight,$Label,$Angle,$Settings,FALSE);
-
- $Offset = $EndAngle - $DataGapAngle; $ID--; $Slice++;
- }
- }
- if ( $DrawLabels && $LabelStacked ) { $this->writeShiftedLabels(); }
-
- $this->pChartObject->Shadow = $RestoreShadow;
-
- return(PIE_RENDERED);
- }
-
- /* Serialize an array */
- function arraySerialize($Data)
- {
- $Result = "";
- foreach($Data as $Key => $Value)
- { if ($Result == "") { $Result = floor($Value); } else { $Result = $Result.",".floor($Value); } }
-
- return($Result);
- }
-
- /* Reverse an array */
- function arrayReverse($Plots)
- {
- $Result = "";
-
- for($i=count($Plots)-1;$i>=0;$i=$i-2)
- { $Result[] = $Plots[$i-1]; $Result[] = $Plots[$i]; }
-
- return($Result);
- }
-
- /* Remove unused series & values */
- function clean0Values($Data,$Palette,$DataSerie,$AbscissaSerie)
- {
- $NewPalette = ""; $NewData = ""; $NewAbscissa = "";
-
- /* Remove unused series */
- foreach($Data["Series"] as $SerieName => $SerieSettings)
- { if ( $SerieName != $DataSerie && $SerieName != $AbscissaSerie ) { unset($Data["Series"][$SerieName]); } }
-
- /* Remove NULL values */
- foreach($Data["Series"][$DataSerie]["Data"] as $Key => $Value)
- {
- if ($Value != 0 )
- {
- $NewData[] = $Value;
- $NewAbscissa[] = $Data["Series"][$AbscissaSerie]["Data"][$Key];
- if ( isset($Palette[$Key]) ) { $NewPalette[] = $Palette[$Key]; }
- }
- }
- $Data["Series"][$DataSerie]["Data"] = $NewData;
- $Data["Series"][$AbscissaSerie]["Data"] = $NewAbscissa;
-
- return(array($Data,$NewPalette));
- }
- }
+<?php
+ /*
+ pPie - class to draw pie charts
+
+ Version : 2.1.4
+ Made by : Jean-Damien POGOLOTTI
+ Last Update : 19/01/2014
+
+ This file can be distributed under the license you can find at :
+
+ http://www.pchart.net/license
+
+ You can find the whole class documentation on the pChart web site.
+ */
+
+ /* Class return codes */
+ define("PIE_NO_ABSCISSA" , 140001);
+ define("PIE_NO_DATASERIE" , 140002);
+ define("PIE_SUMISNULL" , 140003);
+ define("PIE_RENDERED" , 140000);
+
+ define("PIE_LABEL_COLOR_AUTO" , 140010);
+ define("PIE_LABEL_COLOR_MANUAL", 140011);
+
+ define("PIE_VALUE_NATURAL" , 140020);
+ define("PIE_VALUE_PERCENTAGE" , 140021);
+
+ define("PIE_VALUE_INSIDE" , 140030);
+ define("PIE_VALUE_OUTSIDE" , 140031);
+
+ /* pPie class definition */
+ class pPie
+ {
+ var $pChartObject;
+ var $pDataObject;
+ var $LabelPos = "" ;
+
+ /* Class creator */
+ function __construct($Object,$pDataObject)
+ {
+ /* Cache the pChart object reference */
+ $this->pChartObject = $Object;
+
+ /* Cache the pData object reference */
+ $this->pDataObject = $pDataObject;
+ }
+
+ /* Draw a pie chart */
+ function draw2DPie($X,$Y,$Format="")
+ {
+ $Radius = isset($Format["Radius"]) ? $Format["Radius"] : 60;
+ $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0;
+ $DataGapAngle = isset($Format["DataGapAngle"]) ? $Format["DataGapAngle"] : 0;
+ $DataGapRadius = isset($Format["DataGapRadius"]) ? $Format["DataGapRadius"] : 0;
+ $SecondPass = isset($Format["SecondPass"]) ? $Format["SecondPass"] : TRUE;
+ $Border = isset($Format["Border"]) ? $Format["Border"] : FALSE;
+ $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 255;
+ $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 255;
+ $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 255;
+ $Shadow = isset($Format["Shadow"]) ? $Format["Shadow"] : FALSE;
+ $DrawLabels = isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : FALSE;
+ $LabelStacked = isset($Format["LabelStacked"]) ? $Format["LabelStacked"] : FALSE;
+ $LabelColor = isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL;
+ $LabelR = isset($Format["LabelR"]) ? $Format["LabelR"] : 0;
+ $LabelG = isset($Format["LabelG"]) ? $Format["LabelG"] : 0;
+ $LabelB = isset($Format["LabelB"]) ? $Format["LabelB"] : 0;
+ $LabelAlpha = isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100;
+ $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : NULL;
+ $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_OUTSIDE;
+ $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : 15;
+ $ValueSuffix = isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : "";
+ $ValueR = isset($Format["ValueR"]) ? $Format["ValueR"] : 255;
+ $ValueG = isset($Format["ValueG"]) ? $Format["ValueG"] : 255;
+ $ValueB = isset($Format["ValueB"]) ? $Format["ValueB"] : 255;
+ $ValueAlpha = isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100;
+ $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE;
+
+ /* Data Processing */
+ $Data = $this->pDataObject->getData();
+ $Palette = $this->pDataObject->getPalette();
+
+ /* Do we have an abscissa serie defined? */
+ if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); }
+
+ /* Try to find the data serie */
+ $DataSerie = "";
+ foreach ($Data["Series"] as $SerieName => $SerieData)
+ { if ( $SerieName != $Data["Abscissa"]) { $DataSerie = $SerieName; } }
+
+ /* Do we have data to compute? */
+ if ( $DataSerie == "" ) { return(PIE_NO_DATASERIE); }
+
+ /* Remove unused data */
+ list($Data,$Palette) = $this->clean0Values($Data,$Palette,$DataSerie,$Data["Abscissa"]);
+
+ /* Compute the pie sum */
+ $SerieSum = $this->pDataObject->getSum($DataSerie);
+
+ /* Do we have data to draw? */
+ if ( $SerieSum == 0 ) { return(PIE_SUMISNULL); }
+
+ /* Dump the real number of data to draw */
+ $Values = "";
+ foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value)
+ { if ($Value != 0) { $Values[] = $Value; } }
+
+ /* Compute the wasted angular space between series */
+ if (count($Values)==1) { $WastedAngular = 0; } else { $WastedAngular = count($Values) * $DataGapAngle; }
+
+ /* Compute the scale */
+ $ScaleFactor = (360 - $WastedAngular) / $SerieSum;
+
+ $RestoreShadow = $this->pChartObject->Shadow;
+ if ( $this->pChartObject->Shadow )
+ {
+ $this->pChartObject->Shadow = FALSE;
+
+ $ShadowFormat = $Format; $ShadowFormat["Shadow"] = TRUE;
+ $this->draw2DPie($X+$this->pChartObject->ShadowX,$Y+$this->pChartObject->ShadowY,$ShadowFormat);
+ }
+
+ /* Draw the polygon pie elements */
+ $Step = 360 / (2 * PI * $Radius);
+ $Offset = 0; $ID = 0;
+ foreach($Values as $Key => $Value)
+ {
+ if ( $Shadow )
+ $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa);
+ else
+ {
+ if ( !isset($Palette[$ID]["R"]) ) { $Color = $this->pChartObject->getRandomColor(); $Palette[$ID] = $Color; $this->pDataObject->savePalette($ID,$Color); }
+ $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);
+ }
+
+ if ( !$SecondPass && !$Shadow )
+ {
+ if ( !$Border )
+ $Settings["Surrounding"] = 10;
+ else
+ { $Settings["BorderR"] = $BorderR; $Settings["BorderG"] = $BorderG; $Settings["BorderB"] = $BorderB; }
+ }
+
+ $Plots = "";
+ $EndAngle = $Offset+($Value*$ScaleFactor); if ( $EndAngle > 360 ) { $EndAngle = 360; }
+
+ $Angle = ($EndAngle - $Offset)/2 + $Offset;
+ if ($DataGapAngle == 0)
+ { $X0 = $X; $Y0 = $Y; }
+ else
+ {
+ $X0 = cos(($Angle-90)*PI/180) * $DataGapRadius + $X;
+ $Y0 = sin(($Angle-90)*PI/180) * $DataGapRadius + $Y;
+ }
+
+ $Plots[] = $X0; $Plots[] = $Y0;
+
+
+ for($i=$Offset;$i<=$EndAngle;$i=$i+$Step)
+ {
+ $Xc = cos(($i-90)*PI/180) * $Radius + $X;
+ $Yc = sin(($i-90)*PI/180) * $Radius + $Y;
+
+ if ( $SecondPass && ( $i<90 )) { $Yc++; }
+ if ( $SecondPass && ( $i>180 && $i<270 )) { $Xc++; }
+ if ( $SecondPass && ( $i>=270 )) { $Xc++; $Yc++; }
+
+ $Plots[] = $Xc; $Plots[] = $Yc;
+ }
+
+ $this->pChartObject->drawPolygon($Plots,$Settings);
+ if ( $RecordImageMap && !$Shadow ) { $this->pChartObject->addToImageMap("POLY",$this->arraySerialize($Plots),$this->pChartObject->toHTMLColor($Palette[$ID]["R"],$Palette[$ID]["G"],$Palette[$ID]["B"]),$Data["Series"][$Data["Abscissa"]]["Data"][$Key],$Value); }
+
+ if ( $DrawLabels && !$Shadow && !$SecondPass )
+ {
+ if ( $LabelColor == PIE_LABEL_COLOR_AUTO )
+ { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);}
+ else
+ { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); }
+
+ $Angle = ($EndAngle - $Offset)/2 + $Offset;
+ $Xc = cos(($Angle-90)*PI/180) * $Radius + $X;
+ $Yc = sin(($Angle-90)*PI/180) * $Radius + $Y;
+
+ $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key];
+
+ if ( $LabelStacked )
+ $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,TRUE,$X,$Y,$Radius);
+ else
+ $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,FALSE);
+ }
+
+ $Offset = $i + $DataGapAngle; $ID++;
+ }
+
+ /* Second pass to smooth the angles */
+ if ( $SecondPass )
+ {
+ $Step = 360 / (2 * PI * $Radius);
+ $Offset = 0; $ID = 0;
+ foreach($Values as $Key => $Value)
+ {
+ $FirstPoint = TRUE;
+ if ( $Shadow )
+ $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa);
+ else
+ {
+ if ( $Border )
+ $Settings = array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB);
+ else
+ $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);
+ }
+
+ $EndAngle = $Offset+($Value*$ScaleFactor); if ( $EndAngle > 360 ) { $EndAngle = 360; }
+
+ if ($DataGapAngle == 0)
+ { $X0 = $X; $Y0 = $Y; }
+ else
+ {
+ $Angle = ($EndAngle - $Offset)/2 + $Offset;
+ $X0 = cos(($Angle-90)*PI/180) * $DataGapRadius + $X;
+ $Y0 = sin(($Angle-90)*PI/180) * $DataGapRadius + $Y;
+ }
+ $Plots[] = $X0; $Plots[] = $Y0;
+
+ for($i=$Offset;$i<=$EndAngle;$i=$i+$Step)
+ {
+ $Xc = cos(($i-90)*PI/180) * $Radius + $X;
+ $Yc = sin(($i-90)*PI/180) * $Radius + $Y;
+
+ if ( $FirstPoint ) { $this->pChartObject->drawLine($Xc,$Yc,$X0,$Y0,$Settings); } { $FirstPoint = FALSE; }
+
+ $this->pChartObject->drawAntialiasPixel($Xc,$Yc,$Settings);
+ }
+ $this->pChartObject->drawLine($Xc,$Yc,$X0,$Y0,$Settings);
+
+ if ( $DrawLabels && !$Shadow )
+ {
+ if ( $LabelColor == PIE_LABEL_COLOR_AUTO )
+ { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);}
+ else
+ { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); }
+
+ $Angle = ($EndAngle - $Offset)/2 + $Offset;
+ $Xc = cos(($Angle-90)*PI/180) * $Radius + $X;
+ $Yc = sin(($Angle-90)*PI/180) * $Radius + $Y;
+
+ $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key];
+
+ if ( $LabelStacked )
+ $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,TRUE,$X,$Y,$Radius);
+ else
+ $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,FALSE);
+ }
+
+ $Offset = $i + $DataGapAngle; $ID++;
+ }
+ }
+
+ if ( $WriteValues != NULL && !$Shadow )
+ {
+ $Step = 360 / (2 * PI * $Radius);
+ $Offset = 0; $ID = count($Values)-1;
+ $Settings = array("Align"=>TEXT_ALIGN_MIDDLEMIDDLE,"R"=>$ValueR,"G"=>$ValueG,"B"=>$ValueB,"Alpha"=>$ValueAlpha);
+ foreach($Values as $Key => $Value)
+ {
+ $EndAngle = ($Value*$ScaleFactor) + $Offset; if ( (int)$EndAngle > 360 ) { $EndAngle = 0; }
+ $Angle = ($EndAngle - $Offset)/2 + $Offset;
+
+ if ( $ValuePosition == PIE_VALUE_OUTSIDE )
+ {
+ $Xc = cos(($Angle-90)*PI/180) * ($Radius+$ValuePadding) + $X;
+ $Yc = sin(($Angle-90)*PI/180) * ($Radius+$ValuePadding) + $Y;
+ }
+ else
+ {
+ $Xc = cos(($Angle-90)*PI/180) * ($Radius)/2 + $X;
+ $Yc = sin(($Angle-90)*PI/180) * ($Radius)/2 + $Y;
+ }
+
+ if ( $WriteValues == PIE_VALUE_PERCENTAGE )
+ $Display = round(( 100 / $SerieSum ) * $Value,$Precision)."%";
+ elseif ( $WriteValues == PIE_VALUE_NATURAL )
+ $Display = $Value.$ValueSuffix;
+
+ $this->pChartObject->drawText($Xc,$Yc,$Display,$Settings);
+
+ $Offset = $EndAngle + $DataGapAngle; $ID--;
+ }
+ }
+
+ if ( $DrawLabels && $LabelStacked ) { $this->writeShiftedLabels(); }
+
+ $this->pChartObject->Shadow = $RestoreShadow;
+
+ return(PIE_RENDERED);
+ }
+
+ /* Draw a 3D pie chart */
+ function draw3DPie($X,$Y,$Format="")
+ {
+ /* Rendering layout */
+ $Radius = isset($Format["Radius"]) ? $Format["Radius"] : 80;
+ $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0;
+ $SkewFactor = isset($Format["SkewFactor"]) ? $Format["SkewFactor"] : .5;
+ $SliceHeight = isset($Format["SliceHeight"]) ? $Format["SliceHeight"] : 20;
+ $DataGapAngle = isset($Format["DataGapAngle"]) ? $Format["DataGapAngle"] : 0;
+ $DataGapRadius = isset($Format["DataGapRadius"]) ? $Format["DataGapRadius"] : 0;
+ $SecondPass = isset($Format["SecondPass"]) ? $Format["SecondPass"] : TRUE;
+ $Border = isset($Format["Border"]) ? $Format["Border"] : FALSE;
+ $Shadow = isset($Format["Shadow"]) ? $Format["Shadow"] : FALSE;
+ $DrawLabels = isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : FALSE;
+ $LabelStacked = isset($Format["LabelStacked"]) ? $Format["LabelStacked"] : FALSE;
+ $LabelColor = isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL;
+ $LabelR = isset($Format["LabelR"]) ? $Format["LabelR"] : 0;
+ $LabelG = isset($Format["LabelG"]) ? $Format["LabelG"] : 0;
+ $LabelB = isset($Format["LabelB"]) ? $Format["LabelB"] : 0;
+ $LabelAlpha = isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100;
+ $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : NULL; //PIE_VALUE_PERCENTAGE
+ $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_INSIDE;
+ $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : 15;
+ $ValueSuffix = isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : "";
+ $ValueR = isset($Format["ValueR"]) ? $Format["ValueR"] : 255;
+ $ValueG = isset($Format["ValueG"]) ? $Format["ValueG"] : 255;
+ $ValueB = isset($Format["ValueB"]) ? $Format["ValueB"] : 255;
+ $ValueAlpha = isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100;
+ $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE;
+
+ /* Error correction for overlaying rounded corners */
+ if ( $SkewFactor < .5 ) { $SkewFactor = .5; }
+
+ /* Data Processing */
+ $Data = $this->pDataObject->getData();
+ $Palette = $this->pDataObject->getPalette();
+
+ /* Do we have an abscissa serie defined? */
+ if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); }
+
+ /* Try to find the data serie */
+ $DataSerie = "";
+ foreach ($Data["Series"] as $SerieName => $SerieData)
+ { if ( $SerieName != $Data["Abscissa"]) { $DataSerie = $SerieName; } }
+
+ /* Do we have data to compute? */
+ if ( $DataSerie == "" ) { return(PIE_NO_DATASERIE); }
+
+ /* Remove unused data */
+ list($Data,$Palette) = $this->clean0Values($Data,$Palette,$DataSerie,$Data["Abscissa"]);
+
+ /* Compute the pie sum */
+ $SerieSum = $this->pDataObject->getSum($DataSerie);
+
+ /* Do we have data to draw? */
+ if ( $SerieSum == 0 ) { return(PIE_SUMISNULL); }
+
+ /* Dump the real number of data to draw */
+ $Values = "";
+ foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value)
+ { if ($Value != 0) { $Values[] = $Value; } }
+
+ /* Compute the wasted angular space between series */
+ if (count($Values)==1) { $WastedAngular = 0; } else { $WastedAngular = count($Values) * $DataGapAngle; }
+
+ /* Compute the scale */
+ $ScaleFactor = (360 - $WastedAngular) / $SerieSum;
+
+ $RestoreShadow = $this->pChartObject->Shadow;
+ if ( $this->pChartObject->Shadow ) { $this->pChartObject->Shadow = FALSE; }
+
+ /* Draw the polygon pie elements */
+ $Step = 360 / (2 * PI * $Radius);
+ $Offset = 360; $ID = count($Values)-1;
+ $Values = array_reverse($Values);
+ $Slice = 0; $Slices = ""; $SliceColors = ""; $Visible = ""; $SliceAngle = "";
+ foreach($Values as $Key => $Value)
+ {
+ if ( !isset($Palette[$ID]["R"]) ) { $Color = $this->pChartObject->getRandomColor(); $Palette[$ID] = $Color; $this->pDataObject->savePalette($ID,$Color); }
+ $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);
+
+ $SliceColors[$Slice] = $Settings;
+
+ $StartAngle = $Offset;
+ $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; }
+
+ if ( $StartAngle > 180 ) { $Visible[$Slice]["Start"] = TRUE; } else { $Visible[$Slice]["Start"] = TRUE; }
+ if ( $EndAngle < 180 ) { $Visible[$Slice]["End"] = FALSE; } else { $Visible[$Slice]["End"] = TRUE; }
+
+ if ($DataGapAngle == 0)
+ { $X0 = $X; $Y0 = $Y; }
+ else
+ {
+ $Angle = ($EndAngle - $Offset)/2 + $Offset;
+ $X0 = cos(($Angle-90)*PI/180) * $DataGapRadius + $X;
+ $Y0 = sin(($Angle-90)*PI/180) * $DataGapRadius*$SkewFactor + $Y;
+ }
+ $Slices[$Slice][] = $X0; $Slices[$Slice][] = $Y0; $SliceAngle[$Slice][] = 0;
+
+ for($i=$Offset;$i>=$EndAngle;$i=$i-$Step)
+ {
+ $Xc = cos(($i-90)*PI/180) * $Radius + $X;
+ $Yc = sin(($i-90)*PI/180) * $Radius*$SkewFactor + $Y;
+
+ if ( ($SecondPass || $RestoreShadow ) && ( $i<90 )) { $Yc++; }
+ if ( ($SecondPass || $RestoreShadow ) && ( $i>90 && $i<180 )) { $Xc++; }
+ if ( ($SecondPass || $RestoreShadow ) && ( $i>180 && $i<270 )) { $Xc++; }
+ if ( ($SecondPass || $RestoreShadow ) && ( $i>=270 )) { $Xc++; $Yc++; }
+
+ $Slices[$Slice][] = $Xc; $Slices[$Slice][] = $Yc; $SliceAngle[$Slice][] = $i;
+ }
+
+ $Offset = $i - $DataGapAngle; $ID--; $Slice++;
+ }
+
+ /* Draw the bottom shadow if needed */
+ if ( $RestoreShadow && ($this->pChartObject->ShadowX != 0 || $this->pChartObject->ShadowY !=0 ))
+ {
+ foreach($Slices as $SliceID => $Plots)
+ {
+ $ShadowPie = "";
+ for($i=0;$i<count($Plots);$i=$i+2)
+ { $ShadowPie[] = $Plots[$i]+$this->pChartObject->ShadowX; $ShadowPie[] = $Plots[$i+1]+$this->pChartObject->ShadowY; }
+
+ $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa,"NoBorder"=>TRUE);
+ $this->pChartObject->drawPolygon($ShadowPie,$Settings);
+ }
+
+ $Step = 360 / (2 * PI * $Radius);
+ $Offset = 360;
+ foreach($Values as $Key => $Value)
+ {
+ $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; }
+
+ for($i=$Offset;$i>=$EndAngle;$i=$i-$Step)
+ {
+ $Xc = cos(($i-90)*PI/180) * $Radius + $X + $this->pChartObject->ShadowX;
+ $Yc = sin(($i-90)*PI/180) * $Radius*$SkewFactor + $Y + $this->pChartObject->ShadowY;
+
+ $this->pChartObject->drawAntialiasPixel($Xc,$Yc,$Settings);
+ }
+
+ $Offset = $i - $DataGapAngle; $ID--;
+ }
+ }
+
+ /* Draw the bottom pie splice */
+ foreach($Slices as $SliceID => $Plots)
+ {
+ $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE;
+ $this->pChartObject->drawPolygon($Plots,$Settings);
+
+ if ( $SecondPass )
+ {
+ $Settings = $SliceColors[$SliceID];
+ if ( $Border )
+ { $Settings["R"]+= 30; $Settings["G"]+= 30; $Settings["B"]+= 30;; }
+
+ if ( isset($SliceAngle[$SliceID][1]) ) /* Empty error handling */
+ {
+ $Angle = $SliceAngle[$SliceID][1];
+ $Xc = cos(($Angle-90)*PI/180) * $Radius + $X;
+ $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y;
+ $this->pChartObject->drawLine($Plots[0],$Plots[1],$Xc,$Yc,$Settings);
+
+ $Angle = $SliceAngle[$SliceID][count($SliceAngle[$SliceID])-1];
+ $Xc = cos(($Angle-90)*PI/180) * $Radius + $X;
+ $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y;
+ $this->pChartObject->drawLine($Plots[0],$Plots[1],$Xc,$Yc,$Settings);
+ }
+ }
+ }
+
+ /* Draw the two vertical edges */
+ $Slices = array_reverse($Slices);
+ $SliceColors = array_reverse($SliceColors);
+ foreach($Slices as $SliceID => $Plots)
+ {
+ $Settings = $SliceColors[$SliceID];
+ $Settings["R"]+= 10; $Settings["G"]+= 10; $Settings["B"]+= 10; $Settings["NoBorder"] = TRUE;
+
+ if ( $Visible[$SliceID]["Start"] && isset($Plots[2])) /* Empty error handling */
+ {
+ $this->pChartObject->drawLine($Plots[2],$Plots[3],$Plots[2],$Plots[3]- $SliceHeight,array("R"=>$Settings["R"],"G"=>$Settings["G"],"B"=>$Settings["B"]));
+ $Border = "";
+ $Border[] = $Plots[0]; $Border[] = $Plots[1]; $Border[] = $Plots[0]; $Border[] = $Plots[1] - $SliceHeight;
+ $Border[] = $Plots[2]; $Border[] = $Plots[3] - $SliceHeight; $Border[] = $Plots[2]; $Border[] = $Plots[3];
+ $this->pChartObject->drawPolygon($Border,$Settings);
+ }
+ }
+
+ $Slices = array_reverse($Slices);
+ $SliceColors = array_reverse($SliceColors);
+ foreach($Slices as $SliceID => $Plots)
+ {
+ $Settings = $SliceColors[$SliceID];
+ $Settings["R"]+= 10; $Settings["G"]+= 10; $Settings["B"]+= 10; $Settings["NoBorder"] = TRUE;
+ if ( $Visible[$SliceID]["End"] )
+ {
+ $this->pChartObject->drawLine($Plots[count($Plots)-2],$Plots[count($Plots)-1],$Plots[count($Plots)-2],$Plots[count($Plots)-1]- $SliceHeight,array("R"=>$Settings["R"],"G"=>$Settings["G"],"B"=>$Settings["B"]));
+
+ $Border = "";
+ $Border[] = $Plots[0]; $Border[] = $Plots[1]; $Border[] = $Plots[0]; $Border[] = $Plots[1] - $SliceHeight;
+ $Border[] = $Plots[count($Plots)-2]; $Border[] = $Plots[count($Plots)-1] - $SliceHeight; $Border[] = $Plots[count($Plots)-2]; $Border[] = $Plots[count($Plots)-1];
+ $this->pChartObject->drawPolygon($Border,$Settings);
+ }
+ }
+
+ /* Draw the rounded edges */
+ foreach($Slices as $SliceID => $Plots)
+ {
+ $Settings = $SliceColors[$SliceID];
+ $Settings["R"]+= 10; $Settings["G"]+= 10; $Settings["B"]+= 10; $Settings["NoBorder"] = TRUE;
+
+ for ($j=2;$j<count($Plots)-2;$j=$j+2)
+ {
+ $Angle = $SliceAngle[$SliceID][$j/2];
+ if ( $Angle < 270 && $Angle > 90 )
+ {
+ $Border = "";
+ $Border[] = $Plots[$j]; $Border[] = $Plots[$j+1];
+ $Border[] = $Plots[$j+2]; $Border[] = $Plots[$j+3];
+ $Border[] = $Plots[$j+2]; $Border[] = $Plots[$j+3] - $SliceHeight;
+ $Border[] = $Plots[$j]; $Border[] = $Plots[$j+1] - $SliceHeight;
+ $this->pChartObject->drawPolygon($Border,$Settings);
+ }
+ }
+
+ if ( $SecondPass )
+ {
+ $Settings = $SliceColors[$SliceID];
+ if ( $Border )
+ { $Settings["R"]+= 30; $Settings["G"]+= 30; $Settings["B"]+= 30; }
+
+ if ( isset($SliceAngle[$SliceID][1]) ) /* Empty error handling */
+ {
+ $Angle = $SliceAngle[$SliceID][1];
+ if ( $Angle < 270 && $Angle > 90 )
+ {
+ $Xc = cos(($Angle-90)*PI/180) * $Radius + $X;
+ $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y;
+ $this->pChartObject->drawLine($Xc,$Yc,$Xc,$Yc-$SliceHeight,$Settings);
+ }
+ }
+
+ $Angle = $SliceAngle[$SliceID][count($SliceAngle[$SliceID])-1];
+ if ( $Angle < 270 && $Angle > 90 )
+ {
+ $Xc = cos(($Angle-90)*PI/180) * $Radius + $X;
+ $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y;
+ $this->pChartObject->drawLine($Xc,$Yc,$Xc,$Yc-$SliceHeight,$Settings);
+ }
+
+ if ( isset($SliceAngle[$SliceID][1]) && $SliceAngle[$SliceID][1] > 270 && $SliceAngle[$SliceID][count($SliceAngle[$SliceID])-1] < 270 )
+ {
+ $Xc = cos((270-90)*PI/180) * $Radius + $X;
+ $Yc = sin((270-90)*PI/180) * $Radius*$SkewFactor + $Y;
+ $this->pChartObject->drawLine($Xc,$Yc,$Xc,$Yc-$SliceHeight,$Settings);
+ }
+
+ if ( isset($SliceAngle[$SliceID][1]) && $SliceAngle[$SliceID][1] > 90 && $SliceAngle[$SliceID][count($SliceAngle[$SliceID])-1] < 90 )
+ {
+ $Xc = cos((0)*PI/180) * $Radius + $X;
+ $Yc = sin((0)*PI/180) * $Radius*$SkewFactor + $Y;
+ $this->pChartObject->drawLine($Xc,$Yc,$Xc,$Yc-$SliceHeight,$Settings);
+ }
+
+ }
+ }
+
+ /* Draw the top splice */
+ foreach($Slices as $SliceID => $Plots)
+ {
+ $Settings = $SliceColors[$SliceID];
+ $Settings["R"]+= 20; $Settings["G"]+= 20; $Settings["B"]+= 20;
+
+ $Top = "";
+ for($j=0;$j<count($Plots);$j=$j+2) { $Top[] = $Plots[$j]; $Top[] = $Plots[$j+1]- $SliceHeight; }
+ $this->pChartObject->drawPolygon($Top,$Settings);
+
+ if ( $RecordImageMap && !$Shadow ) { $this->pChartObject->addToImageMap("POLY",$this->arraySerialize($Top),$this->pChartObject->toHTMLColor($Settings["R"],$Settings["G"],$Settings["B"]),$Data["Series"][$Data["Abscissa"]]["Data"][count($Slices)-$SliceID-1],$Values[$SliceID]); }
+ }
+
+
+ /* Second pass to smooth the angles */
+ if ( $SecondPass )
+ {
+ $Step = 360 / (2 * PI * $Radius);
+ $Offset = 360; $ID = count($Values)-1;
+ foreach($Values as $Key => $Value)
+ {
+ $FirstPoint = TRUE;
+ if ( $Shadow )
+ $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa);
+ else
+ {
+ if ( $Border )
+ { $Settings = array("R"=>$Palette[$ID]["R"]+30,"G"=>$Palette[$ID]["G"]+30,"B"=>$Palette[$ID]["B"]+30,"Alpha"=>$Palette[$ID]["Alpha"]); }
+ else
+ $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);
+ }
+
+ $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; }
+
+ if ($DataGapAngle == 0)
+ { $X0 = $X; $Y0 = $Y- $SliceHeight; }
+ else
+ {
+ $Angle = ($EndAngle - $Offset)/2 + $Offset;
+ $X0 = cos(($Angle-90)*PI/180) * $DataGapRadius + $X;
+ $Y0 = sin(($Angle-90)*PI/180) * $DataGapRadius*$SkewFactor + $Y - $SliceHeight;
+ }
+ $Plots[] = $X0; $Plots[] = $Y0;
+
+ for($i=$Offset;$i>=$EndAngle;$i=$i-$Step)
+ {
+ $Xc = cos(($i-90)*PI/180) * $Radius + $X;
+ $Yc = sin(($i-90)*PI/180) * $Radius*$SkewFactor + $Y - $SliceHeight;
+
+ if ( $FirstPoint ) { $this->pChartObject->drawLine($Xc,$Yc,$X0,$Y0,$Settings); } { $FirstPoint = FALSE; }
+
+ $this->pChartObject->drawAntialiasPixel($Xc,$Yc,$Settings);
+ if ($i < 270 && $i > 90 ) { $this->pChartObject->drawAntialiasPixel($Xc,$Yc+$SliceHeight,$Settings); }
+ }
+ $this->pChartObject->drawLine($Xc,$Yc,$X0,$Y0,$Settings);
+
+ $Offset = $i - $DataGapAngle; $ID--;
+ }
+ }
+
+ if ( $WriteValues != NULL )
+ {
+ $Step = 360 / (2 * PI * $Radius);
+ $Offset = 360; $ID = count($Values)-1;
+ $Settings = array("Align"=>TEXT_ALIGN_MIDDLEMIDDLE,"R"=>$ValueR,"G"=>$ValueG,"B"=>$ValueB,"Alpha"=>$ValueAlpha);
+ foreach($Values as $Key => $Value)
+ {
+ $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; }
+
+ $Angle = ($EndAngle - $Offset)/2 + $Offset;
+
+ if ( $ValuePosition == PIE_VALUE_OUTSIDE )
+ {
+ $Xc = cos(($Angle-90)*PI/180) * ($Radius+$ValuePadding) + $X;
+ $Yc = sin(($Angle-90)*PI/180) * (($Radius*$SkewFactor)+$ValuePadding) + $Y - $SliceHeight;
+ }
+ else
+ {
+ $Xc = cos(($Angle-90)*PI/180) * ($Radius)/2 + $X;
+ $Yc = sin(($Angle-90)*PI/180) * ($Radius*$SkewFactor)/2 + $Y - $SliceHeight;
+ }
+
+ if ( $WriteValues == PIE_VALUE_PERCENTAGE )
+ $Display = round(( 100 / $SerieSum ) * $Value,$Precision)."%";
+ elseif ( $WriteValues == PIE_VALUE_NATURAL )
+ $Display = $Value.$ValueSuffix;
+
+ $this->pChartObject->drawText($Xc,$Yc,$Display,$Settings);
+
+ $Offset = $EndAngle - $DataGapAngle; $ID--;
+ }
+ }
+
+ if ( $DrawLabels )
+ {
+ $Step = 360 / (2 * PI * $Radius);
+ $Offset = 360; $ID = count($Values)-1;
+ foreach($Values as $Key => $Value)
+ {
+ if ( $LabelColor == PIE_LABEL_COLOR_AUTO )
+ { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);}
+ else
+ { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); }
+
+ $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; }
+
+ $Angle = ($EndAngle - $Offset)/2 + $Offset;
+ $Xc = cos(($Angle-90)*PI/180) * $Radius + $X;
+ $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y - $SliceHeight;
+
+ if ( isset($Data["Series"][$Data["Abscissa"]]["Data"][$ID]) )
+ {
+ $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$ID];
+
+ if ( $LabelStacked )
+ $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,TRUE,$X,$Y,$Radius,TRUE);
+ else
+ $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,FALSE);
+ }
+
+ $Offset = $EndAngle - $DataGapAngle; $ID--;
+ }
+ }
+
+ if ( $DrawLabels && $LabelStacked ) { $this->writeShiftedLabels(); }
+
+ $this->pChartObject->Shadow = $RestoreShadow;
+
+ return(PIE_RENDERED);
+ }
+
+ /* Draw the legend of pie chart */
+ function drawPieLegend($X,$Y,$Format="")
+ {
+ $FontName = isset($Format["FontName"]) ? $Format["FontName"] : $this->pChartObject->FontName;
+ $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->pChartObject->FontSize;
+ $FontR = isset($Format["FontR"]) ? $Format["FontR"] : $this->pChartObject->FontColorR;
+ $FontG = isset($Format["FontG"]) ? $Format["FontG"] : $this->pChartObject->FontColorG;
+ $FontB = isset($Format["FontB"]) ? $Format["FontB"] : $this->pChartObject->FontColorB;
+ $BoxSize = isset($Format["BoxSize"]) ? $Format["BoxSize"] : 5;
+ $Margin = isset($Format["Margin"]) ? $Format["Margin"] : 5;
+ $R = isset($Format["R"]) ? $Format["R"] : 200;
+ $G = isset($Format["G"]) ? $Format["G"] : 200;
+ $B = isset($Format["B"]) ? $Format["B"] : 200;
+ $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;
+ $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 255;
+ $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 255;
+ $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 255;
+ $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL;
+ $Style = isset($Format["Style"]) ? $Format["Style"] : LEGEND_ROUND;
+ $Mode = isset($Format["Mode"]) ? $Format["Mode"] : LEGEND_VERTICAL;
+
+ if ( $Surrounding != NULL ) { $BorderR = $R + $Surrounding; $BorderG = $G + $Surrounding; $BorderB = $B + $Surrounding; }
+
+ $YStep = max($this->pChartObject->FontSize,$BoxSize) + 5;
+ $XStep = $BoxSize + 5;
+
+ /* Data Processing */
+ $Data = $this->pDataObject->getData();
+ $Palette = $this->pDataObject->getPalette();
+
+ /* Do we have an abscissa serie defined? */
+ if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); }
+
+ $Boundaries = ""; $Boundaries["L"] = $X; $Boundaries["T"] = $Y; $Boundaries["R"] = 0; $Boundaries["B"] = 0; $vY = $Y; $vX = $X;
+ foreach($Data["Series"][$Data["Abscissa"]]["Data"] as $Key => $Value)
+ {
+ $BoxArray = $this->pChartObject->getTextBox($vX+$BoxSize+4,$vY+$BoxSize/2,$FontName,$FontSize,0,$Value);
+
+ if ( $Mode == LEGEND_VERTICAL )
+ {
+ if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$BoxSize/2 ) { $Boundaries["T"] = $BoxArray[2]["Y"]+$BoxSize/2; }
+ if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { $Boundaries["R"] = $BoxArray[1]["X"]+2; }
+ if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$BoxSize/2 ) { $Boundaries["B"] = $BoxArray[1]["Y"]+2+$BoxSize/2; }
+ $vY=$vY+$YStep;
+ }
+ elseif ( $Mode == LEGEND_HORIZONTAL )
+ {
+ if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$BoxSize/2 ) { $Boundaries["T"] = $BoxArray[2]["Y"]+$BoxSize/2; }
+ if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { $Boundaries["R"] = $BoxArray[1]["X"]+2; }
+ if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$BoxSize/2 ) { $Boundaries["B"] = $BoxArray[1]["Y"]+2+$BoxSize/2; }
+ $vX=$Boundaries["R"]+$XStep;
+ }
+ }
+ $vY=$vY-$YStep; $vX=$vX-$XStep;
+
+ $TopOffset = $Y - $Boundaries["T"];
+ if ( $Boundaries["B"]-($vY+$BoxSize) < $TopOffset ) { $Boundaries["B"] = $vY+$BoxSize+$TopOffset; }
+
+ if ( $Style == LEGEND_ROUND )
+ $this->pChartObject->drawRoundedFilledRectangle($Boundaries["L"]-$Margin,$Boundaries["T"]-$Margin,$Boundaries["R"]+$Margin,$Boundaries["B"]+$Margin,$Margin,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"BorderR"=>$BorderR,"BorderG"=>$BorderG,"BorderB"=>$BorderB));
+ elseif ( $Style == LEGEND_BOX )
+ $this->pChartObject->drawFilledRectangle($Boundaries["L"]-$Margin,$Boundaries["T"]-$Margin,$Boundaries["R"]+$Margin,$Boundaries["B"]+$Margin,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"BorderR"=>$BorderR,"BorderG"=>$BorderG,"BorderB"=>$BorderB));
+
+ $RestoreShadow = $this->pChartObject->Shadow; $this->pChartObject->Shadow = FALSE;
+ foreach($Data["Series"][$Data["Abscissa"]]["Data"] as $Key => $Value)
+ {
+ $R = $Palette[$Key]["R"]; $G = $Palette[$Key]["G"]; $B = $Palette[$Key]["B"];
+
+ $this->pChartObject->drawFilledRectangle($X+1,$Y+1,$X+$BoxSize+1,$Y+$BoxSize+1,array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>20));
+ $this->pChartObject->drawFilledRectangle($X,$Y,$X+$BoxSize,$Y+$BoxSize,array("R"=>$R,"G"=>$G,"B"=>$B,"Surrounding"=>20));
+ if ( $Mode == LEGEND_VERTICAL )
+ {
+ $this->pChartObject->drawText($X+$BoxSize+4,$Y+$BoxSize/2,$Value,array("R"=>$FontR,"G"=>$FontG,"B"=>$FontB,"Align"=>TEXT_ALIGN_MIDDLELEFT,"FontName"=>$FontName,"FontSize"=>$FontSize));
+ $Y=$Y+$YStep;
+ }
+ elseif ( $Mode == LEGEND_HORIZONTAL )
+ {
+ $BoxArray = $this->pChartObject->drawText($X+$BoxSize+4,$Y+$BoxSize/2,$Value,array("R"=>$FontR,"G"=>$FontG,"B"=>$FontB,"Align"=>TEXT_ALIGN_MIDDLELEFT,"FontName"=>$FontName,"FontSize"=>$FontSize));
+ $X=$BoxArray[1]["X"]+2+$XStep;
+ }
+ }
+
+ $this->Shadow = $RestoreShadow;
+ }
+
+ /* Set the color of the specified slice */
+ function setSliceColor($SliceID,$Format="")
+ {
+ $R = isset($Format["R"]) ? $Format["R"] : 0;
+ $G = isset($Format["G"]) ? $Format["G"] : 0;
+ $B = isset($Format["B"]) ? $Format["B"] : 0;
+ $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100;
+
+ $this->pDataObject->Palette[$SliceID]["R"] = $R;
+ $this->pDataObject->Palette[$SliceID]["G"] = $G;
+ $this->pDataObject->Palette[$SliceID]["B"] = $B;
+ $this->pDataObject->Palette[$SliceID]["Alpha"] = $Alpha;
+ }
+
+ /* Internally used compute the label positions */
+ function writePieLabel($X,$Y,$Label,$Angle,$Settings,$Stacked,$Xc=0,$Yc=0,$Radius=0,$Reversed=FALSE)
+ {
+ $LabelOffset = 30;
+ $FontName = $this->pChartObject->FontName;
+ $FontSize = $this->pChartObject->FontSize;
+
+ if ( !$Stacked )
+ {
+ $Settings["Angle"] = 360-$Angle;
+ $Settings["Length"] = 25;
+ $Settings["Size"] = 8;
+
+ $this->pChartObject->drawArrowLabel($X,$Y," ".$Label." ",$Settings);
+ }
+ else
+ {
+ $X2 = cos(deg2rad($Angle-90))*20+$X;
+ $Y2 = sin(deg2rad($Angle-90))*20+$Y;
+
+ $TxtPos = $this->pChartObject->getTextBox($X,$Y,$FontName,$FontSize,0,$Label);
+ $Height = $TxtPos[0]["Y"] - $TxtPos[2]["Y"];
+ $YTop = $Y2 - $Height/2 - 2;
+ $YBottom = $Y2 + $Height/2 + 2;
+
+ if ( $this->LabelPos != "" )
+ {
+ $Done = FALSE;
+ foreach($this->LabelPos as $Key => $Settings)
+ {
+ if ( !$Done )
+ {
+ if ( $Angle <= 90 && (($YTop >= $Settings["YTop"] && $YTop <= $Settings["YBottom"]) || ($YBottom >= $Settings["YTop"] && $YBottom <= $Settings["YBottom"])))
+ { $this->shift(0,180,-($Height+2),$Reversed); $Done = TRUE; }
+ if ( $Angle > 90 && $Angle <= 180 && (($YTop >= $Settings["YTop"] && $YTop <= $Settings["YBottom"]) || ($YBottom >= $Settings["YTop"] && $YBottom <= $Settings["YBottom"])))
+ { $this->shift(0,180,-($Height+2),$Reversed); $Done = TRUE; }
+ if ( $Angle > 180 && $Angle <= 270 && (($YTop >= $Settings["YTop"] && $YTop <= $Settings["YBottom"]) || ($YBottom >= $Settings["YTop"] && $YBottom <= $Settings["YBottom"])))
+ { $this->shift(180,360,($Height+2),$Reversed); $Done = TRUE; }
+ if ( $Angle > 270 && $Angle <= 360 && (($YTop >= $Settings["YTop"] && $YTop <= $Settings["YBottom"]) || ($YBottom >= $Settings["YTop"] && $YBottom <= $Settings["YBottom"])))
+ { $this->shift(180,360,($Height+2),$Reversed); $Done = TRUE; }
+ }
+ }
+ }
+
+ $LabelSettings = array("YTop"=>$YTop,"YBottom"=>$YBottom,"Label"=>$Label,"Angle"=>$Angle,"X1"=>$X,"Y1"=>$Y,"X2"=>$X2,"Y2"=>$Y2);
+ if ( $Angle <= 180 ) { $LabelSettings["X3"] = $Xc+$Radius+$LabelOffset; }
+ if ( $Angle > 180 ) { $LabelSettings["X3"] = $Xc-$Radius-$LabelOffset; }
+ $this->LabelPos[] = $LabelSettings;
+ }
+ }
+
+ /* Internally used to shift label positions */
+ function shift($StartAngle,$EndAngle,$Offset,$Reversed)
+ {
+ if ( $Reversed ) { $Offset = -$Offset; }
+ foreach($this->LabelPos as $Key => $Settings)
+ {
+ if ( $Settings["Angle"] > $StartAngle && $Settings["Angle"] <= $EndAngle ) { $this->LabelPos[$Key]["YTop"] = $Settings["YTop"] + $Offset; $this->LabelPos[$Key]["YBottom"] = $Settings["YBottom"] + $Offset; $this->LabelPos[$Key]["Y2"] = $Settings["Y2"] + $Offset; }
+ }
+ }
+
+ /* Internally used to write the re-computed labels */
+ function writeShiftedLabels()
+ {
+ if ( $this->LabelPos == "" ) { return(0); }
+ foreach($this->LabelPos as $Key => $Settings)
+ {
+ $X1 = $Settings["X1"]; $Y1 = $Settings["Y1"];
+ $X2 = $Settings["X2"]; $Y2 = $Settings["Y2"];
+ $X3 = $Settings["X3"];
+ $Angle = $Settings["Angle"];
+ $Label = $Settings["Label"];
+
+ $this->pChartObject->drawArrow($X2,$Y2,$X1,$Y1,array("Size"=>8));
+ if ( $Angle <= 180 )
+ {
+ $this->pChartObject->drawLine($X2,$Y2,$X3,$Y2);
+ $this->pChartObject->drawText($X3+2,$Y2,$Label,array("Align"=>TEXT_ALIGN_MIDDLELEFT));
+ }
+ else
+ {
+ $this->pChartObject->drawLine($X2,$Y2,$X3,$Y2);
+ $this->pChartObject->drawText($X3-2,$Y2,$Label,array("Align"=>TEXT_ALIGN_MIDDLERIGHT));
+ }
+ }
+ }
+
+ /* Draw a ring chart */
+ function draw2DRing($X,$Y,$Format="")
+ {
+ $OuterRadius = isset($Format["Radius"]) ? $Format["Radius"] : 60;
+ $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0;
+ $InnerRadius = isset($Format["Radius"]) ? $Format["Radius"] : 30;
+ $Border = isset($Format["Border"]) ? $Format["Border"] : FALSE;
+ $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 255;
+ $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 255;
+ $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 255;
+ $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : 100;
+ $Shadow = isset($Format["Shadow"]) ? $Format["Shadow"] : FALSE;
+ $DrawLabels = isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : FALSE;
+ $LabelStacked = isset($Format["LabelStacked"]) ? $Format["LabelStacked"] : FALSE;
+ $LabelColor = isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL;
+ $LabelR = isset($Format["LabelR"]) ? $Format["LabelR"] : 0;
+ $LabelG = isset($Format["LabelG"]) ? $Format["LabelG"] : 0;
+ $LabelB = isset($Format["LabelB"]) ? $Format["LabelB"] : 0;
+ $LabelAlpha = isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100;
+ $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : NULL; //PIE_VALUE_PERCENTAGE
+ $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : 5;
+ $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_OUTSIDE;
+ $ValueSuffix = isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : "";
+ $ValueR = isset($Format["ValueR"]) ? $Format["ValueR"] : 255;
+ $ValueG = isset($Format["ValueG"]) ? $Format["ValueG"] : 255;
+ $ValueB = isset($Format["ValueB"]) ? $Format["ValueB"] : 255;
+ $ValueAlpha = isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100;
+ $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE;
+
+ /* Data Processing */
+ $Data = $this->pDataObject->getData();
+ $Palette = $this->pDataObject->getPalette();
+
+ /* Do we have an abscissa serie defined? */
+ if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); }
+
+ /* Try to find the data serie */
+ $DataSerie = "";
+ foreach ($Data["Series"] as $SerieName => $SerieData)
+ { if ( $SerieName != $Data["Abscissa"]) { $DataSerie = $SerieName; } }
+
+ /* Do we have data to compute? */
+ if ( $DataSerie == "" ) { return(PIE_NO_DATASERIE); }
+
+ /* Remove unused data */
+ list($Data,$Palette) = $this->clean0Values($Data,$Palette,$DataSerie,$Data["Abscissa"]);
+
+ /* Compute the pie sum */
+ $SerieSum = $this->pDataObject->getSum($DataSerie);
+
+ /* Do we have data to draw? */
+ if ( $SerieSum == 0 ) { return(PIE_SUMISNULL); }
+
+ /* Dump the real number of data to draw */
+ $Values = "";
+ foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value)
+ { if ($Value != 0) { $Values[] = $Value; } }
+
+ /* Compute the wasted angular space between series */
+ if (count($Values)==1) { $WastedAngular = 0; } else { $WastedAngular = 0; } // count($Values)
+
+ /* Compute the scale */
+ $ScaleFactor = (360 - $WastedAngular) / $SerieSum;
+
+ $RestoreShadow = $this->pChartObject->Shadow;
+ if ( $this->pChartObject->Shadow )
+ {
+ $this->pChartObject->Shadow = FALSE;
+
+ $ShadowFormat = $Format; $ShadowFormat["Shadow"] = TRUE;
+ $this->draw2DRing($X+$this->pChartObject->ShadowX,$Y+$this->pChartObject->ShadowY,$ShadowFormat);
+ }
+
+ /* Draw the polygon pie elements */
+ $Step = 360 / (2 * PI * $OuterRadius);
+ $Offset = 0; $ID = 0;
+ foreach($Values as $Key => $Value)
+ {
+ if ( $Shadow )
+ {
+ $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa);
+ $BorderColor = $Settings;
+ }
+ else
+ {
+ if ( !isset($Palette[$ID]["R"]) ) { $Color = $this->pChartObject->getRandomColor(); $Palette[$ID] = $Color; $this->pDataObject->savePalette($ID,$Color); }
+ $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);
+
+ if ( $Border )
+ $BorderColor = array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha);
+ else
+ $BorderColor = $Settings;
+ }
+
+ $Plots = ""; $Boundaries = ""; $AAPixels = "";
+ $EndAngle = $Offset+($Value*$ScaleFactor); if ( $EndAngle > 360 ) { $EndAngle = 360; }
+ for($i=$Offset;$i<=$EndAngle;$i=$i+$Step)
+ {
+ $Xc = cos(($i-90)*PI/180) * $OuterRadius + $X;
+ $Yc = sin(($i-90)*PI/180) * $OuterRadius + $Y;
+
+ if ( !isset($Boundaries[0]["X1"]) ) { $Boundaries[0]["X1"] = $Xc; $Boundaries[0]["Y1"] = $Yc; }
+ $AAPixels[] = array($Xc,$Yc);
+
+ if ( $i<90 ) { $Yc++; }
+ if ( $i>180 && $i<270 ) { $Xc++; }
+ if ( $i>=270 ) { $Xc++; $Yc++; }
+
+ $Plots[] = $Xc; $Plots[] = $Yc;
+ }
+ $Boundaries[1]["X1"] = $Xc; $Boundaries[1]["Y1"] = $Yc;
+ $Lasti = $EndAngle;
+
+ for($i=$EndAngle;$i>=$Offset;$i=$i-$Step)
+ {
+ $Xc = cos(($i-90)*PI/180) * ($InnerRadius-1) + $X;
+ $Yc = sin(($i-90)*PI/180) * ($InnerRadius-1) + $Y;
+
+ if ( !isset($Boundaries[1]["X2"]) ) { $Boundaries[1]["X2"] = $Xc; $Boundaries[1]["Y2"] = $Yc; }
+ $AAPixels[] = array($Xc,$Yc);
+
+ $Xc = cos(($i-90)*PI/180) * $InnerRadius + $X;
+ $Yc = sin(($i-90)*PI/180) * $InnerRadius + $Y;
+
+ if ( $i<90 ) { $Yc++; }
+ if ( $i>180 && $i<270 ) { $Xc++; }
+ if ( $i>=270 ) { $Xc++; $Yc++; }
+
+ $Plots[] = $Xc; $Plots[] = $Yc;
+ }
+ $Boundaries[0]["X2"] = $Xc; $Boundaries[0]["Y2"] = $Yc;
+
+ /* Draw the polygon */
+ $this->pChartObject->drawPolygon($Plots,$Settings);
+ if ( $RecordImageMap && !$Shadow ) { $this->pChartObject->addToImageMap("POLY",$this->arraySerialize($Plots),$this->pChartObject->toHTMLColor($Palette[$ID]["R"],$Palette[$ID]["G"],$Palette[$ID]["B"]),$Data["Series"][$Data["Abscissa"]]["Data"][$Key],$Value); }
+
+ /* Smooth the edges using AA */
+ foreach($AAPixels as $iKey => $Pos ) { $this->pChartObject->drawAntialiasPixel($Pos[0],$Pos[1],$BorderColor); }
+ $this->pChartObject->drawLine($Boundaries[0]["X1"],$Boundaries[0]["Y1"],$Boundaries[0]["X2"],$Boundaries[0]["Y2"],$BorderColor);
+ $this->pChartObject->drawLine($Boundaries[1]["X1"],$Boundaries[1]["Y1"],$Boundaries[1]["X2"],$Boundaries[1]["Y2"],$BorderColor);
+
+ if ( $DrawLabels && !$Shadow )
+ {
+ if ( $LabelColor == PIE_LABEL_COLOR_AUTO )
+ { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);}
+ else
+ { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); }
+
+ $Angle = ($EndAngle - $Offset)/2 + $Offset;
+ $Xc = cos(($Angle-90)*PI/180) * $OuterRadius + $X;
+ $Yc = sin(($Angle-90)*PI/180) * $OuterRadius + $Y;
+
+ $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key];
+
+ if ( $LabelStacked )
+ $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,TRUE,$X,$Y,$OuterRadius);
+ else
+ $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,FALSE);
+ }
+
+ $Offset = $Lasti; $ID++;
+ }
+
+ if ( $DrawLabels && $LabelStacked ) { $this->writeShiftedLabels(); }
+
+ if ( $WriteValues && !$Shadow )
+ {
+ $Step = 360 / (2 * PI * $OuterRadius);
+ $Offset = 0;
+ foreach($Values as $Key => $Value)
+ {
+ $EndAngle = $Offset+($Value*$ScaleFactor);
+ if ( $EndAngle > 360 ) { $EndAngle = 360; }
+
+ $Angle = $Offset+($Value*$ScaleFactor)/2;
+ if ( $ValuePosition == PIE_VALUE_OUTSIDE )
+ {
+ $Xc = cos(($Angle-90)*PI/180) * ($OuterRadius+$ValuePadding) + $X;
+ $Yc = sin(($Angle-90)*PI/180) * ($OuterRadius+$ValuePadding) + $Y;
+ if ( $Angle >=0 && $Angle <= 90 ) { $Align = TEXT_ALIGN_BOTTOMLEFT; }
+ if ( $Angle > 90 && $Angle <= 180 ) { $Align = TEXT_ALIGN_TOPLEFT; }
+ if ( $Angle > 180 && $Angle <= 270 ) { $Align = TEXT_ALIGN_TOPRIGHT; }
+ if ( $Angle > 270 ) { $Align = TEXT_ALIGN_BOTTOMRIGHT; }
+ }
+ else
+ {
+ $Xc = cos(($Angle-90)*PI/180) * (($OuterRadius-$InnerRadius)/2+$InnerRadius) + $X;
+ $Yc = sin(($Angle-90)*PI/180) * (($OuterRadius-$InnerRadius)/2+$InnerRadius) + $Y;
+ $Align = TEXT_ALIGN_MIDDLEMIDDLE;
+ }
+
+ if ( $WriteValues == PIE_VALUE_PERCENTAGE )
+ $Display = round(( 100 / $SerieSum ) * $Value,$Precision)."%";
+ elseif ( $WriteValues == PIE_VALUE_NATURAL )
+ $Display = $Value.$ValueSuffix;
+ else
+ $Label = "";
+
+ $this->pChartObject->drawText($Xc,$Yc,$Display,array("Align"=>$Align,"R"=>$ValueR,"G"=>$ValueG,"B"=>$ValueB));
+ $Offset = $EndAngle;
+ }
+ }
+
+ $this->pChartObject->Shadow = $RestoreShadow;
+
+ return(PIE_RENDERED);
+ }
+
+ /* Draw a 3D ring chart */
+ function draw3DRing($X,$Y,$Format="")
+ {
+ $OuterRadius = isset($Format["OuterRadius"]) ? $Format["OuterRadius"] : 100;
+ $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0;
+ $InnerRadius = isset($Format["InnerRadius"]) ? $Format["InnerRadius"] : 30;
+ $SkewFactor = isset($Format["SkewFactor"]) ? $Format["SkewFactor"] : .6;
+ $SliceHeight = isset($Format["SliceHeight"]) ? $Format["SliceHeight"] : 10;
+ $DataGapAngle = isset($Format["DataGapAngle"]) ? $Format["DataGapAngle"] : 10;
+ $DataGapRadius = isset($Format["DataGapRadius"]) ? $Format["DataGapRadius"] : 10;
+ $Border = isset($Format["Border"]) ? $Format["Border"] : FALSE;
+ $Shadow = isset($Format["Shadow"]) ? $Format["Shadow"] : FALSE;
+ $DrawLabels = isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : FALSE;
+ $LabelStacked = isset($Format["LabelStacked"]) ? $Format["LabelStacked"] : FALSE;
+ $LabelColor = isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL;
+ $LabelR = isset($Format["LabelR"]) ? $Format["LabelR"] : 0;
+ $LabelG = isset($Format["LabelG"]) ? $Format["LabelG"] : 0;
+ $LabelB = isset($Format["LabelB"]) ? $Format["LabelB"] : 0;
+ $LabelAlpha = isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100;
+ $Cf = isset($Format["Cf"]) ? $Format["Cf"] : 20;
+ $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : PIE_VALUE_NATURAL;
+ $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : $SliceHeight + 15;
+ $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_OUTSIDE;
+ $ValueSuffix = isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : "";
+ $ValueR = isset($Format["ValueR"]) ? $Format["ValueR"] : 255;
+ $ValueG = isset($Format["ValueG"]) ? $Format["ValueG"] : 255;
+ $ValueB = isset($Format["ValueB"]) ? $Format["ValueB"] : 255;
+ $ValueAlpha = isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100;
+ $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE;
+
+ /* Error correction for overlaying rounded corners */
+ if ( $SkewFactor < .5 ) { $SkewFactor = .5; }
+
+ /* Data Processing */
+ $Data = $this->pDataObject->getData();
+ $Palette = $this->pDataObject->getPalette();
+
+ /* Do we have an abscissa serie defined? */
+ if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); }
+
+ /* Try to find the data serie */
+ $DataSerie = "";
+ foreach ($Data["Series"] as $SerieName => $SerieData)
+ { if ( $SerieName != $Data["Abscissa"]) { $DataSerie = $SerieName; } }
+
+ /* Do we have data to compute? */
+ if ( $DataSerie == "" ) { return(PIE_NO_DATASERIE); }
+
+ /* Remove unused data */
+ list($Data,$Palette) = $this->clean0Values($Data,$Palette,$DataSerie,$Data["Abscissa"]);
+
+ /* Compute the pie sum */
+ $SerieSum = $this->pDataObject->getSum($DataSerie);
+
+ /* Do we have data to draw? */
+ if ( $SerieSum == 0 ) { return(PIE_SUMISNULL); }
+
+ /* Dump the real number of data to draw */
+ $Values = "";
+ foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value)
+ { if ($Value != 0) { $Values[] = $Value; } }
+
+ /* Compute the wasted angular space between series */
+ if (count($Values)==1) { $WastedAngular = 0; } else { $WastedAngular = count($Values) * $DataGapAngle; }
+
+ /* Compute the scale */
+ $ScaleFactor = (360 - $WastedAngular) / $SerieSum;
+
+ $RestoreShadow = $this->pChartObject->Shadow;
+ if ( $this->pChartObject->Shadow ) { $this->pChartObject->Shadow = FALSE; }
+
+ /* Draw the polygon ring elements */
+ $Offset = 360; $ID = count($Values)-1;
+ $Values = array_reverse($Values);
+ $Slice = 0; $Slices = ""; $SliceColors = ""; $Visible = ""; $SliceAngle = "";
+ foreach($Values as $Key => $Value)
+ {
+ if ( !isset($Palette[$ID]["R"]) ) { $Color = $this->pChartObject->getRandomColor(); $Palette[$ID] = $Color; $this->pDataObject->savePalette($ID,$Color); }
+ $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);
+
+ $SliceColors[$Slice] = $Settings;
+
+ $StartAngle = $Offset;
+ $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; }
+
+ if ( $StartAngle > 180 ) { $Visible[$Slice]["Start"] = TRUE; } else { $Visible[$Slice]["Start"] = TRUE; }
+ if ( $EndAngle < 180 ) { $Visible[$Slice]["End"] = FALSE; } else { $Visible[$Slice]["End"] = TRUE; }
+
+ $Step = (360 / (2 * PI * $OuterRadius))/2;
+ $OutX1 = VOID; $OutY1 = VOID;
+ for($i=$Offset;$i>=$EndAngle;$i=$i-$Step)
+ {
+ $Xc = cos(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius-2) + $X;
+ $Yc = sin(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius-2)*$SkewFactor + $Y;
+ $Slices[$Slice]["AA"][] = array($Xc,$Yc);
+
+ $Xc = cos(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius-1) + $X;
+ $Yc = sin(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius-1)*$SkewFactor + $Y;
+ $Slices[$Slice]["AA"][] = array($Xc,$Yc);
+
+ $Xc = cos(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius) + $X;
+ $Yc = sin(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius)*$SkewFactor + $Y;
+ $this->pChartObject->drawAntialiasPixel($Xc,$Yc,$Settings);
+
+ if ( $OutX1 == VOID ) { $OutX1 = $Xc; $OutY1 = $Yc; }
+
+ if ( $i<90 ) { $Yc++; }
+ if ( $i>90 && $i<180 ) { $Xc++; }
+ if ( $i>180 && $i<270 ) { $Xc++; }
+ if ( $i>=270 ) { $Xc++; $Yc++; }
+
+ $Slices[$Slice]["BottomPoly"][] = floor($Xc); $Slices[$Slice]["BottomPoly"][] = floor($Yc);
+ $Slices[$Slice]["TopPoly"][] = floor($Xc); $Slices[$Slice]["TopPoly"][] = floor($Yc)-$SliceHeight;
+ $Slices[$Slice]["Angle"][] = $i;
+ }
+ $OutX2 = $Xc; $OutY2 = $Yc;
+
+ $Slices[$Slice]["Angle"][] = VOID;
+ $Lasti = $i;
+
+ $Step = (360 / (2 * PI * $InnerRadius))/2;
+ $InX1 = VOID; $InY1 = VOID;
+ for($i=$EndAngle;$i<=$Offset;$i=$i+$Step)
+ {
+ $Xc = cos(($i-90)*PI/180) * ($InnerRadius+$DataGapRadius-1) + $X;
+ $Yc = sin(($i-90)*PI/180) * ($InnerRadius+$DataGapRadius-1)*$SkewFactor + $Y;
+ $Slices[$Slice]["AA"][] = array($Xc,$Yc);
+
+ $Xc = cos(($i-90)*PI/180) * ($InnerRadius+$DataGapRadius) + $X;
+ $Yc = sin(($i-90)*PI/180) * ($InnerRadius+$DataGapRadius)*$SkewFactor + $Y;
+ $Slices[$Slice]["AA"][] = array($Xc,$Yc);
+
+ if ( $InX1 == VOID ) { $InX1 = $Xc; $InY1 = $Yc; }
+
+ if ( $i<90 ) { $Yc++; }
+ if ( $i>90 && $i<180 ) { $Xc++; }
+ if ( $i>180 && $i<270 ) { $Xc++; }
+ if ( $i>=270 ) { $Xc++; $Yc++; }
+
+ $Slices[$Slice]["BottomPoly"][] = floor($Xc); $Slices[$Slice]["BottomPoly"][] = floor($Yc);
+ $Slices[$Slice]["TopPoly"][] = floor($Xc); $Slices[$Slice]["TopPoly"][] = floor($Yc)-$SliceHeight;
+ $Slices[$Slice]["Angle"][] = $i;
+ }
+ $InX2 = $Xc; $InY2 = $Yc;
+
+ $Slices[$Slice]["InX1"] = $InX1; $Slices[$Slice]["InY1"] = $InY1;
+ $Slices[$Slice]["InX2"] = $InX2; $Slices[$Slice]["InY2"] = $InY2;
+ $Slices[$Slice]["OutX1"] = $OutX1; $Slices[$Slice]["OutY1"] = $OutY1;
+ $Slices[$Slice]["OutX2"] = $OutX2; $Slices[$Slice]["OutY2"] = $OutY2;
+
+ $Offset = $Lasti - $DataGapAngle; $ID--; $Slice++;
+ }
+
+ /* Draw the bottom pie splice */
+ foreach($Slices as $SliceID => $Plots)
+ {
+ $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE;
+ $this->pChartObject->drawPolygon($Plots["BottomPoly"],$Settings);
+
+ foreach($Plots["AA"] as $Key => $Pos)
+ $this->pChartObject->drawAntialiasPixel($Pos[0],$Pos[1],$Settings);
+
+ $this->pChartObject->drawLine($Plots["InX1"],$Plots["InY1"],$Plots["OutX2"],$Plots["OutY2"],$Settings);
+ $this->pChartObject->drawLine($Plots["InX2"],$Plots["InY2"],$Plots["OutX1"],$Plots["OutY1"],$Settings);
+ }
+
+ $Slices = array_reverse($Slices);
+ $SliceColors = array_reverse($SliceColors);
+
+ /* Draw the vertical edges (semi-visible) */
+ foreach($Slices as $SliceID => $Plots)
+ {
+ $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE;
+ $Settings["R"] = $Settings["R"]+$Cf; $Settings["G"] = $Settings["G"]+$Cf; $Settings["B"] = $Settings["B"]+$Cf;
+
+ $StartAngle = $Plots["Angle"][0];
+ foreach($Plots["Angle"] as $Key =>$Angle) { if ($Angle == VOID) { $EndAngle = $Plots["Angle"][$Key-1]; } }
+
+ if ( $StartAngle >= 270 || $StartAngle <= 90 )
+ $this->pChartObject->drawLine($Plots["OutX1"],$Plots["OutY1"],$Plots["OutX1"],$Plots["OutY1"]-$SliceHeight,$Settings);
+ if ( $StartAngle >= 270 || $StartAngle <= 90 )
+ $this->pChartObject->drawLine($Plots["OutX2"],$Plots["OutY2"],$Plots["OutX2"],$Plots["OutY2"]-$SliceHeight,$Settings);
+
+ $this->pChartObject->drawLine($Plots["InX1"],$Plots["InY1"],$Plots["InX1"],$Plots["InY1"]-$SliceHeight,$Settings);
+ $this->pChartObject->drawLine($Plots["InX2"],$Plots["InY2"],$Plots["InX2"],$Plots["InY2"]-$SliceHeight,$Settings);
+ }
+
+ /* Draw the inner vertical slices */
+ foreach($Slices as $SliceID => $Plots)
+ {
+ $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE;
+ $Settings["R"] = $Settings["R"]+$Cf; $Settings["G"] = $Settings["G"]+$Cf; $Settings["B"] = $Settings["B"]+$Cf;
+
+ $Outer = TRUE; $Inner = FALSE;
+ $InnerPlotsA = ""; $InnerPlotsB = "";
+ foreach($Plots["Angle"] as $ID => $Angle)
+ {
+ if ( $Angle == VOID )
+ { $Outer = FALSE; $Inner = TRUE; }
+ elseif( $Inner )
+ {
+ if (( $Angle < 90 || $Angle > 270 ) && isset($Plots["BottomPoly"][$ID*2]) )
+ {
+ $Xo = $Plots["BottomPoly"][$ID*2];
+ $Yo = $Plots["BottomPoly"][$ID*2+1];
+
+ $InnerPlotsA[] = $Xo; $InnerPlotsA[] = $Yo;
+ $InnerPlotsB[] = $Xo; $InnerPlotsB[] = $Yo-$SliceHeight;
+ }
+ }
+ }
+
+ if ( $InnerPlotsA != "" )
+ { $InnerPlots = array_merge($InnerPlotsA,$this->arrayReverse($InnerPlotsB)); $this->pChartObject->drawPolygon($InnerPlots,$Settings); }
+ }
+
+ /* Draw the splice top and left poly */
+ foreach($Slices as $SliceID => $Plots)
+ {
+ $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE;
+ $Settings["R"] = $Settings["R"]+$Cf*1.5; $Settings["G"] = $Settings["G"]+$Cf*1.5; $Settings["B"] = $Settings["B"]+$Cf*1.5;
+
+ $StartAngle = $Plots["Angle"][0];
+ foreach($Plots["Angle"] as $Key =>$Angle) { if ($Angle == VOID) { $EndAngle = $Plots["Angle"][$Key-1]; } }
+
+ if ( $StartAngle < 180 )
+ {
+ $Points = "";
+ $Points[] = $Plots["InX2"];
+ $Points[] = $Plots["InY2"];
+ $Points[] = $Plots["InX2"];
+ $Points[] = $Plots["InY2"]-$SliceHeight;
+ $Points[] = $Plots["OutX1"];
+ $Points[] = $Plots["OutY1"]-$SliceHeight;
+ $Points[] = $Plots["OutX1"];
+ $Points[] = $Plots["OutY1"];
+
+ $this->pChartObject->drawPolygon($Points,$Settings);
+ }
+
+ if ( $EndAngle > 180 )
+ {
+ $Points = "";
+ $Points[] = $Plots["InX1"];
+ $Points[] = $Plots["InY1"];
+ $Points[] = $Plots["InX1"];
+ $Points[] = $Plots["InY1"]-$SliceHeight;
+ $Points[] = $Plots["OutX2"];
+ $Points[] = $Plots["OutY2"]-$SliceHeight;
+ $Points[] = $Plots["OutX2"];
+ $Points[] = $Plots["OutY2"];
+
+ $this->pChartObject->drawPolygon($Points,$Settings);
+ }
+ }
+
+
+ /* Draw the vertical edges (visible) */
+ foreach($Slices as $SliceID => $Plots)
+ {
+ $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE;
+ $Settings["R"] = $Settings["R"]+$Cf; $Settings["G"] = $Settings["G"]+$Cf; $Settings["B"] = $Settings["B"]+$Cf;
+
+ $StartAngle = $Plots["Angle"][0];
+ foreach($Plots["Angle"] as $Key =>$Angle) { if ($Angle == VOID) { $EndAngle = $Plots["Angle"][$Key-1]; } }
+
+ if ( $StartAngle <= 270 && $StartAngle >= 90 )
+ $this->pChartObject->drawLine($Plots["OutX1"],$Plots["OutY1"],$Plots["OutX1"],$Plots["OutY1"]-$SliceHeight,$Settings);
+ if ( $EndAngle <= 270 && $EndAngle >= 90 )
+ $this->pChartObject->drawLine($Plots["OutX2"],$Plots["OutY2"],$Plots["OutX2"],$Plots["OutY2"]-$SliceHeight,$Settings);
+ }
+
+
+ /* Draw the outer vertical slices */
+ foreach($Slices as $SliceID => $Plots)
+ {
+ $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE;
+ $Settings["R"] = $Settings["R"]+$Cf; $Settings["G"] = $Settings["G"]+$Cf; $Settings["B"] = $Settings["B"]+$Cf;
+
+ $Outer = TRUE; $Inner = FALSE;
+ $OuterPlotsA = ""; $OuterPlotsB = ""; $InnerPlotsA = ""; $InnerPlotsB = "";
+ foreach($Plots["Angle"] as $ID => $Angle)
+ {
+ if ( $Angle == VOID )
+ { $Outer = FALSE; $Inner = TRUE; }
+ elseif( $Outer )
+ {
+ if ( ( $Angle > 90 && $Angle < 270 ) && isset($Plots["BottomPoly"][$ID*2]) )
+ {
+ $Xo = $Plots["BottomPoly"][$ID*2];
+ $Yo = $Plots["BottomPoly"][$ID*2+1];
+
+ $OuterPlotsA[] = $Xo; $OuterPlotsA[] = $Yo;
+ $OuterPlotsB[] = $Xo; $OuterPlotsB[] = $Yo-$SliceHeight;
+ }
+ }
+ }
+ if ( $OuterPlotsA != "" )
+ { $OuterPlots = array_merge($OuterPlotsA,$this->arrayReverse($OuterPlotsB)); $this->pChartObject->drawPolygon($OuterPlots,$Settings); }
+ }
+
+ $Slices = array_reverse($Slices);
+ $SliceColors = array_reverse($SliceColors);
+
+
+ /* Draw the top pie splice */
+ foreach($Slices as $SliceID => $Plots)
+ {
+ $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE;
+ $Settings["R"] = $Settings["R"]+$Cf*2; $Settings["G"] = $Settings["G"]+$Cf*2; $Settings["B"] = $Settings["B"]+$Cf*2;
+
+ $this->pChartObject->drawPolygon($Plots["TopPoly"],$Settings);
+
+ if ( $RecordImageMap ) { $this->pChartObject->addToImageMap("POLY",$this->arraySerialize($Plots["TopPoly"]),$this->pChartObject->toHTMLColor($Settings["R"],$Settings["G"],$Settings["B"]),$Data["Series"][$Data["Abscissa"]]["Data"][$SliceID],$Data["Series"][$DataSerie]["Data"][count($Slices)-$SliceID-1]); }
+
+ foreach($Plots["AA"] as $Key => $Pos)
+ $this->pChartObject->drawAntialiasPixel($Pos[0],$Pos[1]-$SliceHeight,$Settings);
+
+ $this->pChartObject->drawLine($Plots["InX1"],$Plots["InY1"]-$SliceHeight,$Plots["OutX2"],$Plots["OutY2"]-$SliceHeight,$Settings);
+ $this->pChartObject->drawLine($Plots["InX2"],$Plots["InY2"]-$SliceHeight,$Plots["OutX1"],$Plots["OutY1"]-$SliceHeight,$Settings);
+ }
+
+ if ( $DrawLabels )
+ {
+ $Offset = 360;
+ foreach($Values as $Key => $Value)
+ {
+ $StartAngle = $Offset;
+ $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; }
+
+ if ( $LabelColor == PIE_LABEL_COLOR_AUTO )
+ { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);}
+ else
+ { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); }
+
+ $Angle = ($EndAngle - $Offset)/2 + $Offset;
+ $Xc = cos(($Angle-90)*PI/180) * ($OuterRadius+$DataGapRadius) + $X;
+ $Yc = sin(($Angle-90)*PI/180) * ($OuterRadius+$DataGapRadius)*$SkewFactor + $Y;
+
+ if ( $WriteValues == PIE_VALUE_PERCENTAGE )
+ $Label = $Display = round(( 100 / $SerieSum ) * $Value,$Precision)."%";
+ elseif ( $WriteValues == PIE_VALUE_NATURAL )
+ $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key];
+ else
+ $Label = "";
+
+ if ( $LabelStacked )
+ $this->writePieLabel($Xc,$Yc-$SliceHeight,$Label,$Angle,$Settings,TRUE,$X,$Y,$OuterRadius);
+ else
+ $this->writePieLabel($Xc,$Yc-$SliceHeight,$Label,$Angle,$Settings,FALSE);
+
+ $Offset = $EndAngle - $DataGapAngle; $ID--; $Slice++;
+ }
+ }
+ if ( $DrawLabels && $LabelStacked ) { $this->writeShiftedLabels(); }
+
+ $this->pChartObject->Shadow = $RestoreShadow;
+
+ return(PIE_RENDERED);
+ }
+
+ /* Serialize an array */
+ function arraySerialize($Data)
+ {
+ $Result = "";
+ foreach($Data as $Key => $Value)
+ { if ($Result == "") { $Result = floor($Value); } else { $Result = $Result.",".floor($Value); } }
+
+ return($Result);
+ }
+
+ /* Reverse an array */
+ function arrayReverse($Plots)
+ {
+ $Result = "";
+
+ for($i=count($Plots)-1;$i>=0;$i=$i-2)
+ { $Result[] = $Plots[$i-1]; $Result[] = $Plots[$i]; }
+
+ return($Result);
+ }
+
+ /* Remove unused series & values */
+ function clean0Values($Data,$Palette,$DataSerie,$AbscissaSerie)
+ {
+ $NewPalette = ""; $NewData = ""; $NewAbscissa = "";
+
+ /* Remove unused series */
+ foreach($Data["Series"] as $SerieName => $SerieSettings)
+ { if ( $SerieName != $DataSerie && $SerieName != $AbscissaSerie ) { unset($Data["Series"][$SerieName]); } }
+
+ /* Remove NULL values */
+ foreach($Data["Series"][$DataSerie]["Data"] as $Key => $Value)
+ {
+ if ($Value != 0 )
+ {
+ $NewData[] = $Value;
+ $NewAbscissa[] = $Data["Series"][$AbscissaSerie]["Data"][$Key];
+ if ( isset($Palette[$Key]) ) { $NewPalette[] = $Palette[$Key]; }
+ }
+ }
+ $Data["Series"][$DataSerie]["Data"] = $NewData;
+ $Data["Series"][$AbscissaSerie]["Data"] = $NewAbscissa;
+
+ return(array($Data,$NewPalette));
+ }
+ }
?> \ No newline at end of file