diff --git a/vendor/szymach/c-pchart/.gitignore b/vendor/szymach/c-pchart/.gitignore new file mode 100644 index 0000000000..7bbb9ba6d3 --- /dev/null +++ b/vendor/szymach/c-pchart/.gitignore @@ -0,0 +1,24 @@ +# Created by http://www.gitignore.io + +### NetBeans ### +nbproject +nbproject/* +nbproject/private/ +nbproject/project.properties +nbproject/project.xml +nbproject/private/private.xml +nbproject/private/private.properties +build/ +nbbuild/ +dist/ +nbdist/ +nbactions.xml +nb-configuration.xml + +### vendor / web ### +vendor/* +web +web/* + +### Composer ### +composer.phar \ No newline at end of file diff --git a/vendor/szymach/c-pchart/.travis.yml b/vendor/szymach/c-pchart/.travis.yml new file mode 100644 index 0000000000..cbcc7d494b --- /dev/null +++ b/vendor/szymach/c-pchart/.travis.yml @@ -0,0 +1,16 @@ +language: php + +cache: + directories: + - vendor + +php: + - 5.4 + +before_script: + - composer self-update -n + - composer install -n --prefer-dist -v + +after_failure: + - cat app/logs/dev.log + - cat app/logs/test.log diff --git a/vendor/szymach/c-pchart/GPLv3.txt b/vendor/szymach/c-pchart/GPLv3.txt new file mode 100644 index 0000000000..10926e87f1 --- /dev/null +++ b/vendor/szymach/c-pchart/GPLv3.txt @@ -0,0 +1,675 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. + diff --git a/vendor/szymach/c-pchart/LICENSE b/vendor/szymach/c-pchart/LICENSE new file mode 100644 index 0000000000..a623cb7414 --- /dev/null +++ b/vendor/szymach/c-pchart/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 szymach + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/vendor/szymach/c-pchart/README.md b/vendor/szymach/c-pchart/README.md new file mode 100644 index 0000000000..9c0021e320 --- /dev/null +++ b/vendor/szymach/c-pchart/README.md @@ -0,0 +1,121 @@ +What is CpChart? +=============== + +A project bringing Composer support and some basic PHP 5 standards to pChart 2.0 library. +The aim is to allow pChart integration into modern frameworks like Symfony2. + +What was done: + +- Made a full port of the library's functionality. + +- Defined and added namespaces to all classes. + +- Replaced all 'exit()' / 'die()' commands with 'throw' statements to allow a degree of error control. + +- Reorganized files a bit and refactored code for better readability. Also, basic annotations were added +to functions. + +- Added a factory service for loading the classes. + +- Moved all constants to a single file 'src/Resources/data/constants.php'. This file is *required* +for the library to function. It is now loaded via Composer. + +Installation: +================ + +[GitHub](https://github.com/szymach/c-pchart) + +[Packagist](https://packagist.org/packages/szymach/c-pchart) + +For composer installation, add: + +>"require": { + +> "szymach/c-pchart": "1.*" + +> }, + +to your composer.json file and update your dependencies. After that, all +classes are available under "CpChart\Classes" namespace or "CpChart\Services" +for the factory. + +Usage: +============== + +The main difference is that you can either load the class via the 'use' statement +or use the provided factory. An example below. + +```php +require __DIR__.'/../vendor/autoload.php'; + +use CpChart\Services\pChartFactory; + +try { + // create a factory class - it will load necessary files automatically, + // otherwise you will need to add them on your own + $factory = new pChartFactory(); + + // create and populate the pData class + $myData = $factory->newData(array(VOID, 3, 4, 3, 5), "Serie1"); + + // create the image and set the data + $myPicture = $factory->newImage(700, 230, $myData); + $myPicture->setGraphArea(60, 40, 670, 190); + $myPicture->setFontProperties( + array( + "FontName" => "Forgotte.ttf", + "FontSize" => 11 + ) + ); + + // creating a pie chart - notice that you specify the type of chart, not class name. + // not all charts need to be created through this method (ex. the bar chart), + // some are created via the pImage class (check the documentation before drawing). + $pieChart = $factory->newChart("pie", $myPicture, $myData); + + // do the drawing + $myPicture->drawScale(); + $myPicture->drawSplineChart(); + $myPicture->Stroke(); + +} catch (\Exception $ex) { + echo 'There was an error: '.$ex->getMessage(); +} +``` + +Basically, it should work as defined in the pChart 2.0 documentation with added +support for try/catch functionality. The factory class has methods to load all types of +classes present in the pChart library. + +IMPORTANT! If you want to use any of the fonts or palletes files, provide only +the name of the actual file, do not add the 'fonts' or 'palettes' folder to the +string given into the function. If you want to load them from a different directory +than the default, you need to add the full path to the file (ex. __DIR__.'/folder/to/my/palletes). + +Changelog +========= +1.0 Stable version with basic functionality. + +1.1 Added factory service. + +1.1.1 Changed chart loading via factory a bit (see class annotations). + +1.1.2 Updated service class with Exception handling regarding missing / wrong class name. + +1.1.3 The file with classes' constants is now loaded via Composer (thanks to ThaDafinser). + +References +========== +[The original pChart website](http://www.pchart.net/) + +[Composer](https://getcomposer.org/) + +PHP Framework Interoperability Group at GitHub on PHP coding standards: + +[PSR-0](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md) + +[PSR-1](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md) + +[PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) + +[PSR-4](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md) diff --git a/vendor/szymach/c-pchart/app/cache/cache.db b/vendor/szymach/c-pchart/app/cache/cache.db new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/szymach/c-pchart/app/cache/index.db b/vendor/szymach/c-pchart/app/cache/index.db new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/szymach/c-pchart/composer.json b/vendor/szymach/c-pchart/composer.json new file mode 100644 index 0000000000..adf6dea8d9 --- /dev/null +++ b/vendor/szymach/c-pchart/composer.json @@ -0,0 +1,17 @@ +{ + "name": "szymach/c-pchart", + "license": "MIT", + "type": "project", + "description": "Port of \"pChart\" library into PHP 5.3.", + "keywords": ["pchart", "pChart","composer","statistics","charts", "c-pChart", "c-pchart"], + "homepage": "https://github.com/szymach/c-pchart", + "autoload": { + "psr-4": { "CpChart\\": "src/" }, + "files": ["src/Resources/data/constants.php"] + }, + "require": { + "php": ">=5.3.3", + "ext-gd": "*" + }, + "version": "1.1.5" +} diff --git a/vendor/szymach/c-pchart/readme.txt b/vendor/szymach/c-pchart/readme.txt new file mode 100644 index 0000000000..65917123ab Binary files /dev/null and b/vendor/szymach/c-pchart/readme.txt differ diff --git a/vendor/szymach/c-pchart/src/Classes/pBarcode128.php b/vendor/szymach/c-pchart/src/Classes/pBarcode128.php new file mode 100644 index 0000000000..11c973b72a --- /dev/null +++ b/vendor/szymach/c-pchart/src/Classes/pBarcode128.php @@ -0,0 +1,264 @@ +Codes = ""; + $this->Reverse = ""; + if (file_exists($BasePath."data/128B.db", "r")) { + $FileHandle = @fopen($BasePath."data/128B.db", "r"); + $filePath = $BasePath."data/128B.db"; + } else { + $FileHandle = @fopen(__DIR__.'/../Resources/data/128B.db', "r"); + $filePath = "/../Resources/data/128B.db"; + } + + if (!$FileHandle) { + throw new \Exception( + "Cannot find barcode database (".$filePath.")." + ); + } + + while (!feof($FileHandle)) { + $Buffer = fgets($FileHandle,4096); + $Buffer = str_replace(chr(10),"",$Buffer); + $Buffer = str_replace(chr(13),"",$Buffer); + $Values = preg_split("/;/",$Buffer); + + $this->Codes[$Values[1]]["ID"] = $Values[0]; + $this->Codes[$Values[1]]["Code"] = $Values[2]; + $this->Reverse[$Values[0]]["Code"] = $Values[2]; + $this->Reverse[$Values[0]]["Asc"] = $Values[1]; + } + fclose($FileHandle); + } + + /** + * Return the projected size of a barcode + * + * @param type $TextString + * @param type $Format + * @return array + */ + public function getSize($TextString, $Format = "") + { + $Angle = isset($Format["Angle"]) ? $Format["Angle"] : 0; + $ShowLegend = isset($Format["ShowLegend"]) + ? $Format["ShowLegend"] : false; + $LegendOffset = isset($Format["LegendOffset"]) + ? $Format["LegendOffset"] : 5; + $DrawArea = isset($Format["DrawArea"]) + ? $Format["DrawArea"] : false; + $FontSize = isset($Format["FontSize"]) + ? $Format["FontSize"] : 12; + $Height = isset($Format["Height"]) + ? $Format["Height"] : 30; + + $TextString = $this->encode128($TextString); + $BarcodeLength = strlen($this->Result); + + $WOffset = $DrawArea ? 20 : 0; + $HOffset = $ShowLegend ? $FontSize + $LegendOffset + $WOffset : 0; + + $X1 = cos($Angle * PI / 180) * ($WOffset+$BarcodeLength); + $Y1 = sin($Angle * PI / 180) * ($WOffset+$BarcodeLength); + + $X2 = $X1 + cos(($Angle+90) * PI / 180) * ($HOffset+$Height); + $Y2 = $Y1 + sin(($Angle+90) * PI / 180) * ($HOffset+$Height); + + + $AreaWidth = max(abs($X1), abs($X2)); + $AreaHeight = max(abs($Y1), abs($Y2)); + + return(array("Width" => $AreaWidth, "Height" => $AreaHeight)); + } + + /** + * + * @param type $Value + * @param type $Format + * @return string + */ + public function encode128($Value, $Format = "") + { + $this->Result = "11010010000"; + $this->CRC = 104; + $TextString = ""; + + for ($i=1; $i <= strlen($Value); $i++) { + $CharCode = ord($this->mid($Value,$i,1)); + if ( isset($this->Codes[$CharCode]) ) { + $this->Result = $this->Result.$this->Codes[$CharCode]["Code"]; + $this->CRC = $this->CRC + $i*$this->Codes[$CharCode]["ID"]; + $TextString = $TextString.chr($CharCode); + } + } + $this->CRC = $this->CRC - floor($this->CRC/103)*103; + + $this->Result = $this->Result.$this->Reverse[$this->CRC]["Code"]; + $this->Result = $this->Result."1100011101011"; + + return($TextString); + } + + /** + * Create the encoded string + * @param type $Object + * @param type $Value + * @param type $X + * @param type $Y + * @param type $Format + */ + public function draw($Object, $Value, $X, $Y, $Format = "") + { + $this->pChartObject = $Object; + + $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; + $Height = isset($Format["Height"]) ? $Format["Height"] : 30; + $Angle = isset($Format["Angle"]) ? $Format["Angle"] : 0; + $ShowLegend = isset($Format["ShowLegend"]) + ? $Format["ShowLegend"] : false; + $LegendOffset = isset($Format["LegendOffset"]) + ? $Format["LegendOffset"] : 5; + $DrawArea = isset($Format["DrawArea"]) + ? $Format["DrawArea"] : false; + $AreaR = isset($Format["AreaR"]) ? $Format["AreaR"] : 255; + $AreaG = isset($Format["AreaG"]) ? $Format["AreaG"] : 255; + $AreaB = isset($Format["AreaB"]) ? $Format["AreaB"] : 255; + $AreaBorderR = isset($Format["AreaBorderR"]) + ? $Format["AreaBorderR"] : $AreaR; + $AreaBorderG = isset($Format["AreaBorderG"]) + ? $Format["AreaBorderG"] : $AreaG; + $AreaBorderB = isset($Format["AreaBorderB"]) + ? $Format["AreaBorderB"] : $AreaB; + + $TextString = $this->encode128($Value); + + if ($DrawArea) { + $X1 = $X + cos(($Angle-135) * PI / 180) * 10; + $Y1 = $Y + sin(($Angle-135) * PI / 180) * 10; + + $X2 = $X1 + cos($Angle * PI / 180) * (strlen($this->Result)+20); + $Y2 = $Y1 + sin($Angle * PI / 180) * (strlen($this->Result)+20); + + if ($ShowLegend) { + $X3 = $X2 + cos(($Angle+90) * PI / 180) + * ($Height + $LegendOffset + $this->pChartObject->FontSize + 10); + $Y3 = $Y2 + sin(($Angle+90) * PI / 180) + * ($Height + $LegendOffset + $this->pChartObject->FontSize +10); + } else { + $X3 = $X2 + cos(($Angle+90) * PI / 180) * ($Height+20); + $Y3 = $Y2 + sin(($Angle+90) * PI / 180) * ($Height+20); + } + + $X4 = $X3 + cos(($Angle+180) * PI / 180) * (strlen($this->Result) + 20); + $Y4 = $Y3 + sin(($Angle+180) * PI / 180) * (strlen($this->Result) + 20); + + $Polygon = array($X1, $Y1, $X2, $Y2, $X3, $Y3, $X4, $Y4); + $Settings = array( + "R" => $AreaR, + "G" => $AreaG, + "B" => $AreaB, + "BorderR" => $AreaBorderR, + "BorderG" => $AreaBorderG, + "BorderB" => $AreaBorderB + ); + $this->pChartObject->drawPolygon($Polygon,$Settings); + } + + for ($i=1; $i<=strlen($this->Result); $i++) { + if ($this->mid($this->Result, $i, 1) == 1) { + $X1 = $X + cos($Angle * PI / 180) * $i; + $Y1 = $Y + sin($Angle * PI / 180) * $i; + $X2 = $X1 + cos(($Angle+90) * PI / 180) * $Height; + $Y2 = $Y1 + sin(($Angle+90) * PI / 180) * $Height; + + $Settings = array("R" => $R, "G" => $G, "B" => $B,"Alpha" => $Alpha); + $this->pChartObject->drawLine($X1,$Y1,$X2,$Y2,$Settings); + } + } + + if ($ShowLegend) { + $X1 = $X + cos($Angle * PI / 180) * (strlen($this->Result)/2); + $Y1 = $Y + sin($Angle * PI / 180) * (strlen($this->Result)/2); + + $LegendX = $X1 + cos(($Angle+90) * PI / 180) * ($Height+$LegendOffset); + $LegendY = $Y1 + sin(($Angle+90) * PI / 180) * ($Height+$LegendOffset); + + $Settings = array( + "R" => $R, + "G" => $G, + "B" => $B, + "Alpha" => $Alpha, + "Angle" => -$Angle, + "Align" => TEXT_ALIGN_TOPMIDDLE + ); + $this->pChartObject->drawText($LegendX,$LegendY,$TextString,$Settings); + } + } + + /** + * + * @param type $value + * @param type $NbChar + * @return string + */ + public function left($value, $NbChar) + { + return substr($value, 0, $NbChar); + } + /** + * + * @param type $value + * @param type $NbChar + * @return type + */ + public function right($value, $NbChar) + { + return substr($value, strlen($value) - $NbChar, $NbChar); + } + + /** + * + * @param type $value + * @param type $Depart + * @param type $NbChar + * @return type + */ + public function mid($value, $Depart, $NbChar) + { + return substr($value, $Depart - 1, $NbChar); + } + +} \ No newline at end of file diff --git a/vendor/szymach/c-pchart/src/Classes/pBarcode39.php b/vendor/szymach/c-pchart/src/Classes/pBarcode39.php new file mode 100644 index 0000000000..af08e36d53 --- /dev/null +++ b/vendor/szymach/c-pchart/src/Classes/pBarcode39.php @@ -0,0 +1,247 @@ +MOD43 = $EnableMOD43; + $this->Codes = ""; + $this->Reverse = ""; + if (file_exists($BasePath."data/39.db", "r")) { + $FileHandle = @fopen($BasePath."data/39.db", "r"); + $filePath = $BasePath."data/39.db"; + } else { + $FileHandle = @fopen(__DIR__.'/../Resources/data/39.db', "r"); + $filePath = "/../Resources/data/39.db"; + } + + if (!$FileHandle) { + throw new \Exception( + "Cannot find barcode database (".$filePath.")." + ); + } + + while (!feof($FileHandle)) { + $Buffer = fgets($FileHandle, 4096); + $Buffer = str_replace(chr(10), "", $Buffer); + $Buffer = str_replace(chr(13), "", $Buffer); + $Values = preg_split("/;/", $Buffer); + + $this->Codes[$Values[0]] = $Values[1]; + } + fclose($FileHandle); + } + + /** + * Return the projected size of a barcode + * @param type $TextString + * @param type $Format + * @return type + */ + function getSize($TextString, $Format = "") + { + $Angle = isset($Format["Angle"]) ? $Format["Angle"] : 0; + $ShowLegend = isset($Format["ShowLegend"]) ? $Format["ShowLegend"] : false; + $LegendOffset = isset($Format["LegendOffset"]) ? $Format["LegendOffset"] : 5; + $DrawArea = isset($Format["DrawArea"]) ? $Format["DrawArea"] : false; + $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : 12; + $Height = isset($Format["Height"]) ? $Format["Height"] : 30; + + $TextString = $this->encode39($TextString); + $BarcodeLength = strlen($this->Result); + + $WOffset = $DrawArea ? 20 : 0 ; + $HOffset = $ShowLegend ? $FontSize + $LegendOffset + $WOffset : 0; + + $X1 = cos($Angle * PI / 180) * ($WOffset + $BarcodeLength); + $Y1 = sin($Angle * PI / 180) * ($WOffset + $BarcodeLength); + + $X2 = $X1 + cos(($Angle+90) * PI / 180) * ($HOffset+$Height); + $Y2 = $Y1 + sin(($Angle+90) * PI / 180) * ($HOffset+$Height); + + + $AreaWidth = max(abs($X1),abs($X2)); + $AreaHeight = max(abs($Y1),abs($Y2)); + + return(array("Width" => $AreaWidth, "Height" => $AreaHeight)); + } + + /** + * Create the encoded string + * @param type $Value + * @return string + */ + function encode39($Value) + { + $this->Result = "100101101101"."0"; + $TextString = ""; + for ($i=1; $i <= strlen($Value); $i++) { + $CharCode = ord($this->mid($Value,$i,1)); + if ($CharCode >= 97 && $CharCode <= 122) { + $CharCode = $CharCode - 32; + } + + if (isset($this->Codes[chr($CharCode)])) { + $this->Result = $this->Result.$this->Codes[chr($CharCode)]."0"; + $TextString = $TextString.chr($CharCode); + } + } + + if ($this->MOD43) { + $Checksum = $this->checksum($TextString); + $this->Result = $this->Result.$this->Codes[$Checksum]."0"; + } + + $this->Result = $this->Result."100101101101"; + $TextString = "*".$TextString."*"; + + return $TextString; + } + + /** + * Create the encoded string + * @param type $Object + * @param type $Value + * @param type $X + * @param type $Y + * @param type $Format + */ + function draw($Object,$Value,$X,$Y,$Format="") + { + $this->pChartObject = $Object; + + $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; + $Height = isset($Format["Height"]) ? $Format["Height"] : 30; + $Angle = isset($Format["Angle"]) ? $Format["Angle"] : 0; + $ShowLegend = isset($Format["ShowLegend"]) ? $Format["ShowLegend"] : false; + $LegendOffset = isset($Format["LegendOffset"]) ? $Format["LegendOffset"] : 5; + $DrawArea = isset($Format["DrawArea"]) ? $Format["DrawArea"] : false; + $AreaR = isset($Format["AreaR"]) ? $Format["AreaR"] : 255; + $AreaG = isset($Format["AreaG"]) ? $Format["AreaG"] : 255; + $AreaB = isset($Format["AreaB"]) ? $Format["AreaB"] : 255; + $AreaBorderR = isset($Format["AreaBorderR"]) ? $Format["AreaBorderR"] : $AreaR; + $AreaBorderG = isset($Format["AreaBorderG"]) ? $Format["AreaBorderG"] : $AreaG; + $AreaBorderB = isset($Format["AreaBorderB"]) ? $Format["AreaBorderB"] : $AreaB; + + $TextString = $this->encode39($Value); + + if ($DrawArea) { + $X1 = $X + cos(($Angle-135) * PI / 180) * 10; + $Y1 = $Y + sin(($Angle-135) * PI / 180) * 10; + + $X2 = $X1 + cos($Angle * PI / 180) * (strlen($this->Result)+20); + $Y2 = $Y1 + sin($Angle * PI / 180) * (strlen($this->Result)+20); + + if ($ShowLegend) { + $X3 = $X2 + cos(($Angle+90) * PI / 180) + * ($Height+$LegendOffset+$this->pChartObject->FontSize+10); + $Y3 = $Y2 + sin(($Angle+90) * PI / 180) + * ($Height+$LegendOffset+$this->pChartObject->FontSize+10); + } else { + $X3 = $X2 + cos(($Angle+90) * PI / 180) * ($Height+20); + $Y3 = $Y2 + sin(($Angle+90) * PI / 180) * ($Height+20); + } + + $X4 = $X3 + cos(($Angle+180) * PI / 180) * (strlen($this->Result)+20); + $Y4 = $Y3 + sin(($Angle+180) * PI / 180) * (strlen($this->Result)+20); + + $Polygon = array($X1, $Y1, $X2, $Y2, $X3, $Y3, $X4, $Y4); + $Settings = array( + "R" => $AreaR, + "G" => $AreaG, + "B" =>$AreaB, + "BorderR" => $AreaBorderR, + "BorderG" => $AreaBorderG, + "BorderB" => $AreaBorderB + ); + $this->pChartObject->drawPolygon($Polygon,$Settings); + } + + for ($i=1; $i <= strlen($this->Result); $i++) { + if ($this->mid($this->Result,$i,1) == 1) { + $X1 = $X + cos($Angle * PI / 180) * $i; + $Y1 = $Y + sin($Angle * PI / 180) * $i; + $X2 = $X1 + cos(($Angle+90) * PI / 180) * $Height; + $Y2 = $Y1 + sin(($Angle+90) * PI / 180) * $Height; + + $Settings = array("R" => $R, "G" => $G, "B" => $B, "Alpha" => $Alpha); + $this->pChartObject->drawLine($X1, $Y1, $X2, $Y2, $Settings); + } + } + + if ($ShowLegend) { + $X1 = $X + cos($Angle * PI / 180) * (strlen($this->Result)/2); + $Y1 = $Y + sin($Angle * PI / 180) * (strlen($this->Result)/2); + + $LegendX = $X1 + cos(($Angle+90) * PI / 180) * ($Height+$LegendOffset); + $LegendY = $Y1 + sin(($Angle+90) * PI / 180) * ($Height+$LegendOffset); + + $Settings = array( + "R" => $R, + "G" => $G, + "B" => $B, + "Alpha" => $Alpha, + "Angle" => -$Angle, + "Align" => TEXT_ALIGN_TOPMIDDLE + ); + $this->pChartObject->drawText($LegendX, $LegendY, $TextString, $Settings); + } + } + + function checksum($string) + { + $checksum = 0; + $length = strlen($string); + $charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%'; + + for( $i=0; $i < $length; ++$i ) { + $checksum += strpos( $charset, $string[$i] ); + } + return substr( $charset, ($checksum % 43), 1 ); + } + + 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/vendor/szymach/c-pchart/src/Classes/pBubble.php b/vendor/szymach/c-pchart/src/Classes/pBubble.php new file mode 100644 index 0000000000..155cd9d271 --- /dev/null +++ b/vendor/szymach/c-pchart/src/Classes/pBubble.php @@ -0,0 +1,463 @@ +pChartObject = $pChartObject; + $this->pDataObject = $pDataObject; + } + + /* Prepare the scale */ + public function bubbleScale($DataSeries,$WeightSeries) + { + if (!is_array($DataSeries)) { + $DataSeries = array($DataSeries); + } + if (!is_array($WeightSeries)) { + $WeightSeries = array($WeightSeries); + } + + /* Parse each data series to find the new min & max boundaries to scale */ + $NewPositiveSerie = ""; + $NewNegativeSerie = ""; + $MaxValues = 0; + $LastPositive = 0; + $LastNegative = 0; + + foreach($DataSeries as $Key => $SerieName) { + $SerieWeightName = $WeightSeries[$Key]; + + $this->pDataObject->setSerieDrawable($SerieWeightName,false); + + if (count( + $this->pDataObject->Data["Series"][$SerieName]["Data"] + ) > $MaxValues + ) { + $MaxValues = count($this->pDataObject->Data["Series"][$SerieName]["Data"]); + } + + foreach($this->pDataObject->Data["Series"][$SerieName]["Data"] + as $Key => $Value + ) { + if ($Value >= 0) { + $BubbleBounds = $Value + $this->pDataObject->Data["Series"][$SerieWeightName]["Data"][$Key]; + + if ( !isset($NewPositiveSerie[$Key]) ) { + $NewPositiveSerie[$Key] = $BubbleBounds; + } elseif ($NewPositiveSerie[$Key] < $BubbleBounds) { + $NewPositiveSerie[$Key] = $BubbleBounds; + } + $LastPositive = $BubbleBounds; + } else { + $BubbleBounds = $Value - $this->pDataObject->Data["Series"][$SerieWeightName]["Data"][$Key]; + + if (!isset($NewNegativeSerie[$Key])) { + $NewNegativeSerie[$Key] = $BubbleBounds; + } elseif ($NewNegativeSerie[$Key] > $BubbleBounds) { + $NewNegativeSerie[$Key] = $BubbleBounds; + } + $LastNegative = $BubbleBounds; + } + } + } + + /* Check for missing values and all the fake positive serie */ + if ( $NewPositiveSerie != "" ) { + for ($i=0; $i<$MaxValues; $i++) { + if (!isset($NewPositiveSerie[$i])) { + $NewPositiveSerie[$i] = $LastPositive; + } + } + $this->pDataObject->addPoints($NewPositiveSerie,"BubbleFakePositiveSerie"); + } + + /* Check for missing values and all the fake negative serie */ + if ( $NewNegativeSerie != "" ) { + for ($i = 0; $i < $MaxValues; $i++) { + if (!isset($NewNegativeSerie[$i])) { + $NewNegativeSerie[$i] = $LastNegative; + } + } + + $this->pDataObject->addPoints($NewNegativeSerie,"BubbleFakeNegativeSerie"); + } + } + + public function resetSeriesColors() + { + $Data = $this->pDataObject->getData(); + $Palette = $this->pDataObject->getPalette(); + + $ID = 0; + foreach($Data["Series"] as $SerieName => $SeriesParameters) { + if ( $SeriesParameters["isDrawable"] ) { + $this->pDataObject->Data["Series"][$SerieName]["Color"]["R"] = $Palette[$ID]["R"]; + $this->pDataObject->Data["Series"][$SerieName]["Color"]["G"] = $Palette[$ID]["G"]; + $this->pDataObject->Data["Series"][$SerieName]["Color"]["B"] = $Palette[$ID]["B"]; + $this->pDataObject->Data["Series"][$SerieName]["Color"]["Alpha"] = $Palette[$ID]["Alpha"]; + $ID++; + } + } + } + + /* Prepare the scale */ + public function drawBubbleChart($DataSeries, $WeightSeries, $Format="") + { + $ForceAlpha = isset($Format["ForceAlpha"]) ? $Format["ForceAlpha"] : VOID; + $DrawBorder = isset($Format["DrawBorder"]) ? $Format["DrawBorder"] : TRUE; + $BorderWidth = isset($Format["BorderWidth"]) ? $Format["BorderWidth"] : 1; + $Shape = isset($Format["Shape"]) ? $Format["Shape"] : BUBBLE_SHAPE_ROUND; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 0; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 0; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 0; + $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : 30; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : false; + + if (!is_array($DataSeries)) { + $DataSeries = array($DataSeries); + } + if (!is_array($WeightSeries)) { + $WeightSeries = array($WeightSeries); + } + + $Data = $this->pDataObject->getData(); + $Palette = $this->pDataObject->getPalette(); + + if (isset($Data["Series"]["BubbleFakePositiveSerie"])) { + $this->pDataObject->setSerieDrawable("BubbleFakePositiveSerie",false); + } + if (isset($Data["Series"]["BubbleFakeNegativeSerie"])) { + $this->pDataObject->setSerieDrawable("BubbleFakeNegativeSerie",false); + } + + $this->resetSeriesColors(); + + list($XMargin,$XDivs) = $this->pChartObject->scaleGetXSettings(); + + foreach($DataSeries as $Key => $SerieName) { + $AxisID = $Data["Series"][$SerieName]["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + if (isset($Data["Series"][$SerieName]["Description"])) { + $SerieDescription = $Data["Series"][$SerieName]["Description"]; + } else { + $SerieDescription = $SerieName; + } + + $XStep = ($this->pChartObject->GraphAreaX2 - $this->pChartObject->GraphAreaX1 - $XMargin*2)/$XDivs; + + $X = $this->pChartObject->GraphAreaX1 + $XMargin; + $Y = $this->pChartObject->GraphAreaY1 + $XMargin; + + $Color = array( + "R" => $Palette[$Key]["R"], + "G" => $Palette[$Key]["G"], + "B" => $Palette[$Key]["B"], + "Alpha" => $Palette[$Key]["Alpha"] + ); + + if ( $ForceAlpha != VOID ) { + $Color["Alpha"] = $ForceAlpha; + } + + if ($DrawBorder) { + if ( $BorderWidth != 1 ) { + if ( $Surrounding != NULL ) { + $BorderR = $Palette[$Key]["R"]+$Surrounding; + $BorderG = $Palette[$Key]["G"]+$Surrounding; + $BorderB = $Palette[$Key]["B"]+$Surrounding; + } else { + $BorderR = $BorderR; + $BorderG = $BorderG; + $BorderB = $BorderB; + } + if ( $ForceAlpha != VOID ) { + $BorderAlpha = $ForceAlpha/2; + } + $BorderColor = array( + "R"=>$BorderR, + "G"=>$BorderG, + "B"=>$BorderB, + "Alpha"=>$BorderAlpha + ); + } else { + $Color["BorderAlpha"] = $BorderAlpha; + + if ( $Surrounding != NULL ) { + $Color["BorderR"] = $Palette[$Key]["R"]+$Surrounding; + $Color["BorderG"] = $Palette[$Key]["G"]+$Surrounding; + $Color["BorderB"] = $Palette[$Key]["B"]+$Surrounding; + } else { + $Color["BorderR"] = $BorderR; + $Color["BorderG"] = $BorderG; + $Color["BorderB"] = $BorderB; + } + if ( $ForceAlpha != VOID ) { + $Color["BorderAlpha"] = $ForceAlpha/2; + } + } + } + + foreach($Data["Series"][$SerieName]["Data"] as $iKey => $Point) { + $Weight = $Point + $Data["Series"][$WeightSeries[$Key]]["Data"][$iKey]; + + $PosArray = $this->pChartObject->scaleComputeY( + $Point, + array("AxisID"=>$AxisID) + ); + $WeightArray = $this->pChartObject->scaleComputeY( + $Weight, + array("AxisID"=>$AxisID) + ); + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) { + if ( $XDivs == 0 ) { + $XStep = 0; + } else { + $XStep = ($this->pChartObject->GraphAreaX2 - $this->pChartObject->GraphAreaX1-$XMargin*2)/$XDivs; + } + $Y = floor($PosArray); $CircleRadius = floor(abs($PosArray - $WeightArray)/2); + + if ( $Shape == BUBBLE_SHAPE_SQUARE ) { + if ( $RecordImageMap ) { + $this->pChartObject->addToImageMap( + "RECT", + ( + floor($X-$CircleRadius) + .",".floor($Y-$CircleRadius) + .",".floor($X+$CircleRadius) + .",".floor($Y+$CircleRadius) + ), + $this->pChartObject->toHTMLColor($Palette[$Key]["R"], + $Palette[$Key]["G"],$Palette[$Key]["B"]), + $SerieDescription,$Data["Series"][$WeightSeries[$Key]]["Data"][$iKey] + ); + } + + if ( $BorderWidth != 1 ) { + $this->pChartObject->drawFilledRectangle( + $X-$CircleRadius-$BorderWidth, + $Y-$CircleRadius-$BorderWidth, + $X+$CircleRadius+$BorderWidth, + $Y+$CircleRadius+$BorderWidth, + $BorderColor + ); + $this->pChartObject->drawFilledRectangle( + $X-$CircleRadius, + $Y-$CircleRadius, + $X+$CircleRadius, + $Y+$CircleRadius, + $Color + ); + } else { + $this->pChartObject->drawFilledRectangle( + $X-$CircleRadius, + $Y-$CircleRadius, + $X+$CircleRadius, + $Y+$CircleRadius, + $Color + ); + } + } elseif ( $Shape == BUBBLE_SHAPE_ROUND ) { + if ( $RecordImageMap ) { + $this->pChartObject->addToImageMap( + "CIRCLE", + floor($X).",".floor($Y).",".floor($CircleRadius), + $this->pChartObject->toHTMLColor($Palette[$Key]["R"], + $Palette[$Key]["G"], + $Palette[$Key]["B"]), + $SerieDescription,$Data["Series"][$WeightSeries[$Key]]["Data"][$iKey] + ); + } + + if ( $BorderWidth != 1 ) { + $this->pChartObject->drawFilledCircle($X,$Y,$CircleRadius+$BorderWidth,$BorderColor); + $this->pChartObject->drawFilledCircle($X,$Y,$CircleRadius,$Color); + } else { + $this->pChartObject->drawFilledCircle($X,$Y,$CircleRadius,$Color); + } + } + + $X = $X + $XStep; + } elseif ( $Data["Orientation"] == SCALE_POS_TOPBOTTOM ) { + if ( $XDivs == 0 ) { + $XStep = 0; + } else { + $XStep = ($this->pChartObject->GraphAreaY2-$this->pChartObject->GraphAreaY1-$XMargin*2)/$XDivs; + } + $X = floor($PosArray); $CircleRadius = floor(abs($PosArray - $WeightArray)/2); + + if ( $Shape == BUBBLE_SHAPE_SQUARE ) { + if ( $RecordImageMap ) { + $this->pChartObject->addToImageMap( + "RECT", + floor($X-$CircleRadius).",".floor($Y-$CircleRadius).",".floor($X+$CircleRadius).",".floor($Y+$CircleRadius), + $this->pChartObject->toHTMLColor($Palette[$Key]["R"],$Palette[$Key]["G"],$Palette[$Key]["B"]), + $SerieDescription,$Data["Series"][$WeightSeries[$Key]]["Data"][$iKey] + ); + } + + if ( $BorderWidth != 1 ) { + $this->pChartObject->drawFilledRectangle($X-$CircleRadius-$BorderWidth,$Y-$CircleRadius-$BorderWidth,$X+$CircleRadius+$BorderWidth,$Y+$CircleRadius+$BorderWidth,$BorderColor); + $this->pChartObject->drawFilledRectangle($X-$CircleRadius,$Y-$CircleRadius,$X+$CircleRadius,$Y+$CircleRadius,$Color); + } else { + $this->pChartObject->drawFilledRectangle($X-$CircleRadius,$Y-$CircleRadius,$X+$CircleRadius,$Y+$CircleRadius,$Color); + } + } elseif ( $Shape == BUBBLE_SHAPE_ROUND ) { + if ( $RecordImageMap ) { + $this->pChartObject->addToImageMap( + "CIRCLE", + floor($X).",".floor($Y).",".floor($CircleRadius), + $this->pChartObject->toHTMLColor($Palette[$Key]["R"],$Palette[$Key]["G"],$Palette[$Key]["B"]), + $SerieDescription,$Data["Series"][$WeightSeries[$Key]]["Data"][$iKey] + ); + } + + if ( $BorderWidth != 1 ) { + $this->pChartObject->drawFilledCircle($X,$Y,$CircleRadius+$BorderWidth,$BorderColor); + $this->pChartObject->drawFilledCircle($X,$Y,$CircleRadius,$Color); + } else { + $this->pChartObject->drawFilledCircle($X,$Y,$CircleRadius,$Color); + } + } + + $Y = $Y + $XStep; + } + } + } + } + + public function writeBubbleLabel($SerieName,$SerieWeightName,$Points,$Format="") + { + $OverrideTitle = isset($Format["OverrideTitle"]) ? $Format["OverrideTitle"] : NULL; + $DrawPoint = isset($Format["DrawPoint"]) ? $Format["DrawPoint"] : LABEL_POINT_BOX; + + if ( !is_array($Points) ) { + $Point = $Points; + $Points = ""; + $Points[] = $Point; + } + + $Data = $this->pDataObject->getData(); + $Palette = $this->pDataObject->getPalette(); + + if (!isset($Data["Series"][$SerieName]) + || !isset($Data["Series"][$SerieWeightName]) + ) { + return(0); + } + list($XMargin,$XDivs) = $this->pChartObject->scaleGetXSettings(); + + $AxisID = $Data["Series"][$SerieName]["Axis"]; + $AxisMode = $Data["Axis"][$AxisID]["Display"]; + $AxisFormat = $Data["Axis"][$AxisID]["Format"]; + $AxisUnit = $Data["Axis"][$AxisID]["Unit"]; + $XStep = ($this->pChartObject->GraphAreaX2-$this->pChartObject->GraphAreaX1-$XMargin*2)/$XDivs; + + $X = $this->pChartObject->GraphAreaX1 + $XMargin; + $Y = $this->pChartObject->GraphAreaY1 + $XMargin; + + $Color = array( + "R"=>$Data["Series"][$SerieName]["Color"]["R"], + "G"=>$Data["Series"][$SerieName]["Color"]["G"], + "B"=>$Data["Series"][$SerieName]["Color"]["B"], + "Alpha"=>$Data["Series"][$SerieName]["Color"]["Alpha"] + ); + + foreach($Points as $Key => $Point) { + $Value = $Data["Series"][$SerieName]["Data"][$Point]; + $PosArray = $this->pChartObject->scaleComputeY($Value,array("AxisID"=>$AxisID)); + + if ( isset($Data["Abscissa"]) && isset($Data["Series"][$Data["Abscissa"]]["Data"][$Point]) ) { + $Abscissa = $Data["Series"][$Data["Abscissa"]]["Data"][$Point]." : "; + } else { + $Abscissa = ""; + } + $Value = $this->pChartObject->scaleFormat($Value,$AxisMode,$AxisFormat,$AxisUnit); + $Weight = $Data["Series"][$SerieWeightName]["Data"][$Point]; + $Caption = $Abscissa.$Value." / ".$Weight; + + if ( isset($Data["Series"][$SerieName]["Description"]) ) { + $Description = $Data["Series"][$SerieName]["Description"]; + } else { + $Description = "No description"; + } + $Series = ""; + $Series[] = array("Format" => $Color, "Caption" => $Caption); + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) { + if ( $XDivs == 0 ) { + $XStep = 0; + } else { + $XStep = ($this->pChartObject->GraphAreaX2-$this->pChartObject->GraphAreaX1-$XMargin*2)/$XDivs; + } + + $X = floor($X + $Point * $XStep); + $Y = floor($PosArray); + } else { + if ( $XDivs == 0 ) { + $YStep = 0; + } else { + $YStep = ($this->pChartObject->GraphAreaY2-$this->pChartObject->GraphAreaY1-$XMargin*2)/$XDivs; + } + + $X = floor($PosArray); + $Y = floor($Y + $Point * $YStep); + } + + if ( $DrawPoint == LABEL_POINT_CIRCLE ) { + $this->pChartObject->drawFilledCircle( + $X, + $Y, + 3, + array( + "R"=>255, + "G"=>255, + "B"=>255, + "BorderR"=>0, + "BorderG"=>0, + "BorderB"=>0 + ) + ); + } elseif ( $DrawPoint == LABEL_POINT_BOX ) { + $this->pChartObject->drawFilledRectangle( + $X-2, + $Y-2, + $X+2, + $Y+2, + array( + "R"=>255, + "G"=>255, + "B"=>255, + "BorderR"=>0, + "BorderG"=>0, + "BorderB"=>0 + ) + ); + } + + $this->pChartObject->drawLabelBox($X,$Y-3,$Description,$Series,$Format); + } + } +} \ No newline at end of file diff --git a/vendor/szymach/c-pchart/src/Classes/pCache.php b/vendor/szymach/c-pchart/src/Classes/pCache.php new file mode 100644 index 0000000000..b0b5d94789 --- /dev/null +++ b/vendor/szymach/c-pchart/src/Classes/pCache.php @@ -0,0 +1,367 @@ +CacheFolder = $CacheFolder; + $this->CacheIndex = $CacheIndex; + $this->CacheDB = $CacheDB; + if (!file_exists($this->CacheFolder."/".$this->CacheIndex)) { + touch($this->CacheFolder."/".$this->CacheIndex); + } + if (!file_exists($this->CacheFolder."/".$this->CacheDB)) { + touch($this->CacheFolder."/".$this->CacheDB); + } + } + + /** + * Flush the cache contents + */ + public function flush() + { + if (file_exists($this->CacheFolder."/".$this->CacheIndex)) { + unlink($this->CacheFolder."/".$this->CacheIndex); + touch($this->CacheFolder."/".$this->CacheIndex); + } + if (file_exists($this->CacheFolder."/".$this->CacheDB)) { + unlink($this->CacheFolder."/".$this->CacheDB); + touch($this->CacheFolder."/".$this->CacheDB); + } + } + + /** + * Return the MD5 of the data array to clearly identify the chart + * @param type $Data + * @param type $Marker + * @return type + */ + public function getHash($Data,$Marker="") + { + return(md5($Marker.serialize($Data->Data))); + } + + /** + * Write the generated picture to the cache + * @param type $ID + * @param type $pChartObject + */ + public function writeToCache($ID,$pChartObject) + { + /* Compute the paths */ + $TemporaryFile = $this->CacheFolder."/tmp_".rand(0,1000).".png"; + $Database = $this->CacheFolder."/".$this->CacheDB; + $Index = $this->CacheFolder."/".$this->CacheIndex; + /* Flush the picture to a temporary file */ + imagepng($pChartObject->Picture ,$TemporaryFile); + + /* Retrieve the files size */ + $PictureSize = filesize($TemporaryFile); + $DBSize = filesize($Database); + + /* Save the index */ + $Handle = fopen($Index,"a"); + fwrite($Handle, $ID.",".$DBSize.",".$PictureSize.",".time().",0\r\n"); + fclose($Handle); + + /* Get the picture raw contents */ + $Handle = fopen($TemporaryFile,"r"); + $Raw = fread($Handle,$PictureSize); + fclose($Handle); + + /* Save the picture in the solid database file */ + $Handle = fopen($Database,"a"); + fwrite($Handle, $Raw); + fclose($Handle); + + /* Remove temporary file */ + unlink($TemporaryFile); + } + + /** + * Remove object older than the specified TS + * @param type $Expiry + */ + public function removeOlderThan($Expiry) + { + $this->dbRemoval(array("Expiry"=>$Expiry)); + } + + /** + * Remove an object from the cache + * @param type $ID + */ + public function remove($ID) + { + $this->dbRemoval(array("Name"=>$ID)); + } + + /** + * Remove with specified criterias + * @param type $Settings + * @return type + */ + public function dbRemoval($Settings) + { + $ID = isset($Settings["Name"]) ? $Settings["Name"] : null; + $Expiry = isset($Settings["Expiry"]) ? $Settings["Expiry"] : -(24*60*60); + $TS = time()-$Expiry; + + /* Compute the paths */ + $Database = $this->CacheFolder."/".$this->CacheDB; + $Index = $this->CacheFolder."/".$this->CacheIndex; + $DatabaseTemp = $this->CacheFolder."/".$this->CacheDB.".tmp"; + $IndexTemp = $this->CacheFolder."/".$this->CacheIndex.".tmp"; + + /* Single file removal */ + if ( $ID != null ) { + /* Retrieve object informations */ + $Object = $this->isInCache($ID,true); + + /* If it's not in the cache DB, go away */ + if ( !$Object ) { + return(0); + } + } + + /* Create the temporary files */ + if (!file_exists($DatabaseTemp)) { + touch($DatabaseTemp); + } + if (!file_exists($IndexTemp)) { + touch($IndexTemp); + } + + /* Open the file handles */ + $IndexHandle = @fopen($Index, "r"); + $IndexTempHandle = @fopen($IndexTemp, "w"); + $DBHandle = @fopen($Database, "r"); + $DBTempHandle = @fopen($DatabaseTemp, "w"); + + /* Remove the selected ID from the database */ + while (!feof($IndexHandle)) { + $Entry = fgets($IndexHandle, 4096); + $Entry = str_replace("\r","",$Entry); + $Entry = str_replace("\n","",$Entry); + $Settings = preg_split("/,/",$Entry); + + if ( $Entry != "" ) { + $PicID = $Settings[0]; + $DBPos = $Settings[1]; + $PicSize = $Settings[2]; + $GeneratedTS = $Settings[3]; + $Hits = $Settings[4]; + + if ( $Settings[0] != $ID && $GeneratedTS > $TS) { + $CurrentPos = ftell($DBTempHandle); + fwrite( + $IndexTempHandle, + $PicID.",".$CurrentPos.",".$PicSize."," + .$GeneratedTS.",".$Hits."\r\n" + ); + + fseek($DBHandle,$DBPos); + $Picture = fread($DBHandle,$PicSize); + fwrite($DBTempHandle,$Picture); + } + } + } + + /* Close the handles */ + fclose($IndexHandle); + fclose($IndexTempHandle); + fclose($DBHandle); + fclose($DBTempHandle); + + /* Remove the prod files */ + unlink($Database); + unlink($Index); + + /* Swap the temp & prod DB */ + rename($DatabaseTemp,$Database); + rename($IndexTemp,$Index); + } + + /** + * Is the file in cache? + * @param type $ID + * @param type $Verbose + * @param type $UpdateHitsCount + * @return boolean + */ + public function isInCache($ID,$Verbose=false,$UpdateHitsCount=false) + { + /* Compute the paths */ + $Index = $this->CacheFolder."/".$this->CacheIndex; + + /* Search the picture in the index file */ + $Handle = @fopen($Index, "r"); + while (!feof($Handle)) { + $IndexPos = ftell($Handle); + $Entry = fgets($Handle, 4096); + if ( $Entry != "" ) { + $Settings = preg_split("/,/",$Entry); + $PicID = $Settings[0]; + if ( $PicID == $ID ) { + fclose($Handle); + + $DBPos = $Settings[1]; + $PicSize = $Settings[2]; + $GeneratedTS = $Settings[3]; + $Hits = intval($Settings[4]); + + if ( $UpdateHitsCount ) { + $Hits++; + if ( strlen($Hits) < 7 ) { + $Hits = $Hits.str_repeat(" ",7-strlen($Hits)); + } + + $Handle = @fopen($Index, "r+"); + fseek($Handle,$IndexPos); + fwrite( + $Handle, + $PicID.",".$DBPos.",".$PicSize."," + .$GeneratedTS.",".$Hits."\r\n" + ); + fclose($Handle); + } + + if ($Verbose) { + return( + array( + "DBPos" => $DBPos, + "PicSize" => $PicSize, + "GeneratedTS" => $GeneratedTS, + "Hits" => $Hits + ) + ); + } else { + return true; + } + } + } + } + fclose($Handle); + + /* Picture isn't in the cache */ + return false; + } + + /** + * Automatic output method based on the calling interface + * @param type $ID + * @param type $Destination + */ + public function autoOutput($ID,$Destination="output.png") + { + if (php_sapi_name() == "cli") { + $this->saveFromCache($ID,$Destination); + } else { + $this->strokeFromCache($ID); + } + } + + /** + * Show image from cache + * @param type $ID + * @return boolean + */ + public function strokeFromCache($ID) + { + /* Get the raw picture from the cache */ + $Picture = $this->getFromCache($ID); + + /* Do we have a hit? */ + if ( $Picture == null ) { + return false; + } + + header('Content-type: image/png'); + echo $Picture; + + return true; + } + + /** + * Save file from cache. + * @param type $ID + * @param type $Destination + * @return boolean + */ + public function saveFromCache($ID,$Destination) + { + /* Get the raw picture from the cache */ + $Picture = $this->getFromCache($ID); + + /* Do we have a hit? */ + if ( $Picture == null ) { + return false; + } + + /* Flush the picture to a file */ + $Handle = fopen($Destination,"w"); + fwrite($Handle,$Picture); + fclose($Handle); + + /* All went fine */ + return true; + } + + /** + * Get file from cache + * @param type $ID + * @return string + */ + public function getFromCache($ID) + { + /* Compute the path */ + $Database = $this->CacheFolder."/".$this->CacheDB; + + /* Lookup for the picture in the cache */ + $CacheInfo = $this->isInCache($ID,true,true); + + /* Not in the cache */ + if (!$CacheInfo) { + return null; + } + + /* Get the database extended information */ + $DBPos = $CacheInfo["DBPos"]; + $PicSize = $CacheInfo["PicSize"]; + + /* Extract the picture from the solid cache file */ + $Handle = @fopen($Database, "r"); + fseek($Handle,$DBPos); + $Picture = fread($Handle,$PicSize); + fclose($Handle); + + /* Return back the raw picture data */ + return $Picture; + } +} \ No newline at end of file diff --git a/vendor/szymach/c-pchart/src/Classes/pData.php b/vendor/szymach/c-pchart/src/Classes/pData.php new file mode 100644 index 0000000000..a5284c384c --- /dev/null +++ b/vendor/szymach/c-pchart/src/Classes/pData.php @@ -0,0 +1,1230 @@ +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 + */ + public 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 + * @param type $Values + * @param type $SerieName + * @return int + */ + public 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 + * @param type $Values + * @return type + */ + public 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 + * @param type $Serie + * @return int + */ + public 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 + * @param type $Series + */ + public 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 + * @param type $Serie + * @param type $Index + * @return null + */ + public 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 + * @param type $Serie + * @return null + */ + public 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 + * @param type $Series + */ + public 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 + * @param type $Serie + * @return null + */ + public 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 + * @param type $Serie + * @return null + */ + public 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 */ + public 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 + * @param type $Series + * @param type $Shape + */ + public 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 + * @param type $Series + * @param type $Description + */ + public 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 public function + * @param type $Series + * @param type $Drawable + */ + public 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 + * @param type $Series + * @param type $Picture + */ + public 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 + * @param type $Name + */ + public function setXAxisName($Name) + { $this->Data["XAxisName"] = $Name; } + + /** + * Set the display mode of the X Axis + * @param type $Mode + * @param type $Format + */ + public function setXAxisDisplay($Mode,$Format=null) + { $this->Data["XAxisDisplay"] = $Mode; $this->Data["XAxisFormat"] = $Format; } + + /** + * Set the unit that will be displayed on the X axis + * @param type $Unit + */ + public function setXAxisUnit($Unit) + { $this->Data["XAxisUnit"] = $Unit; } + + /** + * Set the serie that will be used as abscissa + * @param type $Serie + */ + public function setAbscissa($Serie) + { if (isset($this->Data["Series"][$Serie])) { $this->Data["Abscissa"] = $Serie; } } + + /** + * Set the position of the abscissa axis + * @param type $Position + */ + public function setAbsicssaPosition($Position = AXIS_POSITION_BOTTOM) + { $this->Data["AbsicssaPosition"] = $Position; } + + /** + * Set the name of the abscissa axis + * @param type $Name + */ + public function setAbscissaName($Name) + { $this->Data["AbscissaName"] = $Name; } + + /** + * Create a scatter group specifyin X and Y data series + * @param type $SerieX + * @param type $SerieY + * @param type $ID + */ + public 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 + * @param type $ID + * @param type $Shape + */ + public 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 + * @param type $ID + * @param type $Description + */ + public 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 + * @param type $ID + * @param type $Picture + */ + public 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 public function + * @param type $ID + * @param type $Drawable + */ + public 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 + * @param type $ID + * @param type $Width + */ + public 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 + * @param type $ID + * @param type $Weight + */ + public function setScatterSerieWeight($ID,$Weight=0) + { if ( isset($this->Data["ScatterSeries"][$ID]) ) { $this->Data["ScatterSeries"][$ID]["Weight"] = $Weight; } } + + /** + * Associate a color to a scatter serie + * @param type $ID + * @param type $Format + */ + public 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 + * @return type + */ + public 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 + */ + public 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 */ + public 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 + * @param type $Serie + * @return null + */ + public 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 + * @param type $Serie + * @return null + */ + public 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 + * @param type $Serie + * @return null + */ + public 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 + * @param type $Serie + * @return null + */ + public 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 + * @param type $Serie + * @return null + */ + public 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 + * @param type $Serie + * @param type $Percentil + * @return null + */ + public 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 + * @param type $SerieName + * @param type $Options + */ + public 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 + * @return boolean + */ + public 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 + * @param type $AxisID + * @param type $Mode + * @param type $Format + */ + public 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 + * @param type $AxisID + * @param type $Position + */ + public 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 + * @param type $AxisID + * @param type $Unit + */ + public function setAxisUnit($AxisID,$Unit) + { if ( isset($this->Data["Axis"][$AxisID] ) ) { $this->Data["Axis"][$AxisID]["Unit"] = $Unit; } } + + /** + * Associate a name to an axis + * @param type $AxisID + * @param type $Name + */ + public function setAxisName($AxisID,$Name) + { if ( isset($this->Data["Axis"][$AxisID] ) ) { $this->Data["Axis"][$AxisID]["Name"] = $Name; } } + + /** + * Associate a color to an axis + * @param type $AxisID + * @param type $Format + */ + public 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 + * @param type $AxisID + * @param type $Identity + */ + public 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 + * @param type $Series + * @param type $AxisID + */ + public 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 + * @param type $Series + * @param type $Width + */ + public 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 + * @param type $Series + * @param type $Weight + */ + public 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 + * @param type $Serie + * @return null + */ + public 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 + * @param type $Series + * @param type $Format + */ + public 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 + * @param type $FileName + * @param type $Overwrite + * @return type + * @throws \Exception + */ + public function loadPalette($FileName,$Overwrite=false) + { + if (file_exists($FileName)) { + $fileHandle = @fopen($FileName, "r"); + } else { + $fileHandle = @fopen(__DIR__.'/../Resources/palettes/'.$FileName, "r"); + } + + if (!($fileHandle) ) { + throw new \Exception('The requested palette '.$FileName.' was not found!'); + } + if ( $Overwrite ) { + $this->Palette = ""; + } + + 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 + * @param type $ID + * @return int + */ + public 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 + * @param type $Serie + */ + public 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; + } + } + + /** + * + * @param type $NormalizationFactor + * @param type $UnitChange + * @param type $Round + */ + public 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 + * @param type $FileName + * @param type $Options + */ + public 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 + * @param type $SerieName + * @param type $Formula + * @param type $Options + * @return int + */ + public 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); } + } + + /** + * + * @param array $Series + */ + public 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 + * @return type + */ + public function getData() + { + return($this->Data); + } + + /** + * Save a palette element + * @param type $ID + * @param type $Color + */ + public function savePalette($ID,$Color) + { + $this->Palette[$ID] = $Color; + } + + /** + * Return the palette of the series + * @return type + */ + public function getPalette() + { + return($this->Palette); + } + + /** + * Called by the scaling algorithm to save the config + * @param type $Axis + */ + public function saveAxisConfig($Axis) + { + $this->Data["Axis"]=$Axis; + } + + /** + * Save the Y Margin if set + * @param type $Value + */ + public function saveYMargin($Value) + { + $this->Data["YMargin"]=$Value; + } + + /** + * Save extended configuration to the pData object + * @param type $Tag + * @param type $Values + */ + public function saveExtendedData($Tag,$Values) + { + $this->Data["Extended"][$Tag]=$Values; + } + + /** + * Called by the scaling algorithm to save the orientation of the scale + * @param type $Orientation + */ + public function saveOrientation($Orientation) + { + $this->Data["Orientation"]=$Orientation; + } + + /** + * Convert a string to a single elements array + * @param type $Value + * @return type + */ + public function convertToArray($Value) + { + $Values = ""; + $Values[] = $Value; + return($Values); + } + + /** + * Class string wrapper + * @return type + */ + public function __toString() + { + return("pData object."); + } + + /** + * + * @param type $value + * @param type $NbChar + * @return type + */ + public function left($value,$NbChar) + { + return substr($value,0,$NbChar); + } + + /** + * + * @param type $value + * @param type $NbChar + * @return type + */ + public function right($value,$NbChar) + { + return substr($value,strlen($value)-$NbChar,$NbChar); + } + + /** + * + * @param type $value + * @param type $Depart + * @param type $NbChar + * @return type + */ + public function mid($value,$Depart,$NbChar) + { + return substr($value,$Depart-1,$NbChar); + } +} diff --git a/vendor/szymach/c-pchart/src/Classes/pDraw.php b/vendor/szymach/c-pchart/src/Classes/pDraw.php new file mode 100644 index 0000000000..308a0cebbf --- /dev/null +++ b/vendor/szymach/c-pchart/src/Classes/pDraw.php @@ -0,0 +1,10715 @@ +fontPath = __DIR__.'/../Resources'; + return; + } elseif (file_exists($fontPath)) { + $this->fontPath = $fontPath; + return; + } + + throw new \Exception('The specified resources folder is not defined!'); + } + + /** + * Check if requested resource exists and return the path to it if yes. + * @param type $name + * @param type $type + * @return type + * @throws \Exception + */ + protected function loadFont($name, $type) + { + if (empty($this->fontPath)) { + $this->setFontPath(); + } + if (file_exists($name)) { + return $name; + } elseif (file_exists($this->fontPath.'/'.$type.'/'.$name)) { + return $this->fontPath.'/'.$type.'/'.$name; + } + + throw new \Exception( + 'The requested resource '.$name.'('.$type.') has not been found!' + ); + } + + /** + * Returns the number of drawable series + * @return type + */ + public function countDrawableSeries() + { + $Results = 0; + $Data = $this->DataSet->getData(); + + foreach($Data["Series"] as $SerieName => $Serie) + { if ( $Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"] ) { $Results++; } } + + return($Results); + } + + /** + * Fix box coordinates + * @param type $Xa + * @param type $Ya + * @param type $Xb + * @param type $Yb + * @return type + */ + public function fixBoxCoordinates($Xa,$Ya,$Xb,$Yb) + { + $X1 = min($Xa,$Xb); $Y1 = min($Ya,$Yb); + $X2 = max($Xa,$Xb); $Y2 = max($Ya,$Yb); + + return(array($X1,$Y1,$X2,$Y2)); + } + + /** + * Draw a polygon + * @param type $Points + * @param type $Format + */ + public function drawPolygon($Points,$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; + $NoFill = isset($Format["NoFill"]) ? $Format["NoFill"] : false; + $NoBorder = isset($Format["NoBorder"]) ? $Format["NoBorder"] : false; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $R; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $G; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $B; + $BorderAlpha = isset($Format["Alpha"]) ? $Format["Alpha"] : $Alpha / 2; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : null; + $SkipX = isset($Format["SkipX"]) ? $Format["SkipX"] : OUT_OF_SIGHT; + $SkipY = isset($Format["SkipY"]) ? $Format["SkipY"] : OUT_OF_SIGHT; + + /* Calling the ImageFilledPolygon() public function over the $Points array will round it */ + $Backup = $Points; + + if ( $Surrounding != null ) { + $BorderR = $R+$Surrounding; + $BorderG = $G+$Surrounding; + $BorderB = $B+$Surrounding; + } + + if ( $SkipX != OUT_OF_SIGHT ) { + $SkipX = floor($SkipX); + } + if ( $SkipY != OUT_OF_SIGHT ) { + $SkipY = floor($SkipY); + } + + $RestoreShadow = $this->Shadow; + if ( !$NoFill ) { + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) { + $this->Shadow = false; + for ($i=0;$i<=count($Points)-1;$i=$i+2) { + $Shadow[] = $Points[$i] + $this->ShadowX; + $Shadow[] = $Points[$i+1] + $this->ShadowY; + } + $this->drawPolygon( + $Shadow, + array("R"=>$this->ShadowR,"G"=>$this->ShadowG,"B"=>$this->ShadowB,"Alpha"=>$this->Shadowa,"NoBorder"=>true) + ); + } + + $FillColor = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha); + + if ( count($Points) >= 6 ) { + ImageFilledPolygon($this->Picture,$Points,count($Points)/2,$FillColor); + } + } + + if ( !$NoBorder ) { + $Points = $Backup; + + if ( $NoFill ) { + $BorderSettings = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha); + } else { + $BorderSettings = array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha); + } + + for($i=0;$i<=count($Points)-1;$i=$i+2) { + if ( isset($Points[$i+2]) ) { + if ( !($Points[$i] == $Points[$i+2] && $Points[$i] == $SkipX ) && !($Points[$i+1] == $Points[$i+3] && $Points[$i+1] == $SkipY ) ) + $this->drawLine($Points[$i],$Points[$i+1],$Points[$i+2],$Points[$i+3],$BorderSettings); + } else { + if (!($Points[$i] == $Points[0] && $Points[$i] == $SkipX ) + && !($Points[$i+1] == $Points[1] && $Points[$i+1] == $SkipY ) + ) { + $this->drawLine($Points[$i],$Points[$i+1],$Points[0],$Points[1],$BorderSettings); + } + } + } + } + + $this->Shadow = $RestoreShadow; + } + + /* Apply AALias correction to the rounded box boundaries */ + public function offsetCorrection($Value,$Mode) + { + $Value = round($Value,1); + + if ( $Value == 0 && $Mode == 1 ) { + return(.9); + } + if ( $Value == 0 ) { + return(0); + } + + if ( $Mode == 1) { + if ( $Value == 1 ) { return(.9); }; if ( $Value == .1 ) { return(.9); }; if ( $Value == .2 ) { return(.8); }; if ( $Value == .3 ) { return(.8); }; if ( $Value == .4 ) { return(.7); }; if ( $Value == .5 ) { return(.5); }; if ( $Value == .6 ) { return(.8); }; if ( $Value == .7 ) { return(.7); }; if ( $Value == .8 ) { return(.6); }; if ( $Value == .9 ) { return(.9); }; } + + if ( $Mode == 2) + { if ( $Value == 1 ) { return(.9); }; if ( $Value == .1 ) { return(.1); }; if ( $Value == .2 ) { return(.2); }; if ( $Value == .3 ) { return(.3); }; if ( $Value == .4 ) { return(.4); }; if ( $Value == .5 ) { return(.5); }; if ( $Value == .6 ) { return(.8); }; if ( $Value == .7 ) { return(.7); }; if ( $Value == .8 ) { return(.8); }; if ( $Value == .9 ) { return(.9); }; } + + if ( $Mode == 3) + { if ( $Value == 1 ) { return(.1); }; if ( $Value == .1 ) { return(.1); }; if ( $Value == .2 ) { return(.2); }; if ( $Value == .3 ) { return(.3); }; if ( $Value == .4 ) { return(.4); }; if ( $Value == .5 ) { return(.9); }; if ( $Value == .6 ) { return(.6); }; if ( $Value == .7 ) { return(.7); }; if ( $Value == .8 ) { return(.4); }; if ( $Value == .9 ) { return(.5); }; } + + if ( $Mode == 4) + { if ( $Value == 1 ) { return(-1); }; if ( $Value == .1 ) { return(.1); }; if ( $Value == .2 ) { return(.2); }; if ( $Value == .3 ) { return(.3); }; if ( $Value == .4 ) { return(.1); }; if ( $Value == .5 ) { return(-.1); }; if ( $Value == .6 ) { return(.8); }; if ( $Value == .7 ) { return(.1); }; if ( $Value == .8 ) { return(.1); }; if ( $Value == .9 ) { return(.1); }; } + } + + /* Draw a rectangle with rounded corners */ + public function drawRoundedRectangle($X1,$Y1,$X2,$Y2,$Radius,$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; + + list($X1,$Y1,$X2,$Y2) = $this->fixBoxCoordinates($X1,$Y1,$X2,$Y2); + + if ( $X2 - $X1 < $Radius ) { $Radius = floor((($X2-$X1))/2); } + if ( $Y2 - $Y1 < $Radius ) { $Radius = floor((($Y2-$Y1))/2); } + + $Color = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"NoBorder"=>true); + + if ( $Radius <= 0 ) { $this->drawRectangle($X1,$Y1,$X2,$Y2,$Color); return(0); } + + if ( $this->Antialias ) { + $this->drawLine($X1+$Radius,$Y1,$X2-$Radius,$Y1,$Color); + $this->drawLine($X2,$Y1+$Radius,$X2,$Y2-$Radius,$Color); + $this->drawLine($X2-$Radius,$Y2,$X1+$Radius,$Y2,$Color); + $this->drawLine($X1,$Y1+$Radius,$X1,$Y2-$Radius,$Color); + } else { + $Color = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha); + imageline($this->Picture,$X1+$Radius,$Y1,$X2-$Radius,$Y1,$Color); + imageline($this->Picture,$X2,$Y1+$Radius,$X2,$Y2-$Radius,$Color); + imageline($this->Picture,$X2-$Radius,$Y2,$X1+$Radius,$Y2,$Color); + imageline($this->Picture,$X1,$Y1+$Radius,$X1,$Y2-$Radius,$Color); + } + + $Step = 360 / (2 * PI * $Radius); + for($i=0;$i<=90;$i=$i+$Step) { + $X = cos(($i+180)*PI/180) * $Radius + $X1 + $Radius; + $Y = sin(($i+180)*PI/180) * $Radius + $Y1 + $Radius; + $this->drawAntialiasPixel($X,$Y,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + + $X = cos(($i+90)*PI/180) * $Radius + $X1 + $Radius; + $Y = sin(($i+90)*PI/180) * $Radius + $Y2 - $Radius; + $this->drawAntialiasPixel($X,$Y,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + + $X = cos($i*PI/180) * $Radius + $X2 - $Radius; + $Y = sin($i*PI/180) * $Radius + $Y2 - $Radius; + $this->drawAntialiasPixel($X,$Y,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + + $X = cos(($i+270)*PI/180) * $Radius + $X2 - $Radius; + $Y = sin(($i+270)*PI/180) * $Radius + $Y1 + $Radius; + $this->drawAntialiasPixel($X,$Y,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + } + } + + /* Draw a rectangle with rounded corners */ + public function drawRoundedFilledRectangle($X1,$Y1,$X2,$Y2,$Radius,$Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : 0; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : -1; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : -1; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : -1; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : null; + + /* Temporary fix for AA issue */ + $Y1 = floor($Y1); $Y2 = floor($Y2); $X1 = floor($X1); $X2 = floor($X2); + + if ( $Surrounding != null ) { $BorderR = $R+$Surrounding; $BorderG = $G+$Surrounding; $BorderB = $B+$Surrounding; } + if ( $BorderR == -1 ) { $BorderR = $R; $BorderG = $G; $BorderB = $B; } + + list($X1,$Y1,$X2,$Y2) = $this->fixBoxCoordinates($X1,$Y1,$X2,$Y2); + + if ( $X2 - $X1 < $Radius*2 ) { $Radius = floor((($X2-$X1))/4); } + if ( $Y2 - $Y1 < $Radius*2 ) { $Radius = floor((($Y2-$Y1))/4); } + + $RestoreShadow = $this->Shadow; + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) { + $this->Shadow = false; + $this->drawRoundedFilledRectangle( + $X1+$this->ShadowX, + $Y1+$this->ShadowY, + $X2+$this->ShadowX, + $Y2+$this->ShadowY, + $Radius, + array("R"=>$this->ShadowR,"G"=>$this->ShadowG,"B"=>$this->ShadowB,"Alpha"=>$this->Shadowa) + ); + } + + $Color = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"NoBorder"=>true); + + if ( $Radius <= 0 ) { + $this->drawFilledRectangle($X1,$Y1,$X2,$Y2,$Color); + return(0); + } + + $YTop = $Y1+$Radius; + $YBottom = $Y2-$Radius; + + $Step = 360 / (2 * PI * $Radius); + $Positions = ""; + $Radius--; + $MinY = ""; + $MaxY = ""; + for ($i=0;$i<=90;$i=$i+$Step) { + $Xp1 = cos(($i+180)*PI/180) * $Radius + $X1 + $Radius; + $Xp2 = cos(((90-$i)+270)*PI/180) * $Radius + $X2 - $Radius; + $Yp = floor(sin(($i+180)*PI/180) * $Radius + $YTop); + if ( $MinY == "" || $Yp > $MinY ) { + $MinY = $Yp; + } + + if ( $Xp1 <= floor($X1) ) { + $Xp1++; + } + if ( $Xp2 >= floor($X2) ) { + $Xp2--; + } + $Xp1++; + + if ( !isset($Positions[$Yp]) ) { + $Positions[$Yp]["X1"] = $Xp1; + $Positions[$Yp]["X2"] = $Xp2; + } else { + $Positions[$Yp]["X1"] = ($Positions[$Yp]["X1"]+$Xp1)/2; + $Positions[$Yp]["X2"] = ($Positions[$Yp]["X2"]+$Xp2)/2; + } + + $Xp1 = cos(($i+90)*PI/180) * $Radius + $X1 + $Radius; + $Xp2 = cos((90-$i)*PI/180) * $Radius + $X2 - $Radius; + $Yp = floor(sin(($i+90)*PI/180) * $Radius + $YBottom); + if ( $MaxY == "" || $Yp < $MaxY ) { + $MaxY = $Yp; + } + + if ( $Xp1 <= floor($X1) ) { + $Xp1++; + } + if ( $Xp2 >= floor($X2) ) { + $Xp2--; + } + $Xp1++; + + if ( !isset($Positions[$Yp]) ) { + $Positions[$Yp]["X1"] = $Xp1; + $Positions[$Yp]["X2"] = $Xp2; + } else { + $Positions[$Yp]["X1"] = ($Positions[$Yp]["X1"]+$Xp1)/2; + $Positions[$Yp]["X2"] = ($Positions[$Yp]["X2"]+$Xp2)/2; + } + } + + $ManualColor = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha); + foreach($Positions as $Yp => $Bounds) { + $X1 = $Bounds["X1"]; + $X1Dec = $this->getFirstDecimal($X1); + if ( $X1Dec != 0 ) { $X1 = floor($X1)+1; } + $X2 = $Bounds["X2"]; + $X2Dec = $this->getFirstDecimal($X2); + if ( $X2Dec != 0 ) { $X2 = floor($X2)-1; } + imageline($this->Picture,$X1,$Yp,$X2,$Yp,$ManualColor); + } + $this->drawFilledRectangle($X1,$MinY+1,floor($X2),$MaxY-1,$Color); + + $Radius++; + $this->drawRoundedRectangle( + $X1, + $Y1, + $X2+1, + $Y2-1, + $Radius, + array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha) + ); + + $this->Shadow = $RestoreShadow; + } + + /** + * Draw a rectangle with rounded corners + * @param type $X1 + * @param type $Y1 + * @param type $X2 + * @param type $Y2 + * @param type $Radius + * @param type $Format + */ + public function drawRoundedFilledRectangle_deprecated($X1,$Y1,$X2,$Y2,$Radius,$Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : 0; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : -1; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : -1; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : -1; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : null; + + if ( $Surrounding != null ) { + $BorderR = $R+$Surrounding; + $BorderG = $G+$Surrounding; + $BorderB = $B+$Surrounding; + } + if ( $BorderR == -1 ) { $BorderR = $R; $BorderG = $G; $BorderB = $B; } + + list($X1,$Y1,$X2,$Y2) = $this->fixBoxCoordinates($X1,$Y1,$X2,$Y2); + + if ( $X2 - $X1 < $Radius ) { $Radius = floor((($X2-$X1)+2)/2); } + if ( $Y2 - $Y1 < $Radius ) { $Radius = floor((($Y2-$Y1)+2)/2); } + + $RestoreShadow = $this->Shadow; + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) { + $this->Shadow = false; + $this->drawRoundedFilledRectangle( + $X1+$this->ShadowX, + $Y1+$this->ShadowY, + $X2+$this->ShadowX, + $Y2+$this->ShadowY, + $Radius, + array("R"=>$this->ShadowR,"G"=>$this->ShadowG,"B"=>$this->ShadowB,"Alpha"=>$this->Shadowa) + ); + } + + if ( $this->getFirstDecimal($X2) >= 5 ) { $XOffset2 = 1; } else { $XOffset2 = 0; } + if ( $this->getFirstDecimal($X1) <= 5 ) { $XOffset1 = 1; } else { $XOffset1 = 0; } + + if ( !$this->Antialias ) { $XOffset1 = 1; $XOffset2 = 1; } + + $YTop = floor($Y1+$Radius); + $YBottom = floor($Y2-$Radius); + + $this->drawFilledRectangle( + $X1-$XOffset1, + $YTop, + $X2+$XOffset2, + $YBottom, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"NoBorder"=>true) + ); + + $Step = 360 / (2 * PI * $Radius); + $Color = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha); + $Color2 = $this->allocateColor($this->Picture,255,0,0,$Alpha); + $Drawn = ""; + + if ( $Alpha < 100 ) { $Drawn[$YTop] = false; } + if ( $Alpha < 100 ) { $Drawn[$YBottom] = true; } + + for($i=0;$i<=90;$i=$i+$Step) { + $Xp1 = cos(($i+180)*PI/180) * $Radius + $X1 + $Radius; + $Xp2 = cos(((90-$i)+270)*PI/180) * $Radius + $X2 - $Radius; + $Yp = sin(($i+180)*PI/180) * $Radius + $YTop; + + if ( $this->getFirstDecimal($Xp1) > 5 ) { $XOffset1 = 1; } else { $XOffset1 = 0; } + if ( $this->getFirstDecimal($Xp2) > 5 ) { $XOffset2 = 1; } else { $XOffset2 = 0; } + if ( $this->getFirstDecimal($Yp) > 5 ) { $YOffset = 1; } else { $YOffset = 0; } + + if ( !isset($Drawn[$Yp+$YOffset]) || $Alpha == 100 ) { + imageline($this->Picture,$Xp1+$XOffset1,$Yp+$YOffset,$Xp2+$XOffset2,$Yp+$YOffset,$Color); + } + $Drawn[$Yp+$YOffset] = $Xp2; + + $Xp1 = cos(($i+90)*PI/180) * $Radius + $X1 + $Radius; + $Xp2 = cos((90-$i)*PI/180) * $Radius + $X2 - $Radius; + $Yp = sin(($i+90)*PI/180) * $Radius + $YBottom; + + if ( $this->getFirstDecimal($Xp1) > 7 ) { $XOffset1 = 1; } else { $XOffset1 = 0; } + if ( $this->getFirstDecimal($Xp2) > 7 ) { $XOffset2 = 1; } else { $XOffset2 = 0; } + if ( $this->getFirstDecimal($Yp) > 5 ) { $YOffset = 1; } else { $YOffset = 0; } + + if ( !isset($Drawn[$Yp+$YOffset]) || $Alpha == 100 ) { + imageline($this->Picture,$Xp1+$XOffset1,$Yp+$YOffset,$Xp2+$XOffset2,$Yp+$YOffset,$Color); + } + $Drawn[$Yp+$YOffset] = $Xp2; + } + + $this->drawRoundedRectangle( + $X1, + $Y1, + $X2, + $Y2, + $Radius, + array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha) + ); + + $this->Shadow = $RestoreShadow; + } + + /** + * Draw a rectangle + * @param type $X1 + * @param type $Y1 + * @param type $X2 + * @param type $Y2 + * @param type $Format + */ + public function drawRectangle($X1,$Y1,$X2,$Y2,$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; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : null; + $NoAngle = isset($Format["NoAngle"]) ? $Format["NoAngle"] : false; + + if ($X1 > $X2) { list($X1, $X2) = array($X2, $X1); } + if ($Y1 > $Y2) { list($Y1, $Y2) = array($Y2, $Y1); } + + if ( $this->Antialias ) { + if ( $NoAngle ) { + $this->drawLine($X1+1,$Y1,$X2-1,$Y1,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + $this->drawLine($X2,$Y1+1,$X2,$Y2-1,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + $this->drawLine($X2-1,$Y2,$X1+1,$Y2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + $this->drawLine($X1,$Y1+1,$X1,$Y2-1,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + } else { + $this->drawLine($X1+1,$Y1,$X2-1,$Y1,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + $this->drawLine($X2,$Y1,$X2,$Y2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + $this->drawLine($X2-1,$Y2,$X1+1,$Y2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + $this->drawLine($X1,$Y1,$X1,$Y2,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + } + } else { + $Color = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha); + imagerectangle($this->Picture,$X1,$Y1,$X2,$Y2,$Color); + } + } + + /** + * Draw a filled rectangle + * @param type $X1 + * @param type $Y1 + * @param type $X2 + * @param type $Y2 + * @param type $Format + */ + public function drawFilledRectangle($X1,$Y1,$X2,$Y2,$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; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : -1; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : -1; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : -1; + $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : $Alpha; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : null; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : null; + $NoAngle = isset($Format["NoAngle"]) ? $Format["NoAngle"] : null; + $Dash = isset($Format["Dash"]) ? $Format["Dash"] : false; + $DashStep = isset($Format["DashStep"]) ? $Format["DashStep"] : 4; + $DashR = isset($Format["DashR"]) ? $Format["DashR"] : 0; + $DashG = isset($Format["DashG"]) ? $Format["DashG"] : 0; + $DashB = isset($Format["DashB"]) ? $Format["DashB"] : 0; + $NoBorder = isset($Format["NoBorder"]) ? $Format["NoBorder"] : false; + + if ( $Surrounding != null ) { + $BorderR = $R+$Surrounding; + $BorderG = $G+$Surrounding; + $BorderB = $B+$Surrounding; + } + + if ($X1 > $X2) { list($X1, $X2) = array($X2, $X1); } + if ($Y1 > $Y2) { list($Y1, $Y2) = array($Y2, $Y1); } + + $RestoreShadow = $this->Shadow; + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) { + $this->Shadow = false; + $this->drawFilledRectangle( + $X1+$this->ShadowX, + $Y1+$this->ShadowY, + $X2+$this->ShadowX, + $Y2+$this->ShadowY, + array( + "R"=>$this->ShadowR, + "G"=>$this->ShadowG, + "B"=>$this->ShadowB, + "Alpha"=>$this->Shadowa, + "Ticks"=>$Ticks, + "NoAngle"=>$NoAngle + ) + ); + } + + $Color = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha); + if ( $NoAngle ) { + imagefilledrectangle($this->Picture,ceil($X1)+1,ceil($Y1),floor($X2)-1,floor($Y2),$Color); + imageline($this->Picture,ceil($X1),ceil($Y1)+1,ceil($X1),floor($Y2)-1,$Color); + imageline($this->Picture,floor($X2),ceil($Y1)+1,floor($X2),floor($Y2)-1,$Color); + } else { + imagefilledrectangle($this->Picture,ceil($X1),ceil($Y1),floor($X2),floor($Y2),$Color); + } + if ( $Dash ) { + if ( $BorderR != -1 ) { + $iX1=$X1+1; + $iY1=$Y1+1; + $iX2=$X2-1; + $iY2=$Y2-1; + } else { + $iX1=$X1; + $iY1=$Y1; + $iX2=$X2; + $iY2=$Y2; + } + + $Color = $this->allocateColor($this->Picture,$DashR,$DashG,$DashB,$Alpha); + $Y=$iY1-$DashStep; + for($X=$iX1; $X<=$iX2+($iY2-$iY1); $X=$X+$DashStep) { + $Y=$Y+$DashStep; + if ( $X > $iX2 ) { $Xa = $X-($X-$iX2); $Ya = $iY1+($X-$iX2); } else { $Xa = $X; $Ya = $iY1; } + if ( $Y > $iY2 ) { $Xb = $iX1+($Y-$iY2); $Yb = $Y-($Y-$iY2); } else { $Xb = $iX1; $Yb = $Y; } + imageline($this->Picture,$Xa,$Ya,$Xb,$Yb,$Color); + } + } + + if ( $this->Antialias && !$NoBorder ) { + if ( $X1 < ceil($X1) ) { + $AlphaA = $Alpha * (ceil($X1) - $X1); + $Color = $this->allocateColor($this->Picture,$R,$G,$B,$AlphaA); + imageline($this->Picture,ceil($X1)-1,ceil($Y1),ceil($X1)-1,floor($Y2),$Color); + } + + if ( $Y1 < ceil($Y1) ) { + $AlphaA = $Alpha * (ceil($Y1) - $Y1); + $Color = $this->allocateColor($this->Picture,$R,$G,$B,$AlphaA); + imageline($this->Picture,ceil($X1),ceil($Y1)-1,floor($X2),ceil($Y1)-1,$Color); + } + + if ( $X2 > floor($X2) ) { + $AlphaA = $Alpha * (.5-($X2 - floor($X2))); + $Color = $this->allocateColor($this->Picture,$R,$G,$B,$AlphaA); + imageline($this->Picture,floor($X2)+1,ceil($Y1),floor($X2)+1,floor($Y2),$Color); + } + + if ( $Y2 > floor($Y2) ) { + $AlphaA = $Alpha * (.5-($Y2 - floor($Y2))); + $Color = $this->allocateColor($this->Picture,$R,$G,$B,$AlphaA); + imageline($this->Picture,ceil($X1),floor($Y2)+1,floor($X2),floor($Y2)+1,$Color); + } + } + + if ( $BorderR != -1 ) { + $this->drawRectangle( + $X1, + $Y1, + $X2, + $Y2, + array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$Ticks,"NoAngle"=>$NoAngle) + ); + } + $this->Shadow = $RestoreShadow; + } + + /** + * Draw a rectangular marker of the specified size + * @param type $X + * @param type $Y + * @param type $Format + */ + public function drawRectangleMarker($X,$Y,$Format="") + { + $Size = isset($Format["Size"]) ? $Format["Size"] : 4; + + $HalfSize = floor($Size/2); + $this->drawFilledRectangle($X-$HalfSize,$Y-$HalfSize,$X+$HalfSize,$Y+$HalfSize,$Format); + } + + /** + * Drawn a spline based on the bezier public function + * @param type $Coordinates + * @param type $Format + * @return type + */ + public function drawSpline($Coordinates,$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; + $Force = isset($Format["Force"]) ? $Format["Force"] : 30; + $Forces = isset($Format["Forces"]) ? $Format["Forces"] : null; + $ShowC = isset($Format["ShowControl"]) ? $Format["ShowControl"] : false; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : null; + $PathOnly = isset($Format["PathOnly"]) ? $Format["PathOnly"] : false; + $Weight = isset($Format["Weight"]) ? $Format["Weight"] : null; + + $Cpt = null; $Mode = null; $Result = ""; + for ($i=1;$i<=count($Coordinates)-1;$i++) { + $X1 = $Coordinates[$i-1][0]; $Y1 = $Coordinates[$i-1][1]; + $X2 = $Coordinates[$i][0]; $Y2 = $Coordinates[$i][1]; + + if ( $Forces != null ) { $Force = $Forces[$i]; } + + /* First segment */ + if ( $i == 1 ) { + $Xv1 = $X1; + $Yv1 = $Y1; + } else { + $Angle1 = $this->getAngle($XLast,$YLast,$X1,$Y1); + $Angle2 = $this->getAngle($X1,$Y1,$X2,$Y2); + $XOff = cos($Angle2 * PI / 180) * $Force + $X1; + $YOff = sin($Angle2 * PI / 180) * $Force + $Y1; + + $Xv1 = cos($Angle1 * PI / 180) * $Force + $XOff; + $Yv1 = sin($Angle1 * PI / 180) * $Force + $YOff; + } + + /* Last segment */ + if ( $i == count($Coordinates)-1 ) { + $Xv2 = $X2; + $Yv2 = $Y2; + } else { + $Angle1 = $this->getAngle($X2,$Y2,$Coordinates[$i+1][0],$Coordinates[$i+1][1]); + $Angle2 = $this->getAngle($X1,$Y1,$X2,$Y2); + $XOff = cos(($Angle2+180) * PI / 180) * $Force + $X2; + $YOff = sin(($Angle2+180) * PI / 180) * $Force + $Y2; + + $Xv2 = cos(($Angle1+180) * PI / 180) * $Force + $XOff; + $Yv2 = sin(($Angle1+180) * PI / 180) * $Force + $YOff; + } + + $Path = $this->drawBezier($X1,$Y1,$X2,$Y2,$Xv1,$Yv1,$Xv2,$Yv2,$Format); + if ($PathOnly) { + $Result[] = $Path; + } + + $XLast = $X1; $YLast = $Y1; + } + + return($Result); + } + + /** + * Draw a bezier curve with two controls points + * @param type $X1 + * @param type $Y1 + * @param type $X2 + * @param type $Y2 + * @param type $Xv1 + * @param type $Yv1 + * @param type $Xv2 + * @param type $Yv2 + * @param type $Format + * @return type + */ + public function drawBezier($X1,$Y1,$X2,$Y2,$Xv1,$Yv1,$Xv2,$Yv2,$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; + $ShowC = isset($Format["ShowControl"]) ? $Format["ShowControl"] : false; + $Segments = isset($Format["Segments"]) ? $Format["Segments"] : null; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : null; + $NoDraw = isset($Format["NoDraw"]) ? $Format["NoDraw"] : false; + $PathOnly = isset($Format["PathOnly"]) ? $Format["PathOnly"] : false; + $Weight = isset($Format["Weight"]) ? $Format["Weight"] : null; + $DrawArrow = isset($Format["DrawArrow"]) ? $Format["DrawArrow"] : false; + $ArrowSize = isset($Format["ArrowSize"]) ? $Format["ArrowSize"] : 10; + $ArrowRatio = isset($Format["ArrowRatio"]) ? $Format["ArrowRatio"] : .5; + $ArrowTwoHeads = isset($Format["ArrowTwoHeads"]) ? $Format["ArrowTwoHeads"] : false; + + if ( $Segments == null ) { + $Length = $this->getLength($X1,$Y1,$X2,$Y2); + $Precision = ($Length*125)/1000; + } else { + $Precision = $Segments; + } + $P[0]["X"] = $X1; + $P[0]["Y"] = $Y1; + $P[1]["X"] = $Xv1; + $P[1]["Y"] = $Yv1; + $P[2]["X"] = $Xv2; + $P[2]["Y"] = $Yv2; + $P[3]["X"] = $X2; + $P[3]["Y"] = $Y2; + + /* Compute the bezier points */ + $Q = ""; $ID = 0; $Path = ""; + for ($i=0;$i<=$Precision;$i=$i+1) { + $u = $i / $Precision; + + $C = ""; + $C[0] = (1 - $u) * (1 - $u) * (1 - $u); + $C[1] = ($u * 3) * (1 - $u) * (1 - $u); + $C[2] = 3 * $u * $u * (1 - $u); + $C[3] = $u * $u * $u; + + for($j=0;$j<=3;$j++) { + if ( !isset($Q[$ID]) ) { $Q[$ID] = ""; } + if ( !isset($Q[$ID]["X"]) ) { $Q[$ID]["X"] = 0; } + if ( !isset($Q[$ID]["Y"]) ) { $Q[$ID]["Y"] = 0; } + + $Q[$ID]["X"] = $Q[$ID]["X"] + $P[$j]["X"] * $C[$j]; + $Q[$ID]["Y"] = $Q[$ID]["Y"] + $P[$j]["Y"] * $C[$j]; + } + $ID++; + } + $Q[$ID]["X"] = $X2; $Q[$ID]["Y"] = $Y2; + + if ( !$NoDraw ) { + /* Display the control points */ + if ( $ShowC && !$PathOnly ) { + $Xv1 = floor($Xv1); $Yv1 = floor($Yv1); $Xv2 = floor($Xv2); $Yv2 = floor($Yv2); + + $this->drawLine($X1,$Y1,$X2,$Y2,array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>30)); + + $MyMarkerSettings = array("R"=>255,"G"=>0,"B"=>0,"BorderR"=>255,"BorderB"=>255,"BorderG"=>255,"Size"=>4); + $this->drawRectangleMarker($Xv1,$Yv1,$MyMarkerSettings); + $this->drawText($Xv1+4,$Yv1,"v1"); + $MyMarkerSettings = array("R"=>0,"G"=>0,"B"=>255,"BorderR"=>255,"BorderB"=>255,"BorderG"=>255,"Size"=>4); + $this->drawRectangleMarker($Xv2,$Yv2,$MyMarkerSettings); + $this->drawText($Xv2+4,$Yv2,"v2"); + } + + /* Draw the bezier */ + $LastX = null; + $LastY = null; + $Cpt = null; + $Mode = null; + $ArrowS = null; + foreach ($Q as $Key => $Point) { + $X = $Point["X"]; + $Y = $Point["Y"]; + + /* Get the first segment */ + if ( $ArrowS == null && $LastX != null && $LastY != null ) { + $ArrowS["X2"] = $LastX; + $ArrowS["Y2"] = $LastY; + $ArrowS["X1"] = $X; + $ArrowS["Y1"] = $Y; + } + + if ( $LastX != null && $LastY != null && !$PathOnly) { + list($Cpt,$Mode) = $this->drawLine( + $LastX, + $LastY, + $X, + $Y, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Cpt"=>$Cpt,"Mode"=>$Mode,"Weight"=>$Weight) + ); + } + /* Get the last segment */ + $ArrowE["X1"] = $LastX; + $ArrowE["Y1"] = $LastY; + $ArrowE["X2"] = $X; + $ArrowE["Y2"] = $Y; + + $LastX = $X; + $LastY = $Y; + } + + if ( $DrawArrow && !$PathOnly ) { + $ArrowSettings = array("FillR"=>$R,"FillG"=>$G,"FillB"=>$B,"Alpha"=>$Alpha,"Size"=>$ArrowSize,"Ratio"=>$ArrowRatio); + if ( $ArrowTwoHeads ) { + $this->drawArrow($ArrowS["X1"],$ArrowS["Y1"],$ArrowS["X2"],$ArrowS["Y2"],$ArrowSettings); + } + $this->drawArrow($ArrowE["X1"],$ArrowE["Y1"],$ArrowE["X2"],$ArrowE["Y2"],$ArrowSettings); + } + } + return($Q); + } + + /** + * Draw a line between two points + * @param type $X1 + * @param type $Y1 + * @param type $X2 + * @param type $Y2 + * @param type $Format + * @return type + */ + public function drawLine($X1,$Y1,$X2,$Y2,$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; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : null; + $Cpt = isset($Format["Cpt"]) ? $Format["Cpt"] : 1; + $Mode = isset($Format["Mode"]) ? $Format["Mode"] : 1; + $Weight = isset($Format["Weight"]) ? $Format["Weight"] : null; + $Threshold = isset($Format["Threshold"]) ? $Format["Threshold"] : null; + + if ( $this->Antialias == false && $Ticks == null ) { + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) { + $ShadowColor = $this->allocateColor( + $this->Picture, + $this->ShadowR, + $this->ShadowG, + $this->ShadowB, + $this->Shadowa + ); + imageline( + $this->Picture, + $X1+$this->ShadowX, + $Y1+$this->ShadowY, + $X2+$this->ShadowX, + $Y2+$this->ShadowY, + $ShadowColor + ); + } + + $Color = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha); + imageline($this->Picture,$X1,$Y1,$X2,$Y2,$Color); + return(0); + } + + $Distance = sqrt(($X2-$X1)*($X2-$X1)+($Y2-$Y1)*($Y2-$Y1)); + if ( $Distance == 0 ) { return(-1); } + + /* Derivative algorithm for overweighted lines, re-route to polygons primitives */ + if ( $Weight != null ) { + $Angle = $this->getAngle($X1,$Y1,$X2,$Y2); + $PolySettings = array ("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"BorderAlpha"=>$Alpha); + + if ( $Ticks == null ) { + $Points = ""; + $Points[] = cos(deg2rad($Angle-90)) * $Weight + $X1; $Points[] = sin(deg2rad($Angle-90)) * $Weight + $Y1; + $Points[] = cos(deg2rad($Angle+90)) * $Weight + $X1; $Points[] = sin(deg2rad($Angle+90)) * $Weight + $Y1; + $Points[] = cos(deg2rad($Angle+90)) * $Weight + $X2; $Points[] = sin(deg2rad($Angle+90)) * $Weight + $Y2; + $Points[] = cos(deg2rad($Angle-90)) * $Weight + $X2; $Points[] = sin(deg2rad($Angle-90)) * $Weight + $Y2; + + $this->drawPolygon($Points,$PolySettings); + } else { + for($i=0;$i<=$Distance;$i=$i+$Ticks*2) { + $Xa = (($X2-$X1)/$Distance) * $i + $X1; $Ya = (($Y2-$Y1)/$Distance) * $i + $Y1; + $Xb = (($X2-$X1)/$Distance) * ($i+$Ticks) + $X1; $Yb = (($Y2-$Y1)/$Distance) * ($i+$Ticks) + $Y1; + + $Points = ""; + $Points[] = cos(deg2rad($Angle-90)) * $Weight + $Xa; $Points[] = sin(deg2rad($Angle-90)) * $Weight + $Ya; + $Points[] = cos(deg2rad($Angle+90)) * $Weight + $Xa; $Points[] = sin(deg2rad($Angle+90)) * $Weight + $Ya; + $Points[] = cos(deg2rad($Angle+90)) * $Weight + $Xb; $Points[] = sin(deg2rad($Angle+90)) * $Weight + $Yb; + $Points[] = cos(deg2rad($Angle-90)) * $Weight + $Xb; $Points[] = sin(deg2rad($Angle-90)) * $Weight + $Yb; + + $this->drawPolygon($Points,$PolySettings); + } + } + + return(1); + } + + $XStep = ($X2-$X1) / $Distance; + $YStep = ($Y2-$Y1) / $Distance; + + for($i=0;$i<=$Distance;$i++) { + $X = $i * $XStep + $X1; + $Y = $i * $YStep + $Y1; + + $Color = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha); + + if ( $Threshold != null ) { + foreach($Threshold as $Key => $Parameters) { + if ( $Y <= $Parameters["MinX"] && $Y >= $Parameters["MaxX"]) { + if ( isset($Parameters["R"]) ) { $RT = $Parameters["R"]; } else { $RT = 0; } + if ( isset($Parameters["G"]) ) { $GT = $Parameters["G"]; } else { $GT = 0; } + if ( isset($Parameters["B"]) ) { $BT = $Parameters["B"]; } else { $BT = 0; } + if ( isset($Parameters["Alpha"]) ) { $AlphaT = $Parameters["Alpha"]; } else { $AlphaT = 0; } + $Color = array("R"=>$RT,"G"=>$GT,"B"=>$BT,"Alpha"=>$AlphaT); + } + } + } + + if ( $Ticks != null ) { + if ( $Cpt % $Ticks == 0 ) { + $Cpt = 0; + if ( $Mode == 1 ) { + $Mode = 0; + } else { + $Mode = 1; + } + } + + if ( $Mode == 1 ) { + $this->drawAntialiasPixel($X,$Y,$Color); + } + $Cpt++; + } else { + $this->drawAntialiasPixel($X,$Y,$Color); + } + } + + return(array($Cpt,$Mode)); + } + + /** + * Draw a circle + * @param type $Xc + * @param type $Yc + * @param type $Height + * @param type $Width + * @param type $Format + */ + public function drawCircle($Xc,$Yc,$Height,$Width,$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; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : null; + + $Height = abs($Height); + $Width = abs($Width); + + if ( $Height == 0 ) { $Height = 1; } + if ( $Width == 0 ) { $Width = 1; } + $Xc = floor($Xc); $Yc = floor($Yc); + + $RestoreShadow = $this->Shadow; + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) { + $this->Shadow = false; + $this->drawCircle( + $Xc+$this->ShadowX, + $Yc+$this->ShadowY, + $Height, + $Width, + array("R"=>$this->ShadowR,"G"=>$this->ShadowG,"B"=>$this->ShadowB,"Alpha"=>$this->Shadowa,"Ticks"=>$Ticks) + ); + } + + if ( $Width == 0 ) { $Width = $Height; } + if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } + if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } + if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } + + $Step = 360 / (2 * PI * max($Width,$Height)); + $Mode = 1; + $Cpt = 1; + for ($i=0;$i<=360;$i=$i+$Step) { + $X = cos($i*PI/180) * $Height + $Xc; + $Y = sin($i*PI/180) * $Width + $Yc; + + if ( $Ticks != null ) { + if ( $Cpt % $Ticks == 0 ) { + $Cpt = 0; + if ( $Mode == 1 ) { $Mode = 0; } else { $Mode = 1; } + } + + if ( $Mode == 1 ) { + $this->drawAntialiasPixel($X,$Y,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + } + $Cpt++; + } else { + $this->drawAntialiasPixel($X,$Y,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + } + } + $this->Shadow = $RestoreShadow; + } + + /** + * Draw a filled circle + * @param type $X + * @param type $Y + * @param type $Radius + * @param type $Format + */ + public function drawFilledCircle($X,$Y,$Radius,$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; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : -1; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : -1; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : -1; + $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : $Alpha; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : null; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : null; + + if ( $Radius == 0 ) { $Radius = 1; } + if ( $Surrounding != null ) { + $BorderR = $R+$Surrounding; + $BorderG = $G+$Surrounding; + $BorderB = $B+$Surrounding; + } + $X = floor($X); $Y = floor($Y); + + $Radius = abs($Radius); + + $RestoreShadow = $this->Shadow; + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) { + $this->Shadow = false; + $this->drawFilledCircle( + $X+$this->ShadowX, + $Y+$this->ShadowY, + $Radius, + array("R"=>$this->ShadowR,"G"=>$this->ShadowG,"B"=>$this->ShadowB,"Alpha"=>$this->Shadowa,"Ticks"=>$Ticks) + ); + } + + $this->Mask = ""; + $Color = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha); + for ($i=0; $i<=$Radius*2; $i++) { + $Slice = sqrt($Radius * $Radius - ($Radius - $i) * ($Radius - $i)); + $XPos = floor($Slice); + $YPos = $Y + $i - $Radius; + $AAlias = $Slice - floor($Slice); + + $this->Mask[$X-$XPos][$YPos] = true; + $this->Mask[$X+$XPos][$YPos] = true; + imageline($this->Picture,$X-$XPos,$YPos,$X+$XPos,$YPos,$Color); + } + if ( $this->Antialias ) { + $this->drawCircle($X,$Y,$Radius,$Radius,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + } + $this->Mask = ""; + + if ( $BorderR != -1 ) { + $this->drawCircle($X,$Y,$Radius,$Radius,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$Ticks)); + } + $this->Shadow = $RestoreShadow; + } + + /** + * Write text + * @param type $X + * @param type $Y + * @param type $Text + * @param type $Format + * @return type + */ + public function drawText($X,$Y,$Text,$Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : $this->FontColorR; + $G = isset($Format["G"]) ? $Format["G"] : $this->FontColorG; + $B = isset($Format["B"]) ? $Format["B"] : $this->FontColorB; + $Angle = isset($Format["Angle"]) ? $Format["Angle"] : 0; + $Align = isset($Format["Align"]) ? $Format["Align"] : TEXT_ALIGN_BOTTOMLEFT; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : $this->FontColorA; + $FontName = isset($Format["FontName"]) + ? $this->loadFont($Format["FontName"], 'fonts') + : $this->FontName; + $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->FontSize; + $ShowOrigine = isset($Format["ShowOrigine"]) ? $Format["ShowOrigine"] : false; + $TOffset = isset($Format["TOffset"]) ? $Format["TOffset"] : 2; + $DrawBox = isset($Format["DrawBox"]) ? $Format["DrawBox"] : false; + $DrawBoxBorder = isset($Format["DrawBoxBorder"]) ? $Format["DrawBoxBorder"] : true; + $BorderOffset = isset($Format["BorderOffset"]) ? $Format["BorderOffset"] : 6; + $BoxRounded = isset($Format["BoxRounded"]) ? $Format["BoxRounded"] : false; + $RoundedRadius = isset($Format["RoundedRadius"]) ? $Format["RoundedRadius"] : 6; + $BoxR = isset($Format["BoxR"]) ? $Format["BoxR"] : 255; + $BoxG = isset($Format["BoxG"]) ? $Format["BoxG"] : 255; + $BoxB = isset($Format["BoxB"]) ? $Format["BoxB"] : 255; + $BoxAlpha = isset($Format["BoxAlpha"]) ? $Format["BoxAlpha"] : 50; + $BoxSurrounding = isset($Format["BoxSurrounding"]) ? $Format["BoxSurrounding"] : ""; + $BoxBorderR = isset($Format["BoxR"]) ? $Format["BoxR"] : 0; + $BoxBorderG = isset($Format["BoxG"]) ? $Format["BoxG"] : 0; + $BoxBorderB = isset($Format["BoxB"]) ? $Format["BoxB"] : 0; + $BoxBorderAlpha = isset($Format["BoxAlpha"]) ? $Format["BoxAlpha"] : 50; + $NoShadow = isset($Format["NoShadow"]) ? $Format["NoShadow"] : false; + + $Shadow = $this->Shadow; + if ( $NoShadow ) { $this->Shadow = false; } + + if ( $BoxSurrounding != "" ) { + $BoxBorderR = $BoxR - $BoxSurrounding; + $BoxBorderG = $BoxG - $BoxSurrounding; + $BoxBorderB = $BoxB - $BoxSurrounding; + $BoxBorderAlpha = $BoxAlpha; + } + + if ( $ShowOrigine ) { + $MyMarkerSettings = array( + "R"=>255, + "G"=>0, + "B"=>0, + "BorderR"=>255, + "BorderB"=>255, + "BorderG"=>255, + "Size"=>4 + ); + $this->drawRectangleMarker($X,$Y,$MyMarkerSettings); + } + + $TxtPos = $this->getTextBox($X,$Y,$FontName,$FontSize,$Angle,$Text); + + if ($DrawBox && ($Angle == 0 || $Angle == 90 || $Angle == 180 || $Angle == 270)) { + $T[0]["X"]=0; + $T[0]["Y"]=0; + $T[1]["X"]=0; + $T[1]["Y"]=0; + $T[2]["X"]=0; + $T[2]["Y"]=0; + $T[3]["X"]=0; + $T[3]["Y"]=0; + if ( $Angle == 0 ) { + $T[0]["X"]=-$TOffset; + $T[0]["Y"]=$TOffset; + $T[1]["X"]=$TOffset; + $T[1]["Y"]=$TOffset; + $T[2]["X"]=$TOffset; + $T[2]["Y"]=-$TOffset; + $T[3]["X"]=-$TOffset; + $T[3]["Y"]=-$TOffset; + } + + $X1 = min($TxtPos[0]["X"],$TxtPos[1]["X"],$TxtPos[2]["X"],$TxtPos[3]["X"]) - $BorderOffset + 3; + $Y1 = min($TxtPos[0]["Y"],$TxtPos[1]["Y"],$TxtPos[2]["Y"],$TxtPos[3]["Y"]) - $BorderOffset; + $X2 = max($TxtPos[0]["X"],$TxtPos[1]["X"],$TxtPos[2]["X"],$TxtPos[3]["X"]) + $BorderOffset + 3; + $Y2 = max($TxtPos[0]["Y"],$TxtPos[1]["Y"],$TxtPos[2]["Y"],$TxtPos[3]["Y"]) + $BorderOffset - 3; + + $X1 = $X1 - $TxtPos[$Align]["X"] + $X + $T[0]["X"]; + $Y1 = $Y1 - $TxtPos[$Align]["Y"] + $Y + $T[0]["Y"]; + $X2 = $X2 - $TxtPos[$Align]["X"] + $X + $T[0]["X"]; + $Y2 = $Y2 - $TxtPos[$Align]["Y"] + $Y + $T[0]["Y"]; + + $Settings = array( + "R"=>$BoxR, + "G"=>$BoxG, + "B"=>$BoxB, + "Alpha"=>$BoxAlpha, + "BorderR"=>$BoxBorderR, + "BorderG"=>$BoxBorderG, + "BorderB"=>$BoxBorderB, + "BorderAlpha"=>$BoxBorderAlpha + ); + + if ( $BoxRounded ) { + $this->drawRoundedFilledRectangle($X1,$Y1,$X2,$Y2,$RoundedRadius,$Settings); + } else { + $this->drawFilledRectangle($X1,$Y1,$X2,$Y2,$Settings); + } + } + + $X = $X - $TxtPos[$Align]["X"] + $X; + $Y = $Y - $TxtPos[$Align]["Y"] + $Y; + + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) { + $C_ShadowColor = $this->allocateColor( + $this->Picture, + $this->ShadowR, + $this->ShadowG, + $this->ShadowB, + $this->Shadowa + ); + imagettftext( + $this->Picture, + $FontSize, + $Angle, + $X+$this->ShadowX, + $Y+$this->ShadowY, + $C_ShadowColor, + $FontName, + $Text + ); + } + + $C_TextColor = $this->AllocateColor($this->Picture,$R,$G,$B,$Alpha); + imagettftext($this->Picture,$FontSize,$Angle,$X,$Y,$C_TextColor,$FontName,$Text); + + $this->Shadow = $Shadow; + + return($TxtPos); + } + + /** + * Draw a gradient within a defined area + * @param type $X1 + * @param type $Y1 + * @param type $X2 + * @param type $Y2 + * @param type $Direction + * @param type $Format + * @return type + */ + public function drawGradientArea($X1,$Y1,$X2,$Y2,$Direction,$Format="") + { + $StartR = isset($Format["StartR"]) ? $Format["StartR"] : 90; + $StartG = isset($Format["StartG"]) ? $Format["StartG"] : 90; + $StartB = isset($Format["StartB"]) ? $Format["StartB"] : 90; + $EndR = isset($Format["EndR"]) ? $Format["EndR"] : 0; + $EndG = isset($Format["EndG"]) ? $Format["EndG"] : 0; + $EndB = isset($Format["EndB"]) ? $Format["EndB"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $Levels = isset($Format["Levels"]) ? $Format["Levels"] : null; + + $Shadow = $this->Shadow; + $this->Shadow = false; + + if ( $StartR == $EndR && $StartG == $EndG && $StartB == $EndB ) { + $this->drawFilledRectangle($X1,$Y1,$X2,$Y2,array("R"=>$StartR,"G"=>$StartG,"B"=>$StartB,"Alpha"=>$Alpha)); + return(0); + } + + if ( $Levels != null ) { + $EndR=$StartR+$Levels; $EndG=$StartG+$Levels; $EndB=$StartB+$Levels; + } + + if ($X1 > $X2) { list($X1, $X2) = array($X2, $X1); } + if ($Y1 > $Y2) { list($Y1, $Y2) = array($Y2, $Y1); } + + if ( $Direction == DIRECTION_VERTICAL ) { $Width = abs($Y2-$Y1); } + if ( $Direction == DIRECTION_HORIZONTAL ) { $Width = abs($X2-$X1); } + + $Step = max(abs($EndR-$StartR),abs($EndG-$StartG),abs($EndB-$StartB)); + $StepSize = $Width/$Step; + $RStep = ($EndR-$StartR)/$Step; + $GStep = ($EndG-$StartG)/$Step; + $BStep = ($EndB-$StartB)/$Step; + + $R=$StartR; + $G=$StartG; + $B=$StartB; + switch($Direction) { + case DIRECTION_VERTICAL: + $StartY = $Y1; + $EndY = floor($Y2)+1; + $LastY2 = $StartY; + for ($i=0;$i<=$Step;$i++) { + $Y2 = floor($StartY + ($i * $StepSize)); + + if ($Y2 > $EndY) { $Y2 = $EndY; } + if (($Y1 != $Y2 && $Y1 < $Y2) || $Y2 == $EndY) { + $Color = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha); + $this->drawFilledRectangle($X1,$Y1,$X2,$Y2,$Color); + $LastY2 = max($LastY2,$Y2); + $Y1 = $Y2+1; + } + $R = $R + $RStep; + $G = $G + $GStep; + $B = $B + $BStep; + } + if ( $LastY2 < $EndY && isset($Color)) { + for ($i=$LastY2+1;$i<=$EndY;$i++) { + $this->drawLine($X1,$i,$X2,$i,$Color); + } + } + break; + + case DIRECTION_HORIZONTAL: + $StartX = $X1; $EndX = $X2; + for ($i=0;$i<=$Step;$i++) { + $X2 = floor($StartX + ($i * $StepSize)); + + if ($X2 > $EndX) { + $X2 = $EndX; + } + if (($X1 != $X2 && $X1 < $X2) || $X2 == $EndX) { + $Color = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha); + $this->drawFilledRectangle($X1,$Y1,$X2,$Y2,$Color); + $X1 = $X2+1; + } + $R = $R + $RStep; $G = $G + $GStep; $B = $B + $BStep; + } + if ( $X2 < $EndX && isset($Color)) { + $this->drawFilledRectangle($X2,$Y1,$EndX,$Y2,$Color); + } + break; + } + + $this->Shadow = $Shadow; + + } + + /** + * Draw an aliased pixel + * @param type $X + * @param type $Y + * @param type $Format + * @return type + */ + public function drawAntialiasPixel($X,$Y,$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 ( $X < 0 || $Y < 0 || $X >= $this->XSize || $Y >= $this->YSize ) + return(-1); + + if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } + if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } + if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } + + if ( !$this->Antialias ) { + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) { + $ShadowColor = $this->allocateColor( + $this->Picture, + $this->ShadowR, + $this->ShadowG, + $this->ShadowB, + $this->Shadowa + ); + imagesetpixel($this->Picture,$X+$this->ShadowX,$Y+$this->ShadowY,$ShadowColor); + } + + $PlotColor = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha); + imagesetpixel($this->Picture,$X,$Y,$PlotColor); + + return(0); + } + + $Plot = ""; + $Xi = floor($X); + $Yi = floor($Y); + + if ( $Xi == $X && $Yi == $Y) { + if ( $Alpha == 100 ) { + $this->drawAlphaPixel($X,$Y,100,$R,$G,$B); + } else { + $this->drawAlphaPixel($X,$Y,$Alpha,$R,$G,$B); + } + } else { + $Alpha1 = (((1 - ($X - floor($X))) * (1 - ($Y - floor($Y))) * 100) / 100) * $Alpha; + if ( $Alpha1 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi,$Yi,$Alpha1,$R,$G,$B); } + + $Alpha2 = ((($X - floor($X)) * (1 - ($Y - floor($Y))) * 100) / 100) * $Alpha; + if ( $Alpha2 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi+1,$Yi,$Alpha2,$R,$G,$B); } + + $Alpha3 = (((1 - ($X - floor($X))) * ($Y - floor($Y)) * 100) / 100) * $Alpha; + if ( $Alpha3 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi,$Yi+1,$Alpha3,$R,$G,$B); } + + $Alpha4 = ((($X - floor($X)) * ($Y - floor($Y)) * 100) / 100) * $Alpha; + if ( $Alpha4 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi+1,$Yi+1,$Alpha4,$R,$G,$B); } + } + } + + /** + * Draw a semi-transparent pixel + * @param type $X + * @param type $Y + * @param type $Alpha + * @param type $R + * @param type $G + * @param type $B + * @return type + */ + public function drawAlphaPixel($X,$Y,$Alpha,$R,$G,$B) + { + if ( isset($this->Mask[$X])) { + if ( isset($this->Mask[$X][$Y]) ) { + return(0); + } + } + + if ( $X < 0 || $Y < 0 || $X >= $this->XSize || $Y >= $this->YSize ) { + return(-1); + } + if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } + if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } + if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } + + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) { + $AlphaFactor = floor(($Alpha / 100) * $this->Shadowa); + $ShadowColor = $this->allocateColor( + $this->Picture, + $this->ShadowR, + $this->ShadowG, + $this->ShadowB, + $AlphaFactor + ); + imagesetpixel($this->Picture,$X+$this->ShadowX,$Y+$this->ShadowY,$ShadowColor); + } + + $C_Aliased = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha); + imagesetpixel($this->Picture,$X,$Y,$C_Aliased); + } + + /** + * Convert apha to base 10 + * @param type $AlphaValue + * @return type + */ + public function convertAlpha($AlphaValue) + { return((127/100)*(100-$AlphaValue)); } + + /** + * Allocate a color with transparency + * @param type $Picture + * @param type $R + * @param type $G + * @param type $B + * @param type $Alpha + * @return type + */ + public function allocateColor($Picture,$R,$G,$B,$Alpha=100) + { + if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } + if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } + if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } + if ( $Alpha < 0 ) { $Alpha = 0; } + if ( $Alpha > 100) { $Alpha = 100; } + + $Alpha = $this->convertAlpha($Alpha); + return(imagecolorallocatealpha($Picture,$R,$G,$B,$Alpha)); + } + + /** + * Load a PNG file and draw it over the chart + * @param type $X + * @param type $Y + * @param type $FileName + */ + public function drawFromPNG($X,$Y,$FileName) + { $this->drawFromPicture(1,$FileName,$X,$Y); } + + /** + * Load a GIF file and draw it over the chart + * @param type $X + * @param type $Y + * @param type $FileName + */ + public function drawFromGIF($X,$Y,$FileName) + { $this->drawFromPicture(2,$FileName,$X,$Y); } + + /** + * Load a JPEG file and draw it over the chart + * @param type $X + * @param type $Y + * @param type $FileName + */ + public function drawFromJPG($X,$Y,$FileName) + { $this->drawFromPicture(3,$FileName,$X,$Y); } + + /** + * + * @param type $FileName + * @return type + */ + public function getPicInfo($FileName) + { + $Infos = getimagesize($FileName); + $Width = $Infos[0]; + $Height = $Infos[1]; + $Type = $Infos["mime"]; + + if ( $Type == "image/png") { $Type = 1; } + if ( $Type == "image/gif") { $Type = 2; } + if ( $Type == "image/jpeg ") { $Type = 3; } + + return(array($Width,$Height,$Type)); + } + + /** + * Generic loader public function for external pictures + * @param type $PicType + * @param type $FileName + * @param type $X + * @param type $Y + * @return type + */ + public function drawFromPicture($PicType,$FileName,$X,$Y) + { + if ( file_exists($FileName)) { + list($Width,$Height) = $this->getPicInfo($FileName); + + if ( $PicType == 1 ) { + $Raster = imagecreatefrompng($FileName); + } elseif ( $PicType == 2 ) { + $Raster = imagecreatefromgif($FileName); + } elseif ( $PicType == 3 ) { + $Raster = imagecreatefromjpeg($FileName); + } else { + return(0); + } + + + $RestoreShadow = $this->Shadow; + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) { + $this->Shadow = false; + if ( $PicType == 3 ) { + $this->drawFilledRectangle( + $X+$this->ShadowX, + $Y+$this->ShadowY, + $X+$Width+$this->ShadowX, + $Y+$Height+$this->ShadowY, + array("R"=>$this->ShadowR,"G"=>$this->ShadowG,"B"=>$this->ShadowB,"Alpha"=>$this->Shadowa) + ); + } else { + $TranparentID = imagecolortransparent($Raster); + for ($Xc=0;$Xc<=$Width-1;$Xc++) { + for ($Yc=0;$Yc<=$Height-1;$Yc++) { + $RGBa = imagecolorat($Raster,$Xc,$Yc); + $Values = imagecolorsforindex($Raster,$RGBa); + if ( $Values["alpha"] < 120 ) { + $AlphaFactor = floor(($this->Shadowa / 100) * ((100 / 127) * (127-$Values["alpha"]))); + $this->drawAlphaPixel( + $X+$Xc+$this->ShadowX, + $Y+$Yc+$this->ShadowY, + $AlphaFactor, + $this->ShadowR, + $this->ShadowG, + $this->ShadowB + ); + } + } + } + } + } + $this->Shadow = $RestoreShadow; + + imagecopy($this->Picture,$Raster,$X,$Y,0,0,$Width,$Height); + imagedestroy($Raster); + } + } + + /** + * Draw an arrow + * @param type $X1 + * @param type $Y1 + * @param type $X2 + * @param type $Y2 + * @param type $Format + */ + public function drawArrow($X1,$Y1,$X2,$Y2,$Format="") + { + $FillR = isset($Format["FillR"]) ? $Format["FillR"] : 0; + $FillG = isset($Format["FillG"]) ? $Format["FillG"] : 0; + $FillB = isset($Format["FillB"]) ? $Format["FillB"] : 0; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $FillR; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $FillG; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $FillB; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $Size = isset($Format["Size"]) ? $Format["Size"] : 10; + $Ratio = isset($Format["Ratio"]) ? $Format["Ratio"] : .5; + $TwoHeads = isset($Format["TwoHeads"]) ? $Format["TwoHeads"] : false; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : false; + + /* Calculate the line angle */ + $Angle = $this->getAngle($X1,$Y1,$X2,$Y2); + + /* Override Shadow support, this will be managed internally */ + $RestoreShadow = $this->Shadow; + if ( $this->Shadow && $this->ShadowX != 0 && $this->ShadowY != 0 ) { + $this->Shadow = false; + $this->drawArrow( + $X1+$this->ShadowX, + $Y1+$this->ShadowY, + $X2+$this->ShadowX, + $Y2+$this->ShadowY, + array( + "FillR"=>$this->ShadowR, + "FillG"=>$this->ShadowG, + "FillB"=>$this->ShadowB, + "Alpha"=>$this->Shadowa, + "Size"=>$Size, + "Ratio"=>$Ratio, + "TwoHeads"=>$TwoHeads, + "Ticks"=>$Ticks + ) + ); + } + + /* Draw the 1st Head */ + $TailX = cos(($Angle-180)*PI/180)*$Size+$X2; + $TailY = sin(($Angle-180)*PI/180)*$Size+$Y2; + + $Points = ""; + $Points[] = $X2; $Points[] = $Y2; + $Points[] = cos(($Angle-90)*PI/180)*$Size*$Ratio+$TailX; $Points[] = sin(($Angle-90)*PI/180)*$Size*$Ratio+$TailY; + $Points[] = cos(($Angle-270)*PI/180)*$Size*$Ratio+$TailX; $Points[] = sin(($Angle-270)*PI/180)*$Size*$Ratio+$TailY; + $Points[] = $X2; $Points[] = $Y2; + + /* Visual correction */ + if ($Angle == 180 || $Angle == 360 ) { + $Points[4] = $Points[2]; + } + if ($Angle == 90 || $Angle == 270 ) { + $Points[5] = $Points[3]; + } + + $ArrowColor = $this->allocateColor($this->Picture,$FillR,$FillG,$FillB,$Alpha); + ImageFilledPolygon($this->Picture,$Points,4,$ArrowColor); + + $this->drawLine($Points[0],$Points[1],$Points[2],$Points[3],array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha)); + $this->drawLine($Points[2],$Points[3],$Points[4],$Points[5],array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha)); + $this->drawLine($Points[0],$Points[1],$Points[4],$Points[5],array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha)); + + /* Draw the second head */ + if ( $TwoHeads ) { + $Angle = $this->getAngle($X2,$Y2,$X1,$Y1); + + $TailX2 = cos(($Angle-180)*PI/180)*$Size+$X1; + $TailY2 = sin(($Angle-180)*PI/180)*$Size+$Y1; + + $Points = ""; + $Points[] = $X1; $Points[] = $Y1; + $Points[] = cos(($Angle-90)*PI/180)*$Size*$Ratio+$TailX2; $Points[] = sin(($Angle-90)*PI/180)*$Size*$Ratio+$TailY2; + $Points[] = cos(($Angle-270)*PI/180)*$Size*$Ratio+$TailX2; $Points[] = sin(($Angle-270)*PI/180)*$Size*$Ratio+$TailY2; + $Points[] = $X1; $Points[] = $Y1; + + /* Visual correction */ + if ($Angle == 180 || $Angle == 360 ) { $Points[4] = $Points[2]; } + if ($Angle == 90 || $Angle == 270 ) { $Points[5] = $Points[3]; } + + $ArrowColor = $this->allocateColor($this->Picture,$FillR,$FillG,$FillB,$Alpha); + ImageFilledPolygon($this->Picture,$Points,4,$ArrowColor); + + $this->drawLine($Points[0],$Points[1],$Points[2],$Points[3],array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha)); + $this->drawLine($Points[2],$Points[3],$Points[4],$Points[5],array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha)); + $this->drawLine($Points[0],$Points[1],$Points[4],$Points[5],array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha)); + + $this->drawLine($TailX,$TailY,$TailX2,$TailY2,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + } else { + $this->drawLine($X1,$Y1,$TailX,$TailY,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + } + /* Re-enable shadows */ + $this->Shadow = $RestoreShadow; + } + + /** + * Draw a label with associated arrow + * @param type $X1 + * @param type $Y1 + * @param type $Text + * @param type $Format + */ + public function drawArrowLabel($X1,$Y1,$Text,$Format="") + { + $FillR = isset($Format["FillR"]) ? $Format["FillR"] : 0; + $FillG = isset($Format["FillG"]) ? $Format["FillG"] : 0; + $FillB = isset($Format["FillB"]) ? $Format["FillB"] : 0; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $FillR; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $FillG; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $FillB; + $FontName = isset($Format["FontName"]) + ? $this->loadFont($Format["FontName"], 'fonts') + : $this->FontName; + $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->FontSize; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $Length = isset($Format["Length"]) ? $Format["Length"] : 50; + $Angle = isset($Format["Angle"]) ? $Format["Angle"] : 315; + $Size = isset($Format["Size"]) ? $Format["Size"] : 10; + $Position = isset($Format["Position"]) ? $Format["Position"] : POSITION_TOP; + $RoundPos = isset($Format["RoundPos"]) ? $Format["RoundPos"] : false; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : null; + + $Angle = $Angle % 360; + + $X2 = sin(($Angle+180)*PI/180)*$Length+$X1; + $Y2 = cos(($Angle+180)*PI/180)*$Length+$Y1; + + if ( $RoundPos && $Angle > 0 && $Angle < 180 ) { $Y2 = ceil($Y2); } + if ( $RoundPos && $Angle > 180 ) { $Y2 = floor($Y2); } + + $this->drawArrow($X2,$Y2,$X1,$Y1,$Format); + + $Size = imagettfbbox($FontSize,0,$FontName,$Text); + $TxtWidth = max(abs($Size[2]-$Size[0]),abs($Size[0]-$Size[6])); + $TxtHeight = max(abs($Size[1]-$Size[7]),abs($Size[3]-$Size[1])); + + if ( $Angle > 0 && $Angle < 180 ) { + $this->drawLine( + $X2, + $Y2, + $X2-$TxtWidth, + $Y2, + array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha,"Ticks"=>$Ticks) + ); + if ( $Position == POSITION_TOP ) { + $this->drawText( + $X2, + $Y2-2, + $Text, + array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha,"Align"=>TEXT_ALIGN_BOTTOMRIGHT) + ); + } else { + $this->drawText( + $X2, + $Y2+4, + $Text + ,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha,"Align"=>TEXT_ALIGN_TOPRIGHT) + ); + } + } else { + $this->drawLine($X2,$Y2,$X2+$TxtWidth,$Y2,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha,"Ticks"=>$Ticks)); + if ( $Position == POSITION_TOP ) { + $this->drawText($X2,$Y2-2,$Text,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha)); + } else { + $this->drawText($X2,$Y2+4,$Text,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$Alpha,"Align"=>TEXT_ALIGN_TOPLEFT)); + } + } + } + + /** + * Draw a progress bar filled with specified % + * @param type $X + * @param type $Y + * @param type $Percent + * @param type $Format + */ + public function drawProgress($X,$Y,$Percent,$Format="") + { + if ( $Percent > 100 ) { $Percent = 100; } + if ( $Percent < 0 ) { $Percent = 0; } + + $Width = isset($Format["Width"]) ? $Format["Width"] : 200; + $Height = isset($Format["Height"]) ? $Format["Height"] : 20; + $Orientation = isset($Format["Orientation"]) ? $Format["Orientation"] : ORIENTATION_HORIZONTAL; + $ShowLabel = isset($Format["ShowLabel"]) ? $Format["ShowLabel"] : false; + $LabelPos = isset($Format["LabelPos"]) ? $Format["LabelPos"] : LABEL_POS_INSIDE; + $Margin = isset($Format["Margin"]) ? $Format["Margin"] : 10; + $R = isset($Format["R"]) ? $Format["R"] : 130; + $G = isset($Format["G"]) ? $Format["G"] : 130; + $B = isset($Format["B"]) ? $Format["B"] : 130; + $RFade = isset($Format["RFade"]) ? $Format["RFade"] : -1; + $GFade = isset($Format["GFade"]) ? $Format["GFade"] : -1; + $BFade = isset($Format["BFade"]) ? $Format["BFade"] : -1; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $R; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $G; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $B; + $BoxBorderR = isset($Format["BoxBorderR"]) ? $Format["BoxBorderR"] : 0; + $BoxBorderG = isset($Format["BoxBorderG"]) ? $Format["BoxBorderG"] : 0; + $BoxBorderB = isset($Format["BoxBorderB"]) ? $Format["BoxBorderB"] : 0; + $BoxBackR = isset($Format["BoxBackR"]) ? $Format["BoxBackR"] : 255; + $BoxBackG = isset($Format["BoxBackG"]) ? $Format["BoxBackG"] : 255; + $BoxBackB = isset($Format["BoxBackB"]) ? $Format["BoxBackB"] : 255; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : null; + $BoxSurrounding = isset($Format["BoxSurrounding"]) ? $Format["BoxSurrounding"] : null; + $NoAngle = isset($Format["NoAngle"]) ? $Format["NoAngle"] : false; + + if ( $RFade != -1 && $GFade != -1 && $BFade != -1 ) { + $RFade = (($RFade-$R)/100)*$Percent+$R; + $GFade = (($GFade-$G)/100)*$Percent+$G; + $BFade = (($BFade-$B)/100)*$Percent+$B; + } + + if ( $Surrounding != null ) { + $BorderR = $R + $Surrounding; + $BorderG = $G + $Surrounding; + $BorderB = $B + $Surrounding; + } + if ( $BoxSurrounding != null ) { + $BoxBorderR = $BoxBackR + $Surrounding; + $BoxBorderG = $BoxBackG + $Surrounding; + $BoxBorderB = $BoxBackB + $Surrounding; + } + + if ( $Orientation == ORIENTATION_VERTICAL ) { + $InnerHeight = (($Height-2)/100)*$Percent; + $this->drawFilledRectangle( + $X, + $Y, + $X+$Width, + $Y-$Height, + array( + "R"=>$BoxBackR, + "G"=>$BoxBackG, + "B"=>$BoxBackB, + "BorderR"=>$BoxBorderR, + "BorderG"=>$BoxBorderG, + "BorderB"=>$BoxBorderB, + "NoAngle"=>$NoAngle + ) + ); + + $RestoreShadow = $this->Shadow; $this->Shadow = false; + if ( $RFade != -1 && $GFade != -1 && $BFade != -1 ) { + $GradientOptions = array( + "StartR"=>$RFade, + "StartG"=>$GFade, + "StartB"=>$BFade, + "EndR"=>$R, + "EndG"=>$G, + "EndB"=>$B + ); + $this->drawGradientArea($X+1,$Y-1,$X+$Width-1,$Y-$InnerHeight,DIRECTION_VERTICAL,$GradientOptions); + + if ( $Surrounding ) { + $this->drawRectangle( + $X+1, + $Y-1, + $X+$Width-1, + $Y-$InnerHeight, + array("R"=>255,"G"=>255,"B"=>255,"Alpha"=>$Surrounding) + ); + } + } else { + $this->drawFilledRectangle( + $X+1, + $Y-1, + $X+$Width-1, + $Y-$InnerHeight, + array("R"=>$R,"G"=>$G,"B"=>$B,"BorderR"=>$BorderR,"BorderG"=>$BorderG,"BorderB"=>$BorderB) + ); + } + $this->Shadow = $RestoreShadow; + + if ( $ShowLabel && $LabelPos == LABEL_POS_BOTTOM ) { + $this->drawText($X+($Width/2),$Y+$Margin,$Percent."%",array("Align"=>TEXT_ALIGN_TOPMIDDLE)); + } + if ( $ShowLabel && $LabelPos == LABEL_POS_TOP ) { + $this->drawText($X+($Width/2),$Y-$Height-$Margin,$Percent."%",array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE)); + } + if ( $ShowLabel && $LabelPos == LABEL_POS_INSIDE ) { + $this->drawText($X+($Width/2),$Y-$InnerHeight-$Margin,$Percent."%",array("Align"=>TEXT_ALIGN_MIDDLELEFT,"Angle"=>90)); + } + if ( $ShowLabel && $LabelPos == LABEL_POS_CENTER ) { + $this->drawText($X+($Width/2),$Y-($Height/2),$Percent."%",array("Align"=>TEXT_ALIGN_MIDDLEMIDDLE,"Angle"=>90)); + } + } else { + if ( $Percent == 100 ) { + $InnerWidth = $Width-1; + } else { + $InnerWidth = (($Width-2)/100)*$Percent; + } + $this->drawFilledRectangle( + $X, + $Y, + $X+$Width, + $Y+$Height, + array( + "R"=>$BoxBackR, + "G"=>$BoxBackG, + "B"=>$BoxBackB, + "BorderR"=>$BoxBorderR, + "BorderG"=>$BoxBorderG, + "BorderB"=>$BoxBorderB, + "NoAngle"=>$NoAngle + ) + ); + + $RestoreShadow = $this->Shadow; + $this->Shadow = false; + if ( $RFade != -1 && $GFade != -1 && $BFade != -1 ) { + $GradientOptions = array( + "StartR"=>$R, + "StartG"=>$G, + "StartB"=>$B, + "EndR"=>$RFade, + "EndG"=>$GFade, + "EndB"=>$BFade + ); + $this->drawGradientArea($X+1,$Y+1,$X+$InnerWidth,$Y+$Height-1,DIRECTION_HORIZONTAL,$GradientOptions); + + if ( $Surrounding ) { + $this->drawRectangle($X+1,$Y+1,$X+$InnerWidth,$Y+$Height-1,array("R"=>255,"G"=>255,"B"=>255,"Alpha"=>$Surrounding)); + } + } else { + $this->drawFilledRectangle( + $X+1, + $Y+1, + $X+$InnerWidth, + $Y+$Height-1, + array("R"=>$R,"G"=>$G,"B"=>$B,"BorderR"=>$BorderR,"BorderG"=>$BorderG,"BorderB"=>$BorderB) + ); + } + $this->Shadow = $RestoreShadow; + + if ( $ShowLabel && $LabelPos == LABEL_POS_LEFT ) { + $this->drawText($X-$Margin,$Y+($Height/2),$Percent."%",array("Align"=>TEXT_ALIGN_MIDDLERIGHT)); + } + if ( $ShowLabel && $LabelPos == LABEL_POS_RIGHT ) { + $this->drawText($X+$Width+$Margin,$Y+($Height/2),$Percent."%",array("Align"=>TEXT_ALIGN_MIDDLELEFT)); + } + if ( $ShowLabel && $LabelPos == LABEL_POS_CENTER ) { + $this->drawText($X+($Width/2),$Y+($Height/2),$Percent."%",array("Align"=>TEXT_ALIGN_MIDDLEMIDDLE)); + } + if ( $ShowLabel && $LabelPos == LABEL_POS_INSIDE ) { + $this->drawText($X+$InnerWidth+$Margin,$Y+($Height/2),$Percent."%",array("Align"=>TEXT_ALIGN_MIDDLELEFT)); + } + } + } + + /** + * Get the legend box size + * @param type $Format + * @return type + */ + public function getLegendSize($Format="") + { + $FontName = isset($Format["FontName"]) + ? $this->loadFont($Format["FontName"], 'fonts') + : $this->FontName; + $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->FontSize; + $BoxSize = isset($Format["BoxSize"]) ? $Format["BoxSize"] : 5; + $Margin = isset($Format["Margin"]) ? $Format["Margin"] : 5; + $Style = isset($Format["Style"]) ? $Format["Style"] : LEGEND_ROUND; + $Mode = isset($Format["Mode"]) ? $Format["Mode"] : LEGEND_VERTICAL; + $BoxWidth = isset($Format["BoxWidth"]) ? $Format["BoxWidth"] : 5; + $BoxHeight = isset($Format["BoxHeight"]) ? $Format["BoxHeight"] : 5; + $IconAreaWidth = isset($Format["IconAreaWidth"]) ? $Format["IconAreaWidth"] : $BoxWidth; + $IconAreaHeight = isset($Format["IconAreaHeight"]) ? $Format["IconAreaHeight"] : $BoxHeight; + $XSpacing = isset($Format["XSpacing"]) ? $Format["XSpacing"] : 5; + + $Data = $this->DataSet->getData(); + + foreach ($Data["Series"] as $SerieName => $Serie) { + if ($Serie["isDrawable"] == true + && $SerieName != $Data["Abscissa"] + && isset($Serie["Picture"]) + ) { + list($PicWidth,$PicHeight) = $this->getPicInfo($Serie["Picture"]); + if ( $IconAreaWidth < $PicWidth ) { $IconAreaWidth = $PicWidth; } + if ( $IconAreaHeight < $PicHeight ) { $IconAreaHeight = $PicHeight; } + } + } + + $YStep = max($this->FontSize,$IconAreaHeight) + 5; + $XStep = $IconAreaWidth + 5; + $XStep = $XSpacing; + + $X=100; + $Y=100; + + $Boundaries = ""; + $Boundaries["L"] = $X; + $Boundaries["T"] = $Y; + $Boundaries["R"] = 0; + $Boundaries["B"] = 0; + $vY = $Y; + $vX = $X; + foreach($Data["Series"] as $SerieName => $Serie) { + if ( $Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"] ) { + if ( $Mode == LEGEND_VERTICAL ) { + $BoxArray = $this->getTextBox( + $vX+$IconAreaWidth+4, + $vY+$IconAreaHeight/2, + $FontName, + $FontSize,0, + $Serie["Description"] + ); + + if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$IconAreaHeight/2 ) { + $Boundaries["T"] = $BoxArray[2]["Y"]+$IconAreaHeight/2; + } + if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { + $Boundaries["R"] = $BoxArray[1]["X"]+2; + } + if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$IconAreaHeight/2 ) { + $Boundaries["B"] = $BoxArray[1]["Y"]+2+$IconAreaHeight/2; + } + + $Lines = preg_split("/\n/",$Serie["Description"]); + $vY = $vY + max($this->FontSize*count($Lines),$IconAreaHeight) + 5; + } elseif ( $Mode == LEGEND_HORIZONTAL ) { + $Lines = preg_split("/\n/",$Serie["Description"]); + $Width = ""; + foreach($Lines as $Key => $Value) { + $BoxArray = $this->getTextBox( + $vX+$IconAreaWidth+6, + $Y+$IconAreaHeight/2+(($this->FontSize+3)*$Key), + $FontName, + $FontSize, + 0, + $Value + ); + + if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$IconAreaHeight/2 ) { + $Boundaries["T"] = $BoxArray[2]["Y"]+$IconAreaHeight/2; + } + if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { + $Boundaries["R"] = $BoxArray[1]["X"]+2; + } + if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$IconAreaHeight/2 ) { + $Boundaries["B"] = $BoxArray[1]["Y"]+2+$IconAreaHeight/2; + } + + $Width[] = $BoxArray[1]["X"]; + } + + $vX=max($Width)+$XStep; + } + } + } + $vY=$vY-$YStep; + $vX=$vX-$XStep; + + $TopOffset = $Y - $Boundaries["T"]; + if ( $Boundaries["B"]-($vY+$IconAreaHeight) < $TopOffset ) { + $Boundaries["B"] = $vY+$IconAreaHeight+$TopOffset; + } + + $Width = ($Boundaries["R"]+$Margin) - ($Boundaries["L"]-$Margin); + $Height = ($Boundaries["B"]+$Margin) - ($Boundaries["T"]-$Margin); + + return(array("Width"=>$Width,"Height"=>$Height)); + } + + /** + * Draw the legend of the active series + * @param type $X + * @param type $Y + * @param type $Format + */ + public function drawLegend($X,$Y,$Format="") + { + $Family = isset($Format["Family"]) ? $Format["Family"] : LEGEND_FAMILY_BOX; + $FontName = isset($Format["FontName"]) + ? $this->loadFont($Format["FontName"], 'fonts') + : $this->FontName; + $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->FontSize; + $FontR = isset($Format["FontR"]) ? $Format["FontR"] : $this->FontColorR; + $FontG = isset($Format["FontG"]) ? $Format["FontG"] : $this->FontColorG; + $FontB = isset($Format["FontB"]) ? $Format["FontB"] : $this->FontColorB; + $BoxWidth = isset($Format["BoxWidth"]) ? $Format["BoxWidth"] : 5; + $BoxHeight = isset($Format["BoxHeight"]) ? $Format["BoxHeight"] : 5; + $IconAreaWidth = isset($Format["IconAreaWidth"]) ? $Format["IconAreaWidth"] : $BoxWidth; + $IconAreaHeight = isset($Format["IconAreaHeight"]) ? $Format["IconAreaHeight"] : $BoxHeight; + $XSpacing = isset($Format["XSpacing"]) ? $Format["XSpacing"] : 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; + } + + $Data = $this->DataSet->getData(); + + foreach($Data["Series"] as $SerieName => $Serie) { + if ($Serie["isDrawable"] == true + && $SerieName != $Data["Abscissa"] + && isset($Serie["Picture"]) + ) { + list($PicWidth,$PicHeight) = $this->getPicInfo($Serie["Picture"]); + if ( $IconAreaWidth < $PicWidth ) { $IconAreaWidth = $PicWidth; } + if ( $IconAreaHeight < $PicHeight ) { $IconAreaHeight = $PicHeight; } + } + } + + $YStep = max($this->FontSize,$IconAreaHeight) + 5; + $XStep = $IconAreaWidth + 5; + $XStep = $XSpacing; + + $Boundaries = ""; + $Boundaries["L"] = $X; + $Boundaries["T"] = $Y; + $Boundaries["R"] = 0; + $Boundaries["B"] = 0; + $vY = $Y; + $vX = $X; + foreach($Data["Series"] as $SerieName => $Serie) { + if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { + if ( $Mode == LEGEND_VERTICAL ) { + $BoxArray = $this->getTextBox( + $vX+$IconAreaWidth+4, + $vY+$IconAreaHeight/2, + $FontName, + $FontSize, + 0, + $Serie["Description"] + ); + + if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$IconAreaHeight/2 ) { + $Boundaries["T"] = $BoxArray[2]["Y"]+$IconAreaHeight/2; + } + if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { + $Boundaries["R"] = $BoxArray[1]["X"]+2; + } + if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$IconAreaHeight/2 ) { + $Boundaries["B"] = $BoxArray[1]["Y"]+2+$IconAreaHeight/2; + } + + $Lines = preg_split("/\n/",$Serie["Description"]); + $vY = $vY + max($this->FontSize*count($Lines),$IconAreaHeight) + 5; + } elseif ( $Mode == LEGEND_HORIZONTAL ) { + $Lines = preg_split("/\n/",$Serie["Description"]); + $Width = ""; + foreach($Lines as $Key => $Value) { + $BoxArray = $this->getTextBox( + $vX+$IconAreaWidth+6, + $Y+$IconAreaHeight/2+(($this->FontSize+3)*$Key), + $FontName, + $FontSize, + 0, + $Value + ); + + if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$IconAreaHeight/2 ) { + $Boundaries["T"] = $BoxArray[2]["Y"]+$IconAreaHeight/2; + } + if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { + $Boundaries["R"] = $BoxArray[1]["X"]+2; + } + if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$IconAreaHeight/2 ) { + $Boundaries["B"] = $BoxArray[1]["Y"]+2+$IconAreaHeight/2; + } + + $Width[] = $BoxArray[1]["X"]; + } + + $vX=max($Width)+$XStep; + } + } + } + $vY=$vY-$YStep; + $vX=$vX-$XStep; + + $TopOffset = $Y - $Boundaries["T"]; + if ( $Boundaries["B"]-($vY+$IconAreaHeight) < $TopOffset ) { + $Boundaries["B"] = $vY+$IconAreaHeight+$TopOffset; + } + + if ( $Style == LEGEND_ROUND ) { + $this->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->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->Shadow; + $this->Shadow = false; + foreach($Data["Series"] as $SerieName => $Serie) { + if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { + $R = $Serie["Color"]["R"]; + $G = $Serie["Color"]["G"]; + $B = $Serie["Color"]["B"]; + $Ticks = $Serie["Ticks"]; + $Weight = $Serie["Weight"]; + + if ( isset($Serie["Picture"]) ) { + $Picture = $Serie["Picture"]; + list($PicWidth,$PicHeight) = $this->getPicInfo($Picture); + $PicX = $X+$IconAreaWidth/2; $PicY = $Y+$IconAreaHeight/2; + + $this->drawFromPNG($PicX-$PicWidth/2,$PicY-$PicHeight/2,$Picture); + } else { + if ( $Family == LEGEND_FAMILY_BOX ) { + if ( $BoxWidth != $IconAreaWidth ) { + $XOffset = floor(($IconAreaWidth-$BoxWidth)/2); + } else { + $XOffset = 0; + } + if ( $BoxHeight != $IconAreaHeight ) { + $YOffset = floor(($IconAreaHeight-$BoxHeight)/2); + } else { + $YOffset = 0; + } + + $this->drawFilledRectangle( + $X+1+$XOffset, + $Y+1+$YOffset, + $X+$BoxWidth+$XOffset+1, + $Y+$BoxHeight+1+$YOffset, + array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>20) + ); + $this->drawFilledRectangle( + $X+$XOffset, + $Y+$YOffset, + $X+$BoxWidth+$XOffset, + $Y+$BoxHeight+$YOffset, + array("R"=>$R,"G"=>$G,"B"=>$B,"Surrounding"=>20) + ); + } elseif ( $Family == LEGEND_FAMILY_CIRCLE ) { + $this->drawFilledCircle( + $X+1+$IconAreaWidth/2, + $Y+1+$IconAreaHeight/2, + min($IconAreaHeight/2,$IconAreaWidth/2), + array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>20) + ); + $this->drawFilledCircle( + $X+$IconAreaWidth/2, + $Y+$IconAreaHeight/2, + min($IconAreaHeight/2,$IconAreaWidth/2), + array("R"=>$R,"G"=>$G,"B"=>$B,"Surrounding"=>20) + ); + } elseif ( $Family == LEGEND_FAMILY_LINE ) { + $this->drawLine( + $X+1, + $Y+1+$IconAreaHeight/2, + $X+1+$IconAreaWidth, + $Y+1+$IconAreaHeight/2, + array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>20,"Ticks"=>$Ticks,"Weight"=>$Weight) + ); + $this->drawLine( + $X, + $Y+$IconAreaHeight/2, + $X+$IconAreaWidth, + $Y+$IconAreaHeight/2, + array("R"=>$R,"G"=>$G,"B"=>$B,"Ticks"=>$Ticks,"Weight"=>$Weight) + ); + } + } + + if ( $Mode == LEGEND_VERTICAL ) { + $Lines = preg_split("/\n/",$Serie["Description"]); + foreach($Lines as $Key => $Value) { + $this->drawText( + $X+$IconAreaWidth+4, + $Y+$IconAreaHeight/2+(($this->FontSize+3)*$Key), + $Value, + array( + "R"=>$FontR, + "G"=>$FontG, + "B"=>$FontB, + "Align"=>TEXT_ALIGN_MIDDLELEFT, + "FontSize"=>$FontSize, + "FontName"=>$FontName + ) + ); + } + $Y=$Y+max($this->FontSize*count($Lines),$IconAreaHeight) + 5; + } elseif ( $Mode == LEGEND_HORIZONTAL ) { + $Lines = preg_split("/\n/",$Serie["Description"]); + $Width = ""; + foreach($Lines as $Key => $Value) { + $BoxArray = $this->drawText( + $X+$IconAreaWidth+4, + $Y+$IconAreaHeight/2+(($this->FontSize+3)*$Key), + $Value, + array( + "R"=>$FontR, + "G"=>$FontG, + "B"=>$FontB, + "Align"=>TEXT_ALIGN_MIDDLELEFT, + "FontSize"=>$FontSize, + "FontName"=>$FontName + ) + ); + $Width[] = $BoxArray[1]["X"]; + } + $X=max($Width)+2+$XStep; + } + } + } + + + $this->Shadow = $RestoreShadow; + } + + public function drawScale($Format="") + { + $Pos = isset($Format["Pos"]) ? $Format["Pos"] : SCALE_POS_LEFTRIGHT; + $Floating = isset($Format["Floating"]) ? $Format["Floating"] : false; + $Mode = isset($Format["Mode"]) ? $Format["Mode"] : SCALE_MODE_FLOATING; + $RemoveXAxis = isset($Format["RemoveXAxis"]) ? $Format["RemoveXAxis"] : false; + $RemoveYAxis = isset($Format["RemoveYAxis"]) ? $Format["RemoveYAxis"] : false; + $RemoveYAxiValues = isset($Format["RemoveYAxisValues"]) ? $Format["RemoveYAxisValues"] : false; + $MinDivHeight = isset($Format["MinDivHeight"]) ? $Format["MinDivHeight"] : 20; + $Factors = isset($Format["Factors"]) ? $Format["Factors"] : array(1,2,5); + $ManualScale = isset($Format["ManualScale"]) ? $Format["ManualScale"] : array("0"=>array("Min"=>-100,"Max"=>100)); + $XMargin = isset($Format["XMargin"]) ? $Format["XMargin"] : AUTO; + $YMargin = isset($Format["YMargin"]) ? $Format["YMargin"] : 0; + $ScaleSpacing = isset($Format["ScaleSpacing"]) ? $Format["ScaleSpacing"] : 15; + $InnerTickWidth = isset($Format["InnerTickWidth"]) ? $Format["InnerTickWidth"] : 2; + $OuterTickWidth = isset($Format["OuterTickWidth"]) ? $Format["OuterTickWidth"] : 2; + $DrawXLines = isset($Format["DrawXLines"]) ? $Format["DrawXLines"] : true; + $DrawYLines = isset($Format["DrawYLines"]) ? $Format["DrawYLines"] : ALL; + $GridTicks = isset($Format["GridTicks"]) ? $Format["GridTicks"] : 4; + $GridR = isset($Format["GridR"]) ? $Format["GridR"] : 255; + $GridG = isset($Format["GridG"]) ? $Format["GridG"] : 255; + $GridB = isset($Format["GridB"]) ? $Format["GridB"] : 255; + $GridAlpha = isset($Format["GridAlpha"]) ? $Format["GridAlpha"] : 40; + $AxisRo = isset($Format["AxisR"]) ? $Format["AxisR"] : 0; + $AxisGo = isset($Format["AxisG"]) ? $Format["AxisG"] : 0; + $AxisBo = isset($Format["AxisB"]) ? $Format["AxisB"] : 0; + $AxisAlpha = isset($Format["AxisAlpha"]) ? $Format["AxisAlpha"] : 100; + $TickRo = isset($Format["TickR"]) ? $Format["TickR"] : 0; + $TickGo = isset($Format["TickG"]) ? $Format["TickG"] : 0; + $TickBo = isset($Format["TickB"]) ? $Format["TickB"] : 0; + $TickAlpha = isset($Format["TickAlpha"]) ? $Format["TickAlpha"] : 100; + $DrawSubTicks = isset($Format["DrawSubTicks"]) ? $Format["DrawSubTicks"] : false; + $InnerSubTickWidth = isset($Format["InnerSubTickWidth"]) ? $Format["InnerSubTickWidth"] : 0; + $OuterSubTickWidth = isset($Format["OuterSubTickWidth"]) ? $Format["OuterSubTickWidth"] : 2; + $SubTickR = isset($Format["SubTickR"]) ? $Format["SubTickR"] : 255; + $SubTickG = isset($Format["SubTickG"]) ? $Format["SubTickG"] : 0; + $SubTickB = isset($Format["SubTickB"]) ? $Format["SubTickB"] : 0; + $SubTickAlpha = isset($Format["SubTickAlpha"]) ? $Format["SubTickAlpha"] : 100; + $AutoAxisLabels = isset($Format["AutoAxisLabels"]) ? $Format["AutoAxisLabels"] : true; + $XReleasePercent = isset($Format["XReleasePercent"]) ? $Format["XReleasePercent"] : 1; + $DrawArrows = isset($Format["DrawArrows"]) ? $Format["DrawArrows"] : false; + $ArrowSize = isset($Format["ArrowSize"]) ? $Format["ArrowSize"] : 8; + $CycleBackground = isset($Format["CycleBackground"]) ? $Format["CycleBackground"] : false; + $BackgroundR1 = isset($Format["BackgroundR1"]) ? $Format["BackgroundR1"] : 255; + $BackgroundG1 = isset($Format["BackgroundG1"]) ? $Format["BackgroundG1"] : 255; + $BackgroundB1 = isset($Format["BackgroundB1"]) ? $Format["BackgroundB1"] : 255; + $BackgroundAlpha1 = isset($Format["BackgroundAlpha1"]) ? $Format["BackgroundAlpha1"] : 20; + $BackgroundR2 = isset($Format["BackgroundR2"]) ? $Format["BackgroundR2"] : 230; + $BackgroundG2 = isset($Format["BackgroundG2"]) ? $Format["BackgroundG2"] : 230; + $BackgroundB2 = isset($Format["BackgroundB2"]) ? $Format["BackgroundB2"] : 230; + $BackgroundAlpha2 = isset($Format["BackgroundAlpha2"]) ? $Format["BackgroundAlpha2"] : 20; + $LabelingMethod = isset($Format["LabelingMethod"]) ? $Format["LabelingMethod"] : LABELING_ALL; + $LabelSkip = isset($Format["LabelSkip"]) ? $Format["LabelSkip"] : 0; + $LabelRotation = isset($Format["LabelRotation"]) ? $Format["LabelRotation"] : 0; + $RemoveSkippedAxis = isset($Format["RemoveSkippedAxis"]) ? $Format["RemoveSkippedAxis"] : false; + $SkippedAxisTicks = isset($Format["SkippedAxisTicks"]) ? $Format["SkippedAxisTicks"] : $GridTicks+2; + $SkippedAxisR = isset($Format["SkippedAxisR"]) ? $Format["SkippedAxisR"] : $GridR; + $SkippedAxisG = isset($Format["SkippedAxisG"]) ? $Format["SkippedAxisG"] : $GridG; + $SkippedAxisB = isset($Format["SkippedAxisB"]) ? $Format["SkippedAxisB"] : $GridB; + $SkippedAxisAlpha = isset($Format["SkippedAxisAlpha"]) ? $Format["SkippedAxisAlpha"] : $GridAlpha-30; + $SkippedTickR = isset($Format["SkippedTickR"]) ? $Format["SkippedTickR"] : $TickRo; + $SkippedTickG = isset($Format["SkippedTickG"]) ? $Format["SkippedTickG"] : $TickGo; + $SkippedTickB = isset($Format["SkippedTicksB"]) ? $Format["SkippedTickB"] : $TickBo; + $SkippedTickAlpha = isset($Format["SkippedTickAlpha"]) ? $Format["SkippedTickAlpha"] : $TickAlpha-80; + $SkippedInnerTickWidth = isset($Format["SkippedInnerTickWidth"]) ? $Format["SkippedInnerTickWidth"] : 0; + $SkippedOuterTickWidth = isset($Format["SkippedOuterTickWidth"]) ? $Format["SkippedOuterTickWidth"] : 2; + + /* Floating scale require X & Y margins to be set manually */ + if ( $Floating && ( $XMargin == AUTO || $YMargin == 0 ) ) { + $Floating = false; + } + + /* Skip a NOTICE event in case of an empty array */ + if ( $DrawYLines == NONE || $DrawYLines == false ) { + $DrawYLines = array("zarma"=>"31"); + } + + /* Define the color for the skipped elements */ + $SkippedAxisColor = array( + "R"=>$SkippedAxisR, + "G"=>$SkippedAxisG, + "B"=>$SkippedAxisB, + "Alpha"=>$SkippedAxisAlpha, + "Ticks"=>$SkippedAxisTicks + ); + $SkippedTickColor = array( + "R"=>$SkippedTickR, + "G"=>$SkippedTickG, + "B"=>$SkippedTickB, + "Alpha"=>$SkippedTickAlpha + ); + + $Data = $this->DataSet->getData(); + if ( isset($Data["Abscissa"]) ) { + $Abscissa = $Data["Abscissa"]; + } else { + $Abscissa = null; + } + + /* Unset the abscissa axis, needed if we display multiple charts on the same picture */ + if ( $Abscissa != null ) { + foreach($Data["Axis"] as $AxisID => $Parameters) { + if ($Parameters["Identity"] == AXIS_X) { + unset($Data["Axis"][$AxisID]); + } + } + } + + /* Build the scale settings */ + $GotXAxis = false; + foreach($Data["Axis"] as $AxisID => $AxisParameter) { + if ( $AxisParameter["Identity"] == AXIS_X ) { $GotXAxis = true; } + + if ( $Pos == SCALE_POS_LEFTRIGHT && $AxisParameter["Identity"] == AXIS_Y) { + $Height = $this->GraphAreaY2-$this->GraphAreaY1 - $YMargin*2; + } elseif ( $Pos == SCALE_POS_LEFTRIGHT && $AxisParameter["Identity"] == AXIS_X) { + $Height = $this->GraphAreaX2-$this->GraphAreaX1; + } elseif ( $Pos == SCALE_POS_TOPBOTTOM && $AxisParameter["Identity"] == AXIS_Y) { + $Height = $this->GraphAreaX2-$this->GraphAreaX1 - $YMargin*2;; + } else { + $Height = $this->GraphAreaY2-$this->GraphAreaY1; + } + + $AxisMin = ABSOLUTE_MAX; $AxisMax = OUT_OF_SIGHT; + if ( $Mode == SCALE_MODE_FLOATING || $Mode == SCALE_MODE_START0 ) { + foreach($Data["Series"] as $SerieID => $SerieParameter) { + if ($SerieParameter["Axis"] == $AxisID + && $Data["Series"][$SerieID]["isDrawable"] + && $Data["Abscissa"] != $SerieID + ) { + $AxisMax = max($AxisMax,$Data["Series"][$SerieID]["Max"]); + $AxisMin = min($AxisMin,$Data["Series"][$SerieID]["Min"]); + } + } + $AutoMargin = (($AxisMax-$AxisMin)/100)*$XReleasePercent; + + $Data["Axis"][$AxisID]["Min"] = $AxisMin-$AutoMargin; + $Data["Axis"][$AxisID]["Max"] = $AxisMax+$AutoMargin; + if ( $Mode == SCALE_MODE_START0 ) { + $Data["Axis"][$AxisID]["Min"] = 0; + } + } elseif ( $Mode == SCALE_MODE_MANUAL ) { + if ( isset($ManualScale[$AxisID]["Min"]) && isset($ManualScale[$AxisID]["Max"]) ) { + $Data["Axis"][$AxisID]["Min"] = $ManualScale[$AxisID]["Min"]; + $Data["Axis"][$AxisID]["Max"] = $ManualScale[$AxisID]["Max"]; + } else { + throw new \Exception("Manual scale boundaries not set."); + } + } elseif ( $Mode == SCALE_MODE_ADDALL || $Mode == SCALE_MODE_ADDALL_START0 ) { + $Series = ""; + foreach($Data["Series"] as $SerieID => $SerieParameter) { + if ($SerieParameter["Axis"] == $AxisID + && $SerieParameter["isDrawable"] + && $Data["Abscissa"] != $SerieID + ) { + $Series[$SerieID] = count($Data["Series"][$SerieID]["Data"]); + } + } + + for ($ID=0;$ID<=max($Series)-1;$ID++) { + $PointMin = 0; + $PointMax = 0; + foreach($Series as $SerieID => $ValuesCount ) { + if (isset($Data["Series"][$SerieID]["Data"][$ID]) + && $Data["Series"][$SerieID]["Data"][$ID] != null + ) { + $Value = $Data["Series"][$SerieID]["Data"][$ID]; + if ( $Value > 0 ) { + $PointMax = $PointMax + $Value; + } else { + $PointMin = $PointMin + $Value; + } + } + } + $AxisMax = max($AxisMax,$PointMax); + $AxisMin = min($AxisMin,$PointMin); + } + $AutoMargin = (($AxisMax-$AxisMin)/100)*$XReleasePercent; + $Data["Axis"][$AxisID]["Min"] = $AxisMin-$AutoMargin; + $Data["Axis"][$AxisID]["Max"] = $AxisMax+$AutoMargin; + } + $MaxDivs = floor($Height/$MinDivHeight); + + if ( $Mode == SCALE_MODE_ADDALL_START0 ) { + $Data["Axis"][$AxisID]["Min"] = 0; + } + + $Scale = $this->computeScale( + $Data["Axis"][$AxisID]["Min"], + $Data["Axis"][$AxisID]["Max"], + $MaxDivs,$Factors,$AxisID + ); + + $Data["Axis"][$AxisID]["Margin"] = $AxisParameter["Identity"] == AXIS_X ? $XMargin : $YMargin; + $Data["Axis"][$AxisID]["ScaleMin"] = $Scale["XMin"]; + $Data["Axis"][$AxisID]["ScaleMax"] = $Scale["XMax"]; + $Data["Axis"][$AxisID]["Rows"] = $Scale["Rows"]; + $Data["Axis"][$AxisID]["RowHeight"] = $Scale["RowHeight"]; + + if ( isset($Scale["Format"]) ) { + $Data["Axis"][$AxisID]["Format"] = $Scale["Format"]; + } + if ( !isset($Data["Axis"][$AxisID]["Display"]) ) { + $Data["Axis"][$AxisID]["Display"] = null; + } + if ( !isset($Data["Axis"][$AxisID]["Format"]) ) { + $Data["Axis"][$AxisID]["Format"] = null; + } + if ( !isset($Data["Axis"][$AxisID]["Unit"]) ) { + $Data["Axis"][$AxisID]["Unit"] = null; + } + } + + /* Still no X axis */ + if ( $GotXAxis == false ) { + if ( $Abscissa != null ) { + $Points = count($Data["Series"][$Abscissa]["Data"]); + if ( $AutoAxisLabels ) { + $AxisName = isset($Data["Series"][$Abscissa]["Description"]) ? $Data["Series"][$Abscissa]["Description"] : null; + } else { + $AxisName = null; + } + } else { + $Points = 0; + $AxisName = isset($Data["XAxisName"]) ? $Data["XAxisName"] : null; + foreach($Data["Series"] as $SerieID => $SerieParameter) { + if ( $SerieParameter["isDrawable"] ) { + $Points = max($Points,count($SerieParameter["Data"])); + } + } + } + + $AxisID = count($Data["Axis"]); + $Data["Axis"][$AxisID]["Identity"] = AXIS_X; + if ( $Pos == SCALE_POS_LEFTRIGHT ) { + $Data["Axis"][$AxisID]["Position"] = AXIS_POSITION_BOTTOM; + } else { + $Data["Axis"][$AxisID]["Position"] = AXIS_POSITION_LEFT; + } + if ( isset($Data["AbscissaName"]) ) { + $Data["Axis"][$AxisID]["Name"] = $Data["AbscissaName"]; + } + if ( $XMargin == AUTO ) { + if ( $Pos == SCALE_POS_LEFTRIGHT ) { + $Height = $this->GraphAreaX2-$this->GraphAreaX1; + + } else { + $Height = $this->GraphAreaY2-$this->GraphAreaY1; + } + + if ( $Points == 1 ) { + $Data["Axis"][$AxisID]["Margin"] = $Height / 2; + } else { + $Data["Axis"][$AxisID]["Margin"] = ($Height/$Points) / 2; + } + } else { + $Data["Axis"][$AxisID]["Margin"] = $XMargin; + } + $Data["Axis"][$AxisID]["Rows"] = $Points-1; + if ( !isset($Data["Axis"][$AxisID]["Display"]) ) { $Data["Axis"][$AxisID]["Display"] = null; } + if ( !isset($Data["Axis"][$AxisID]["Format"]) ) { $Data["Axis"][$AxisID]["Format"] = null; } + if ( !isset($Data["Axis"][$AxisID]["Unit"]) ) { $Data["Axis"][$AxisID]["Unit"] = null; } + } + + /* Do we need to reverse the abscissa position? */ + if ( $Pos != SCALE_POS_LEFTRIGHT ) { + if ( $Data["AbsicssaPosition"] == AXIS_POSITION_BOTTOM ) { + $Data["AbsicssaPosition"] = AXIS_POSITION_LEFT; + } else { + $Data["AbsicssaPosition"] = AXIS_POSITION_RIGHT; + } + } + $Data["Axis"][$AxisID]["Position"] = $Data["AbsicssaPosition"]; + + $this->DataSet->saveOrientation($Pos); + $this->DataSet->saveAxisConfig($Data["Axis"]); + $this->DataSet->saveYMargin($YMargin); + + $FontColorRo = $this->FontColorR; + $FontColorGo = $this->FontColorG; + $FontColorBo = $this->FontColorB; + + $AxisPos["L"] = $this->GraphAreaX1; + $AxisPos["R"] = $this->GraphAreaX2; + $AxisPos["T"] = $this->GraphAreaY1; + $AxisPos["B"] = $this->GraphAreaY2; + foreach($Data["Axis"] as $AxisID => $Parameters) { + if ( isset($Parameters["Color"]) ) { + $AxisR = $Parameters["Color"]["R"]; + $AxisG = $Parameters["Color"]["G"]; + $AxisB = $Parameters["Color"]["B"]; + $TickR = $Parameters["Color"]["R"]; + $TickG = $Parameters["Color"]["G"]; + $TickB = $Parameters["Color"]["B"]; + $this->setFontProperties( + array( + "R"=>$Parameters["Color"]["R"], + "G"=>$Parameters["Color"]["G"], + "B"=>$Parameters["Color"]["B"] + ) + ); + } else { + $AxisR = $AxisRo; + $AxisG = $AxisGo; + $AxisB = $AxisBo; + $TickR = $TickRo; + $TickG = $TickGo; + $TickB = $TickBo; + $this->setFontProperties(array("R"=>$FontColorRo,"G"=>$FontColorGo,"B"=>$FontColorBo)); + } + + $LastValue = "w00t"; + $ID = 1; + if ( $Parameters["Identity"] == AXIS_X ) { + if ( $Pos == SCALE_POS_LEFTRIGHT ) { + if ( $Parameters["Position"] == AXIS_POSITION_BOTTOM ) { + if ( $LabelRotation == 0 ) { + $LabelAlign = TEXT_ALIGN_TOPMIDDLE; + $YLabelOffset = 2; + } + if ( $LabelRotation > 0 && $LabelRotation < 190 ) { + $LabelAlign = TEXT_ALIGN_MIDDLERIGHT; + $YLabelOffset = 5; + } + if ( $LabelRotation == 180 ) { + $LabelAlign = TEXT_ALIGN_BOTTOMMIDDLE; + $YLabelOffset = 5; + } + if ( $LabelRotation > 180 && $LabelRotation < 360 ) { + $LabelAlign = TEXT_ALIGN_MIDDLELEFT; + $YLabelOffset = 2; + } + + if ( !$RemoveXAxis ) { + if ( $Floating ) { + $FloatingOffset = $YMargin; + $this->drawLine( + $this->GraphAreaX1+$Parameters["Margin"], + $AxisPos["B"], + $this->GraphAreaX2-$Parameters["Margin"], + $AxisPos["B"], + array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + } + else { + $FloatingOffset = 0; + $this->drawLine( + $this->GraphAreaX1, + $AxisPos["B"], + $this->GraphAreaX2, + $AxisPos["B"], + array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + } + + if ( $DrawArrows ) { + $this->drawArrow( + $this->GraphAreaX2-$Parameters["Margin"], + $AxisPos["B"], + $this->GraphAreaX2+($ArrowSize*2), + $AxisPos["B"], + array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize) + ); + } + } + + $Width = ($this->GraphAreaX2 - $this->GraphAreaX1) - $Parameters["Margin"]*2; + + if ($Parameters["Rows"] == 0 ) { + $Step = $Width; + } else { + $Step = $Width / ($Parameters["Rows"]); + } + + $MaxBottom = $AxisPos["B"]; + for ($i=0;$i<=$Parameters["Rows"];$i++) { + $XPos = $this->GraphAreaX1 + $Parameters["Margin"] + $Step*$i; + $YPos = $AxisPos["B"]; + + if ( $Abscissa != null ) { + if ( isset($Data["Series"][$Abscissa]["Data"][$i]) ) { + $Value = $this->scaleFormat( + $Data["Series"][$Abscissa]["Data"][$i], + $Data["XAxisDisplay"], + $Data["XAxisFormat"], + $Data["XAxisUnit"] + ); + } else { + $Value = ""; + } + } else { + if (isset($Parameters["ScaleMin"]) && isset ($Parameters["RowHeight"])) { + $Value = $this->scaleFormat( + $Parameters["ScaleMin"] + $Parameters["RowHeight"]*$i, + $Data["XAxisDisplay"], + $Data["XAxisFormat"], + $Data["XAxisUnit"] + ); + } else { + $Value = $i; + } + } + + $ID++; + $Skipped = true; + if ($this->isValidLabel($Value,$LastValue,$LabelingMethod,$ID,$LabelSkip) && !$RemoveXAxis) { + $Bounds = $this->drawText( + $XPos, + $YPos+$OuterTickWidth+$YLabelOffset, + $Value, + array("Angle"=>$LabelRotation,"Align"=>$LabelAlign) + ); + $TxtBottom = $YPos+$OuterTickWidth+2+($Bounds[0]["Y"]-$Bounds[2]["Y"]); + $MaxBottom = max($MaxBottom,$TxtBottom); + $LastValue = $Value; + $Skipped = false; + } + + if ( $RemoveXAxis ) { + $Skipped = false; + } + + if ( $Skipped ) { + if ( $DrawXLines && !$RemoveSkippedAxis ) { + $this->drawLine( + $XPos, + $this->GraphAreaY1+$FloatingOffset, + $XPos, + $this->GraphAreaY2-$FloatingOffset, + $SkippedAxisColor + ); + } + if (($SkippedInnerTickWidth !=0 || $SkippedOuterTickWidth != 0) + && !$RemoveXAxis + && !$RemoveSkippedAxis + ) { + $this->drawLine( + $XPos, + $YPos-$SkippedInnerTickWidth, + $XPos, + $YPos+$SkippedOuterTickWidth, + $SkippedTickColor + ); + } + } else { + if ($DrawXLines + && ($XPos != $this->GraphAreaX1 && $XPos != $this->GraphAreaX2) + ) { + $this->drawLine( + $XPos, + $this->GraphAreaY1+$FloatingOffset, + $XPos, + $this->GraphAreaY2-$FloatingOffset, + array("R"=>$GridR,"G"=>$GridG,"B"=>$GridB,"Alpha"=>$GridAlpha,"Ticks"=>$GridTicks) + ); + } + if (($InnerTickWidth !=0 || $OuterTickWidth != 0) && !$RemoveXAxis ) { + $this->drawLine( + $XPos, + $YPos-$InnerTickWidth, + $XPos, + $YPos+$OuterTickWidth, + array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha) + ); + } + } + } + + if ( isset($Parameters["Name"]) && !$RemoveXAxis) { + $YPos = $MaxBottom+2; + $XPos = $this->GraphAreaX1+($this->GraphAreaX2-$this->GraphAreaX1)/2; + $Bounds = $this->drawText( + $XPos, + $YPos, + $Parameters["Name"], + array("Align"=>TEXT_ALIGN_TOPMIDDLE) + ); + $MaxBottom = $Bounds[0]["Y"]; + + $this->DataSet->Data["GraphArea"]["Y2"] = $MaxBottom + $this->FontSize; + } + + $AxisPos["B"] = $MaxBottom + $ScaleSpacing; + } elseif ( $Parameters["Position"] == AXIS_POSITION_TOP ) { + if ( $LabelRotation == 0 ) { + $LabelAlign = TEXT_ALIGN_BOTTOMMIDDLE; + $YLabelOffset = 2; + } + if ( $LabelRotation > 0 && $LabelRotation < 190 ) { + $LabelAlign = TEXT_ALIGN_MIDDLELEFT; + $YLabelOffset = 2; + } + if ( $LabelRotation == 180 ) { + $LabelAlign = TEXT_ALIGN_TOPMIDDLE; + $YLabelOffset = 5; + } + if ( $LabelRotation > 180 && $LabelRotation < 360 ) { + $LabelAlign = TEXT_ALIGN_MIDDLERIGHT; + $YLabelOffset = 5; + } + + if ( !$RemoveXAxis ) { + if ( $Floating ) { + $FloatingOffset = $YMargin; + $this->drawLine( + $this->GraphAreaX1+$Parameters["Margin"], + $AxisPos["T"], + $this->GraphAreaX2-$Parameters["Margin"], + $AxisPos["T"], + array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + } else { + $FloatingOffset = 0; + $this->drawLine( + $this->GraphAreaX1, + $AxisPos["T"], + $this->GraphAreaX2, + $AxisPos["T"], + array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + } + + if ( $DrawArrows ) { + $this->drawArrow( + $this->GraphAreaX2-$Parameters["Margin"], + $AxisPos["T"], + $this->GraphAreaX2+($ArrowSize*2), + $AxisPos["T"], + array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize) + ); + } + } + + $Width = ($this->GraphAreaX2 - $this->GraphAreaX1) - $Parameters["Margin"]*2; + + if ($Parameters["Rows"] == 0 ) { + $Step = $Width; + } else { + $Step = $Width / $Parameters["Rows"]; + } + + $MinTop = $AxisPos["T"]; + for($i=0;$i<=$Parameters["Rows"];$i++) { + $XPos = $this->GraphAreaX1 + $Parameters["Margin"] + $Step*$i; + $YPos = $AxisPos["T"]; + + if ( $Abscissa != null ) { + if ( isset($Data["Series"][$Abscissa]["Data"][$i]) ) { + $Value = $this->scaleFormat( + $Data["Series"][$Abscissa]["Data"][$i], + $Data["XAxisDisplay"], + $Data["XAxisFormat"], + $Data["XAxisUnit"] + ); + } else { + $Value = ""; + } + } else { + if ( isset($Parameters["ScaleMin"]) && isset ($Parameters["RowHeight"])) { + $Value = $this->scaleFormat( + $Parameters["ScaleMin"] + $Parameters["RowHeight"]*$i, + $Data["XAxisDisplay"], + $Data["XAxisFormat"], + $Data["XAxisUnit"] + ); + } else { + $Value = $i; + } + } + + $ID++; + $Skipped = true; + if ($this->isValidLabel($Value,$LastValue,$LabelingMethod,$ID,$LabelSkip) && !$RemoveXAxis) { + $Bounds = $this->drawText( + $XPos, + $YPos-$OuterTickWidth-$YLabelOffset, + $Value, + array("Angle"=>$LabelRotation,"Align"=>$LabelAlign) + ); + $TxtBox = $YPos-$OuterTickWidth-2-($Bounds[0]["Y"]-$Bounds[2]["Y"]); + $MinTop = min($MinTop,$TxtBox); + $LastValue = $Value; + $Skipped = false; + } + + if ( $RemoveXAxis ) { + $Skipped = false; + } + + if ( $Skipped ) { + if ($DrawXLines && !$RemoveSkippedAxis) { + $this->drawLine( + $XPos, + $this->GraphAreaY1+$FloatingOffset, + $XPos, + $this->GraphAreaY2-$FloatingOffset, + $SkippedAxisColor + ); + } + if (($SkippedInnerTickWidth !=0 || $SkippedOuterTickWidth != 0) + && !$RemoveXAxis + && !$RemoveSkippedAxis + ) { + $this->drawLine( + $XPos, + $YPos+$SkippedInnerTickWidth, + $XPos, + $YPos-$SkippedOuterTickWidth, + $SkippedTickColor + ); + } + } else { + if ( $DrawXLines ) { + $this->drawLine( + $XPos, + $this->GraphAreaY1+$FloatingOffset, + $XPos, + $this->GraphAreaY2-$FloatingOffset, + array("R"=>$GridR,"G"=>$GridG,"B"=>$GridB,"Alpha"=>$GridAlpha,"Ticks"=>$GridTicks) + ); + } + if (($InnerTickWidth !=0 || $OuterTickWidth != 0) && !$RemoveXAxis ) { + $this->drawLine( + $XPos, + $YPos+$InnerTickWidth, + $XPos, + $YPos-$OuterTickWidth, + array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha) + ); + } + } + } + + if (isset($Parameters["Name"]) && !$RemoveXAxis ) { + $YPos = $MinTop-2; + $XPos = $this->GraphAreaX1+($this->GraphAreaX2-$this->GraphAreaX1)/2; + $Bounds = $this->drawText($XPos,$YPos,$Parameters["Name"],array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE)); + $MinTop = $Bounds[2]["Y"]; + + $this->DataSet->Data["GraphArea"]["Y1"] = $MinTop; + } + + $AxisPos["T"] = $MinTop - $ScaleSpacing; + } + } elseif ( $Pos == SCALE_POS_TOPBOTTOM ) { + if ($Parameters["Position"] == AXIS_POSITION_LEFT) { + if ( $LabelRotation == 0 ) { $LabelAlign = TEXT_ALIGN_MIDDLERIGHT; $XLabelOffset = -2; } + if ( $LabelRotation > 0 && $LabelRotation < 190 ) { $LabelAlign = TEXT_ALIGN_MIDDLERIGHT; $XLabelOffset = -6; } + if ( $LabelRotation == 180 ) { $LabelAlign = TEXT_ALIGN_MIDDLELEFT; $XLabelOffset = -2; } + if ( $LabelRotation > 180 && $LabelRotation < 360 ) { $LabelAlign = TEXT_ALIGN_MIDDLELEFT; $XLabelOffset = -5; } + + if ( !$RemoveXAxis ) { + if ( $Floating ) { + $FloatingOffset = $YMargin; + $this->drawLine( + $AxisPos["L"], + $this->GraphAreaY1+$Parameters["Margin"], + $AxisPos["L"], + $this->GraphAreaY2-$Parameters["Margin"], + array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + } else { + $FloatingOffset = 0; + $this->drawLine( + $AxisPos["L"], + $this->GraphAreaY1, + $AxisPos["L"], + $this->GraphAreaY2, + array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + } + + if ( $DrawArrows ) { + $this->drawArrow( + $AxisPos["L"], + $this->GraphAreaY2-$Parameters["Margin"], + $AxisPos["L"], + $this->GraphAreaY2+($ArrowSize*2), + array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize) + ); + } + } + + $Height = ($this->GraphAreaY2 - $this->GraphAreaY1) - $Parameters["Margin"]*2; + + if ($Parameters["Rows"] == 0 ) { + $Step = $Height; + } else { + $Step = $Height / $Parameters["Rows"]; + } + + $MinLeft = $AxisPos["L"]; + for ($i=0;$i<=$Parameters["Rows"];$i++) { + $YPos = $this->GraphAreaY1 + $Parameters["Margin"] + $Step*$i; + $XPos = $AxisPos["L"]; + + if ( $Abscissa != null ) { + if ( isset($Data["Series"][$Abscissa]["Data"][$i]) ) { + $Value = $this->scaleFormat( + $Data["Series"][$Abscissa]["Data"][$i], + $Data["XAxisDisplay"], + $Data["XAxisFormat"], + $Data["XAxisUnit"] + ); + } else { + $Value = ""; + } + } else { + if (isset($Parameters["ScaleMin"]) && isset ($Parameters["RowHeight"])) { + $Value = $this->scaleFormat( + $Parameters["ScaleMin"] + $Parameters["RowHeight"]*$i, + $Data["XAxisDisplay"], + $Data["XAxisFormat"], + $Data["XAxisUnit"] + ); + } else { + $Value = $i; + } + } + + $ID++; + $Skipped = true; + if ( $this->isValidLabel($Value,$LastValue,$LabelingMethod,$ID,$LabelSkip) && !$RemoveXAxis) { + $Bounds = $this->drawText( + $XPos-$OuterTickWidth+$XLabelOffset, + $YPos, + $Value, + array("Angle"=>$LabelRotation,"Align"=>$LabelAlign) + ); + $TxtBox = $XPos-$OuterTickWidth-2-($Bounds[1]["X"]-$Bounds[0]["X"]); + $MinLeft = min($MinLeft,$TxtBox); + $LastValue = $Value; + $Skipped = false; + } + + if ($RemoveXAxis) { + $Skipped = false; + } + + if ($Skipped) { + if ($DrawXLines && !$RemoveSkippedAxis) { + $this->drawLine( + $this->GraphAreaX1+$FloatingOffset, + $YPos, + $this->GraphAreaX2-$FloatingOffset, + $YPos,$SkippedAxisColor + ); + } + if (($SkippedInnerTickWidth !=0 || $SkippedOuterTickWidth != 0) + && !$RemoveXAxis + && !$RemoveSkippedAxis + ) { + $this->drawLine( + $XPos-$SkippedOuterTickWidth, + $YPos, + $XPos+$SkippedInnerTickWidth, + $YPos,$SkippedTickColor + ); + } + } else { + if ( $DrawXLines && ($YPos != $this->GraphAreaY1 && $YPos != $this->GraphAreaY2) ) { + $this->drawLine( + $this->GraphAreaX1+$FloatingOffset, + $YPos, + $this->GraphAreaX2-$FloatingOffset, + $YPos, + array( + "R"=>$GridR, + "G"=>$GridG, + "B"=>$GridB, + "Alpha"=>$GridAlpha, + "Ticks"=>$GridTicks + ) + ); + } + if (($InnerTickWidth !=0 || $OuterTickWidth != 0) && !$RemoveXAxis ) { + $this->drawLine( + $XPos-$OuterTickWidth, + $YPos, + $XPos+$InnerTickWidth, + $YPos, + array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha) + ); + } + } + } + if ( isset($Parameters["Name"]) && !$RemoveXAxis ) { + $XPos = $MinLeft-2; + $YPos = $this->GraphAreaY1+($this->GraphAreaY2-$this->GraphAreaY1)/2; + $Bounds = $this->drawText( + $XPos, + $YPos, + $Parameters["Name"], + array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE,"Angle"=>90) + ); + $MinLeft = $Bounds[0]["X"]; + + $this->DataSet->Data["GraphArea"]["X1"] = $MinLeft; + } + + $AxisPos["L"] = $MinLeft - $ScaleSpacing; + } elseif ( $Parameters["Position"] == AXIS_POSITION_RIGHT ) { + if ( $LabelRotation == 0 ) { + $LabelAlign = TEXT_ALIGN_MIDDLELEFT; + $XLabelOffset = 2; + } + if ( $LabelRotation > 0 && $LabelRotation < 190 ) { + $LabelAlign = TEXT_ALIGN_MIDDLELEFT; + $XLabelOffset = 6; + } + if ( $LabelRotation == 180 ) { + $LabelAlign = TEXT_ALIGN_MIDDLERIGHT; + $XLabelOffset = 5; + } + if ( $LabelRotation > 180 && $LabelRotation < 360 ) { + $LabelAlign = TEXT_ALIGN_MIDDLERIGHT; + $XLabelOffset = 7; + } + + if ( !$RemoveXAxis ) { + if ( $Floating ) { + $FloatingOffset = $YMargin; + $this->drawLine( + $AxisPos["R"], + $this->GraphAreaY1+$Parameters["Margin"], + $AxisPos["R"], + $this->GraphAreaY2-$Parameters["Margin"], + array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + } else { + $FloatingOffset = 0; + $this->drawLine( + $AxisPos["R"], + $this->GraphAreaY1, + $AxisPos["R"], + $this->GraphAreaY2, + array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + } + + if ($DrawArrows) { + $this->drawArrow( + $AxisPos["R"], + $this->GraphAreaY2-$Parameters["Margin"], + $AxisPos["R"], + $this->GraphAreaY2+($ArrowSize*2), + array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize) + ); + } + } + + $Height = ($this->GraphAreaY2 - $this->GraphAreaY1) - $Parameters["Margin"]*2; + + if ($Parameters["Rows"] == 0 ) { + $Step = $Height; + } else { + $Step = $Height / $Parameters["Rows"]; + } + + $MaxRight = $AxisPos["R"]; + for ($i=0;$i<=$Parameters["Rows"];$i++) { + $YPos = $this->GraphAreaY1 + $Parameters["Margin"] + $Step*$i; + $XPos = $AxisPos["R"]; + + if ($Abscissa != null ) { + if (isset($Data["Series"][$Abscissa]["Data"][$i]) ) { + $Value = $this->scaleFormat( + $Data["Series"][$Abscissa]["Data"][$i], + $Data["XAxisDisplay"], + $Data["XAxisFormat"], + $Data["XAxisUnit"] + ); + } else { + $Value = ""; + } + } else { + if ( isset($Parameters["ScaleMin"]) && isset($Parameters["RowHeight"])) { + $Value = $this->scaleFormat( + $Parameters["ScaleMin"] + $Parameters["RowHeight"]*$i, + $Data["XAxisDisplay"], + $Data["XAxisFormat"], + $Data["XAxisUnit"] + ); + } else { + $Value = $i; + } + } + + $ID++; + $Skipped = true; + if ($this->isValidLabel($Value,$LastValue,$LabelingMethod,$ID,$LabelSkip) && !$RemoveXAxis) { + $Bounds = $this->drawText( + $XPos+$OuterTickWidth+$XLabelOffset, + $YPos, + $Value, + array("Angle"=>$LabelRotation,"Align"=>$LabelAlign) + ); + $TxtBox = $XPos+$OuterTickWidth+2+($Bounds[1]["X"]-$Bounds[0]["X"]); + $MaxRight = max($MaxRight,$TxtBox); + $LastValue = $Value; + $Skipped = false; + } + + if ($RemoveXAxis) { + $Skipped = false; + } + + if ($Skipped) { + if ($DrawXLines && !$RemoveSkippedAxis) { + $this->drawLine( + $this->GraphAreaX1+$FloatingOffset, + $YPos, + $this->GraphAreaX2-$FloatingOffset, + $YPos, + $SkippedAxisColor + ); + } + if (($SkippedInnerTickWidth != 0 || $SkippedOuterTickWidth != 0) + && !$RemoveXAxis && !$RemoveSkippedAxis + ) { + $this->drawLine( + $XPos+$SkippedOuterTickWidth, + $YPos, + $XPos-$SkippedInnerTickWidth, + $YPos, + $SkippedTickColor + ); + } + } else { + if ($DrawXLines ) { + $this->drawLine( + $this->GraphAreaX1+$FloatingOffset, + $YPos, + $this->GraphAreaX2-$FloatingOffset, + $YPos, + array("R"=>$GridR,"G"=>$GridG,"B"=>$GridB,"Alpha"=>$GridAlpha,"Ticks"=>$GridTicks) + ); + } + if (($InnerTickWidth != 0 || $OuterTickWidth != 0) && !$RemoveXAxis ) { + $this->drawLine( + $XPos+$OuterTickWidth, + $YPos, + $XPos-$InnerTickWidth, + $YPos, + array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha) + ); + } + } + + } + + if ( isset($Parameters["Name"]) && !$RemoveXAxis) { + $XPos = $MaxRight+4; + $YPos = $this->GraphAreaY1+($this->GraphAreaY2-$this->GraphAreaY1)/2; + $Bounds = $this->drawText( + $XPos, + $YPos, + $Parameters["Name"], + array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE,"Angle"=>270) + ); + $MaxRight = $Bounds[1]["X"]; + + $this->DataSet->Data["GraphArea"]["X2"] = $MaxRight + $this->FontSize; + } + + $AxisPos["R"] = $MaxRight + $ScaleSpacing; + } + } + } + + if ( $Parameters["Identity"] == AXIS_Y && !$RemoveYAxis) { + if ( $Pos == SCALE_POS_LEFTRIGHT ) { + if ( $Parameters["Position"] == AXIS_POSITION_LEFT ) { + + if ( $Floating ) { + $FloatingOffset = $XMargin; + $this->drawLine( + $AxisPos["L"], + $this->GraphAreaY1+$Parameters["Margin"], + $AxisPos["L"], + $this->GraphAreaY2-$Parameters["Margin"], + array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + + } else { + $FloatingOffset = 0; + $this->drawLine( + $AxisPos["L"], + $this->GraphAreaY1, + $AxisPos["L"], + $this->GraphAreaY2, + array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + + } + + if ($DrawArrows) { + $this->drawArrow( + $AxisPos["L"], + $this->GraphAreaY1+$Parameters["Margin"], + $AxisPos["L"], + $this->GraphAreaY1-($ArrowSize*2), + array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize) + ); + } + + $Height = ($this->GraphAreaY2 - $this->GraphAreaY1) - $Parameters["Margin"]*2; + $Step = $Height / $Parameters["Rows"]; + $SubTicksSize = $Step /2; + $MinLeft = $AxisPos["L"]; + $LastY = null; + for ($i=0;$i<=$Parameters["Rows"];$i++) { + $YPos = $this->GraphAreaY2 - $Parameters["Margin"] - $Step*$i; + $XPos = $AxisPos["L"]; + $Value = $this->scaleFormat( + $Parameters["ScaleMin"] + $Parameters["RowHeight"]*$i, + $Parameters["Display"], + $Parameters["Format"], + $Parameters["Unit"] + ); + + if ( $i%2 == 1 ) { + $BGColor = array( + "R"=>$BackgroundR1, + "G"=>$BackgroundG1, + "B"=>$BackgroundB1, + "Alpha"=>$BackgroundAlpha1 + ); + } else { + $BGColor = array( + "R"=>$BackgroundR2, + "G"=>$BackgroundG2, + "B"=>$BackgroundB2, + "Alpha"=>$BackgroundAlpha2 + ); + } + if ($LastY != null + && $CycleBackground + && ( $DrawYLines == ALL || in_array($AxisID,$DrawYLines) ) + ) { + $this->drawFilledRectangle( + $this->GraphAreaX1+$FloatingOffset, + $LastY, + $this->GraphAreaX2-$FloatingOffset, + $YPos, + $BGColor + ); + } + + if ($DrawYLines == ALL || in_array($AxisID,$DrawYLines)) { + $this->drawLine( + $this->GraphAreaX1+$FloatingOffset, + $YPos, + $this->GraphAreaX2-$FloatingOffset, + $YPos, + array("R"=>$GridR,"G"=>$GridG,"B"=>$GridB,"Alpha"=>$GridAlpha,"Ticks"=>$GridTicks) + ); + } + + if ( $DrawSubTicks && $i != $Parameters["Rows"] ) { + $this->drawLine( + $XPos-$OuterSubTickWidth, + $YPos-$SubTicksSize, + $XPos+$InnerSubTickWidth, + $YPos-$SubTicksSize, + array("R"=>$SubTickR,"G"=>$SubTickG,"B"=>$SubTickB,"Alpha"=>$SubTickAlpha) + ); + } + if (!$RemoveYAxiValues) { + $this->drawLine($XPos-$OuterTickWidth,$YPos,$XPos+$InnerTickWidth,$YPos,array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha)); + $Bounds = $this->drawText($XPos-$OuterTickWidth-2,$YPos,$Value,array("Align"=>TEXT_ALIGN_MIDDLERIGHT)); + $TxtLeft = $XPos-$OuterTickWidth-2-($Bounds[1]["X"]-$Bounds[0]["X"]); + $MinLeft = min($MinLeft,$TxtLeft); + } + + $LastY = $YPos; + } + + if ( isset($Parameters["Name"]) ) { + $XPos = $MinLeft-2; + $YPos = $this->GraphAreaY1+($this->GraphAreaY2-$this->GraphAreaY1)/2; + $Bounds = $this->drawText( + $XPos, + $YPos, + $Parameters["Name"], + array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE,"Angle"=>90) + ); + $MinLeft = $Bounds[2]["X"]; + + $this->DataSet->Data["GraphArea"]["X1"] = $MinLeft; + } + + $AxisPos["L"] = $MinLeft - $ScaleSpacing; + } elseif ($Parameters["Position"] == AXIS_POSITION_RIGHT) { + if ( $Floating ) { + $FloatingOffset = $XMargin; + $this->drawLine( + $AxisPos["R"], + $this->GraphAreaY1+$Parameters["Margin"], + $AxisPos["R"], + $this->GraphAreaY2-$Parameters["Margin"], + array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + } else { + $FloatingOffset = 0; + $this->drawLine( + $AxisPos["R"], + $this->GraphAreaY1, + $AxisPos["R"], + $this->GraphAreaY2, + array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + } + + if ($DrawArrows) { + $this->drawArrow( + $AxisPos["R"], + $this->GraphAreaY1+$Parameters["Margin"], + $AxisPos["R"], + $this->GraphAreaY1-($ArrowSize*2), + array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize) + ); + } + + $Height = ($this->GraphAreaY2 - $this->GraphAreaY1) - $Parameters["Margin"]*2; + $Step = $Height / $Parameters["Rows"]; + $SubTicksSize = $Step /2; + $MaxLeft = $AxisPos["R"]; + $LastY = null; + for ($i=0;$i<=$Parameters["Rows"];$i++) { + $YPos = $this->GraphAreaY2 - $Parameters["Margin"] - $Step*$i; + $XPos = $AxisPos["R"]; + $Value = $this->scaleFormat( + $Parameters["ScaleMin"] + $Parameters["RowHeight"]*$i, + $Parameters["Display"], + $Parameters["Format"], + $Parameters["Unit"] + ); + + if ($i%2 == 1) { + $BGColor = array( + "R"=>$BackgroundR1, + "G"=>$BackgroundG1, + "B"=>$BackgroundB1, + "Alpha"=>$BackgroundAlpha1 + ); + } else { + $BGColor = array( + "R"=>$BackgroundR2, + "G"=>$BackgroundG2, + "B"=>$BackgroundB2, + "Alpha"=>$BackgroundAlpha2 + ); + } + if ($LastY != null + && $CycleBackground + && ( $DrawYLines == ALL || in_array($AxisID,$DrawYLines)) + ) { + $this->drawFilledRectangle( + $this->GraphAreaX1+$FloatingOffset, + $LastY, + $this->GraphAreaX2-$FloatingOffset, + $YPos, + $BGColor + ); + } + + if ( $DrawYLines == ALL || in_array($AxisID,$DrawYLines) ) { + $this->drawLine( + $this->GraphAreaX1+$FloatingOffset, + $YPos, + $this->GraphAreaX2-$FloatingOffset, + $YPos, + array("R"=>$GridR,"G"=>$GridG,"B"=>$GridB,"Alpha"=>$GridAlpha,"Ticks"=>$GridTicks) + ); + } + + if ( $DrawSubTicks && $i != $Parameters["Rows"] ) { + $this->drawLine( + $XPos-$OuterSubTickWidth, + $YPos-$SubTicksSize, + $XPos+$InnerSubTickWidth, + $YPos-$SubTicksSize, + array("R"=>$SubTickR,"G"=>$SubTickG,"B"=>$SubTickB,"Alpha"=>$SubTickAlpha) + ); + } + $this->drawLine( + $XPos-$InnerTickWidth, + $YPos, + $XPos+$OuterTickWidth, + $YPos, + array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha) + ); + $Bounds = $this->drawText( + $XPos+$OuterTickWidth+2, + $YPos, + $Value,array("Align"=>TEXT_ALIGN_MIDDLELEFT) + ); + $TxtLeft = $XPos+$OuterTickWidth+2+($Bounds[1]["X"]-$Bounds[0]["X"]); + $MaxLeft = max($MaxLeft,$TxtLeft); + + $LastY = $YPos; + } + + if (isset($Parameters["Name"])) { + $XPos = $MaxLeft+6; + $YPos = $this->GraphAreaY1+($this->GraphAreaY2-$this->GraphAreaY1)/2; + $Bounds = $this->drawText( + $XPos, + $YPos, + $Parameters["Name"], + array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE,"Angle"=>270) + ); + $MaxLeft = $Bounds[2]["X"]; + + $this->DataSet->Data["GraphArea"]["X2"] = $MaxLeft + $this->FontSize; + } + $AxisPos["R"] = $MaxLeft + $ScaleSpacing; + } + } elseif ( $Pos == SCALE_POS_TOPBOTTOM ) { + if ( $Parameters["Position"] == AXIS_POSITION_TOP ) { + if ($Floating) { + $FloatingOffset = $XMargin; + $this->drawLine( + $this->GraphAreaX1+$Parameters["Margin"], + $AxisPos["T"], + $this->GraphAreaX2-$Parameters["Margin"], + $AxisPos["T"], + array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + } else { + $FloatingOffset = 0; + $this->drawLine( + $this->GraphAreaX1, + $AxisPos["T"], + $this->GraphAreaX2, + $AxisPos["T"], + array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + } + + if ($DrawArrows) { + $this->drawArrow( + $this->GraphAreaX2-$Parameters["Margin"], + $AxisPos["T"], + $this->GraphAreaX2+($ArrowSize*2), + $AxisPos["T"], + array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize) + ); + } + + $Width = ($this->GraphAreaX2 - $this->GraphAreaX1) - $Parameters["Margin"]*2; + $Step = $Width / $Parameters["Rows"]; + $SubTicksSize = $Step /2; + $MinTop = $AxisPos["T"]; + $LastX = null; + for ($i=0;$i<=$Parameters["Rows"];$i++) { + $XPos = $this->GraphAreaX1 + $Parameters["Margin"] + $Step*$i; + $YPos = $AxisPos["T"]; + $Value = $this->scaleFormat( + $Parameters["ScaleMin"] + $Parameters["RowHeight"]*$i, + $Parameters["Display"], + $Parameters["Format"], + $Parameters["Unit"] + ); + + if ($i%2 == 1) { + $BGColor = array( + "R"=>$BackgroundR1, + "G"=>$BackgroundG1, + "B"=>$BackgroundB1, + "Alpha"=>$BackgroundAlpha1 + ); + } else { + $BGColor = array( + "R"=>$BackgroundR2, + "G"=>$BackgroundG2, + "B"=>$BackgroundB2, + "Alpha"=>$BackgroundAlpha2 + ); + } + if ($LastX != null + && $CycleBackground + && ( $DrawYLines == ALL || in_array($AxisID,$DrawYLines)) + ) { + $this->drawFilledRectangle( + $LastX, + $this->GraphAreaY1+$FloatingOffset, + $XPos, + $this->GraphAreaY2-$FloatingOffset, + $BGColor + ); + } + + if ($DrawYLines == ALL || in_array($AxisID,$DrawYLines)) { + $this->drawLine( + $XPos, + $this->GraphAreaY1+$FloatingOffset, + $XPos, + $this->GraphAreaY2-$FloatingOffset, + array("R"=>$GridR,"G"=>$GridG,"B"=>$GridB,"Alpha"=>$GridAlpha,"Ticks"=>$GridTicks) + ); + } + + if ( $DrawSubTicks && $i != $Parameters["Rows"] ) { + $this->drawLine( + $XPos+$SubTicksSize, + $YPos-$OuterSubTickWidth, + $XPos+$SubTicksSize, + $YPos+$InnerSubTickWidth, + array("R"=>$SubTickR,"G"=>$SubTickG,"B"=>$SubTickB,"Alpha"=>$SubTickAlpha) + ); + } + $this->drawLine( + $XPos, + $YPos-$OuterTickWidth, + $XPos, + $YPos+$InnerTickWidth, + array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha) + ); + $Bounds = $this->drawText( + $XPos, + $YPos-$OuterTickWidth-2, + $Value, + array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE) + ); + $TxtHeight = $YPos-$OuterTickWidth-2-($Bounds[1]["Y"]-$Bounds[2]["Y"]); + $MinTop = min($MinTop,$TxtHeight); + + $LastX = $XPos; + } + + if (isset($Parameters["Name"])) { + $YPos = $MinTop-2; + $XPos = $this->GraphAreaX1+($this->GraphAreaX2-$this->GraphAreaX1)/2; + $Bounds = $this->drawText( + $XPos, + $YPos, + $Parameters["Name"], + array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE) + ); + $MinTop = $Bounds[2]["Y"]; + + $this->DataSet->Data["GraphArea"]["Y1"] = $MinTop; + } + + $AxisPos["T"] = $MinTop - $ScaleSpacing; + } elseif ( $Parameters["Position"] == AXIS_POSITION_BOTTOM ) { + if ( $Floating ) { + $FloatingOffset = $XMargin; + $this->drawLine( + $this->GraphAreaX1+$Parameters["Margin"], + $AxisPos["B"], + $this->GraphAreaX2-$Parameters["Margin"], + $AxisPos["B"], + array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + } else { + $FloatingOffset = 0; + $this->drawLine( + $this->GraphAreaX1, + $AxisPos["B"], + $this->GraphAreaX2, + $AxisPos["B"], + array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + } + + if ( $DrawArrows ) { + $this->drawArrow( + $this->GraphAreaX2-$Parameters["Margin"], + $AxisPos["B"], + $this->GraphAreaX2+($ArrowSize*2), + $AxisPos["B"], + array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize) + ); + } + + $Width = ($this->GraphAreaX2 - $this->GraphAreaX1) - $Parameters["Margin"]*2; + $Step = $Width / $Parameters["Rows"]; + $SubTicksSize = $Step /2; + $MaxBottom = $AxisPos["B"]; + $LastX = null; + for($i=0;$i<=$Parameters["Rows"];$i++) { + $XPos = $this->GraphAreaX1 + $Parameters["Margin"] + $Step*$i; + $YPos = $AxisPos["B"]; + $Value = $this->scaleFormat( + $Parameters["ScaleMin"] + $Parameters["RowHeight"]*$i, + $Parameters["Display"], + $Parameters["Format"], + $Parameters["Unit"] + ); + + if ( $i%2 == 1 ) { + $BGColor = array( + "R"=>$BackgroundR1, + "G"=>$BackgroundG1, + "B"=>$BackgroundB1, + "Alpha"=>$BackgroundAlpha1 + ); + } else { + $BGColor = array( + "R"=>$BackgroundR2, + "G"=>$BackgroundG2, + "B"=>$BackgroundB2, + "Alpha"=>$BackgroundAlpha2 + ); + } + if ($LastX != null + && $CycleBackground + && ( $DrawYLines == ALL || in_array($AxisID,$DrawYLines)) + ) { + $this->drawFilledRectangle( + $LastX,$this->GraphAreaY1+$FloatingOffset, + $XPos,$this->GraphAreaY2-$FloatingOffset, + $BGColor + ); + + } + + if ( $DrawYLines == ALL || in_array($AxisID,$DrawYLines) ) { + $this->drawLine( + $XPos, + $this->GraphAreaY1+$FloatingOffset, + $XPos, + $this->GraphAreaY2-$FloatingOffset, + array("R"=>$GridR,"G"=>$GridG,"B"=>$GridB,"Alpha"=>$GridAlpha,"Ticks"=>$GridTicks) + ); + } + + if ( $DrawSubTicks && $i != $Parameters["Rows"] ) { + $this->drawLine( + $XPos+$SubTicksSize, + $YPos-$OuterSubTickWidth, + $XPos+$SubTicksSize, + $YPos+$InnerSubTickWidth, + array("R"=>$SubTickR,"G"=>$SubTickG,"B"=>$SubTickB,"Alpha"=>$SubTickAlpha) + ); + } + $this->drawLine( + $XPos, + $YPos-$OuterTickWidth, + $XPos, + $YPos+$InnerTickWidth, + array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha) + ); + $Bounds = $this->drawText( + $XPos, + $YPos+$OuterTickWidth+2, + $Value, + array("Align"=>TEXT_ALIGN_TOPMIDDLE) + ); + $TxtHeight = $YPos+$OuterTickWidth+2+($Bounds[1]["Y"]-$Bounds[2]["Y"]); + $MaxBottom = max($MaxBottom,$TxtHeight); + + $LastX = $XPos; + } + + if (isset($Parameters["Name"])) { + $YPos = $MaxBottom+2; + $XPos = $this->GraphAreaX1+($this->GraphAreaX2-$this->GraphAreaX1)/2; + $Bounds = $this->drawText( + $XPos, + $YPos, + $Parameters["Name"], + array("Align"=>TEXT_ALIGN_TOPMIDDLE) + ); + $MaxBottom = $Bounds[0]["Y"]; + + $this->DataSet->Data["GraphArea"]["Y2"] = $MaxBottom + $this->FontSize; + } + + $AxisPos["B"] = $MaxBottom + $ScaleSpacing; + } + } + } + } + } + + /** + * + * @param type $Value + * @param type $LastValue + * @param type $LabelingMethod + * @param type $ID + * @param type $LabelSkip + * @return type + */ + public function isValidLabel($Value,$LastValue,$LabelingMethod,$ID,$LabelSkip) + { + if ( $LabelingMethod == LABELING_DIFFERENT && $Value != $LastValue ) { + return(true); + } + if ( $LabelingMethod == LABELING_DIFFERENT && $Value == $LastValue ) { + return(false); + } + if ( $LabelingMethod == LABELING_ALL && $LabelSkip == 0 ) { + return(true); + } + if ( $LabelingMethod == LABELING_ALL && ($ID+$LabelSkip) % ($LabelSkip+1) != 1 ) { + return(false); + } + + return(true); + } + + /** + * Compute the scale, check for the best visual factors + * @param type $XMin + * @param type $XMax + * @param type $MaxDivs + * @param type $Factors + * @param type $AxisID + * @return type + */ + public function computeScale($XMin,$XMax,$MaxDivs,$Factors,$AxisID=0) + { + /* Compute each factors */ + $Results = ""; + foreach ($Factors as $Key => $Factor) { + $Results[$Factor] = $this->processScale($XMin,$XMax,$MaxDivs,array($Factor),$AxisID); + } + /* Remove scales that are creating to much decimals */ + $GoodScaleFactors = ""; + foreach ($Results as $Key => $Result) { + $Decimals = preg_split("/\./",$Result["RowHeight"]); + if ( (!isset($Decimals[1])) || (strlen($Decimals[1]) < 6) ) { $GoodScaleFactors[] = $Key; } + } + + /* Found no correct scale, shame,... returns the 1st one as default */ + if ( $GoodScaleFactors == "" ) { + return($Results[$Factors[0]]); + } + + /* Find the factor that cause the maximum number of Rows */ + $MaxRows = 0; + $BestFactor = 0; + foreach($GoodScaleFactors as $Key => $Factor) { + if ( $Results[$Factor]["Rows"] > $MaxRows ) { + $MaxRows = $Results[$Factor]["Rows"]; + $BestFactor = $Factor; + } + } + + /* Return the best visual scale */ + return($Results[$BestFactor]); + } + + /** + * Compute the best matching scale based on size & factors + * @param type $XMin + * @param type $XMax + * @param type $MaxDivs + * @param type $Factors + * @param type $AxisID + * @return type + */ + public function processScale($XMin,$XMax,$MaxDivs,$Factors,$AxisID) + { + $ScaleHeight = abs(ceil($XMax)-floor($XMin)); + + if (isset($this->DataSet->Data["Axis"][$AxisID]["Format"])) { + $Format = $this->DataSet->Data["Axis"][$AxisID]["Format"]; + } else { + $Format = null; + } + if (isset($this->DataSet->Data["Axis"][$AxisID]["Display"])) { + $Mode = $this->DataSet->Data["Axis"][$AxisID]["Display"]; + } else { + $Mode = AXIS_FORMAT_DEFAULT; + } + $Scale = ""; + if ($XMin != $XMax) { + $Found = false; + $Rescaled = false; + $Scaled10Factor = .0001; + $Result = 0; + while(!$Found) { + foreach($Factors as $Key => $Factor) { + if ( !$Found ) { + if (!($this->modulo($XMin,$Factor*$Scaled10Factor) == 0) + || ($XMin != floor($XMin)) + ) { + $XMinRescaled = floor($XMin/($Factor*$Scaled10Factor)) + * $Factor*$Scaled10Factor; + } else { + $XMinRescaled = $XMin; + } + if (!($this->modulo($XMax,$Factor*$Scaled10Factor) == 0) + || ($XMax != floor($XMax)) + ) { + $XMaxRescaled = floor($XMax/($Factor*$Scaled10Factor)) + * $Factor*$Scaled10Factor+($Factor*$Scaled10Factor); + } else { + $XMaxRescaled = $XMax; + } + $ScaleHeightRescaled = abs($XMaxRescaled-$XMinRescaled); + + if (!$Found + && floor($ScaleHeightRescaled/($Factor*$Scaled10Factor)) <= $MaxDivs + ) { + $Found = true; + $Rescaled = true; + $Result = $Factor * $Scaled10Factor; + } + } + } + $Scaled10Factor = $Scaled10Factor * 10; + } + + /* ReCall Min / Max / Height */ + if ($Rescaled) { + $XMin = $XMinRescaled; + $XMax = $XMaxRescaled; + $ScaleHeight = $ScaleHeightRescaled; + } + + /* Compute rows size */ + $Rows = floor($ScaleHeight / $Result); + if ($Rows == 0) { + $Rows = 1; + } + $RowHeight = $ScaleHeight / $Rows; + + /* Return the results */ + $Scale["Rows"] = $Rows; + $Scale["RowHeight"] = $RowHeight; + $Scale["XMin"] = $XMin; + $Scale["XMax"] = $XMax; + + /* Compute the needed decimals for the metric view to avoid repetition of the same X Axis labels */ + if ( $Mode == AXIS_FORMAT_METRIC && $Format == null ) { + $Done = false; + $GoodDecimals = 0; + for($Decimals=0; $Decimals<=10; $Decimals++) { + if (!$Done) { + $LastLabel = "zob"; $ScaleOK = true; + for ($i=0;$i<=$Rows;$i++) { + $Value = $XMin + $i*$RowHeight; + $Label = $this->scaleFormat($Value,AXIS_FORMAT_METRIC,$Decimals); + + if ( $LastLabel == $Label ) { + $ScaleOK = false; + } + $LastLabel = $Label; + } + if ($ScaleOK) { + $Done = true; + $GoodDecimals = $Decimals; + } + } + } + $Scale["Format"] = $GoodDecimals; + } + } else { + /* If all values are the same we keep a +1/-1 scale */ + $Rows = 2; + $XMin = $XMax-1; + $XMax = $XMax+1; + $RowHeight = 1; + + /* Return the results */ + $Scale["Rows"] = $Rows; + $Scale["RowHeight"] = $RowHeight; + $Scale["XMin"] = $XMin; + $Scale["XMax"] = $XMax; + } + + return($Scale); + } + + /** + * + * @param type $Value1 + * @param type $Value2 + * @return type + */ + public function modulo($Value1,$Value2) + { + if (floor($Value2) == 0) { + return(0); + } + if (floor($Value2) != 0) { + return($Value1 % $Value2); + } + + $MinValue = min($Value1,$Value2); + $Factor = 10; + while ( floor($MinValue*$Factor) == 0 ) { + $Factor = $Factor * 10; + } + + return(($Value1*$Factor) % ($Value2*$Factor)); + } + + /** + * Draw an X threshold + * @param type $Value + * @param boolean $Format + * @return type + */ + public function drawXThreshold($Value,$Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : 255; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 50; + $Weight = isset($Format["Weight"]) ? $Format["Weight"] : null; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : 6; + $Wide = isset($Format["Wide"]) ? $Format["Wide"] : false; + $WideFactor = isset($Format["WideFactor"]) ? $Format["WideFactor"] : 5; + $WriteCaption = isset($Format["WriteCaption"]) ? $Format["WriteCaption"] : false; + $Caption = isset($Format["Caption"]) ? $Format["Caption"] : null; + $CaptionAlign = isset($Format["CaptionAlign"]) ? $Format["CaptionAlign"] : CAPTION_LEFT_TOP; + $CaptionOffset = isset($Format["CaptionOffset"]) ? $Format["CaptionOffset"] : 5; + $CaptionR = isset($Format["CaptionR"]) ? $Format["CaptionR"] : 255; + $CaptionG = isset($Format["CaptionG"]) ? $Format["CaptionG"] : 255; + $CaptionB = isset($Format["CaptionB"]) ? $Format["CaptionB"] : 255; + $CaptionAlpha = isset($Format["CaptionAlpha"]) ? $Format["CaptionAlpha"] : 100; + $DrawBox = isset($Format["DrawBox"]) ? $Format["DrawBox"] : true; + $DrawBoxBorder = isset($Format["DrawBoxBorder"]) ? $Format["DrawBoxBorder"] : false; + $BorderOffset = isset($Format["BorderOffset"]) ? $Format["BorderOffset"] : 3; + $BoxRounded = isset($Format["BoxRounded"]) ? $Format["BoxRounded"] : true; + $RoundedRadius = isset($Format["RoundedRadius"]) ? $Format["RoundedRadius"] : 3; + $BoxR = isset($Format["BoxR"]) ? $Format["BoxR"] : 0; + $BoxG = isset($Format["BoxG"]) ? $Format["BoxG"] : 0; + $BoxB = isset($Format["BoxB"]) ? $Format["BoxB"] : 0; + $BoxAlpha = isset($Format["BoxAlpha"]) ? $Format["BoxAlpha"] : 30; + $BoxSurrounding = isset($Format["BoxSurrounding"]) ? $Format["BoxSurrounding"] : ""; + $BoxBorderR = isset($Format["BoxBorderR"]) ? $Format["BoxBorderR"] : 255; + $BoxBorderG = isset($Format["BoxBorderG"]) ? $Format["BoxBorderG"] : 255; + $BoxBorderB = isset($Format["BoxBorderB"]) ? $Format["BoxBorderB"] : 255; + $BoxBorderAlpha = isset($Format["BoxBorderAlpha"]) ? $Format["BoxBorderAlpha"] : 100; + $ValueIsLabel = isset($Format["ValueIsLabel"]) ? $Format["ValueIsLabel"] : false; + + $Data = $this->DataSet->getData(); + $AbscissaMargin = $this->getAbscissaMargin($Data); + $XScale = $this->scaleGetXSettings(); + + if ( is_array($Value) ) { + foreach ($Value as $Key => $ID) { + $this->drawXThreshold($ID,$Format); + } + return(0); + } + + if ( $ValueIsLabel ) { + $Format["ValueIsLabel"] = false; + foreach($Data["Series"][$Data["Abscissa"]]["Data"] as $Key => $SerieValue) { + if ( $SerieValue == $Value ) { + $this->drawXThreshold($Key,$Format); + } + } + return(0); + } + + $CaptionSettings = array( + "DrawBox"=>$DrawBox, + "DrawBoxBorder"=>$DrawBoxBorder, + "BorderOffset"=>$BorderOffset, + "BoxRounded"=>$BoxRounded, + "RoundedRadius"=>$RoundedRadius, + "BoxR"=>$BoxR, + "BoxG"=>$BoxG, + "BoxB"=>$BoxB, + "BoxAlpha"=>$BoxAlpha, + "BoxSurrounding"=>$BoxSurrounding, + "BoxBorderR"=>$BoxBorderR, + "BoxBorderG"=>$BoxBorderG, + "BoxBorderB"=>$BoxBorderB, + "BoxBorderAlpha"=>$BoxBorderAlpha, + "R"=>$CaptionR, + "G"=>$CaptionG, + "B"=>$CaptionB, + "Alpha"=>$CaptionAlpha + ); + + if ( $Caption == null ) { + if (isset($Data["Abscissa"])) { + if (isset($Data["Series"][$Data["Abscissa"]]["Data"][$Value])) { + $Caption = $Data["Series"][$Data["Abscissa"]]["Data"][$Value]; + } else { + $Caption = $Value; + } + } else { + $Caption = $Value; + } + } + + if ($Data["Orientation"] == SCALE_POS_LEFTRIGHT) { + $XStep = (($this->GraphAreaX2 - $this->GraphAreaX1) - $XScale[0] *2 ) / $XScale[1]; + $XPos = $this->GraphAreaX1 + $XScale[0] + $XStep * $Value; + $YPos1 = $this->GraphAreaY1 + $Data["YMargin"]; + $YPos2 = $this->GraphAreaY2 - $Data["YMargin"]; + + if ($XPos >= $this->GraphAreaX1 + $AbscissaMargin + && $XPos <= $this->GraphAreaX2 - $AbscissaMargin + ) { + $this->drawLine( + $XPos, + $YPos1, + $XPos, + $YPos2, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Weight"=>$Weight) + ); + + if ( $Wide ) { + $this->drawLine( + $XPos-1, + $YPos1, + $XPos-1, + $YPos2, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks) + ); + $this->drawLine( + $XPos+1, + $YPos1, + $XPos+1, + $YPos2, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks) + ); + } + + if ( $WriteCaption ) { + if ( $CaptionAlign == CAPTION_LEFT_TOP ) { + $Y = $YPos1 + $CaptionOffset; + $CaptionSettings["Align"] = TEXT_ALIGN_TOPMIDDLE; + } else { + $Y = $YPos2 - $CaptionOffset; + $CaptionSettings["Align"] = TEXT_ALIGN_BOTTOMMIDDLE; + } + $this->drawText($XPos,$Y,$Caption,$CaptionSettings); + } + + return(array("X"=>$XPos)); + } + } elseif($Data["Orientation"] == SCALE_POS_TOPBOTTOM) { + $XStep = (($this->GraphAreaY2 - $this->GraphAreaY1) - $XScale[0] *2 ) / $XScale[1]; + $XPos = $this->GraphAreaY1 + $XScale[0] + $XStep * $Value; + $YPos1 = $this->GraphAreaX1 + $Data["YMargin"]; + $YPos2 = $this->GraphAreaX2 - $Data["YMargin"]; + + if ($XPos >= $this->GraphAreaY1 + $AbscissaMargin + && $XPos <= $this->GraphAreaY2 - $AbscissaMargin + ) { + $this->drawLine( + $YPos1, + $XPos, + $YPos2, + $XPos, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Weight"=>$Weight) + ); + + if ( $Wide ) { + $this->drawLine( + $YPos1, + $XPos-1, + $YPos2, + $XPos-1, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks) + ); + $this->drawLine( + $YPos1, + $XPos+1, + $YPos2, + $XPos+1, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks) + ); + } + + if ( $WriteCaption ) { + if ( $CaptionAlign == CAPTION_LEFT_TOP ) { + $Y = $YPos1 + $CaptionOffset; + $CaptionSettings["Align"] = TEXT_ALIGN_MIDDLELEFT; + } else { + $Y = $YPos2 - $CaptionOffset; + $CaptionSettings["Align"] = TEXT_ALIGN_MIDDLERIGHT; + } + + $this->drawText($Y,$XPos,$Caption,$CaptionSettings); + } + + return(array("X"=>$XPos)); + } + } + } + + /** + * Draw an X threshold area + * @param type $Value1 + * @param type $Value2 + * @param type $Format + * @return type + */ + public function drawXThresholdArea($Value1,$Value2,$Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : 255; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 20; + $Border = isset($Format["Border"]) ? $Format["Border"] : true; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $R; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $G; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $B; + $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : $Alpha + 20; + $BorderTicks = isset($Format["BorderTicks"]) ? $Format["BorderTicks"] : 2; + $AreaName = isset($Format["AreaName"]) ? $Format["AreaName"] : null; + $NameAngle = isset($Format["NameAngle"]) ? $Format["NameAngle"] : ZONE_NAME_ANGLE_AUTO; + $NameR = isset($Format["NameR"]) ? $Format["NameR"] : 255; + $NameG = isset($Format["NameG"]) ? $Format["NameG"] : 255; + $NameB = isset($Format["NameB"]) ? $Format["NameB"] : 255; + $NameAlpha = isset($Format["NameAlpha"]) ? $Format["NameAlpha"] : 100; + $DisableShadowOnArea = isset($Format["DisableShadowOnArea"]) ? $Format["DisableShadowOnArea"] : true; + + $RestoreShadow = $this->Shadow; + if ($DisableShadowOnArea && $this->Shadow) { + $this->Shadow = false; + } + + if ($BorderAlpha >100) { + $BorderAlpha = 100; + } + + $Data = $this->DataSet->getData(); + $XScale = $this->scaleGetXSettings(); + $AbscissaMargin = $this->getAbscissaMargin($Data); + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) { + $XStep = (($this->GraphAreaX2 - $this->GraphAreaX1) - $XScale[0] *2 ) / $XScale[1]; + $XPos1 = $this->GraphAreaX1 + $XScale[0] + $XStep * $Value1; + $XPos2 = $this->GraphAreaX1 + $XScale[0] + $XStep * $Value2; + $YPos1 = $this->GraphAreaY1 + $Data["YMargin"]; + $YPos2 = $this->GraphAreaY2 - $Data["YMargin"]; + + if ( $XPos1 < $this->GraphAreaX1 + $XScale[0] ) { + $XPos1 = $this->GraphAreaX1 + $XScale[0]; + } + if ( $XPos1 > $this->GraphAreaX2 - $XScale[0] ) { + $XPos1 = $this->GraphAreaX2 - $XScale[0]; + } + if ( $XPos2 < $this->GraphAreaX1 + $XScale[0] ) { + $XPos2 = $this->GraphAreaX1 + $XScale[0]; + } + if ( $XPos2 > $this->GraphAreaX2 - $XScale[0] ) { + $XPos2 = $this->GraphAreaX2 - $XScale[0]; + } + + $this->drawFilledRectangle( + $XPos1, + $YPos1, + $XPos2, + $YPos2, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha) + ); + + if ( $Border ) { + $this->drawLine( + $XPos1, + $YPos1, + $XPos1, + $YPos2, + array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$BorderTicks) + ); + $this->drawLine( + $XPos2, + $YPos1, + $XPos2, + $YPos2, + array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$BorderTicks) + ); + } + + if ( $AreaName != null ) { + $XPos = ($XPos2-$XPos1)/2 + $XPos1; + $YPos = ($YPos2-$YPos1)/2 + $YPos1; + + if ( $NameAngle == ZONE_NAME_ANGLE_AUTO ) { + $TxtPos = $this->getTextBox( + $XPos, + $YPos, + $this->FontName, + $this->FontSize, + 0, + $AreaName + ); + $TxtWidth = $TxtPos[1]["X"] - $TxtPos[0]["X"]; + if (abs($XPos2 - $XPos1) > $TxtWidth) { + $NameAngle = 0; + } else { + $NameAngle = 90; + } + } + $this->Shadow = $RestoreShadow; + $this->drawText( + $XPos, + $YPos, + $AreaName, + array( + "R"=>$NameR, + "G"=>$NameG, + "B"=>$NameB, + "Alpha"=>$NameAlpha, + "Angle"=>$NameAngle, + "Align"=>TEXT_ALIGN_MIDDLEMIDDLE + ) + ); + if ( $DisableShadowOnArea ) { + $this->Shadow = false; + } + } + + $this->Shadow = $RestoreShadow; + return(array("X1"=>$XPos1,"X2"=>$XPos2)); + } elseif ($Data["Orientation"] == SCALE_POS_TOPBOTTOM) { + $XStep = (($this->GraphAreaY2 - $this->GraphAreaY1) - $XScale[0] *2 ) / $XScale[1]; + $XPos1 = $this->GraphAreaY1 + $XScale[0] + $XStep * $Value1; + $XPos2 = $this->GraphAreaY1 + $XScale[0] + $XStep * $Value2; + $YPos1 = $this->GraphAreaX1 + $Data["YMargin"]; + $YPos2 = $this->GraphAreaX2 - $Data["YMargin"]; + + if ( $XPos1 < $this->GraphAreaY1 + $XScale[0] ) { + $XPos1 = $this->GraphAreaY1 + $XScale[0]; + } + if ( $XPos1 > $this->GraphAreaY2 - $XScale[0] ) { + $XPos1 = $this->GraphAreaY2 - $XScale[0]; + } + if ( $XPos2 < $this->GraphAreaY1 + $XScale[0] ) { + $XPos2 = $this->GraphAreaY1 + $XScale[0]; + } + if ( $XPos2 > $this->GraphAreaY2 - $XScale[0] ) { + $XPos2 = $this->GraphAreaY2 - $XScale[0]; + } + + $this->drawFilledRectangle( + $YPos1, + $XPos1, + $YPos2, + $XPos2, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha) + ); + + if ( $Border ) { + $this->drawLine( + $YPos1, + $XPos1, + $YPos2, + $XPos1, + array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$BorderTicks) + ); + $this->drawLine( + $YPos1, + $XPos2, + $YPos2, + $XPos2, + array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$BorderTicks) + ); + } + + if ( $AreaName != null ) { + $XPos = ($XPos2-$XPos1)/2 + $XPos1; + $YPos = ($YPos2-$YPos1)/2 + $YPos1; + + $this->Shadow = $RestoreShadow; + $this->drawText( + $YPos, + $XPos, + $AreaName, + array( + "R"=>$NameR, + "G"=>$NameG, + "B"=>$NameB, + "Alpha"=>$NameAlpha, + "Angle"=>0, + "Align"=>TEXT_ALIGN_MIDDLEMIDDLE + ) + ); + if ($DisableShadowOnArea) { + $this->Shadow = false; + } + } + + $this->Shadow = $RestoreShadow; + return(array("X1"=>$XPos1,"X2"=>$XPos2)); + } + } + + /** + * Draw an Y threshold with the computed scale + * @param type $Value + * @param type $Format + * @return type + */ + public function drawThreshold($Value,$Format="") + { + $AxisID = isset($Format["AxisID"]) ? $Format["AxisID"] : 0; + $R = isset($Format["R"]) ? $Format["R"] : 255; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 50; + $Weight = isset($Format["Weight"]) ? $Format["Weight"] : null; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : 6; + $Wide = isset($Format["Wide"]) ? $Format["Wide"] : false; + $WideFactor = isset($Format["WideFactor"]) ? $Format["WideFactor"] : 5; + $WriteCaption = isset($Format["WriteCaption"]) ? $Format["WriteCaption"] : false; + $Caption = isset($Format["Caption"]) ? $Format["Caption"] : null; + $CaptionAlign = isset($Format["CaptionAlign"]) ? $Format["CaptionAlign"] : CAPTION_LEFT_TOP; + $CaptionOffset = isset($Format["CaptionOffset"]) ? $Format["CaptionOffset"] : 10; + $CaptionR = isset($Format["CaptionR"]) ? $Format["CaptionR"] : 255; + $CaptionG = isset($Format["CaptionG"]) ? $Format["CaptionG"] : 255; + $CaptionB = isset($Format["CaptionB"]) ? $Format["CaptionB"] : 255; + $CaptionAlpha = isset($Format["CaptionAlpha"]) ? $Format["CaptionAlpha"] : 100; + $DrawBox = isset($Format["DrawBox"]) ? $Format["DrawBox"] : true; + $DrawBoxBorder = isset($Format["DrawBoxBorder"]) ? $Format["DrawBoxBorder"] : false; + $BorderOffset = isset($Format["BorderOffset"]) ? $Format["BorderOffset"] : 5; + $BoxRounded = isset($Format["BoxRounded"]) ? $Format["BoxRounded"] : true; + $RoundedRadius = isset($Format["RoundedRadius"]) ? $Format["RoundedRadius"] : 3; + $BoxR = isset($Format["BoxR"]) ? $Format["BoxR"] : 0; + $BoxG = isset($Format["BoxG"]) ? $Format["BoxG"] : 0; + $BoxB = isset($Format["BoxB"]) ? $Format["BoxB"] : 0; + $BoxAlpha = isset($Format["BoxAlpha"]) ? $Format["BoxAlpha"] : 20; + $BoxSurrounding = isset($Format["BoxSurrounding"]) ? $Format["BoxSurrounding"] : ""; + $BoxBorderR = isset($Format["BoxBorderR"]) ? $Format["BoxBorderR"] : 255; + $BoxBorderG = isset($Format["BoxBorderG"]) ? $Format["BoxBorderG"] : 255; + $BoxBorderB = isset($Format["BoxBorderB"]) ? $Format["BoxBorderB"] : 255; + $BoxBorderAlpha = isset($Format["BoxBorderAlpha"]) ? $Format["BoxBorderAlpha"] : 100; + $NoMargin = isset($Format["NoMargin"]) ? $Format["NoMargin"] : false; + + if ( is_array($Value) ) { + foreach ($Value as $Key => $ID) { + $this->drawThreshold($ID,$Format); + } + return(0); + } + + $CaptionSettings = array( + "DrawBox"=>$DrawBox, + "DrawBoxBorder"=>$DrawBoxBorder, + "BorderOffset"=>$BorderOffset, + "BoxRounded"=>$BoxRounded, + "RoundedRadius"=>$RoundedRadius, + "BoxR"=>$BoxR, + "BoxG"=>$BoxG, + "BoxB"=>$BoxB, + "BoxAlpha"=>$BoxAlpha, + "BoxSurrounding"=>$BoxSurrounding, + "BoxBorderR"=>$BoxBorderR, + "BoxBorderG"=>$BoxBorderG, + "BoxBorderB"=>$BoxBorderB, + "BoxBorderAlpha"=>$BoxBorderAlpha, + "R"=>$CaptionR, + "G"=>$CaptionG, + "B"=>$CaptionB, + "Alpha"=>$CaptionAlpha + ); + + $Data = $this->DataSet->getData(); + $AbscissaMargin = $this->getAbscissaMargin($Data); + + if ($NoMargin) { + $AbscissaMargin = 0; + } + if (!isset($Data["Axis"][$AxisID])) { + return(-1); + } + if ($Caption == null) { + $Caption = $Value; + } + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) { + $YPos = $this->scaleComputeY($Value,array("AxisID"=>$AxisID)); + if ($YPos >= $this->GraphAreaY1+$Data["Axis"][$AxisID]["Margin"] + && $YPos <= $this->GraphAreaY2-$Data["Axis"][$AxisID]["Margin"] + ) { + $X1 = $this->GraphAreaX1 + $AbscissaMargin; + $X2 = $this->GraphAreaX2 - $AbscissaMargin; + + $this->drawLine( + $X1, + $YPos, + $X2, + $YPos, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Weight"=>$Weight) + ); + + if ($Wide) { + $this->drawLine( + $X1, + $YPos-1, + $X2, + $YPos-1, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks) + ); + $this->drawLine( + $X1, + $YPos+1, + $X2, + $YPos+1, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks) + ); + } + + if ($WriteCaption) { + if ( $CaptionAlign == CAPTION_LEFT_TOP ) { + $X = $X1 + $CaptionOffset; + $CaptionSettings["Align"] = TEXT_ALIGN_MIDDLELEFT; + } else { + $X = $X2 - $CaptionOffset; + $CaptionSettings["Align"] = TEXT_ALIGN_MIDDLERIGHT; + } + + $this->drawText($X,$YPos,$Caption,$CaptionSettings); + } + } + + return(array("Y"=>$YPos)); + } + + if ( $Data["Orientation"] == SCALE_POS_TOPBOTTOM ) { + $XPos = $this->scaleComputeY($Value,array("AxisID"=>$AxisID)); + if ($XPos >= $this->GraphAreaX1+$Data["Axis"][$AxisID]["Margin"] + && $XPos <= $this->GraphAreaX2-$Data["Axis"][$AxisID]["Margin"] + ) { + $Y1 = $this->GraphAreaY1 + $AbscissaMargin; + $Y2 = $this->GraphAreaY2 - $AbscissaMargin; + + $this->drawLine( + $XPos, + $Y1, + $XPos, + $Y2, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Weight"=>$Weight) + ); + + if ( $Wide ) { + $this->drawLine( + $XPos-1, + $Y1, + $XPos-1, + $Y2, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks) + ); + $this->drawLine( + $XPos+1, + $Y1, + $XPos+1, + $Y2, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks) + ); + } + + if ( $WriteCaption ) { + if ( $CaptionAlign == CAPTION_LEFT_TOP ) { + $Y = $Y1 + $CaptionOffset; + $CaptionSettings["Align"] = TEXT_ALIGN_TOPMIDDLE; + } else { + $Y = $Y2 - $CaptionOffset; + $CaptionSettings["Align"] = TEXT_ALIGN_BOTTOMMIDDLE; + } + + $CaptionSettings["Align"] = TEXT_ALIGN_TOPMIDDLE; + $this->drawText($XPos,$Y,$Caption,$CaptionSettings); + } + } + + return(array("Y"=>$XPos)); + } + } + + /** + * Draw a threshold with the computed scale + * @param type $Value1 + * @param type $Value2 + * @param type $Format + * @return type + */ + public function drawThresholdArea($Value1,$Value2,$Format="") + { + $AxisID = isset($Format["AxisID"]) ? $Format["AxisID"] : 0; + $R = isset($Format["R"]) ? $Format["R"] : 255; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 20; + $Border = isset($Format["Border"]) ? $Format["Border"] : true; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $R; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $G; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $B; + $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : $Alpha + 20; + $BorderTicks = isset($Format["BorderTicks"]) ? $Format["BorderTicks"] : 2; + $AreaName = isset($Format["AreaName"]) ? $Format["AreaName"] : null; + $NameAngle = isset($Format["NameAngle"]) ? $Format["NameAngle"] : ZONE_NAME_ANGLE_AUTO; + $NameR = isset($Format["NameR"]) ? $Format["NameR"] : 255; + $NameG = isset($Format["NameG"]) ? $Format["NameG"] : 255; + $NameB = isset($Format["NameB"]) ? $Format["NameB"] : 255; + $NameAlpha = isset($Format["NameAlpha"]) ? $Format["NameAlpha"] : 100; + $DisableShadowOnArea = isset($Format["DisableShadowOnArea"]) ? $Format["DisableShadowOnArea"] : true; + $NoMargin = isset($Format["NoMargin"]) ? $Format["NoMargin"] : false; + + if ($Value1 > $Value2) { + list($Value1, $Value2) = array($Value2, $Value1); + } + + $RestoreShadow = $this->Shadow; + if ($DisableShadowOnArea && $this->Shadow) { + $this->Shadow = false; + } + + if ($BorderAlpha >100) { + $BorderAlpha = 100; + } + + $Data = $this->DataSet->getData(); + $AbscissaMargin = $this->getAbscissaMargin($Data); + + if ( $NoMargin ) { + $AbscissaMargin = 0; + } + if ( !isset($Data["Axis"][$AxisID]) ) { + return(-1); + } + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) { + $XPos1 = $this->GraphAreaX1 + $AbscissaMargin; + $XPos2 = $this->GraphAreaX2 - $AbscissaMargin; + $YPos1 = $this->scaleComputeY($Value1,array("AxisID"=>$AxisID)); + $YPos2 = $this->scaleComputeY($Value2,array("AxisID"=>$AxisID)); + + if ( $YPos1 < $this->GraphAreaY1+$Data["Axis"][$AxisID]["Margin"] ) { + $YPos1 = $this->GraphAreaY1+$Data["Axis"][$AxisID]["Margin"]; + } + if ( $YPos1 > $this->GraphAreaY2-$Data["Axis"][$AxisID]["Margin"] ) { + $YPos1 = $this->GraphAreaY2-$Data["Axis"][$AxisID]["Margin"]; + } + if ( $YPos2 < $this->GraphAreaY1+$Data["Axis"][$AxisID]["Margin"] ) { + $YPos2 = $this->GraphAreaY1+$Data["Axis"][$AxisID]["Margin"]; + } + if ( $YPos2 > $this->GraphAreaY2-$Data["Axis"][$AxisID]["Margin"] ) { + $YPos2 = $this->GraphAreaY2-$Data["Axis"][$AxisID]["Margin"]; + } + + $this->drawFilledRectangle( + $XPos1, + $YPos1, + $XPos2, + $YPos2, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha) + ); + if ( $Border ) { + $this->drawLine( + $XPos1, + $YPos1, + $XPos2, + $YPos1, + array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$BorderTicks) + ); + $this->drawLine( + $XPos1, + $YPos2, + $XPos2, + $YPos2, + array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$BorderTicks) + ); + } + + if ( $AreaName != null ) { + $XPos = ($XPos2-$XPos1)/2 + $XPos1; + $YPos = ($YPos2-$YPos1)/2 + $YPos1; + $this->Shadow = $RestoreShadow; + $this->drawText( + $XPos, + $YPos, + $AreaName, + array( + "R"=>$NameR, + "G"=>$NameG, + "B"=>$NameB, + "Alpha"=>$NameAlpha, + "Angle"=>0, + "Align"=>TEXT_ALIGN_MIDDLEMIDDLE + ) + ); + if ($DisableShadowOnArea) { + $this->Shadow = false; + } + } + + $this->Shadow = $RestoreShadow; + return(array("Y1"=>$YPos1,"Y2"=>$YPos2)); + } elseif ($Data["Orientation"] == SCALE_POS_TOPBOTTOM) { + $YPos1 = $this->GraphAreaY1 + $AbscissaMargin; + $YPos2 = $this->GraphAreaY2 - $AbscissaMargin; + $XPos1 = $this->scaleComputeY($Value1,array("AxisID"=>$AxisID)); + $XPos2 = $this->scaleComputeY($Value2,array("AxisID"=>$AxisID)); + + if ( $XPos1 < $this->GraphAreaX1+$Data["Axis"][$AxisID]["Margin"] ) { + $XPos1 = $this->GraphAreaX1+$Data["Axis"][$AxisID]["Margin"]; + } + if ( $XPos1 > $this->GraphAreaX2-$Data["Axis"][$AxisID]["Margin"] ) { + $XPos1 = $this->GraphAreaX2-$Data["Axis"][$AxisID]["Margin"]; + } + if ( $XPos2 < $this->GraphAreaX1+$Data["Axis"][$AxisID]["Margin"] ) { + $XPos2 = $this->GraphAreaX1+$Data["Axis"][$AxisID]["Margin"]; + } + if ( $XPos2 > $this->GraphAreaX2-$Data["Axis"][$AxisID]["Margin"] ) { + $XPos2 = $this->GraphAreaX2-$Data["Axis"][$AxisID]["Margin"]; + } + + $this->drawFilledRectangle( + $XPos1, + $YPos1, + $XPos2, + $YPos2, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha) + ); + if ($Border) { + $this->drawLine( + $XPos1, + $YPos1, + $XPos1, + $YPos2, + array( + "R"=>$BorderR, + "G"=>$BorderG, + "B"=>$BorderB, + "Alpha"=>$BorderAlpha, + "Ticks"=>$BorderTicks + ) + ); + $this->drawLine( + $XPos2, + $YPos1, + $XPos2, + $YPos2, + array( + "R"=>$BorderR, + "G"=>$BorderG, + "B"=>$BorderB, + "Alpha"=>$BorderAlpha, + "Ticks"=>$BorderTicks + ) + ); + } + + if ( $AreaName != null ) { + $XPos = ($YPos2-$YPos1)/2 + $YPos1; + $YPos = ($XPos2-$XPos1)/2 + $XPos1; + + if ( $NameAngle == ZONE_NAME_ANGLE_AUTO ) { + $TxtPos = $this->getTextBox( + $XPos, + $YPos, + $this->FontName, + $this->FontSize, + 0, + $AreaName + ); + $TxtWidth = $TxtPos[1]["X"] - $TxtPos[0]["X"]; + if ( abs($XPos2 - $XPos1) > $TxtWidth ) { + $NameAngle = 0; + } else { + $NameAngle = 90; + } + } + $this->Shadow = $RestoreShadow; + $this->drawText( + $YPos, + $XPos, + $AreaName, + array( + "R"=>$NameR, + "G"=>$NameG, + "B"=>$NameB, + "Alpha"=>$NameAlpha, + "Angle"=>$NameAngle, + "Align"=>TEXT_ALIGN_MIDDLEMIDDLE + ) + ); + if ( $DisableShadowOnArea ) { + $this->Shadow = false; + } + } + + $this->Shadow = $RestoreShadow; + return(array("Y1"=>$XPos1,"Y2"=>$XPos2)); + } + } + + /** + * + * @return type + */ + public function scaleGetXSettings() + { + $Data = $this->DataSet->getData(); + foreach($Data["Axis"] as $AxisID => $Settings) { + if ( $Settings["Identity"] == AXIS_X ) { + $Rows = $Settings["Rows"]; + + return(array($Settings["Margin"],$Rows)); + } + } + } + + /** + * + * @param type $Values + * @param type $Option + * @param type $ReturnOnly0Height + * @return type + */ + public function scaleComputeY($Values,$Option="",$ReturnOnly0Height=false) + { + $AxisID = isset($Option["AxisID"]) ? $Option["AxisID"] : 0; + $SerieName = isset($Option["SerieName"]) ? $Option["SerieName"] : null; + + $Data = $this->DataSet->getData(); + if (!isset($Data["Axis"][$AxisID])) { + return(-1); + } + + if ( $SerieName != null ) { + $AxisID = $Data["Series"][$SerieName]["Axis"]; + } + if ( !is_array($Values) ) { + $tmp = $Values; + $Values = ""; + $Values[0] = $tmp; + } + + $Result = ""; + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) { + $Height = ($this->GraphAreaY2 - $this->GraphAreaY1) - $Data["Axis"][$AxisID]["Margin"]*2; + $ScaleHeight = $Data["Axis"][$AxisID]["ScaleMax"] - $Data["Axis"][$AxisID]["ScaleMin"]; + $Step = $Height / $ScaleHeight; + + if ( $ReturnOnly0Height ) { + foreach($Values as $Key => $Value) { + if ( $Value == VOID ) { + $Result[] = VOID; + } else { + $Result[] = $Step * $Value; + } + } + + } else { + foreach($Values as $Key => $Value) { + if ( $Value == VOID ) { + $Result[] = VOID; + + } else { + $Result[] = $this->GraphAreaY2 - $Data["Axis"][$AxisID]["Margin"] + - ($Step * ($Value-$Data["Axis"][$AxisID]["ScaleMin"])); + } + } + } + } else { + $Width = ($this->GraphAreaX2 - $this->GraphAreaX1) - $Data["Axis"][$AxisID]["Margin"]*2; + $ScaleWidth = $Data["Axis"][$AxisID]["ScaleMax"] - $Data["Axis"][$AxisID]["ScaleMin"]; + $Step = $Width / $ScaleWidth; + + if ( $ReturnOnly0Height ) { + foreach($Values as $Key => $Value) { + if ( $Value == VOID ) { + $Result[] = VOID; + } else { + $Result[] = $Step * $Value; + } + } + + } else { + foreach($Values as $Key => $Value) { + if ( $Value == VOID ) { + $Result[] = VOID; + } else { + $Result[] = $this->GraphAreaX1 + $Data["Axis"][$AxisID]["Margin"] + + ($Step * ($Value-$Data["Axis"][$AxisID]["ScaleMin"])); + } + } + } + } + + if ( count($Result) == 1 ) { + return($Result[0]); + } else { + return($Result); + } + } + + /** + * Format the axis values + * @param type $Value + * @param type $Mode + * @param type $Format + * @param type $Unit + * @return type + */ + public function scaleFormat($Value,$Mode=null,$Format=null,$Unit=null) + { + if ( $Value == VOID ) { + return(""); + } + + if ( $Mode == AXIS_FORMAT_TRAFFIC ) { + if ( $Value == 0 ) { + return("0B"); + } + $Units = array("B","KB","MB","GB","TB","PB"); + $Sign = ""; + if ($Value < 0) { + $Value = abs($Value); + $Sign = "-"; + } + + $Value = number_format($Value/pow(1024,($Scale=floor(log($Value,1024)))),2,",","."); + return($Sign.$Value." ".$Units[$Scale]); + } + + if ( $Mode == AXIS_FORMAT_CUSTOM ) { + if ( function_exists($Format) ) { + return(call_user_func($Format,$Value)); + } + } + + if ( $Mode == AXIS_FORMAT_DATE ) { + if ( $Format == null ) { + $Pattern = "d/m/Y"; + } else { + $Pattern = $Format; + } + return(gmdate($Pattern,$Value)); + } + + if ( $Mode == AXIS_FORMAT_TIME ) { + if ( $Format == null ) { + $Pattern = "H:i:s"; + } else { + $Pattern = $Format; + } + return(gmdate($Pattern,$Value)); + } + + if ( $Mode == AXIS_FORMAT_CURRENCY ) { + return($Format.number_format($Value,2)); + } + + if ( $Mode == AXIS_FORMAT_METRIC ) { + if (abs($Value) > 1000000000) { + return(round($Value/1000000000,$Format)."g".$Unit); + } + if (abs($Value) > 1000000) { + return(round($Value/1000000,$Format)."m".$Unit); + } elseif (abs($Value) >= 1000) { + return(round($Value/1000,$Format)."k".$Unit); + } + } + return($Value.$Unit); + } + + /** + * Write Max value on a chart + * @param type $Type + * @param type $Format + */ + public function writeBounds($Type=BOUND_BOTH,$Format=null) + { + $MaxLabelTxt = isset($Format["MaxLabelTxt"]) ? $Format["MaxLabelTxt"] : "max="; + $MinLabelTxt = isset($Format["MinLabelTxt"]) ? $Format["MinLabelTxt"] : "min="; + $Decimals = isset($Format["Decimals"]) ? $Format["Decimals"] : 1; + $ExcludedSeries = isset($Format["ExcludedSeries"]) ? $Format["ExcludedSeries"] : ""; + $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 4; + $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; + $MaxDisplayR = isset($Format["MaxDisplayR"]) ? $Format["MaxDisplayR"] : 0; + $MaxDisplayG = isset($Format["MaxDisplayG"]) ? $Format["MaxDisplayG"] : 0; + $MaxDisplayB = isset($Format["MaxDisplayB"]) ? $Format["MaxDisplayB"] : 0; + $MinDisplayR = isset($Format["MinDisplayR"]) ? $Format["MinDisplayR"] : 255; + $MinDisplayG = isset($Format["MinDisplayG"]) ? $Format["MinDisplayG"] : 255; + $MinDisplayB = isset($Format["MinDisplayB"]) ? $Format["MinDisplayB"] : 255; + $MinLabelPos = isset($Format["MinLabelPos"]) ? $Format["MinLabelPos"] : BOUND_LABEL_POS_AUTO; + $MaxLabelPos = isset($Format["MaxLabelPos"]) ? $Format["MaxLabelPos"] : BOUND_LABEL_POS_AUTO; + $DrawBox = isset($Format["DrawBox"]) ? $Format["DrawBox"] : true; + $DrawBoxBorder = isset($Format["DrawBoxBorder"]) ? $Format["DrawBoxBorder"] : false; + $BorderOffset = isset($Format["BorderOffset"]) ? $Format["BorderOffset"] : 5; + $BoxRounded = isset($Format["BoxRounded"]) ? $Format["BoxRounded"] : true; + $RoundedRadius = isset($Format["RoundedRadius"]) ? $Format["RoundedRadius"] : 3; + $BoxR = isset($Format["BoxR"]) ? $Format["BoxR"] : 0; + $BoxG = isset($Format["BoxG"]) ? $Format["BoxG"] : 0; + $BoxB = isset($Format["BoxB"]) ? $Format["BoxB"] : 0; + $BoxAlpha = isset($Format["BoxAlpha"]) ? $Format["BoxAlpha"] : 20; + $BoxSurrounding = isset($Format["BoxSurrounding"]) ? $Format["BoxSurrounding"] : ""; + $BoxBorderR = isset($Format["BoxBorderR"]) ? $Format["BoxBorderR"] : 255; + $BoxBorderG = isset($Format["BoxBorderG"]) ? $Format["BoxBorderG"] : 255; + $BoxBorderB = isset($Format["BoxBorderB"]) ? $Format["BoxBorderB"] : 255; + $BoxBorderAlpha = isset($Format["BoxBorderAlpha"]) ? $Format["BoxBorderAlpha"] : 100; + + $CaptionSettings = array( + "DrawBox"=>$DrawBox, + "DrawBoxBorder"=>$DrawBoxBorder, + "BorderOffset"=>$BorderOffset, + "BoxRounded"=>$BoxRounded, + "RoundedRadius"=>$RoundedRadius, + "BoxR"=>$BoxR, + "BoxG"=>$BoxG, + "BoxB"=>$BoxB, + "BoxAlpha"=>$BoxAlpha, + "BoxSurrounding"=>$BoxSurrounding, + "BoxBorderR"=>$BoxBorderR, + "BoxBorderG"=>$BoxBorderG, + "BoxBorderB"=>$BoxBorderB, + "BoxBorderAlpha"=>$BoxBorderAlpha + ); + + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + + $Data = $this->DataSet->getData(); + foreach($Data["Series"] as $SerieName => $Serie) { + if ( $Serie["isDrawable"] == true + && $SerieName != $Data["Abscissa"] + && !isset($ExcludedSeries[$SerieName]) + ) { + $R = $Serie["Color"]["R"]; + $G = $Serie["Color"]["G"]; + $B = $Serie["Color"]["B"]; + $Alpha = $Serie["Color"]["Alpha"]; + $Ticks = $Serie["Ticks"]; + if ($DisplayColor == DISPLAY_AUTO ) { + $DisplayR = $R; + $DisplayG = $G; + $DisplayB = $B; + } + + $MinValue = $this->DataSet->getMin($SerieName); + $MaxValue = $this->DataSet->getMax($SerieName); + + $MinPos = VOID; + $MaxPos = VOID; + foreach($Serie["Data"] as $Key => $Value) { + if ( $Value == $MinValue && $MinPos == VOID ) { + $MinPos = $Key; + } + if ( $Value == $MaxValue ) { + $MaxPos = $Key; + } + } + + $AxisID = $Serie["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + $PosArray = $this->scaleComputeY( + $Serie["Data"], + array("AxisID"=>$Serie["Axis"]) + ); + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; + $X = $this->GraphAreaX1 + $XMargin; + $SerieOffset = isset($Serie["XOffset"]) ? $Serie["XOffset"] : 0; + + if ( $Type == BOUND_MAX || $Type == BOUND_BOTH ) { + if ($MaxLabelPos == BOUND_LABEL_POS_TOP + || ( $MaxLabelPos == BOUND_LABEL_POS_AUTO && $MaxValue >= 0) + ) { + $YPos = $PosArray[$MaxPos] - $DisplayOffset + 2; + $Align = TEXT_ALIGN_BOTTOMMIDDLE; + } + if ($MaxLabelPos == BOUND_LABEL_POS_BOTTOM + || ( $MaxLabelPos == BOUND_LABEL_POS_AUTO && $MaxValue < 0) + ) { + $YPos = $PosArray[$MaxPos] + $DisplayOffset + 2; + $Align = TEXT_ALIGN_TOPMIDDLE; + } + + $XPos = $X + $MaxPos*$XStep + $SerieOffset; + $Label = $MaxLabelTxt + . $this->scaleFormat(round($MaxValue,$Decimals),$Mode,$Format,$Unit); + + $TxtPos = $this->getTextBox($XPos,$YPos,$this->FontName,$this->FontSize,0,$Label); + $XOffset = 0; $YOffset = 0; + if ( $TxtPos[0]["X"] < $this->GraphAreaX1 ) { + $XOffset = (($this->GraphAreaX1 - $TxtPos[0]["X"])/2); + } + if ( $TxtPos[1]["X"] > $this->GraphAreaX2 ) { + $XOffset = -(($TxtPos[1]["X"] - $this->GraphAreaX2)/2); + } + if ( $TxtPos[2]["Y"] < $this->GraphAreaY1 ) { + $YOffset = $this->GraphAreaY1 - $TxtPos[2]["Y"]; + } + if ( $TxtPos[0]["Y"] > $this->GraphAreaY2 ) { + $YOffset = -($TxtPos[0]["Y"] - $this->GraphAreaY2); + } + + $CaptionSettings["R"] = $MaxDisplayR; + $CaptionSettings["G"] = $MaxDisplayG; + $CaptionSettings["B"] = $MaxDisplayB; + $CaptionSettings["Align"] = $Align; + + $this->drawText($XPos+$XOffset,$YPos+$YOffset,$Label,$CaptionSettings); + } + + if ( $Type == BOUND_MIN || $Type == BOUND_BOTH ) { + if ($MinLabelPos == BOUND_LABEL_POS_TOP + || ( $MinLabelPos == BOUND_LABEL_POS_AUTO && $MinValue >= 0) + ) { + $YPos = $PosArray[$MinPos] - $DisplayOffset + 2; + $Align = TEXT_ALIGN_BOTTOMMIDDLE; + } + if ($MinLabelPos == BOUND_LABEL_POS_BOTTOM + || ($MinLabelPos == BOUND_LABEL_POS_AUTO && $MinValue < 0) + ) { + $YPos = $PosArray[$MinPos] + $DisplayOffset + 2; + $Align = TEXT_ALIGN_TOPMIDDLE; + } + + $XPos = $X + $MinPos*$XStep + $SerieOffset; + $Label = $MinLabelTxt.$this->scaleFormat(round($MinValue,$Decimals),$Mode,$Format,$Unit); + + $TxtPos = $this->getTextBox($XPos,$YPos,$this->FontName,$this->FontSize,0,$Label); + $XOffset = 0; $YOffset = 0; + if ($TxtPos[0]["X"] < $this->GraphAreaX1 ) { + $XOffset = (($this->GraphAreaX1 - $TxtPos[0]["X"])/2); + } + if ($TxtPos[1]["X"] > $this->GraphAreaX2 ) { + $XOffset = -(($TxtPos[1]["X"] - $this->GraphAreaX2)/2); + } + if ($TxtPos[2]["Y"] < $this->GraphAreaY1 ) { + $YOffset = $this->GraphAreaY1 - $TxtPos[2]["Y"]; + } + if ($TxtPos[0]["Y"] > $this->GraphAreaY2 ) { + $YOffset = -($TxtPos[0]["Y"] - $this->GraphAreaY2); + } + + $CaptionSettings["R"] = $MinDisplayR; + $CaptionSettings["G"] = $MinDisplayG; + $CaptionSettings["B"] = $MinDisplayB; + $CaptionSettings["Align"] = $Align; + + $this->drawText( + $XPos+$XOffset, + $YPos-$DisplayOffset+$YOffset, + $Label, + $CaptionSettings + ); + } + } else { + $XStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; + $X = $this->GraphAreaY1 + $XMargin; + $SerieOffset = isset($Serie["XOffset"]) ? $Serie["XOffset"] : 0; + + if ( $Type == BOUND_MAX || $Type == BOUND_BOTH ) { + if ($MaxLabelPos == BOUND_LABEL_POS_TOP + || ( $MaxLabelPos == BOUND_LABEL_POS_AUTO && $MaxValue >= 0) + ) { + $YPos = $PosArray[$MaxPos] + $DisplayOffset + 2; + $Align = TEXT_ALIGN_MIDDLELEFT; + } + if ($MaxLabelPos == BOUND_LABEL_POS_BOTTOM + || ( $MaxLabelPos == BOUND_LABEL_POS_AUTO && $MaxValue < 0) + ) { + $YPos = $PosArray[$MaxPos] - $DisplayOffset + 2; + $Align = TEXT_ALIGN_MIDDLERIGHT; + } + + $XPos = $X + $MaxPos*$XStep + $SerieOffset; + $Label = $MaxLabelTxt.$this->scaleFormat($MaxValue,$Mode,$Format,$Unit); + + $TxtPos = $this->getTextBox($YPos,$XPos,$this->FontName,$this->FontSize,0,$Label); + $XOffset = 0; $YOffset = 0; + if ( $TxtPos[0]["X"] < $this->GraphAreaX1 ) { + $XOffset = $this->GraphAreaX1 - $TxtPos[0]["X"]; + } + if ( $TxtPos[1]["X"] > $this->GraphAreaX2 ) { + $XOffset = -($TxtPos[1]["X"] - $this->GraphAreaX2); + } + if ( $TxtPos[2]["Y"] < $this->GraphAreaY1 ) { + $YOffset = ($this->GraphAreaY1 - $TxtPos[2]["Y"])/2; + } + if ( $TxtPos[0]["Y"] > $this->GraphAreaY2 ) { + $YOffset = -(($TxtPos[0]["Y"] - $this->GraphAreaY2)/2); + } + + $CaptionSettings["R"] = $MaxDisplayR; + $CaptionSettings["G"] = $MaxDisplayG; + $CaptionSettings["B"] = $MaxDisplayB; + $CaptionSettings["Align"] = $Align; + + $this->drawText($YPos+$XOffset,$XPos+$YOffset,$Label,$CaptionSettings); + } + + if ( $Type == BOUND_MIN || $Type == BOUND_BOTH ) { + if ($MinLabelPos == BOUND_LABEL_POS_TOP + || ( $MinLabelPos == BOUND_LABEL_POS_AUTO && $MinValue >= 0) + ) { + $YPos = $PosArray[$MinPos] + $DisplayOffset + 2; + $Align = TEXT_ALIGN_MIDDLELEFT; + } + if ($MinLabelPos == BOUND_LABEL_POS_BOTTOM + || ( $MinLabelPos == BOUND_LABEL_POS_AUTO && $MinValue < 0) + ) { + $YPos = $PosArray[$MinPos] - $DisplayOffset + 2; + $Align = TEXT_ALIGN_MIDDLERIGHT; + } + + $XPos = $X + $MinPos*$XStep + $SerieOffset; + $Label = $MinLabelTxt.$this->scaleFormat($MinValue,$Mode,$Format,$Unit); + + $TxtPos = $this->getTextBox($YPos,$XPos,$this->FontName,$this->FontSize,0,$Label); + $XOffset = 0; $YOffset = 0; + if ( $TxtPos[0]["X"] < $this->GraphAreaX1 ) { + $XOffset = $this->GraphAreaX1 - $TxtPos[0]["X"]; + } + if ( $TxtPos[1]["X"] > $this->GraphAreaX2 ) { + $XOffset = -($TxtPos[1]["X"] - $this->GraphAreaX2); + } + if ( $TxtPos[2]["Y"] < $this->GraphAreaY1 ) { + $YOffset = ($this->GraphAreaY1 - $TxtPos[2]["Y"])/2; + } + if ( $TxtPos[0]["Y"] > $this->GraphAreaY2 ) { + $YOffset = -(($TxtPos[0]["Y"] - $this->GraphAreaY2)/2); + } + + $CaptionSettings["R"] = $MinDisplayR; + $CaptionSettings["G"] = $MinDisplayG; + $CaptionSettings["B"] = $MinDisplayB; + $CaptionSettings["Align"] = $Align; + + $this->drawText($YPos+$XOffset,$XPos+$YOffset,$Label,$CaptionSettings); + } + } + } + } + } + + /** + * Draw a plot chart + * @param type $Format + */ + public function drawPlotChart($Format=null) + { + $PlotSize = isset($Format["PlotSize"]) ? $Format["PlotSize"] : null; + $PlotBorder = isset($Format["PlotBorder"]) ? $Format["PlotBorder"] : false; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 50; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 50; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 50; + $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : 30; + $BorderSize = isset($Format["BorderSize"]) ? $Format["BorderSize"] : 2; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : null; + $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] : false; + $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 4; + $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; + $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; + $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; + $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : false; + + $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + + foreach($Data["Series"] as $SerieName => $Serie) { + if ( $Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"] ) { + if ( isset($Serie["Weight"]) ) { + $SerieWeight = $Serie["Weight"] + 2; + } else { + $SerieWeight = 2; + } + if ( $PlotSize != null ) { + $SerieWeight = $PlotSize; + } + + $R = $Serie["Color"]["R"]; + $G = $Serie["Color"]["G"]; + $B = $Serie["Color"]["B"]; + $Alpha = $Serie["Color"]["Alpha"]; + $Ticks = $Serie["Ticks"]; + if ( $Surrounding != null ) { + $BorderR = $R + $Surrounding; + $BorderG = $G + $Surrounding; + $BorderB = $B + $Surrounding; + } + if ( isset($Serie["Picture"]) ) { + $Picture = $Serie["Picture"]; + list($PicWidth,$PicHeight,$PicType) = $this->getPicInfo($Picture); + } else { + $Picture = null; + $PicOffset = 0; + } + + if ($DisplayColor == DISPLAY_AUTO ) { + $DisplayR = $R; + $DisplayG = $G; + $DisplayB = $B; + } + + $AxisID = $Serie["Axis"]; + $Shape = $Serie["Shape"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + if (isset($Serie["Description"])) { + $SerieDescription = $Serie["Description"]; + } else { + $SerieDescription = $SerieName; + } + + $PosArray = $this->scaleComputeY($Serie["Data"],array("AxisID"=>$Serie["Axis"])); + + $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) { + if ( $XDivs == 0 ) { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; + } else { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; + } + if ( $Picture != null ) { + $PicOffset = $PicHeight / 2; + $SerieWeight = 0; + } + $X = $this->GraphAreaX1 + $XMargin; + + if ( !is_array($PosArray) ) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + foreach($PosArray as $Key => $Y) { + if ( $DisplayValues ) { + $this->drawText( + $X, + $Y-$DisplayOffset-$SerieWeight-$BorderSize-$PicOffset, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit), + array("R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>TEXT_ALIGN_BOTTOMMIDDLE) + ); + } + if ( $Y != VOID ) { + if ( $RecordImageMap ) { + $this->addToImageMap( + "CIRCLE", + floor($X).",".floor($Y).",".$SerieWeight, + $this->toHTMLColor($R,$G,$B), + $SerieDescription, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit) + ); + } + + if ( $Picture != null ) { + $this->drawFromPicture($PicType,$Picture,$X-$PicWidth/2,$Y-$PicHeight/2); + } + else { + $this->drawShape( + $X, + $Y, + $Shape, + $SerieWeight, + $PlotBorder, + $BorderSize, + $R, + $G, + $B, + $Alpha, + $BorderR, + $BorderG, + $BorderB, + $BorderAlpha + ); + } + } + $X = $X + $XStep; + } + } else { + if ( $XDivs == 0 ) { + $YStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; + } else { + $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; + } + if ( $Picture != null ) { + $PicOffset = $PicWidth / 2; + $SerieWeight = 0; + } + $Y = $this->GraphAreaY1 + $XMargin; + + if ( !is_array($PosArray) ) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + foreach($PosArray as $Key => $X) { + if ( $DisplayValues ) { + $this->drawText( + $X+$DisplayOffset+$SerieWeight+$BorderSize+$PicOffset, + $Y, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit), + array( + "Angle"=>270, + "R"=>$DisplayR, + "G"=>$DisplayG, + "B"=>$DisplayB, + "Align"=>TEXT_ALIGN_BOTTOMMIDDLE + ) + ); + } + if ( $X != VOID ) { + if ( $RecordImageMap ) { + $this->addToImageMap( + "CIRCLE", + floor($X).",".floor($Y).",".$SerieWeight, + $this->toHTMLColor($R,$G,$B), + $SerieDescription, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit) + ); + } + + if ( $Picture != null ) { + $this->drawFromPicture($PicType,$Picture,$X-$PicWidth/2,$Y-$PicHeight/2); + } else { + $this->drawShape( + $X, + $Y, + $Shape, + $SerieWeight, + $PlotBorder, + $BorderSize, + $R, + $G, + $B, + $Alpha, + $BorderR, + $BorderG, + $BorderB, + $BorderAlpha + ); + } + } + $Y = $Y + $YStep; + } + } + } + } + } + + /** + * Draw a spline chart + * @param type $Format + */ + public function drawSplineChart($Format=null) + { + $BreakVoid = isset($Format["BreakVoid"]) ? $Format["BreakVoid"] : true; + $VoidTicks = isset($Format["VoidTicks"]) ? $Format["VoidTicks"] : 4; + $BreakR = isset($Format["BreakR"]) ? $Format["BreakR"] : null; // 234 + $BreakG = isset($Format["BreakG"]) ? $Format["BreakG"] : null; // 55 + $BreakB = isset($Format["BreakB"]) ? $Format["BreakB"] : null; // 26 + $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] : false; + $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 2; + $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; + $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; + $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; + $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : false; + $ImageMapPlotSize = isset($Format["ImageMapPlotSize"]) ? $Format["ImageMapPlotSize"] : 5; + + $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + foreach($Data["Series"] as $SerieName => $Serie) { + if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { + $R = $Serie["Color"]["R"]; + $G = $Serie["Color"]["G"]; + $B = $Serie["Color"]["B"]; + $Alpha = $Serie["Color"]["Alpha"]; + $Ticks = $Serie["Ticks"]; + $Weight = $Serie["Weight"]; + + if ($BreakR == null) { + $BreakSettings = array( + "R"=>$R, + "G"=>$G, + "B"=>$B, + "Alpha"=>$Alpha, + "Ticks"=>$VoidTicks + ); + } else { + $BreakSettings = array( + "R"=>$BreakR, + "G"=>$BreakG, + "B"=>$BreakB, + "Alpha"=>$Alpha, + "Ticks"=>$VoidTicks, + "Weight"=>$Weight + ); + } + if ($DisplayColor == DISPLAY_AUTO) { + $DisplayR = $R; + $DisplayG = $G; + $DisplayB = $B; + } + + $AxisID = $Serie["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + if (isset($Serie["Description"])) { + $SerieDescription = $Serie["Description"]; + } else { + $SerieDescription = $SerieName; + } + + $PosArray = $this->scaleComputeY( + $Serie["Data"], + array("AxisID"=>$Serie["Axis"]) + ); + + $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) { + if ( $XDivs == 0 ) { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; + } else { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; + } + $X = $this->GraphAreaX1 + $XMargin; $WayPoints = ""; + $Force = $XStep / 5; + + if (!is_array($PosArray)) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + $LastGoodY = null; + $LastGoodX = null; + $LastX = 1; + $LastY = 1; + foreach($PosArray as $Key => $Y) { + if ( $DisplayValues ) { + $this->drawText( + $X, + $Y-$DisplayOffset, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit), + array("R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>TEXT_ALIGN_BOTTOMMIDDLE) + ); + } + if ( $RecordImageMap && $Y != VOID ) { + $this->addToImageMap( + "CIRCLE", + floor($X).",".floor($Y).",".$ImageMapPlotSize, + $this->toHTMLColor($R,$G,$B), + $SerieDescription, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit) + ); + } + + if ( $Y == VOID && $LastY != null ) { + $this->drawSpline( + $WayPoints, + array( + "Force"=>$Force, + "R"=>$R, + "G"=>$G, + "B"=>$B, + "Alpha"=>$Alpha, + "Ticks"=>$Ticks, + "Weight"=>$Weight + ) + ); + $WayPoints = ""; + } + + if ( $Y != VOID && $LastY == null && $LastGoodY != null && !$BreakVoid ) { + $this->drawLine($LastGoodX,$LastGoodY,$X,$Y,$BreakSettings); + } + + if ( $Y != VOID ) { + $WayPoints[] = array($X,$Y); + } + if ( $Y != VOID ) { + $LastGoodY = $Y; + $LastGoodX = $X; + } + if ( $Y == VOID ) { + $Y = null; + } + + $LastX = $X; $LastY = $Y; + $X = $X + $XStep; + } + $this->drawSpline( + $WayPoints, + array( + "Force"=>$Force, + "R"=>$R, + "G"=>$G, + "B"=>$B, + "Alpha"=>$Alpha, + "Ticks"=>$Ticks, + "Weight"=>$Weight + ) + ); + } else { + if ( $XDivs == 0 ) { + $YStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; + } else { + $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; + } + $Y = $this->GraphAreaY1 + $XMargin; + $WayPoints = ""; + $Force = $YStep / 5; + + if (!is_array($PosArray)) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + $LastGoodY = null; + $LastGoodX = null; + $LastX = 1; $LastY = 1; + foreach($PosArray as $Key => $X) { + if ( $DisplayValues ) { + $this->drawText( + $X+$DisplayOffset, + $Y, + $this->scaleFormat( + $Serie["Data"][$Key], + $Mode, + $Format, + $Unit + ), + array( + "Angle"=>270, + "R"=>$DisplayR, + "G"=>$DisplayG, + "B"=>$DisplayB, + "Align"=>TEXT_ALIGN_BOTTOMMIDDLE + ) + ); + } + if ($RecordImageMap && $X != VOID) { + $this->addToImageMap( + "CIRCLE", + floor($X).",".floor($Y).",".$ImageMapPlotSize, + $this->toHTMLColor($R,$G,$B), + $SerieDescription, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit) + ); + } + + if ( $X == VOID && $LastX != null ) { + $this->drawSpline( + $WayPoints, + array( + "Force"=>$Force, + "R"=>$R, + "G"=>$G, + "B"=>$B, + "Alpha"=>$Alpha, + "Ticks"=>$Ticks, + "Weight"=>$Weight + ) + ); + $WayPoints = ""; + } + + if ( $X != VOID && $LastX == null && $LastGoodX != null && !$BreakVoid ) { + $this->drawLine($LastGoodX,$LastGoodY,$X,$Y,$BreakSettings); + } + + if ( $X != VOID ) { + $WayPoints[] = array($X,$Y); + } + if ( $X != VOID ) { + $LastGoodX = $X; + $LastGoodY = $Y; + } + if ( $X == VOID ) { + $X = null; + } + + $LastX = $X; + $LastY = $Y; + $Y = $Y + $YStep; + } + $this->drawSpline( + $WayPoints, + array( + "Force"=>$Force, + "R"=>$R, + "G"=>$G, + "B"=>$B, + "Alpha"=>$Alpha, + "Ticks"=>$Ticks, + "Weight"=>$Weight + ) + ); + } + } + } + } + + /** + * Draw a filled spline chart + * @param type $Format + */ + public function drawFilledSplineChart($Format=null) + { + $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] : false; + $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 2; + $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; + $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; + $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; + $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; + $AroundZero = isset($Format["AroundZero"]) ? $Format["AroundZero"] : true; + $Threshold = isset($Format["Threshold"]) ? $Format["Threshold"] : null; + + $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + foreach($Data["Series"] as $SerieName => $Serie) { + if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { + $R = $Serie["Color"]["R"]; + $G = $Serie["Color"]["G"]; + $B = $Serie["Color"]["B"]; + $Alpha = $Serie["Color"]["Alpha"]; + $Ticks = $Serie["Ticks"]; + if ( $DisplayColor == DISPLAY_AUTO ) { + $DisplayR = $R; + $DisplayG = $G; + $DisplayB = $B; + } + + $AxisID = $Serie["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + $PosArray = $this->scaleComputeY( + $Serie["Data"], + array("AxisID"=>$Serie["Axis"]) + ); + if ( $AroundZero ) { + $YZero = $this->scaleComputeY(0,array("AxisID"=>$Serie["Axis"])); + } + + if ( $Threshold != null ) { + foreach($Threshold as $Key => $Params) { + $Threshold[$Key]["MinX"] = $this->scaleComputeY( + $Params["Min"], + array("AxisID"=>$Serie["Axis"]) + ); + $Threshold[$Key]["MaxX"] = $this->scaleComputeY( + $Params["Max"], + array("AxisID"=>$Serie["Axis"]) + ); + } + } + + $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) { + if ( $XDivs == 0 ) { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; + } else { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; + } + $X = $this->GraphAreaX1 + $XMargin; + $WayPoints = ""; + $Force = $XStep / 5; + + if ( !$AroundZero ) { + $YZero = $this->GraphAreaY2-1; + } + if ( $YZero > $this->GraphAreaY2-1 ) { + $YZero = $this->GraphAreaY2-1; + } + if ( $YZero < $this->GraphAreaY1+1 ) { + $YZero = $this->GraphAreaY1+1; + } + + $LastX = ""; + $LastY = ""; + if ( !is_array($PosArray) ) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + foreach($PosArray as $Key => $Y) { + if ( $DisplayValues ) { + $this->drawText( + $X, + $Y-$DisplayOffset, + $this->scaleFormat( + $Serie["Data"][$Key], + $Mode, + $Format, + $Unit + ), + array( + "R"=>$DisplayR, + "G"=>$DisplayG, + "B"=>$DisplayB, + "Align"=>TEXT_ALIGN_BOTTOMMIDDLE + ) + ); + } + if ( $Y == VOID ) { + $Area = $this->drawSpline( + $WayPoints, + array("Force"=>$Force,"PathOnly"=>true) + ); + + if ( $Area != "" ) { + foreach ($Area as $key => $Points) { + $Corners = ""; + $Corners[] = $Area[$key][0]["X"]; + $Corners[] = $YZero; + foreach($Points as $subKey => $Point) { + if ( $subKey == count($Points)-1) { + $Corners[] = $Point["X"]-1; + + } else { + $Corners[] = $Point["X"]; + } + $Corners[] = $Point["Y"]+1; + } + $Corners[] = $Points[$subKey]["X"]-1; $Corners[] = $YZero; + + $this->drawPolygonChart( + $Corners, + array( + "R"=>$R, + "G"=>$G, + "B"=>$B, + "Alpha"=>$Alpha/2, + "NoBorder"=>true, + "Threshold"=>$Threshold + ) + ); + } + $this->drawSpline( + $WayPoints, + array( + "Force"=>$Force, + "R"=>$R, + "G"=>$G, + "B"=>$B, + "Alpha"=>$Alpha, + "Ticks"=>$Ticks + ) + ); + } + + $WayPoints = ""; + } else { + $WayPoints[] = array($X,$Y-.5); /* -.5 for AA visual fix */ + } + $X = $X + $XStep; + } + $Area = $this->drawSpline($WayPoints,array("Force"=>$Force,"PathOnly"=>true)); + + if ( $Area != "" ) { + foreach ($Area as $key => $Points) { + $Corners = ""; + $Corners[] = $Area[$key][0]["X"]; + $Corners[] = $YZero; + foreach($Points as $subKey => $Point) { + if ( $subKey == count($Points)-1) { + $Corners[] = $Point["X"]-1; + } else { + $Corners[] = $Point["X"]; + } + $Corners[] = $Point["Y"]+1; + } + $Corners[] = $Points[$subKey]["X"]-1; + $Corners[] = $YZero; + + $this->drawPolygonChart( + $Corners, + array( + "R"=>$R, + "G"=>$G, + "B"=>$B, + "Alpha"=>$Alpha/2, + "NoBorder"=>true, + "Threshold"=>$Threshold + ) + ); + } + $this->drawSpline( + $WayPoints, + array( + "Force"=>$Force, + "R"=>$R, + "G"=>$G, + "B"=>$B, + "Alpha"=>$Alpha, + "Ticks"=>$Ticks + ) + ); + } + } else { + if ( $XDivs == 0 ) { + $YStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; + } else { + $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; + } + $Y = $this->GraphAreaY1 + $XMargin; + $WayPoints = ""; + $Force = $YStep / 5; + + if ( !$AroundZero ) { + $YZero = $this->GraphAreaX1+1; + } + if ( $YZero > $this->GraphAreaX2-1 ) { + $YZero = $this->GraphAreaX2-1; + } + if ( $YZero < $this->GraphAreaX1+1 ) { + $YZero = $this->GraphAreaX1+1; + } + + if ( !is_array($PosArray) ) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + foreach($PosArray as $Key => $X) { + if ( $DisplayValues ) { + $this->drawText( + $X+$DisplayOffset, + $Y, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit), + array("Angle"=>270,"R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>TEXT_ALIGN_BOTTOMMIDDLE) + ); + } + if ( $X == VOID ) { + $Area = $this->drawSpline( + $WayPoints, + array("Force"=>$Force,"PathOnly"=>true) + ); + + if ( $Area != "" ) { + foreach ($Area as $key => $Points) { + $Corners = ""; + $Corners[] = $YZero; + $Corners[] = $Area[$key][0]["Y"]; + foreach($Points as $subKey => $Point) { + if ( $subKey == count($Points)-1) { + $Corners[] = $Point["X"]-1; + } else { + $Corners[] = $Point["X"]; + } + $Corners[] = $Point["Y"]; + } + $Corners[] = $YZero; + $Corners[] = $Points[$subKey]["Y"]-1; + + $this->drawPolygonChart( + $Corners, + array( + "R"=>$R, + "G"=>$G, + "B"=>$B, + "Alpha"=>$Alpha/2, + "NoBorder"=>true, + "Threshold"=>$Threshold + ) + ); + } + $this->drawSpline( + $WayPoints, + array( + "Force"=>$Force, + "R"=>$R, + "G"=>$G, + "B"=>$B, + "Alpha"=>$Alpha, + "Ticks"=>$Ticks + ) + ); + } + + $WayPoints = ""; + } else { + $WayPoints[] = array($X,$Y); + } + $Y = $Y + $YStep; + } + $Area = $this->drawSpline( + $WayPoints, + array("Force"=>$Force,"PathOnly"=>true) + ); + + if ( $Area != "" ) { + foreach ($Area as $key => $Points) { + $Corners = ""; + $Corners[] = $YZero; + $Corners[] = $Area[$key][0]["Y"]; + foreach($Points as $subKey => $Point) { + if ( $subKey == count($Points)-1) { + $Corners[] = $Point["X"]-1; + } else { + $Corners[] = $Point["X"]; + } + $Corners[] = $Point["Y"]; + } + $Corners[] = $YZero; + $Corners[] = $Points[$subKey]["Y"]-1; + + $this->drawPolygonChart( + $Corners, + array( + "R"=>$R, + "G"=>$G, + "B"=>$B, + "Alpha"=>$Alpha/2, + "NoBorder"=>true, + "Threshold"=>$Threshold + ) + ); + } + $this->drawSpline( + $WayPoints, + array( + "Force"=>$Force, + "R"=>$R, + "G"=>$G, + "B"=>$B, + "Alpha"=>$Alpha, + "Ticks"=>$Ticks + ) + ); + } + } + } + } + } + + /** + * Draw a line chart + * @param type $Format + */ + public function drawLineChart($Format=null) + { + $BreakVoid = isset($Format["BreakVoid"]) ? $Format["BreakVoid"] : true; + $VoidTicks = isset($Format["VoidTicks"]) ? $Format["VoidTicks"] : 4; + $BreakR = isset($Format["BreakR"]) ? $Format["BreakR"] : null; + $BreakG = isset($Format["BreakG"]) ? $Format["BreakG"] : null; + $BreakB = isset($Format["BreakB"]) ? $Format["BreakB"] : null; + $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] : false; + $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 2; + $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; + $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; + $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; + $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : false; + $ImageMapPlotSize = isset($Format["ImageMapPlotSize"]) ? $Format["ImageMapPlotSize"] : 5; + $ForceColor = isset($Format["ForceColor"]) ? $Format["ForceColor"] : false; + $ForceR = isset($Format["ForceR"]) ? $Format["ForceR"] : 0; + $ForceG = isset($Format["ForceG"]) ? $Format["ForceG"] : 0; + $ForceB = isset($Format["ForceB"]) ? $Format["ForceB"] : 0; + $ForceAlpha = isset($Format["ForceAlpha"]) ? $Format["ForceAlpha"] : 100; + + $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + foreach($Data["Series"] as $SerieName => $Serie) { + if ( $Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"] ) { + $R = $Serie["Color"]["R"]; + $G = $Serie["Color"]["G"]; + $B = $Serie["Color"]["B"]; + $Alpha = $Serie["Color"]["Alpha"]; + $Ticks = $Serie["Ticks"]; + $Weight = $Serie["Weight"]; + + if ( $ForceColor ) { + $R = $ForceR; + $G = $ForceG; + $B = $ForceB; + $Alpha = $ForceAlpha; + } + + if ( $BreakR == null ) { + $BreakSettings = array( + "R"=>$R, + "G"=>$G, + "B"=>$B, + "Alpha"=>$Alpha, + "Ticks"=>$VoidTicks, + "Weight"=>$Weight + ); + } else { + $BreakSettings = array( + "R"=>$BreakR, + "G"=>$BreakG, + "B"=>$BreakB, + "Alpha"=>$Alpha, + "Ticks"=>$VoidTicks, + "Weight"=>$Weight + ); + } + if ( $DisplayColor == DISPLAY_AUTO ) { + $DisplayR = $R; + $DisplayG = $G; + $DisplayB = $B; + } + + $AxisID = $Serie["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + if (isset($Serie["Description"])) { + $SerieDescription = $Serie["Description"]; + } else { + $SerieDescription = $SerieName; + } + + $PosArray = $this->scaleComputeY( + $Serie["Data"], + array("AxisID"=>$Serie["Axis"]) + ); + + $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) { + if ( $XDivs == 0 ) { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; + } else { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; + } + $X = $this->GraphAreaX1 + $XMargin; + $LastX = null; + $LastY = null; + + if ( !is_array($PosArray) ) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + $LastGoodY = null; + $LastGoodX = null; + foreach($PosArray as $Key => $Y) { + if ( $DisplayValues && $Serie["Data"][$Key] != VOID ) { + if ( $Serie["Data"][$Key] > 0 ) { + $Align = TEXT_ALIGN_BOTTOMMIDDLE; + $Offset = $DisplayOffset; + } else { + $Align = TEXT_ALIGN_TOPMIDDLE; + $Offset = -$DisplayOffset; + } + $this->drawText( + $X, + $Y-$Offset-$Weight, + $this->scaleFormat( + $Serie["Data"][$Key], + $Mode, + $Format, + $Unit + ), + array( + "R"=>$DisplayR, + "G"=>$DisplayG, + "B"=>$DisplayB, + "Align"=>$Align + ) + ); + } + + if ( $RecordImageMap && $Y != VOID ) { + $this->addToImageMap( + "CIRCLE", + floor($X).",".floor($Y).",".$ImageMapPlotSize, + $this->toHTMLColor($R,$G,$B), + $SerieDescription, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit) + ); + } + + if ( $Y != VOID && $LastX != null && $LastY != null ) { + $this->drawLine( + $LastX, + $LastY, + $X, + $Y, + array( + "R"=>$R, + "G"=>$G, + "B"=>$B, + "Alpha"=>$Alpha, + "Ticks"=>$Ticks, + "Weight"=>$Weight + ) + ); + } + if ( $Y != VOID && $LastY == null && $LastGoodY != null && !$BreakVoid ) { + $this->drawLine( + $LastGoodX, + $LastGoodY, + $X, + $Y, + $BreakSettings + ); + $LastGoodY = null; + } + + if ( $Y != VOID ) { + $LastGoodY = $Y; + $LastGoodX = $X; } + if ( $Y == VOID ) { + $Y = null; + } + + $LastX = $X; + $LastY = $Y; + $X = $X + $XStep; + } + } else { + if ( $XDivs == 0 ) { + $YStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; + } else { + $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; + } + $Y = $this->GraphAreaY1 + $XMargin; + $LastX = null; + $LastY = null; + + if ( !is_array($PosArray) ) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + $LastGoodY = null; + $LastGoodX = null; + foreach($PosArray as $Key => $X) { + if ( $DisplayValues && $Serie["Data"][$Key] != VOID ) { + $this->drawText( + $X+$DisplayOffset+$Weight, + $Y, + $this->scaleFormat( + $Serie["Data"][$Key], + $Mode, + $Format, + $Unit + ), + array( + "Angle"=>270, + "R"=>$DisplayR, + "G"=>$DisplayG, + "B"=>$DisplayB, + "Align"=>TEXT_ALIGN_BOTTOMMIDDLE + ) + ); + } + + if ( $RecordImageMap && $X != VOID ) { + $this->addToImageMap( + "CIRCLE", + floor($X).",".floor($Y).",".$ImageMapPlotSize, + $this->toHTMLColor($R,$G,$B), + $SerieDescription, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit) + ); + } + + if ( $X != VOID && $LastX != null && $LastY != null ) { + $this->drawLine( + $LastX, + $LastY, + $X, + $Y, + array( + "R"=>$R, + "G"=>$G, + "B"=>$B, + "Alpha"=>$Alpha, + "Ticks"=>$Ticks, + "Weight"=>$Weight + ) + ); + } + if ( $X != VOID && $LastX == null && $LastGoodY != null && !$BreakVoid ) { + $this->drawLine( + $LastGoodX, + $LastGoodY, + $X, + $Y, + $BreakSettings + ); + $LastGoodY = null; + } + + if ( $X != VOID ) { + $LastGoodY = $Y; + $LastGoodX = $X; + } + if ( $X == VOID ) { + $X = null; + } + + $LastX = $X; + $LastY = $Y; + $Y = $Y + $YStep; + } + } + } + } + } + + /** + * Draw a line chart + * @param type $SerieA + * @param type $SerieB + * @param type $Format + * @return type + */ + public function drawZoneChart($SerieA,$SerieB,$Format=null) + { + $AxisID = isset($Format["AxisID"]) ? $Format["AxisID"] : 0; + $LineR = isset($Format["LineR"]) ? $Format["LineR"] : 150; + $LineG = isset($Format["LineG"]) ? $Format["LineG"] : 150; + $LineB = isset($Format["LineB"]) ? $Format["LineB"] : 150; + $LineAlpha = isset($Format["LineAlpha"]) ? $Format["LineAlpha"] : 50; + $LineTicks = isset($Format["LineTicks"]) ? $Format["LineTicks"] : 1; + $AreaR = isset($Format["AreaR"]) ? $Format["AreaR"] : 150; + $AreaG = isset($Format["AreaG"]) ? $Format["AreaG"] : 150; + $AreaB = isset($Format["AreaB"]) ? $Format["AreaB"] : 150; + $AreaAlpha = isset($Format["AreaAlpha"]) ? $Format["AreaAlpha"] : 5; + + $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; + + $Data = $this->DataSet->getData(); + if (!isset($Data["Series"][$SerieA]["Data"]) + || !isset($Data["Series"][$SerieB]["Data"]) + ) { + return(0); + } + $SerieAData = $Data["Series"][$SerieA]["Data"]; + $SerieBData = $Data["Series"][$SerieB]["Data"]; + + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + $PosArrayA = $this->scaleComputeY($SerieAData,array("AxisID"=>$AxisID)); + $PosArrayB = $this->scaleComputeY($SerieBData,array("AxisID"=>$AxisID)); + if ( count($PosArrayA) != count($PosArrayB) ) { + return(0); + } + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) { + if ( $XDivs == 0 ) { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; + } else { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; + } + $X = $this->GraphAreaX1 + $XMargin; + $LastX = null; + $LastY = null; + + $LastX = null; + $LastY1 = null; + $LastY2 = null; + $BoundsA = ""; + $BoundsB = ""; + foreach($PosArrayA as $Key => $Y1) { + $Y2 = $PosArrayB[$Key]; + + $BoundsA[] = $X; + $BoundsA[] = $Y1; + $BoundsB[] = $X; + $BoundsB[] = $Y2; + + $LastX = $X; + $LastY1 = $Y1; + $LastY2 = $Y2; + + $X = $X + $XStep; + } + $Bounds = array_merge($BoundsA,$this->reversePlots($BoundsB)); + $this->drawPolygonChart( + $Bounds, + array( + "R"=>$AreaR, + "G"=>$AreaG, + "B"=>$AreaB, + "Alpha"=>$AreaAlpha + ) + ); + + for ($i=0;$i<=count($BoundsA)-4;$i=$i+2) { + $this->drawLine( + $BoundsA[$i], + $BoundsA[$i+1], + $BoundsA[$i+2], + $BoundsA[$i+3], + array( + "R"=>$LineR, + "G"=>$LineG, + "B"=>$LineB, + "Alpha"=>$LineAlpha, + "Ticks"=>$LineTicks + ) + ); + $this->drawLine( + $BoundsB[$i], + $BoundsB[$i+1], + $BoundsB[$i+2], + $BoundsB[$i+3], + array( + "R"=>$LineR, + "G"=>$LineG, + "B"=>$LineB, + "Alpha"=>$LineAlpha, + "Ticks"=>$LineTicks + ) + ); + } + } else { + if ( $XDivs == 0 ) { + $YStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; + } else { + $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; + } + $Y = $this->GraphAreaY1 + $XMargin; + $LastX = null; + $LastY = null; + + $LastY = null; + $LastX1 = null; + $LastX2 = null; + $BoundsA = ""; + $BoundsB = ""; + foreach($PosArrayA as $Key => $X1) { + $X2 = $PosArrayB[$Key]; + + $BoundsA[] = $X1; + $BoundsA[] = $Y; + $BoundsB[] = $X2; + $BoundsB[] = $Y; + + $LastY = $Y; + $LastX1 = $X1; + $LastX2 = $X2; + + $Y = $Y + $YStep; + } + $Bounds = array_merge($BoundsA,$this->reversePlots($BoundsB)); + $this->drawPolygonChart( + $Bounds, + array("R"=>$AreaR,"G"=>$AreaG,"B"=>$AreaB,"Alpha"=>$AreaAlpha) + ); + + for ($i=0;$i<=count($BoundsA)-4;$i=$i+2) { + $this->drawLine( + $BoundsA[$i], + $BoundsA[$i+1], + $BoundsA[$i+2], + $BoundsA[$i+3], + array( + "R"=>$LineR, + "G"=>$LineG, + "B"=>$LineB, + "Alpha"=>$LineAlpha, + "Ticks"=>$LineTicks + ) + ); + $this->drawLine( + $BoundsB[$i], + $BoundsB[$i+1], + $BoundsB[$i+2], + $BoundsB[$i+3], + array( + "R"=>$LineR, + "G"=>$LineG, + "B"=>$LineB, + "Alpha"=>$LineAlpha, + "Ticks"=>$LineTicks + ) + ); + } + } + } + + /** + * Draw a step chart + * @param type $Format + */ + public function drawStepChart($Format=null) + { + $BreakVoid = isset($Format["BreakVoid"]) ? $Format["BreakVoid"] : false; + $ReCenter = isset($Format["ReCenter"]) ? $Format["ReCenter"] : true; + $VoidTicks = isset($Format["VoidTicks"]) ? $Format["VoidTicks"] : 4; + $BreakR = isset($Format["BreakR"]) ? $Format["BreakR"] : null; + $BreakG = isset($Format["BreakG"]) ? $Format["BreakG"] : null; + $BreakB = isset($Format["BreakB"]) ? $Format["BreakB"] : null; + $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] :false; + $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 2; + $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; + $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; + $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; + $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : false; + $ImageMapPlotSize = isset($Format["ImageMapPlotSize"]) ? $Format["ImageMapPlotSize"] : 5; + + $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + foreach($Data["Series"] as $SerieName => $Serie) { + if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { + $R = $Serie["Color"]["R"]; + $G = $Serie["Color"]["G"]; + $B = $Serie["Color"]["B"]; + $Alpha = $Serie["Color"]["Alpha"]; + $Ticks = $Serie["Ticks"]; + $Weight = $Serie["Weight"]; + + if (isset($Serie["Description"])) { + $SerieDescription = $Serie["Description"]; + } else { + $SerieDescription = $SerieName; + } + + if ( $BreakR == null ) { + $BreakSettings = array( + "R"=>$R, + "G"=>$G, + "B"=>$B, + "Alpha"=>$Alpha, + "Ticks"=>$VoidTicks, + "Weight"=>$Weight + ); + } else { + $BreakSettings = array( + "R"=>$BreakR, + "G"=>$BreakG, + "B"=>$BreakB, + "Alpha"=>$Alpha, + "Ticks"=>$VoidTicks, + "Weight"=>$Weight + ); + } + if ( $DisplayColor == DISPLAY_AUTO ) { + $DisplayR = $R; + $DisplayG = $G; + $DisplayB = $B; + } + + $AxisID = $Serie["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + $Color = array( + "R"=>$R, + "G"=>$G, + "B"=>$B, + "Alpha"=>$Alpha, + "Ticks"=>$Ticks, + "Weight"=>$Weight + ); + + $PosArray = $this->scaleComputeY( + $Serie["Data"], + array("AxisID"=>$Serie["Axis"]) + ); + + $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) { + if ( $XDivs == 0 ) { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; + } else { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; + } + $X = $this->GraphAreaX1 + $XMargin; + $LastX = null; + $LastY = null; + + if (!is_array($PosArray)) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + $LastGoodY = null; + $LastGoodX = null; + $Init = false; + foreach($PosArray as $Key => $Y) { + if ( $DisplayValues && $Serie["Data"][$Key] != VOID ) { + if ( $Y <= $LastY ) { + $Align = TEXT_ALIGN_BOTTOMMIDDLE; + $Offset = $DisplayOffset; + } else { + $Align = TEXT_ALIGN_TOPMIDDLE; + $Offset = -$DisplayOffset; + } + $this->drawText( + $X, + $Y-$Offset-$Weight, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit), + array("R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>$Align) + ); + } + + if ( $Y != VOID && $LastX != null && $LastY != null ) { + $this->drawLine($LastX,$LastY,$X,$LastY,$Color); + $this->drawLine($X,$LastY,$X,$Y,$Color); + if ( $ReCenter && $X+$XStep < $this->GraphAreaX2 - $XMargin ) { + $this->drawLine($X,$Y,$X+$XStep,$Y,$Color); + if ( $RecordImageMap ) { + $this->addToImageMap( + "RECT", + floor($X-$ImageMapPlotSize)."," + .floor($Y-$ImageMapPlotSize)."," + .floor($X+$XStep+$ImageMapPlotSize)."," + .floor($Y+$ImageMapPlotSize), + $this->toHTMLColor($R,$G,$B), + $SerieDescription, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit) + ); + } + } else { + if ( $RecordImageMap ) { + $this->addToImageMap( + "RECT", + floor($LastX-$ImageMapPlotSize)."," + .floor($LastY-$ImageMapPlotSize)."," + .floor($X+$ImageMapPlotSize)."," + .floor($LastY+$ImageMapPlotSize), + $this->toHTMLColor($R,$G,$B), + $SerieDescription, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit) + ); + } + } + } + + if ( $Y != VOID && $LastY == null && $LastGoodY != null && !$BreakVoid ) { + if ( $ReCenter ) { + $this->drawLine($LastGoodX+$XStep,$LastGoodY,$X,$LastGoodY,$BreakSettings); + if ( $RecordImageMap ) { + $this->addToImageMap( + "RECT", + floor($LastGoodX+$XStep-$ImageMapPlotSize) + .",".floor($LastGoodY-$ImageMapPlotSize) + .",".floor($X+$ImageMapPlotSize) + .",".floor($LastGoodY+$ImageMapPlotSize), + $this->toHTMLColor($R,$G,$B), + $SerieDescription, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit) + ); + } + } else { + $this->drawLine($LastGoodX,$LastGoodY,$X,$LastGoodY,$BreakSettings); + if ( $RecordImageMap ) { + $this->addToImageMap( + "RECT", + floor($LastGoodX-$ImageMapPlotSize) + .",".floor($LastGoodY-$ImageMapPlotSize) + .",".floor($X+$ImageMapPlotSize) + .",".floor($LastGoodY+$ImageMapPlotSize), + $this->toHTMLColor($R,$G,$B), + $SerieDescription, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit) + ); + } + } + + $this->drawLine($X,$LastGoodY,$X,$Y,$BreakSettings); + $LastGoodY = null; + } elseif( !$BreakVoid && $LastGoodY == null && $Y != VOID ) { + $this->drawLine($this->GraphAreaX1 + $XMargin,$Y,$X,$Y,$BreakSettings); + if ( $RecordImageMap ) { + $this->addToImageMap( + "RECT", + floor($this->GraphAreaX1+$XMargin-$ImageMapPlotSize) + .",".floor($Y-$ImageMapPlotSize) + .",".floor($X+$ImageMapPlotSize) + .",".floor($Y+$ImageMapPlotSize), + $this->toHTMLColor($R,$G,$B), + $SerieDescription, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit) + ); + } + } + + if ( $Y != VOID ) { + $LastGoodY = $Y; + $LastGoodX = $X; + } + if ( $Y == VOID ) { + $Y = null; + } + + if ( !$Init && $ReCenter ) { + $X = $X - $XStep/2; + $Init = true; + } + $LastX = $X; + $LastY = $Y; + if ( $LastX < $this->GraphAreaX1 + $XMargin ) { + $LastX = $this->GraphAreaX1 + $XMargin; + } + $X = $X + $XStep; + } + if ( $ReCenter ) { + $this->drawLine($LastX,$LastY,$this->GraphAreaX2 - $XMargin,$LastY,$Color); + if ( $RecordImageMap ) { + $this->addToImageMap( + "RECT", + floor($LastX-$ImageMapPlotSize)."," + .floor($LastY-$ImageMapPlotSize)."," + .floor($this->GraphAreaX2-$XMargin+$ImageMapPlotSize) + .",".floor($LastY+$ImageMapPlotSize), + $this->toHTMLColor($R,$G,$B), + $SerieDescription, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit) + ); + } + } + } else { + if ( $XDivs == 0 ) { + $YStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; + } else { + $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; + } + $Y = $this->GraphAreaY1 + $XMargin; + $LastX = null; + $LastY = null; + + if ( !is_array($PosArray) ) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + $LastGoodY = null; + $LastGoodX = null; + $Init = false; + foreach($PosArray as $Key => $X) { + if ( $DisplayValues && $Serie["Data"][$Key] != VOID ) { + if ( $X >= $LastX ) { + $Align = TEXT_ALIGN_MIDDLELEFT; + $Offset = $DisplayOffset; + } else { + $Align = TEXT_ALIGN_MIDDLERIGHT; + $Offset = -$DisplayOffset; + } + $this->drawText( + $X+$Offset+$Weight, + $Y, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit), + array("R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>$Align) + ); + } + + if ( $X != VOID && $LastX != null && $LastY != null ) { + $this->drawLine($LastX,$LastY,$LastX,$Y,$Color); + $this->drawLine($LastX,$Y,$X,$Y,$Color); + + if ( $RecordImageMap ) { + $this->addToImageMap( + "RECT", + floor($LastX-$ImageMapPlotSize)."," + .floor($LastY-$ImageMapPlotSize)."," + .floor($LastX+$XStep+$ImageMapPlotSize)."," + .floor($Y+$ImageMapPlotSize), + $this->toHTMLColor($R,$G,$B), + $SerieDescription, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit) + ); + } + } + + if ( $X != VOID && $LastX == null && $LastGoodY != null && !$BreakVoid ) { + $this->drawLine( + $LastGoodX, + $LastGoodY, + $LastGoodX, + $LastGoodY+$YStep, + $Color + ); + if ( $RecordImageMap ) { + $this->addToImageMap( + "RECT", + floor($LastGoodX-$ImageMapPlotSize)."," + .floor($LastGoodY-$ImageMapPlotSize)."," + .floor($LastGoodX+$ImageMapPlotSize)."," + .floor($LastGoodY+$YStep+$ImageMapPlotSize), + $this->toHTMLColor($R,$G,$B), + $SerieDescription, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit) + ); + } + + $this->drawLine( + $LastGoodX, + $LastGoodY+$YStep, + $LastGoodX, + $Y, + $BreakSettings + ); + if ( $RecordImageMap ) { + $this->addToImageMap( + "RECT", + floor($LastGoodX-$ImageMapPlotSize)."," + .floor($LastGoodY+$YStep-$ImageMapPlotSize)."," + .floor($LastGoodX+$ImageMapPlotSize)."," + .floor($YStep+$ImageMapPlotSize), + $this->toHTMLColor($R,$G,$B), + $SerieDescription, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit) + ); + } + + $this->drawLine($LastGoodX,$Y,$X,$Y,$BreakSettings); + $LastGoodY = null; + } elseif ( $X != VOID && $LastGoodY == null && !$BreakVoid ) { + $this->drawLine($X,$this->GraphAreaY1 + $XMargin,$X,$Y,$BreakSettings); + if ( $RecordImageMap ) { + $this->addToImageMap( + "RECT", + floor($X-$ImageMapPlotSize)."," + .floor($this->GraphAreaY1+$XMargin-$ImageMapPlotSize)."," + .floor($X+$ImageMapPlotSize)."," + .floor($Y+$ImageMapPlotSize), + $this->toHTMLColor($R,$G,$B), + $SerieDescription, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit) + ); + } + } + + if ( $X != VOID ) { $LastGoodY = $Y; $LastGoodX = $X; } + if ( $X == VOID ) { $X = null; } + + if ( !$Init && $ReCenter ) { $Y = $Y - $YStep/2; $Init = true; } + $LastX = $X; $LastY = $Y; + if ( $LastY < $this->GraphAreaY1 + $XMargin ) { $LastY = $this->GraphAreaY1 + $XMargin; } + $Y = $Y + $YStep; + } + if ( $ReCenter ) { + $this->drawLine($LastX,$LastY,$LastX,$this->GraphAreaY2 - $XMargin,$Color); + if ( $RecordImageMap ) { + $this->addToImageMap( + "RECT", + floor($LastX-$ImageMapPlotSize)."," + .floor($LastY-$ImageMapPlotSize)."," + .floor($LastX+$ImageMapPlotSize)."," + .floor($this->GraphAreaY2-$XMargin+$ImageMapPlotSize), + $this->toHTMLColor($R,$G,$B), + $SerieDescription, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit) + ); + } + } + } + } + } + } + + /** + * Draw a step chart + * @param type $Format + */ + public function drawFilledStepChart($Format=null) + { + $ReCenter = isset($Format["ReCenter"]) ? $Format["ReCenter"] : true; + $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] :false; + $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 2; + $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; + $ForceTransparency = isset($Format["ForceTransparency"]) ? $Format["ForceTransparency"] : null; + $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; + $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; + $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; + $AroundZero = isset($Format["AroundZero"]) ? $Format["AroundZero"] : true; + + $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + foreach($Data["Series"] as $SerieName => $Serie) { + if ( $Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"] ) { + $R = $Serie["Color"]["R"]; + $G = $Serie["Color"]["G"]; + $B = $Serie["Color"]["B"]; + $Alpha = $Serie["Color"]["Alpha"]; + $Ticks = $Serie["Ticks"]; + $Weight = $Serie["Weight"]; + + if ( $DisplayColor == DISPLAY_AUTO ) { + $DisplayR = $R; + $DisplayG = $G; + $DisplayB = $B; + } + + $AxisID = $Serie["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + $Color = array("R"=>$R,"G"=>$G,"B"=>$B); + if ( $ForceTransparency != null ) { + $Color["Alpha"] = $ForceTransparency; + } else { + $Color["Alpha"] = $Alpha; + } + + $PosArray = $this->scaleComputeY($Serie["Data"],array("AxisID"=>$Serie["Axis"])); + $YZero = $this->scaleComputeY(0,array("AxisID"=>$Serie["Axis"])); + + $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) { + if ( $YZero > $this->GraphAreaY2-1 ) { + $YZero = $this->GraphAreaY2-1; + } + if ( $YZero < $this->GraphAreaY1+1 ) { + $YZero = $this->GraphAreaY1+1; + } + + if ( $XDivs == 0 ) { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; + } else { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; + } + $X = $this->GraphAreaX1 + $XMargin; + $LastX = null; + $LastY = null; + + if ( !$AroundZero ) { + $YZero = $this->GraphAreaY2-1; + } + + if ( !is_array($PosArray) ) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + $LastGoodY = null; + $LastGoodX = null; + $Points = ""; + $Init = false; + foreach($PosArray as $Key => $Y) { + if ( $Y == VOID && $LastX != null && $LastY != null && $Points !="" ) { + $Points[] = $LastX; + $Points[] = $LastY; + $Points[] = $X; + $Points[] = $LastY; + $Points[] = $X; + $Points[] = $YZero; + $this->drawPolygon($Points,$Color); + $Points = ""; + } + + if ( $Y != VOID && $LastX != null && $LastY != null ) { + if ( $Points == "") { + $Points[] = $LastX; + $Points[] = $YZero; + } + $Points[] = $LastX; + $Points[] = $LastY; + $Points[] = $X; + $Points[] = $LastY; + $Points[] = $X; + $Points[] = $Y; + } + + if ( $Y != VOID ) { + $LastGoodY = $Y; + $LastGoodX = $X; + } + if ( $Y == VOID ) { + $Y = null; + } + + if ( !$Init && $ReCenter ) { + $X = $X - $XStep/2; + $Init = true; + } + $LastX = $X; + $LastY = $Y; + if ( $LastX < $this->GraphAreaX1 + $XMargin ) { + $LastX = $this->GraphAreaX1 + $XMargin; + } + $X = $X + $XStep; + } + + if ( $ReCenter ) { + $Points[] = $LastX+$XStep/2; + $Points[] = $LastY; + $Points[] = $LastX+$XStep/2; + $Points[] = $YZero; + } else { + $Points[] = $LastX; + $Points[] = $YZero; + } + + $this->drawPolygon($Points,$Color); + } else { + if ( $YZero < $this->GraphAreaX1+1 ) { + $YZero = $this->GraphAreaX1+1; + } + if ( $YZero > $this->GraphAreaX2-1 ) { + $YZero = $this->GraphAreaX2-1; + } + + if ( $XDivs == 0 ) { + $YStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; + } else { + $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; + } + $Y = $this->GraphAreaY1 + $XMargin; + $LastX = null; + $LastY = null; + + if ( !is_array($PosArray) ) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + $LastGoodY = null; + $LastGoodX = null; + $Points = ""; + foreach($PosArray as $Key => $X) { + if ($X == VOID && $LastX != null && $LastY != null && $Points !="") { + $Points[] = $LastX; + $Points[] = $LastY; + $Points[] = $LastX; + $Points[] = $Y; + $Points[] = $YZero; + $Points[] = $Y; + $this->drawPolygon($Points,$Color); + $Points = ""; + } + + if ($X != VOID && $LastX != null && $LastY != null) { + if ( $Points == "") { + $Points[] = $YZero; + $Points[] = $LastY; + } + $Points[] = $LastX; + $Points[] = $LastY; + $Points[] = $LastX; + $Points[] = $Y; + $Points[] = $X; + $Points[] = $Y; + } + + if ( $X != VOID ) { + $LastGoodY = $Y; + $LastGoodX = $X; + } + if ( $X == VOID ) { + $X = null; + } + + if ( $LastX == null && $ReCenter ) { + $Y = $Y - $YStep/2; + } + $LastX = $X; + $LastY = $Y; + if ( $LastY < $this->GraphAreaY1 + $XMargin ) { + $LastY = $this->GraphAreaY1 + $XMargin; + } + $Y = $Y + $YStep; + } + + if ( $ReCenter ) { + $Points[] = $LastX; + $Points[] = $LastY+$YStep/2; + $Points[] = $YZero; + $Points[] = $LastY+$YStep/2; + } else { + $Points[] = $YZero; + $Points[] = $LastY; + } + + $this->drawPolygon($Points,$Color); + } + } + } + } + + /** + * Draw an area chart + * @param type $Format + */ + public function drawAreaChart($Format=null) + { + $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] : false; + $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 2; + $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; + $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; + $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; + $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; + $ForceTransparency = isset($Format["ForceTransparency"]) ? $Format["ForceTransparency"] : 25; + $AroundZero = isset($Format["AroundZero"]) ? $Format["AroundZero"] : true; + $Threshold = isset($Format["Threshold"]) ? $Format["Threshold"] : null; + + $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + + foreach($Data["Series"] as $SerieName => $Serie) { + if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { + $R = $Serie["Color"]["R"]; + $G = $Serie["Color"]["G"]; + $B = $Serie["Color"]["B"]; + $Alpha = $Serie["Color"]["Alpha"]; + $Ticks = $Serie["Ticks"]; + if ( $DisplayColor == DISPLAY_AUTO ) { + $DisplayR = $R; + $DisplayG = $G; + $DisplayB = $B; + } + + $AxisID = $Serie["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + $PosArray = $this->scaleComputeY($Serie["Data"],array("AxisID"=>$Serie["Axis"])); + $YZero = $this->scaleComputeY(0,array("AxisID"=>$Serie["Axis"])); + + if ( $Threshold != null ) { + foreach($Threshold as $Key => $Params) { + $Threshold[$Key]["MinX"] = $this->scaleComputeY( + $Params["Min"], + array("AxisID"=>$Serie["Axis"]) + ); + $Threshold[$Key]["MaxX"] = $this->scaleComputeY( + $Params["Max"], + array("AxisID"=>$Serie["Axis"]) + ); + } + } + + $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) { + if ( $YZero > $this->GraphAreaY2-1 ) { + $YZero = $this->GraphAreaY2-1; + } + + $Areas = ""; + $AreaID = 0; + $Areas[$AreaID][] = $this->GraphAreaX1 + $XMargin; + if ( $AroundZero ) { + $Areas[$AreaID][] = $YZero; + } else { + $Areas[$AreaID][] = $this->GraphAreaY2-1; + } + + if ( $XDivs == 0 ) { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; + } else { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; + } + $X = $this->GraphAreaX1 + $XMargin; + $LastX = null; + $LastY = null; + + if ( !is_array($PosArray) ) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + foreach($PosArray as $Key => $Y) { + if ( $DisplayValues && $Serie["Data"][$Key] != VOID ) { + if ( $Serie["Data"][$Key] > 0 ) { + $Align = TEXT_ALIGN_BOTTOMMIDDLE; + $Offset = $DisplayOffset; + } else { + $Align = TEXT_ALIGN_TOPMIDDLE; + $Offset = -$DisplayOffset; + } + $this->drawText( + $X, + $Y-$Offset, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit), + array("R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>$Align) + ); + } + + if ( $Y == VOID && isset($Areas[$AreaID]) ) { + if($LastX == null) { + $Areas[$AreaID][] = $X; + } else { + $Areas[$AreaID][] = $LastX; + } + + if ( $AroundZero ) { + $Areas[$AreaID][] = $YZero; + } else { + $Areas[$AreaID][] = $this->GraphAreaY2-1; + } + $AreaID++; + } elseif ($Y != VOID) { + if ( !isset($Areas[$AreaID]) ) { + $Areas[$AreaID][] = $X; + if ( $AroundZero ) { + $Areas[$AreaID][] = $YZero; + } else { + $Areas[$AreaID][] = $this->GraphAreaY2-1; + } + } + + $Areas[$AreaID][] = $X; + $Areas[$AreaID][] = $Y; + } + + $LastX = $X; + $X = $X + $XStep; + } + $Areas[$AreaID][] = $LastX; + if ( $AroundZero ) { + $Areas[$AreaID][] = $YZero; + } else { + $Areas[$AreaID][] = $this->GraphAreaY2-1; + } + + /* Handle shadows in the areas */ + if ( $this->Shadow ) { + $ShadowArea = ""; + foreach($Areas as $Key => $Points) { + $ShadowArea[$Key] = ""; + foreach($Points as $Key2 => $Value) { + if ( $Key2 % 2 == 0 ) { + $ShadowArea[$Key][] = $Value + $this->ShadowX; + } else { + $ShadowArea[$Key][] = $Value + $this->ShadowY; + } + } + } + + foreach($ShadowArea as $Key => $Points) { + $this->drawPolygonChart( + $Points, + array( + "R"=>$this->ShadowR, + "G"=>$this->ShadowG, + "B"=>$this->ShadowB, + "Alpha"=>$this->Shadowa + ) + ); + } + } + + $Alpha = $ForceTransparency != null ? $ForceTransparency : $Alpha; + $Color = array( + "R"=>$R, + "G"=>$G, + "B"=>$B, + "Alpha"=>$Alpha, + "Threshold"=>$Threshold + ); + + foreach ($Areas as $Key => $Points) { + $this->drawPolygonChart($Points,$Color); + } + } else { + if ( $YZero < $this->GraphAreaX1+1 ) { + $YZero = $this->GraphAreaX1+1; + } + if ( $YZero > $this->GraphAreaX2-1 ) { + $YZero = $this->GraphAreaX2-1; + } + + $Areas = ""; + $AreaID = 0; + if ( $AroundZero ) { + $Areas[$AreaID][] = $YZero; + } else { + $Areas[$AreaID][] = $this->GraphAreaX1+1; + } + $Areas[$AreaID][] = $this->GraphAreaY1 + $XMargin; + + if ( $XDivs == 0 ) { + $YStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; + } else { + $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; + } + $Y = $this->GraphAreaY1 + $XMargin; + $LastX = null; + $LastY = null; + + if ( !is_array($PosArray) ) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + foreach($PosArray as $Key => $X) { + if ( $DisplayValues && $Serie["Data"][$Key] != VOID ) { + if ( $Serie["Data"][$Key] > 0 ) { + $Align = TEXT_ALIGN_BOTTOMMIDDLE; + $Offset = $DisplayOffset; + } else { + $Align = TEXT_ALIGN_TOPMIDDLE; + $Offset = -$DisplayOffset; + } + $this->drawText( + $X+$Offset, + $Y, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit), + array("Angle"=>270,"R"=>$DisplayR,"G"=>$DisplayG,"B"=>$DisplayB,"Align"=>$Align) + ); + } + + if ( $X == VOID && isset($Areas[$AreaID]) ) { + if ( $AroundZero ) { + $Areas[$AreaID][] = $YZero; + } else { + $Areas[$AreaID][] = $this->GraphAreaX1+1; + } + + if($LastY == null) { + $Areas[$AreaID][] = $Y; + } else { + $Areas[$AreaID][] = $LastY; + } + + $AreaID++; + } elseif ($X != VOID) { + if ( !isset($Areas[$AreaID]) ) { + if ( $AroundZero ) { + $Areas[$AreaID][] = $YZero; + } else { + $Areas[$AreaID][] = $this->GraphAreaX1+1; + } + $Areas[$AreaID][] = $Y; + } + + $Areas[$AreaID][] = $X; + $Areas[$AreaID][] = $Y; + } + + $LastX = $X; $LastY = $Y; + $Y = $Y + $YStep; + } + if ( $AroundZero ) { + $Areas[$AreaID][] = $YZero; + } else { + $Areas[$AreaID][] = $this->GraphAreaX1+1; + } + $Areas[$AreaID][] = $LastY; + + /* Handle shadows in the areas */ + if ( $this->Shadow ) { + $ShadowArea = ""; + foreach($Areas as $Key => $Points) { + $ShadowArea[$Key] = ""; + foreach($Points as $Key2 => $Value) { + if ( $Key2 % 2 == 0 ) { + $ShadowArea[$Key][] = $Value + $this->ShadowX; + } else { + $ShadowArea[$Key][] = $Value + $this->ShadowY; + } + } + } + + foreach($ShadowArea as $Key => $Points) { + $this->drawPolygonChart( + $Points, + array( + "R"=>$this->ShadowR, + "G"=>$this->ShadowG, + "B"=>$this->ShadowB, + "Alpha"=>$this->Shadowa + ) + ); + } + } + + $Alpha = $ForceTransparency != null ? $ForceTransparency : $Alpha; + $Color = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Threshold"=>$Threshold); + + foreach($Areas as $Key => $Points) { + $this->drawPolygonChart($Points,$Color); + } + } + } + } + } + + + /** + * Draw a bar chart + * @param type $Format + */ + public function drawBarChart($Format=null) + { + $Floating0Serie = isset($Format["Floating0Serie"]) ? $Format["Floating0Serie"] : null; + $Floating0Value = isset($Format["Floating0Value"]) ? $Format["Floating0Value"] : null; + $Draw0Line = isset($Format["Draw0Line"]) ? $Format["Draw0Line"] : false; + $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] : false; + $DisplayOrientation = isset($Format["DisplayOrientation"]) ? $Format["DisplayOrientation"] : ORIENTATION_HORIZONTAL; + $DisplayOffset = isset($Format["DisplayOffset"]) ? $Format["DisplayOffset"] : 2; + $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; + $DisplayFont = isset($Format["DisplaySize"]) ? $Format["DisplaySize"] : $this->FontName; + $DisplaySize = isset($Format["DisplaySize"]) ? $Format["DisplaySize"] : $this->FontSize; + $DisplayPos = isset($Format["DisplayPos"]) ? $Format["DisplayPos"] : LABEL_POS_OUTSIDE; + $DisplayShadow = isset($Format["DisplayShadow"]) ? $Format["DisplayShadow"] : true; + $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; + $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; + $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; + $AroundZero = isset($Format["AroundZero"]) ? $Format["AroundZero"] : true; + $Interleave = isset($Format["Interleave"]) ? $Format["Interleave"] : .5; + $Rounded = isset($Format["Rounded"]) ? $Format["Rounded"] : false; + $RoundRadius = isset($Format["RoundRadius"]) ? $Format["RoundRadius"] : 4; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : null; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : -1; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : -1; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : -1; + $Gradient = isset($Format["Gradient"]) ? $Format["Gradient"] : false; + $GradientMode = isset($Format["GradientMode"]) ? $Format["GradientMode"] : GRADIENT_SIMPLE; + $GradientAlpha = isset($Format["GradientAlpha"]) ? $Format["GradientAlpha"] : 20; + $GradientStartR = isset($Format["GradientStartR"]) ? $Format["GradientStartR"] : 255; + $GradientStartG = isset($Format["GradientStartG"]) ? $Format["GradientStartG"] : 255; + $GradientStartB = isset($Format["GradientStartB"]) ? $Format["GradientStartB"] : 255; + $GradientEndR = isset($Format["GradientEndR"]) ? $Format["GradientEndR"] : 0; + $GradientEndG = isset($Format["GradientEndG"]) ? $Format["GradientEndG"] : 0; + $GradientEndB = isset($Format["GradientEndB"]) ? $Format["GradientEndB"] : 0; + $TxtMargin = isset($Format["TxtMargin"]) ? $Format["TxtMargin"] : 6; + $OverrideColors = isset($Format["OverrideColors"]) ? $Format["OverrideColors"] : null; + $OverrideSurrounding = isset($Format["OverrideSurrounding"]) ? $Format["OverrideSurrounding"] : 30; + $InnerSurrounding = isset($Format["InnerSurrounding"]) ? $Format["InnerSurrounding"] : null; + $InnerBorderR = isset($Format["InnerBorderR"]) ? $Format["InnerBorderR"] : -1; + $InnerBorderG = isset($Format["InnerBorderG"]) ? $Format["InnerBorderG"] : -1; + $InnerBorderB = isset($Format["InnerBorderB"]) ? $Format["InnerBorderB"] : -1; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : false; + + $this->LastChartLayout = CHART_LAST_LAYOUT_REGULAR; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + + if ( $OverrideColors != null ) { + $OverrideColors = $this->validatePalette($OverrideColors,$OverrideSurrounding); + $this->DataSet->saveExtendedData("Palette",$OverrideColors); + } + + $RestoreShadow = $this->Shadow; + + $SeriesCount = $this->countDrawableSeries(); + $CurrentSerie = 0; + foreach($Data["Series"] as $SerieName => $Serie) { + if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { + $R = $Serie["Color"]["R"]; + $G = $Serie["Color"]["G"]; + $B = $Serie["Color"]["B"]; + $Alpha = $Serie["Color"]["Alpha"]; + $Ticks = $Serie["Ticks"]; + if ( $DisplayColor == DISPLAY_AUTO ) { + $DisplayR = $R; + $DisplayG = $G; + $DisplayB = $B; + } + if ( $Surrounding != null ) { + $BorderR = $R+$Surrounding; + $BorderG = $G+$Surrounding; + $BorderB = $B+$Surrounding; + } + if ( $InnerSurrounding != null ) { + $InnerBorderR = $R+$InnerSurrounding; + $InnerBorderG = $G+$InnerSurrounding; + $InnerBorderB = $B+$InnerSurrounding; + } + if ( $InnerBorderR == -1 ) { + $InnerColor = null; + } else { + $InnerColor = array( + "R"=>$InnerBorderR, + "G"=>$InnerBorderG, + "B"=>$InnerBorderB + ); + } + $Color = array( + "R"=>$R, + "G"=>$G, + "B"=>$B, + "Alpha"=>$Alpha, + "BorderR"=>$BorderR, + "BorderG"=>$BorderG, + "BorderB"=>$BorderB + ); + + $AxisID = $Serie["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + if (isset($Serie["Description"])) { + $SerieDescription = $Serie["Description"]; + } else { + $SerieDescription = $SerieName; + } + + $PosArray = $this->scaleComputeY( + $Serie["Data"], + array("AxisID"=>$Serie["Axis"]) + ); + + if ( $Floating0Value != null ) { + $YZero = $this->scaleComputeY( + $Floating0Value, + array("AxisID"=>$Serie["Axis"]) + ); + } else { + $YZero = $this->scaleComputeY(0,array("AxisID"=>$Serie["Axis"])); + } + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) { + if ( $YZero > $this->GraphAreaY2-1 ) { + $YZero = $this->GraphAreaY2-1; + } + if ( $YZero < $this->GraphAreaY1+1 ) { + $YZero = $this->GraphAreaY1+1; + } + + if ( $XDivs == 0 ) { + $XStep = 0; + } else { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; + } + $X = $this->GraphAreaX1 + $XMargin; + + if ( $AroundZero ) { + $Y1 = $YZero; + } else { + $Y1 = $this->GraphAreaY2-1; + } + if ( $XDivs == 0 ) { + $XSize = ($this->GraphAreaX2-$this->GraphAreaX1)/($SeriesCount+$Interleave); + } else { + $XSize = ($XStep / ($SeriesCount+$Interleave) ); + } + + $XOffset = -($XSize*$SeriesCount)/2 + $CurrentSerie * $XSize; + if ( $X + $XOffset <= $this->GraphAreaX1 ) { + $XOffset = $this->GraphAreaX1 - $X + 1 ; + } + + $this->DataSet->Data["Series"][$SerieName]["XOffset"] = $XOffset + $XSize / 2; + + if ( $Rounded || $BorderR != -1) { + $XSpace = 1; + } else { + $XSpace = 0; + } + + if ( !is_array($PosArray) ) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + + $ID = 0; + foreach($PosArray as $Key => $Y2) { + if ( $Floating0Serie != null ) { + if ( isset($Data["Series"][$Floating0Serie]["Data"][$Key]) ) { + $Value = $Data["Series"][$Floating0Serie]["Data"][$Key]; + } else { + $Value = 0; + } + + $YZero = $this->scaleComputeY($Value,array("AxisID"=>$Serie["Axis"])); + if ( $YZero > $this->GraphAreaY2-1 ) { + $YZero = $this->GraphAreaY2-1; + } + if ( $YZero < $this->GraphAreaY1+1 ) { + $YZero = $this->GraphAreaY1+1; + } + + if ( $AroundZero ) { + $Y1 = $YZero; + } else { + $Y1 = $this->GraphAreaY2-1; + } + } + + if ( $OverrideColors != null ) { + if ( isset($OverrideColors[$ID]) ) { + $Color = array( + "R"=>$OverrideColors[$ID]["R"], + "G"=>$OverrideColors[$ID]["G"], + "B"=>$OverrideColors[$ID]["B"], + "Alpha"=>$OverrideColors[$ID]["Alpha"], + "BorderR"=>$OverrideColors[$ID]["BorderR"], + "BorderG"=>$OverrideColors[$ID]["BorderG"], + "BorderB"=>$OverrideColors[$ID]["BorderB"] + ); + } else { + $Color = $this->getRandomColor(); + } + } + + if ( $Y2 != VOID ) { + $BarHeight = $Y1 - $Y2; + + if ( $Serie["Data"][$Key] == 0 ) { + $this->drawLine( + $X+$XOffset+$XSpace, + $Y1, + $X+$XOffset+$XSize-$XSpace, + $Y1, + $Color + ); + if ( $RecordImageMap ) { + $this->addToImageMap( + "RECT", + floor($X+$XOffset+$XSpace).",".floor($Y1-1) + .",".floor($X+$XOffset+$XSize-$XSpace)."," + .floor($Y1+1), + $this->toHTMLColor($R,$G,$B), + $SerieDescription, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit) + ); + } + } else { + if ( $RecordImageMap ) { + $this->addToImageMap( + "RECT", + floor($X+$XOffset+$XSpace).",".floor($Y1) + .",".floor($X+$XOffset+$XSize-$XSpace)."," + .floor($Y2), + $this->toHTMLColor($R,$G,$B), + $SerieDescription, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit) + ); + } + + if ( $Rounded ) { + $this->drawRoundedFilledRectangle( + $X+$XOffset+$XSpace, + $Y1, + $X+$XOffset+$XSize-$XSpace, + $Y2, + $RoundRadius, + $Color + ); + } else { + $this->drawFilledRectangle( + $X+$XOffset+$XSpace, + $Y1, + $X+$XOffset+$XSize-$XSpace, + $Y2, + $Color + ); + + if ( $InnerColor != null ) { + $this->drawRectangle( + $X+$XOffset+$XSpace+1, + min($Y1,$Y2)+1, + $X+$XOffset+$XSize-$XSpace-1, + max($Y1,$Y2)-1, + $InnerColor + ); + } + + if ( $Gradient ) { + $this->Shadow = false; + + if ( $GradientMode == GRADIENT_SIMPLE ) { + if ( $Serie["Data"][$Key] >= 0 ) { + $GradienColor = array( + "StartR"=>$GradientStartR, + "StartG"=>$GradientStartG, + "StartB"=>$GradientStartB, + "EndR"=>$GradientEndR, + "EndG"=>$GradientEndG, + "EndB"=>$GradientEndB, + "Alpha"=>$GradientAlpha + ); + } else { + $GradienColor = array( + "StartR"=>$GradientEndR, + "StartG"=>$GradientEndG, + "StartB"=>$GradientEndB, + "EndR"=>$GradientStartR, + "EndG"=>$GradientStartG, + "EndB"=>$GradientStartB, + "Alpha"=>$GradientAlpha + ); + } + $this->drawGradientArea( + $X+$XOffset+$XSpace, + $Y1, + $X+$XOffset+$XSize-$XSpace, + $Y2, + DIRECTION_VERTICAL, + $GradienColor + ); + } elseif ( $GradientMode == GRADIENT_EFFECT_CAN ) { + $GradienColor1 = array( + "StartR"=>$GradientEndR, + "StartG"=>$GradientEndG, + "StartB"=>$GradientEndB, + "EndR"=>$GradientStartR, + "EndG"=>$GradientStartG, + "EndB"=>$GradientStartB, + "Alpha"=>$GradientAlpha + ); + $GradienColor2 = array( + "StartR"=>$GradientStartR, + "StartG"=>$GradientStartG, + "StartB"=>$GradientStartB, + "EndR"=>$GradientEndR, + "EndG"=>$GradientEndG, + "EndB"=>$GradientEndB, + "Alpha"=>$GradientAlpha + ); + $XSpan = floor($XSize / 3); + + $this->drawGradientArea( + $X+$XOffset+$XSpace, + $Y1, + $X+$XOffset+$XSpan-$XSpace, + $Y2, + DIRECTION_HORIZONTAL, + $GradienColor1 + ); + $this->drawGradientArea( + $X+$XOffset+$XSpan+$XSpace, + $Y1, + $X+$XOffset+$XSize-$XSpace, + $Y2, + DIRECTION_HORIZONTAL, + $GradienColor2 + ); + } + $this->Shadow = $RestoreShadow; + } + } + + if ( $Draw0Line ) { + $Line0Color = array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>20); + + if ( abs($Y1 - $Y2) > 3 ) { + $Line0Width = 3; + } else { + $Line0Width = 1; + } + if ( $Y1 - $Y2 < 0 ) { + $Line0Width = -$Line0Width; + } + + $this->drawFilledRectangle( + $X+$XOffset+$XSpace, + floor($Y1), + $X+$XOffset+$XSize-$XSpace, + floor($Y1)-$Line0Width, + $Line0Color + ); + $this->drawLine( + $X+$XOffset+$XSpace, + floor($Y1), + $X+$XOffset+$XSize-$XSpace, + floor($Y1), + $Line0Color + ); + } + } + + if ( $DisplayValues && $Serie["Data"][$Key] != VOID ) { + if ( $DisplayShadow ) { + $this->Shadow = true; + } + + $Caption = $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit); + $TxtPos = $this->getTextBox(0,0,$DisplayFont,$DisplaySize,90,$Caption); + $TxtHeight = $TxtPos[0]["Y"] - $TxtPos[1]["Y"] + $TxtMargin; + + if ( $DisplayPos == LABEL_POS_INSIDE && abs($TxtHeight) < abs($BarHeight) ) { + $CenterX = (($X+$XOffset+$XSize-$XSpace)-($X+$XOffset+$XSpace))/2 + $X+$XOffset+$XSpace; + $CenterY = ($Y2-$Y1)/2 + $Y1; + + $this->drawText( + $CenterX, + $CenterY, + $Caption, + array( + "R"=>$DisplayR, + "G"=>$DisplayG, + "B"=>$DisplayB, + "Align"=>TEXT_ALIGN_MIDDLEMIDDLE, + "FontSize"=>$DisplaySize, + "Angle"=>90 + ) + ); + } else { + if ( $Serie["Data"][$Key] >= 0 ) { + $Align = TEXT_ALIGN_BOTTOMMIDDLE; + $Offset = $DisplayOffset; + } else { + $Align = TEXT_ALIGN_TOPMIDDLE; + $Offset = -$DisplayOffset; + } + $this->drawText( + $X+$XOffset+$XSize/2, + $Y2-$Offset, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit), + array( + "R"=>$DisplayR, + "G"=>$DisplayG, + "B"=>$DisplayB, + "Align"=>$Align, + "FontSize"=>$DisplaySize + ) + ); + } + + $this->Shadow = $RestoreShadow; + } + } + + $X = $X + $XStep; + $ID++; + } + } else { + if ( $YZero < $this->GraphAreaX1+1 ) { + $YZero = $this->GraphAreaX1+1; + } + if ( $YZero > $this->GraphAreaX2-1 ) { + $YZero = $this->GraphAreaX2-1; + } + + if ( $XDivs == 0 ) { + $YStep = 0; + } else { + $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; + } + + $Y = $this->GraphAreaY1 + $XMargin; + + if ( $AroundZero ) { + $X1 = $YZero; + } else { + $X1 = $this->GraphAreaX1+1; + } + if ( $XDivs == 0 ) { + $YSize = ($this->GraphAreaY2-$this->GraphAreaY1)/($SeriesCount+$Interleave); + } else { + $YSize = ($YStep / ($SeriesCount+$Interleave) ); + } + + $YOffset = -($YSize*$SeriesCount)/2 + $CurrentSerie * $YSize; + if ( $Y + $YOffset <= $this->GraphAreaY1 ) { + $YOffset = $this->GraphAreaY1 - $Y + 1 ; + } + + $this->DataSet->Data["Series"][$SerieName]["XOffset"] = $YOffset + $YSize / 2; + + if ( $Rounded || $BorderR != -1 ) { + $YSpace = 1; + } else { + $YSpace = 0; + } + + if ( !is_array($PosArray) ) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + + $ID = 0 ; + foreach ($PosArray as $Key => $X2) { + if ( $Floating0Serie != null ) { + if ( isset($Data["Series"][$Floating0Serie]["Data"][$Key]) ) { + $Value = $Data["Series"][$Floating0Serie]["Data"][$Key]; + } else { + $Value = 0; + } + + $YZero = $this->scaleComputeY($Value,array("AxisID"=>$Serie["Axis"])); + if ( $YZero < $this->GraphAreaX1+1 ) { + $YZero = $this->GraphAreaX1+1; + } + if ( $YZero > $this->GraphAreaX2-1 ) { + $YZero = $this->GraphAreaX2-1; + } + if ( $AroundZero ) { + $X1 = $YZero; + } else { + $X1 = $this->GraphAreaX1+1; + } + } + + if ( $OverrideColors != null ) { + if ( isset($OverrideColors[$ID]) ) { + $Color = array( + "R"=>$OverrideColors[$ID]["R"], + "G"=>$OverrideColors[$ID]["G"], + "B"=>$OverrideColors[$ID]["B"], + "Alpha"=>$OverrideColors[$ID]["Alpha"], + "BorderR"=>$OverrideColors[$ID]["BorderR"], + "BorderG"=>$OverrideColors[$ID]["BorderG"], + "BorderB"=>$OverrideColors[$ID]["BorderB"] + ); + } else { + $Color = $this->getRandomColor(); + } + } + + if ( $X2 != VOID ) { + $BarWidth = $X2 - $X1; + if ( $Serie["Data"][$Key] == 0 ) { + $this->drawLine($X1,$Y+$YOffset+$YSpace,$X1,$Y+$YOffset+$YSize-$YSpace,$Color); + if ( $RecordImageMap ) { + $this->addToImageMap( + "RECT", + floor($X1-1).",".floor($Y+$YOffset+$YSpace) + .",".floor($X1+1).",".floor($Y+$YOffset+$YSize-$YSpace), + $this->toHTMLColor($R,$G,$B), + $SerieDescription, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit) + ); + } + } else { + if ( $RecordImageMap ) { + $this->addToImageMap( + "RECT", + floor($X1).",".floor($Y+$YOffset+$YSpace) + .",".floor($X2).",".floor($Y+$YOffset+$YSize-$YSpace), + $this->toHTMLColor($R,$G,$B), + $SerieDescription, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit) + ); + } + + if ( $Rounded ) { + $this->drawRoundedFilledRectangle( + $X1+1, + $Y+$YOffset+$YSpace, + $X2, + $Y+$YOffset+$YSize-$YSpace, + $RoundRadius, + $Color + ); + } else { + $this->drawFilledRectangle( + $X1, + $Y+$YOffset+$YSpace, + $X2, + $Y+$YOffset+$YSize-$YSpace, + $Color + ); + + if ( $InnerColor != null ) { + $this->drawRectangle( + min($X1,$X2)+1, + $Y+$YOffset+$YSpace+1, + max($X1,$X2)-1, + $Y+$YOffset+$YSize-$YSpace-1, + $InnerColor + ); + } + + if ( $Gradient ) { + $this->Shadow = false; + + if ( $GradientMode == GRADIENT_SIMPLE ) { + if ( $Serie["Data"][$Key] >= 0 ) { + $GradienColor = array( + "StartR"=>$GradientStartR, + "StartG"=>$GradientStartG, + "StartB"=>$GradientStartB, + "EndR"=>$GradientEndR, + "EndG"=>$GradientEndG, + "EndB"=>$GradientEndB, + "Alpha"=>$GradientAlpha + ); + } else { + $GradienColor = array( + "StartR"=>$GradientEndR, + "StartG"=>$GradientEndG, + "StartB"=>$GradientEndB, + "EndR"=>$GradientStartR, + "EndG"=>$GradientStartG, + "EndB"=>$GradientStartB, + "Alpha"=>$GradientAlpha + ); + } + $this->drawGradientArea( + $X1, + $Y+$YOffset+$YSpace, + $X2, + $Y+$YOffset+$YSize-$YSpace, + DIRECTION_HORIZONTAL, + $GradienColor + ); + } elseif ( $GradientMode == GRADIENT_EFFECT_CAN ) { + $GradienColor1 = array( + "StartR"=>$GradientEndR, + "StartG"=>$GradientEndG, + "StartB"=>$GradientEndB, + "EndR"=>$GradientStartR, + "EndG"=>$GradientStartG, + "EndB"=>$GradientStartB, + "Alpha"=>$GradientAlpha + ); + $GradienColor2 = array( + "StartR"=>$GradientStartR, + "StartG"=>$GradientStartG, + "StartB"=>$GradientStartB, + "EndR"=>$GradientEndR, + "EndG"=>$GradientEndG, + "EndB"=>$GradientEndB, + "Alpha"=>$GradientAlpha + ); + $YSpan = floor($YSize / 3); + + $this->drawGradientArea( + $X1, + $Y+$YOffset+$YSpace, + $X2, + $Y+$YOffset+$YSpan-$YSpace, + DIRECTION_VERTICAL, + $GradienColor1 + ); + $this->drawGradientArea( + $X1, + $Y+$YOffset+$YSpan, + $X2, + $Y+$YOffset+$YSize-$YSpace, + DIRECTION_VERTICAL, + $GradienColor2 + ); + } + $this->Shadow = $RestoreShadow; + } + } + + if ( $Draw0Line ) { + $Line0Color = array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>20); + + if ( abs($X1 - $X2) > 3 ) { + $Line0Width = 3; + } else { + $Line0Width = 1; + } + if ( $X2 - $X1 < 0 ) { + $Line0Width = -$Line0Width; + } + + $this->drawFilledRectangle( + floor($X1), + $Y+$YOffset+$YSpace, + floor($X1)+$Line0Width, + $Y+$YOffset+$YSize-$YSpace, + $Line0Color + ); + $this->drawLine( + floor($X1), + $Y+$YOffset+$YSpace, + floor($X1), + $Y+$YOffset+$YSize-$YSpace, + $Line0Color + ); + } + } + + if ($DisplayValues && $Serie["Data"][$Key] != VOID) { + if ( $DisplayShadow ) { + $this->Shadow = true; + } + + $Caption = $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit); + $TxtPos = $this->getTextBox(0,0,$DisplayFont,$DisplaySize,0,$Caption); + $TxtWidth = $TxtPos[1]["X"] - $TxtPos[0]["X"] + $TxtMargin; + + if ($DisplayPos == LABEL_POS_INSIDE && abs($TxtWidth) < abs($BarWidth)) { + $CenterX = ($X2-$X1)/2 + $X1; + $CenterY = (($Y+$YOffset+$YSize-$YSpace) + -($Y+$YOffset+$YSpace))/2 + ($Y+$YOffset+$YSpace); + + $this->drawText( + $CenterX, + $CenterY, + $Caption, + array( + "R"=>$DisplayR, + "G"=>$DisplayG, + "B"=>$DisplayB, + "Align"=>TEXT_ALIGN_MIDDLEMIDDLE, + "FontSize"=>$DisplaySize + ) + ); + } else { + if ( $Serie["Data"][$Key] >= 0 ) { + $Align = TEXT_ALIGN_MIDDLELEFT; + $Offset = $DisplayOffset; + + } else { + $Align = TEXT_ALIGN_MIDDLERIGHT; + $Offset = -$DisplayOffset; + } + $this->drawText( + $X2+$Offset, + $Y+$YOffset+$YSize/2, + $Caption, + array( + "R"=>$DisplayR, + "G"=>$DisplayG, + "B"=>$DisplayB, + "Align"=>$Align, + "FontSize"=>$DisplaySize + ) + ); + } + + $this->Shadow = $RestoreShadow; + } + } + $Y = $Y + $YStep; + $ID++; + } + } + $CurrentSerie++; + } + } + } + + /** + * Draw a bar chart + * @param type $Format + */ + public function drawStackedBarChart($Format=null) + { + $DisplayValues = isset($Format["DisplayValues"]) ? $Format["DisplayValues"] : false; + $DisplayOrientation = isset($Format["DisplayOrientation"]) ? $Format["DisplayOrientation"] : ORIENTATION_AUTO; + $DisplayRound = isset($Format["DisplayRound"]) ? $Format["DisplayRound"] : 0; + $DisplayColor = isset($Format["DisplayColor"]) ? $Format["DisplayColor"] : DISPLAY_MANUAL; + $DisplayFont = isset($Format["DisplayFont"]) ? $Format["DisplayFont"] : $this->FontName; + $DisplaySize = isset($Format["DisplaySize"]) ? $Format["DisplaySize"] : $this->FontSize; + $DisplayR = isset($Format["DisplayR"]) ? $Format["DisplayR"] : 0; + $DisplayG = isset($Format["DisplayG"]) ? $Format["DisplayG"] : 0; + $DisplayB = isset($Format["DisplayB"]) ? $Format["DisplayB"] : 0; + $Interleave = isset($Format["Interleave"]) ? $Format["Interleave"] : .5; + $Rounded = isset($Format["Rounded"]) ? $Format["Rounded"] : false; + $RoundRadius = isset($Format["RoundRadius"]) ? $Format["RoundRadius"] : 4; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : null; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : -1; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : -1; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : -1; + $Gradient = isset($Format["Gradient"]) ? $Format["Gradient"] : false; + $GradientMode = isset($Format["GradientMode"]) ? $Format["GradientMode"] : GRADIENT_SIMPLE; + $GradientAlpha = isset($Format["GradientAlpha"]) ? $Format["GradientAlpha"] : 20; + $GradientStartR = isset($Format["GradientStartR"]) ? $Format["GradientStartR"] : 255; + $GradientStartG = isset($Format["GradientStartG"]) ? $Format["GradientStartG"] : 255; + $GradientStartB = isset($Format["GradientStartB"]) ? $Format["GradientStartB"] : 255; + $GradientEndR = isset($Format["GradientEndR"]) ? $Format["GradientEndR"] : 0; + $GradientEndG = isset($Format["GradientEndG"]) ? $Format["GradientEndG"] : 0; + $GradientEndB = isset($Format["GradientEndB"]) ? $Format["GradientEndB"] : 0; + $InnerSurrounding = isset($Format["InnerSurrounding"]) ? $Format["InnerSurrounding"] : null; + $InnerBorderR = isset($Format["InnerBorderR"]) ? $Format["InnerBorderR"] : -1; + $InnerBorderG = isset($Format["InnerBorderG"]) ? $Format["InnerBorderG"] : -1; + $InnerBorderB = isset($Format["InnerBorderB"]) ? $Format["InnerBorderB"] : -1; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : false; + $FontFactor = isset($Format["FontFactor"]) ? $Format["FontFactor"] : 8; + + $this->LastChartLayout = CHART_LAST_LAYOUT_STACKED; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + + $RestoreShadow = $this->Shadow; + + $LastX = ""; + $LastY = ""; + foreach($Data["Series"] as $SerieName => $Serie) + { + if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { + $R = $Serie["Color"]["R"]; + $G = $Serie["Color"]["G"]; + $B = $Serie["Color"]["B"]; + $Alpha = $Serie["Color"]["Alpha"]; + $Ticks = $Serie["Ticks"]; + if ( $DisplayColor == DISPLAY_AUTO ) { + $DisplayR = 255; + $DisplayG = 255; + $DisplayB = 255; + } + if ( $Surrounding != null ) { + $BorderR = $R+$Surrounding; + $BorderG = $G+$Surrounding; + $BorderB = $B+$Surrounding; + } + if ( $InnerSurrounding != null ) { + $InnerBorderR = $R+$InnerSurrounding; + $InnerBorderG = $G+$InnerSurrounding; + $InnerBorderB = $B+$InnerSurrounding; + } + if ( $InnerBorderR == -1 ) { + $InnerColor = null; + } else { + $InnerColor = array( + "R"=>$InnerBorderR, + "G"=>$InnerBorderG, + "B"=>$InnerBorderB + ); + } + + $AxisID = $Serie["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + if (isset($Serie["Description"])) { + $SerieDescription = $Serie["Description"]; + } else { + $SerieDescription = $SerieName; + } + + $PosArray = $this->scaleComputeY( + $Serie["Data"], + array("AxisID"=>$Serie["Axis"]), + true + ); + $YZero = $this->scaleComputeY(0,array("AxisID"=>$Serie["Axis"])); + + $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; + + $Color = array( + "TransCorner"=>true, + "R"=>$R, + "G"=>$G, + "B"=>$B, + "Alpha"=>$Alpha, + "BorderR"=>$BorderR, + "BorderG"=>$BorderG, + "BorderB"=>$BorderB + ); + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) { + if ( $YZero > $this->GraphAreaY2-1 ) { + $YZero = $this->GraphAreaY2-1; + } + if ( $YZero > $this->GraphAreaY2-1 ) { + $YZero = $this->GraphAreaY2-1; + } + + if ( $XDivs == 0 ) { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; + } else { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; + } + $X = $this->GraphAreaX1 + $XMargin; + + $XSize = ($XStep / (1+$Interleave) ); + $XOffset = -($XSize/2); + + if ( !is_array($PosArray) ) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + foreach($PosArray as $Key => $Height) { + if ( $Height != VOID && $Serie["Data"][$Key] != 0 ) { + if ( $Serie["Data"][$Key] > 0 ) { + $Pos = "+"; + } else { + $Pos = "-"; + } + + if ( !isset($LastY[$Key] ) ) { + $LastY[$Key] = ""; + } + if ( !isset($LastY[$Key][$Pos] ) ) { + $LastY[$Key][$Pos] = $YZero; + } + + $Y1 = $LastY[$Key][$Pos]; + $Y2 = $Y1 - $Height; + + if ( ($Rounded || $BorderR != -1) && ($Pos == "+" && $Y1 != $YZero) ) { + $YSpaceUp = 1; + } else { + $YSpaceUp = 0; + } + if ( ($Rounded || $BorderR != -1) && ($Pos == "-" && $Y1 != $YZero) ) { + $YSpaceDown = 1; + } else { + $YSpaceDown = 0; + } + + if ( $RecordImageMap ) { + $this->addToImageMap( + "RECT", + floor($X+$XOffset)."," + .floor($Y1-$YSpaceUp+$YSpaceDown)."," + .floor($X+$XOffset+$XSize).",".floor($Y2), + $this->toHTMLColor($R,$G,$B), + $SerieDescription, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit) + ); + } + + if ( $Rounded ) { + $this->drawRoundedFilledRectangle( + $X+$XOffset, + $Y1-$YSpaceUp+$YSpaceDown, + $X+$XOffset+$XSize, + $Y2, + $RoundRadius, + $Color + ); + } else { + $this->drawFilledRectangle( + $X+$XOffset, + $Y1-$YSpaceUp+$YSpaceDown, + $X+$XOffset+$XSize, + $Y2, + $Color + ); + + if ( $InnerColor != null ) { + $RestoreShadow = $this->Shadow; + $this->Shadow = false; + $this->drawRectangle( + min($X+$XOffset+1,$X+$XOffset+$XSize), + min($Y1-$YSpaceUp+$YSpaceDown,$Y2)+1, + max($X+$XOffset+1,$X+$XOffset+$XSize)-1, + max($Y1-$YSpaceUp+$YSpaceDown,$Y2)-1, + $InnerColor + ); + $this->Shadow = $RestoreShadow; + } + + if ( $Gradient ) { + $this->Shadow = false; + + if ( $GradientMode == GRADIENT_SIMPLE ) { + $GradientColor = array( + "StartR"=>$GradientStartR, + "StartG"=>$GradientStartG, + "StartB"=>$GradientStartB, + "EndR"=>$GradientEndR, + "EndG"=>$GradientEndG, + "EndB"=>$GradientEndB, + "Alpha"=>$GradientAlpha + ); + $this->drawGradientArea( + $X+$XOffset, + $Y1-1-$YSpaceUp+$YSpaceDown, + $X+$XOffset+$XSize, + $Y2+1, + DIRECTION_VERTICAL, + $GradientColor + ); + } elseif ( $GradientMode == GRADIENT_EFFECT_CAN ) { + $GradientColor1 = array( + "StartR"=>$GradientEndR, + "StartG"=>$GradientEndG, + "StartB"=>$GradientEndB, + "EndR"=>$GradientStartR, + "EndG"=>$GradientStartG, + "EndB"=>$GradientStartB, + "Alpha"=>$GradientAlpha + ); + $GradientColor2 = array( + "StartR"=>$GradientStartR, + "StartG"=>$GradientStartG, + "StartB"=>$GradientStartB, + "EndR"=>$GradientEndR, + "EndG"=>$GradientEndG, + "EndB"=>$GradientEndB, + "Alpha"=>$GradientAlpha + ); + $XSpan = floor($XSize / 3); + + $this->drawGradientArea( + $X+$XOffset-.5, + $Y1-.5-$YSpaceUp+$YSpaceDown, + $X+$XOffset+$XSpan, + $Y2+.5, + DIRECTION_HORIZONTAL, + $GradientColor1 + ); + $this->drawGradientArea( + $X+$XSpan+$XOffset-.5, + $Y1-.5-$YSpaceUp+$YSpaceDown, + $X+$XOffset+$XSize, + $Y2+.5, + DIRECTION_HORIZONTAL, + $GradientColor2 + ); + } + $this->Shadow = $RestoreShadow; + } + } + + if ( $DisplayValues ) { + $BarHeight = abs($Y2-$Y1)-2; + $BarWidth = $XSize+($XOffset/2)-$FontFactor; + + $Caption = $this->scaleFormat(round($Serie["Data"][$Key],$DisplayRound),$Mode,$Format,$Unit); + $TxtPos = $this->getTextBox(0,0,$DisplayFont,$DisplaySize,0,$Caption); + $TxtHeight = abs($TxtPos[2]["Y"] - $TxtPos[0]["Y"]); + $TxtWidth = abs($TxtPos[1]["X"] - $TxtPos[0]["X"]); + + $XCenter = ( ($X+$XOffset+$XSize) - ($X+$XOffset) ) / 2 + $X+$XOffset; + $YCenter = ( ($Y2) - ($Y1-$YSpaceUp+$YSpaceDown) ) / 2 + $Y1-$YSpaceUp+$YSpaceDown; + + $Done = false; + if ($DisplayOrientation == ORIENTATION_HORIZONTAL + || $DisplayOrientation == ORIENTATION_AUTO + ) { + if ($TxtHeight < $BarHeight && $TxtWidth < $BarWidth) { + $this->drawText( + $XCenter, + $YCenter, + $this->scaleFormat( + $Serie["Data"][$Key], + $Mode, + $Format, + $Unit + ), + array( + "R"=>$DisplayR, + "G"=>$DisplayG, + "B"=>$DisplayB, + "Align"=>TEXT_ALIGN_MIDDLEMIDDLE, + "FontSize"=>$DisplaySize, + "FontName"=>$DisplayFont + ) + ); + $Done = true; + } + } + + if ($DisplayOrientation == ORIENTATION_VERTICAL + || ( $DisplayOrientation == ORIENTATION_AUTO + && !$Done) + ) { + if ( $TxtHeight < $BarWidth && $TxtWidth < $BarHeight ) { + $this->drawText( + $XCenter, + $YCenter, + $this->scaleFormat( + $Serie["Data"][$Key], + $Mode, + $Format, + $Unit + ), + array( + "R"=>$DisplayR, + "G"=>$DisplayG, + "B"=>$DisplayB, + "Angle"=>90, + "Align"=>TEXT_ALIGN_MIDDLEMIDDLE, + "FontSize"=>$DisplaySize, + "FontName"=>$DisplayFont + ) + ); + } + } + } + $LastY[$Key][$Pos] = $Y2; + } + $X = $X + $XStep; + } + } else { + if ( $YZero < $this->GraphAreaX1+1 ) { + $YZero = $this->GraphAreaX1+1; + } + if ( $YZero > $this->GraphAreaX2-1 ) { + $YZero = $this->GraphAreaX2-1; + } + + if ( $XDivs == 0 ) { + $YStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; + } else { + $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; + } + $Y = $this->GraphAreaY1 + $XMargin; + + $YSize = $YStep / (1+$Interleave); + $YOffset = -($YSize/2); + + if ( !is_array($PosArray) ) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + foreach($PosArray as $Key => $Width) { + if ( $Width != VOID && $Serie["Data"][$Key] != 0 ) { + if ( $Serie["Data"][$Key] > 0 ) { + $Pos = "+"; + } else { + $Pos = "-"; + } + + if (!isset($LastX[$Key])) { + $LastX[$Key] = ""; + } + if (!isset($LastX[$Key][$Pos])) { + $LastX[$Key][$Pos] = $YZero; + } + + $X1 = $LastX[$Key][$Pos]; + $X2 = $X1 + $Width; + + if ( ($Rounded || $BorderR != -1) && ($Pos == "+" && $X1 != $YZero) ) { + $XSpaceLeft = 2; + } else { + $XSpaceLeft = 0; + } + if ( ($Rounded || $BorderR != -1) && ($Pos == "-" && $X1 != $YZero) ) { + $XSpaceRight = 2; + } else { + $XSpaceRight = 0; + } + + if ( $RecordImageMap ) { + $this->addToImageMap( + "RECT", + floor($X1+$XSpaceLeft).",".floor($Y+$YOffset) + .",".floor($X2-$XSpaceRight) + .",".floor($Y+$YOffset+$YSize), + $this->toHTMLColor($R,$G,$B), + $SerieDescription, + $this->scaleFormat($Serie["Data"][$Key],$Mode,$Format,$Unit) + ); + } + + if ( $Rounded ) { + $this->drawRoundedFilledRectangle( + $X1+$XSpaceLeft, + $Y+$YOffset, + $X2-$XSpaceRight, + $Y+$YOffset+$YSize, + $RoundRadius, + $Color + ); + } else { + $this->drawFilledRectangle( + $X1+$XSpaceLeft, + $Y+$YOffset, + $X2-$XSpaceRight, + $Y+$YOffset+$YSize, + $Color + ); + + if ( $InnerColor != null ) { + $RestoreShadow = $this->Shadow; + $this->Shadow = false; + $this->drawRectangle( + min($X1+$XSpaceLeft,$X2-$XSpaceRight)+1, + min($Y+$YOffset,$Y+$YOffset+$YSize)+1, + max($X1+$XSpaceLeft,$X2-$XSpaceRight)-1, + max($Y+$YOffset,$Y+$YOffset+$YSize)-1, + $InnerColor + ); + $this->Shadow = $RestoreShadow; + } + + if ( $Gradient ) { + $this->Shadow = false; + + if ($GradientMode == GRADIENT_SIMPLE) { + $GradientColor = array( + "StartR"=>$GradientStartR, + "StartG"=>$GradientStartG, + "StartB"=>$GradientStartB, + "EndR"=>$GradientEndR, + "EndG"=>$GradientEndG, + "EndB"=>$GradientEndB, + "Alpha"=>$GradientAlpha + ); + $this->drawGradientArea( + $X1+$XSpaceLeft, + $Y+$YOffset, + $X2-$XSpaceRight, + $Y+$YOffset+$YSize, + DIRECTION_HORIZONTAL, + $GradientColor + ); + } elseif ($GradientMode == GRADIENT_EFFECT_CAN) { + $GradientColor1 = array( + "StartR"=>$GradientEndR, + "StartG"=>$GradientEndG, + "StartB"=>$GradientEndB, + "EndR"=>$GradientStartR, + "EndG"=>$GradientStartG, + "EndB"=>$GradientStartB, + "Alpha"=>$GradientAlpha + ); + $GradientColor2 = array( + "StartR"=>$GradientStartR, + "StartG"=>$GradientStartG, + "StartB"=>$GradientStartB, + "EndR"=>$GradientEndR, + "EndG"=>$GradientEndG, + "EndB"=>$GradientEndB, + "Alpha"=>$GradientAlpha + ); + $YSpan = floor($YSize / 3); + + $this->drawGradientArea( + $X1+$XSpaceLeft, + $Y+$YOffset, + $X2-$XSpaceRight, + $Y+$YOffset+$YSpan, + DIRECTION_VERTICAL, + $GradientColor1 + ); + $this->drawGradientArea( + $X1+$XSpaceLeft, + $Y+$YOffset+$YSpan, + $X2-$XSpaceRight, + $Y+$YOffset+$YSize, + DIRECTION_VERTICAL, + $GradientColor2 + ); + } + $this->Shadow = $RestoreShadow; + } + } + + if ( $DisplayValues ) { + $BarWidth = abs($X2-$X1)-$FontFactor; + $BarHeight = $YSize+($YOffset/2)-$FontFactor/2; + $Caption = $this->scaleFormat( + round($Serie["Data"][$Key],$DisplayRound), + $Mode, + $Format, + $Unit + ); + $TxtPos = $this->getTextBox(0,0,$DisplayFont,$DisplaySize,0,$Caption); + $TxtHeight = abs($TxtPos[2]["Y"] - $TxtPos[0]["Y"]); + $TxtWidth = abs($TxtPos[1]["X"] - $TxtPos[0]["X"]); + + $XCenter = ( $X2 - $X1 ) / 2 + $X1; + $YCenter = ( ($Y+$YOffset+$YSize) - ($Y+$YOffset) ) / 2 + $Y+$YOffset; + + $Done = false; + if ($DisplayOrientation == ORIENTATION_HORIZONTAL + || $DisplayOrientation == ORIENTATION_AUTO + ) { + if ($TxtHeight < $BarHeight && $TxtWidth < $BarWidth) { + $this->drawText( + $XCenter, + $YCenter, + $this->scaleFormat( + $Serie["Data"][$Key], + $Mode, + $Format, + $Unit + ), + array( + "R"=>$DisplayR, + "G"=>$DisplayG, + "B"=>$DisplayB, + "Align"=>TEXT_ALIGN_MIDDLEMIDDLE, + "FontSize"=>$DisplaySize, + "FontName"=>$DisplayFont + ) + ); + $Done = true; + } + } + + if ($DisplayOrientation == ORIENTATION_VERTICAL + || ( $DisplayOrientation == ORIENTATION_AUTO && !$Done) + ) { + if ($TxtHeight < $BarWidth && $TxtWidth < $BarHeight) { + $this->drawText( + $XCenter, + $YCenter, + $this->scaleFormat( + $Serie["Data"][$Key], + $Mode, + $Format, + $Unit + ), + array( + "R"=>$DisplayR, + "G"=>$DisplayG, + "B"=>$DisplayB, + "Angle"=>90, + "Align"=>TEXT_ALIGN_MIDDLEMIDDLE, + "FontSize"=>$DisplaySize, + "FontName"=>$DisplayFont + ) + ); + } + } + } + + $LastX[$Key][$Pos] = $X2; + } + + $Y = $Y + $YStep; + } + } + } + } + } + + /** + * Draw a stacked area chart + * @param type $Format + */ + public function drawStackedAreaChart($Format=null) + { + $DrawLine = isset($Format["DrawLine"]) ? $Format["DrawLine"] : false; + $LineSurrounding = isset($Format["LineSurrounding"]) ? $Format["LineSurrounding"] : null; + $LineR = isset($Format["LineR"]) ? $Format["LineR"] : VOID; + $LineG = isset($Format["LineG"]) ? $Format["LineG"] : VOID; + $LineB = isset($Format["LineB"]) ? $Format["LineB"] : VOID; + $LineAlpha = isset($Format["LineAlpha"]) ? $Format["LineAlpha"] : 100; + $DrawPlot = isset($Format["DrawPlot"]) ? $Format["DrawPlot"] : false; + $PlotRadius = isset($Format["PlotRadius"]) ? $Format["PlotRadius"] : 2; + $PlotBorder = isset($Format["PlotBorder"]) ? $Format["PlotBorder"] : 1; + $PlotBorderSurrounding = isset($Format["PlotBorderSurrounding"]) ? $Format["PlotBorderSurrounding"] : null; + $PlotBorderR = isset($Format["PlotBorderR"]) ? $Format["PlotBorderR"] : 0; + $PlotBorderG = isset($Format["PlotBorderG"]) ? $Format["PlotBorderG"] : 0; + $PlotBorderB = isset($Format["PlotBorderB"]) ? $Format["PlotBorderB"] : 0; + $PlotBorderAlpha = isset($Format["PlotBorderAlpha"]) ? $Format["PlotBorderAlpha"] : 50; + $ForceTransparency = isset($Format["ForceTransparency"]) ? $Format["ForceTransparency"] : null; + + $this->LastChartLayout = CHART_LAST_LAYOUT_STACKED; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + + $RestoreShadow = $this->Shadow; + $this->Shadow = false; + + /* Build the offset data series */ + $OffsetData = ""; + $OverallOffset = ""; + $SerieOrder = ""; + foreach($Data["Series"] as $SerieName => $Serie) { + if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { + $SerieOrder[] = $SerieName; + + foreach($Serie["Data"] as $Key => $Value) { + if ( $Value == VOID ) { + $Value = 0; + } + if ($Value >= 0) { + $Sign = "+"; + } else { + $Sign = "-"; + } + if ( !isset($OverallOffset[$Key]) + || !isset($OverallOffset[$Key][$Sign]) + ) { + $OverallOffset[$Key][$Sign] = 0; + } + + if ( $Sign == "+" ) { + $Data["Series"][$SerieName]["Data"][$Key] = $Value + $OverallOffset[$Key][$Sign]; + } else { + $Data["Series"][$SerieName]["Data"][$Key] = $Value - $OverallOffset[$Key][$Sign]; + } + + $OverallOffset[$Key][$Sign] = $OverallOffset[$Key][$Sign] + abs($Value); + } + } + } + $SerieOrder = array_reverse($SerieOrder); + + $LastX = ""; + $LastY = ""; + foreach($SerieOrder as $Key => $SerieName) { + $Serie = $Data["Series"][$SerieName]; + if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { + $R = $Serie["Color"]["R"]; + $G = $Serie["Color"]["G"]; + $B = $Serie["Color"]["B"]; + $Alpha = $Serie["Color"]["Alpha"]; + $Ticks = $Serie["Ticks"]; + if ( $ForceTransparency != null ) { + $Alpha = $ForceTransparency; + } + + $Color = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha); + + if ( $LineSurrounding != null ) { + $LineColor = array( + "R"=>$R+$LineSurrounding, + "G"=>$G+$LineSurrounding, + "B"=>$B+$LineSurrounding, + "Alpha"=>$Alpha + ); + } elseif ( $LineR != VOID ) { + $LineColor = array( + "R"=>$LineR, + "G"=>$LineG, + "B"=>$LineB, + "Alpha"=>$LineAlpha + ); + } else { + $LineColor = $Color; + } + if ( $PlotBorderSurrounding != null ) { + $PlotBorderColor = array( + "R"=>$R+$PlotBorderSurrounding, + "G"=>$G+$PlotBorderSurrounding, + "B"=>$B+$PlotBorderSurrounding, + "Alpha"=>$PlotBorderAlpha + ); + } else { + $PlotBorderColor = array( + "R"=>$PlotBorderR, + "G"=>$PlotBorderG, + "B"=>$PlotBorderB, + "Alpha"=>$PlotBorderAlpha + ); + } + $AxisID = $Serie["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + $PosArray = $this->scaleComputeY( + $Serie["Data"], + array("AxisID"=>$Serie["Axis"]), + true + ); + $YZero = $this->scaleComputeY(0,array("AxisID"=>$Serie["Axis"])); + + $this->DataSet->Data["Series"][$SerieName]["XOffset"] = 0; + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) { + if ( $YZero < $this->GraphAreaY1+1 ) { + $YZero = $this->GraphAreaY1+1; + } + if ( $YZero > $this->GraphAreaY2-1 ) { + $YZero = $this->GraphAreaY2-1; + } + + if ( $XDivs == 0 ) { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; + } else { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; + } + $X = $this->GraphAreaX1 + $XMargin; + + if (!is_array($PosArray)) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + + $Plots = ""; + $Plots[] = $X; + $Plots[] = $YZero; + foreach($PosArray as $Key => $Height) { + if ( $Height != VOID ) { + $Plots[] = $X; + $Plots[] = $YZero-$Height; + } + $X = $X + $XStep; + } + $Plots[] = $X-$XStep; + $Plots[] = $YZero; + + $this->drawPolygon($Plots,$Color); + + $this->Shadow = $RestoreShadow; + if ( $DrawLine ) { + for ($i=2; $i<=count($Plots)-6; $i=$i+2) { + $this->drawLine( + $Plots[$i], + $Plots[$i+1], + $Plots[$i+2], + $Plots[$i+3], + $LineColor + ); + } + } + if ( $DrawPlot ) { + for($i=2; $i<=count($Plots)-4; $i=$i+2) { + if ( $PlotBorder != 0 ) { + $this->drawFilledCircle( + $Plots[$i], + $Plots[$i+1], + $PlotRadius+$PlotBorder, + $PlotBorderColor + ); + } + $this->drawFilledCircle($Plots[$i],$Plots[$i+1],$PlotRadius,$Color); + } + } + $this->Shadow = false; + } elseif ($Data["Orientation"] == SCALE_POS_TOPBOTTOM) { + if ( $YZero < $this->GraphAreaX1+1 ) { + $YZero = $this->GraphAreaX1+1; + } + if ( $YZero > $this->GraphAreaX2-1 ) { + $YZero = $this->GraphAreaX2-1; + } + + if ( $XDivs == 0 ) { + $YStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; + } else { + $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; + } + $Y = $this->GraphAreaY1 + $XMargin; + + if ( !is_array($PosArray) ) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + + $Plots = ""; + $Plots[] = $YZero; + $Plots[] = $Y; + foreach($PosArray as $Key => $Height) { + if ( $Height != VOID ) { + $Plots[] = $YZero+$Height; + $Plots[] = $Y; + } + $Y = $Y + $YStep; + } + $Plots[] = $YZero; + $Plots[] = $Y-$YStep; + + $this->drawPolygon($Plots,$Color); + + $this->Shadow = $RestoreShadow; + if ( $DrawLine ) { + for ($i=2; $i<=count($Plots)-6; $i=$i+2) { + $this->drawLine($Plots[$i],$Plots[$i+1],$Plots[$i+2],$Plots[$i+3],$LineColor); + } + } + if ( $DrawPlot ) { + for($i=2; $i<=count($Plots)-4; $i=$i+2) { + if ( $PlotBorder != 0 ) { + $this->drawFilledCircle( + $Plots[$i], + $Plots[$i+1], + $PlotRadius+$PlotBorder, + $PlotBorderColor + ); + } + + $this->drawFilledCircle($Plots[$i],$Plots[$i+1],$PlotRadius,$Color); + } + } + $this->Shadow = false; + } + } + } + $this->Shadow = $RestoreShadow; + } + + /** + * Returns a random color + * @param type $Alpha + * @return type + */ + public function getRandomColor($Alpha=100) + { + return( + array( + "R"=>rand(0,255), + "G"=>rand(0,255), + "B"=>rand(0,255), + "Alpha"=>$Alpha + ) + ); + } + + /** + * Validate a palette + * @param type $Colors + * @param type $Surrounding + * @return type + */ + public function validatePalette($Colors,$Surrounding=null) + { + $Result = ""; + + if ( !is_array($Colors) ) { + return($this->getRandomColor()); + } + + foreach($Colors as $Key => $Values) { + if ( isset($Values["R"]) ) { + $Result[$Key]["R"] = $Values["R"]; + } else { + $Result[$Key]["R"] = rand(0,255); + } + + if ( isset($Values["G"]) ) { + $Result[$Key]["G"] = $Values["G"]; + } else { + $Result[$Key]["G"] = rand(0,255); + } + + if ( isset($Values["B"]) ) { + $Result[$Key]["B"] = $Values["B"]; + } else { + $Result[$Key]["B"] = rand(0,255); + } + if ( isset($Values["Alpha"]) ) { + $Result[$Key]["Alpha"] = $Values["Alpha"]; + } else { + $Result[$Key]["Alpha"] = 100; + } + + if ( $Surrounding != null ) { + $Result[$Key]["BorderR"] = $Result[$Key]["R"] + $Surrounding; + $Result[$Key]["BorderG"] = $Result[$Key]["G"] + $Surrounding; + $Result[$Key]["BorderB"] = $Result[$Key]["B"] + $Surrounding; + } else { + if ( isset($Values["BorderR"])) { + $Result[$Key]["BorderR"] = $Values["BorderR"]; + } else { + $Result[$Key]["BorderR"] = $Result[$Key]["R"]; + } + if ( isset($Values["BorderG"])) { + $Result[$Key]["BorderG"] = $Values["BorderG"]; + } else { + $Result[$Key]["BorderG"] = $Result[$Key]["G"]; + } + if ( isset($Values["BorderB"])) { + $Result[$Key]["BorderB"] = $Values["BorderB"]; + } else { + $Result[$Key]["BorderB"] = $Result[$Key]["B"]; + } + if ( isset($Values["BorderAlpha"])) { + $Result[$Key]["BorderAlpha"] = $Values["BorderAlpha"]; + } else { + $Result[$Key]["BorderAlpha"] = $Result[$Key]["Alpha"]; + } + } + } + return($Result); + } + + /** + * Draw the derivative chart associated to the data series + * @param type $Format + */ + public function drawDerivative($Format=null) + { + $Offset = isset($Format["Offset"]) ? $Format["Offset"] : 10; + $SerieSpacing = isset($Format["SerieSpacing"]) ? $Format["SerieSpacing"] : 3; + $DerivativeHeight = isset($Format["DerivativeHeight"]) ? $Format["DerivativeHeight"] : 4; + $ShadedSlopeBox = isset($Format["ShadedSlopeBox"]) ? $Format["ShadedSlopeBox"] : false; + $DrawBackground = isset($Format["DrawBackground"]) ? $Format["DrawBackground"] : true; + $BackgroundR = isset($Format["BackgroundR"]) ? $Format["BackgroundR"] : 255; + $BackgroundG = isset($Format["BackgroundG"]) ? $Format["BackgroundG"] : 255; + $BackgroundB = isset($Format["BackgroundB"]) ? $Format["BackgroundB"] : 255; + $BackgroundAlpha= isset($Format["BackgroundAlpha"]) ? $Format["BackgroundAlpha"] : 20; + $DrawBorder = isset($Format["DrawBorder"]) ? $Format["DrawBorder"] : true; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 0; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 0; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 0; + $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : 100; + $Caption = isset($Format["Caption"]) ? $Format["Caption"] : true; + $CaptionHeight = isset($Format["CaptionHeight"]) ? $Format["CaptionHeight"] : 10; + $CaptionWidth = isset($Format["CaptionWidth"]) ? $Format["CaptionWidth"] : 20; + $CaptionMargin = isset($Format["CaptionMargin"]) ? $Format["CaptionMargin"] : 4; + $CaptionLine = isset($Format["CaptionLine"]) ? $Format["CaptionLine"] : false; + $CaptionBox = isset($Format["CaptionBox"]) ? $Format["CaptionBox"] : false; + $CaptionBorderR = isset($Format["CaptionBorderR"]) ? $Format["CaptionBorderR"] : 0; + $CaptionBorderG = isset($Format["CaptionBorderG"]) ? $Format["CaptionBorderG"] : 0; + $CaptionBorderB = isset($Format["CaptionBorderB"]) ? $Format["CaptionBorderB"] : 0; + $CaptionFillR = isset($Format["CaptionFillR"]) ? $Format["CaptionFillR"] : 255; + $CaptionFillG = isset($Format["CaptionFillG"]) ? $Format["CaptionFillG"] : 255; + $CaptionFillB = isset($Format["CaptionFillB"]) ? $Format["CaptionFillB"] : 255; + $CaptionFillAlpha = isset($Format["CaptionFillAlpha"]) ? $Format["CaptionFillAlpha"] : 80; + $PositiveSlopeStartR = isset($Format["PositiveSlopeStartR"]) ? $Format["PositiveSlopeStartR"] : 184; + $PositiveSlopeStartG = isset($Format["PositiveSlopeStartG"]) ? $Format["PositiveSlopeStartG"] : 234; + $PositiveSlopeStartB = isset($Format["PositiveSlopeStartB"]) ? $Format["PositiveSlopeStartB"] : 88; + $PositiveSlopeEndR = isset($Format["PositiveSlopeStartR"]) ? $Format["PositiveSlopeStartR"] : 239; + $PositiveSlopeEndG = isset($Format["PositiveSlopeStartG"]) ? $Format["PositiveSlopeStartG"] : 31; + $PositiveSlopeEndB = isset($Format["PositiveSlopeStartB"]) ? $Format["PositiveSlopeStartB"] : 36; + $NegativeSlopeStartR = isset($Format["NegativeSlopeStartR"]) ? $Format["NegativeSlopeStartR"] : 184; + $NegativeSlopeStartG = isset($Format["NegativeSlopeStartG"]) ? $Format["NegativeSlopeStartG"] : 234; + $NegativeSlopeStartB = isset($Format["NegativeSlopeStartB"]) ? $Format["NegativeSlopeStartB"] : 88; + $NegativeSlopeEndR = isset($Format["NegativeSlopeStartR"]) ? $Format["NegativeSlopeStartR"] : 67; + $NegativeSlopeEndG = isset($Format["NegativeSlopeStartG"]) ? $Format["NegativeSlopeStartG"] : 124; + $NegativeSlopeEndB = isset($Format["NegativeSlopeStartB"]) ? $Format["NegativeSlopeStartB"] : 227; + + $Data = $this->DataSet->getData(); + + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) { + $YPos = $this->DataSet->Data["GraphArea"]["Y2"] + $Offset; + } else { + $XPos = $this->DataSet->Data["GraphArea"]["X2"] + $Offset; + } + foreach($Data["Series"] as $SerieName => $Serie) { + if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { + $R = $Serie["Color"]["R"]; + $G = $Serie["Color"]["G"]; + $B = $Serie["Color"]["B"]; + $Alpha = $Serie["Color"]["Alpha"]; + $Ticks = $Serie["Ticks"]; + $Weight = $Serie["Weight"]; + + $AxisID = $Serie["Axis"]; + $PosArray = $this->scaleComputeY( + $Serie["Data"], + array("AxisID"=>$Serie["Axis"]) + ); + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) { + if ( $Caption ) { + if ( $CaptionLine ) { + $StartX = floor($this->GraphAreaX1-$CaptionWidth+$XMargin-$CaptionMargin); + $EndX = floor($this->GraphAreaX1-$CaptionMargin+$XMargin); + + $CaptionSettings = array( + "R"=>$R, + "G"=>$G, + "B"=>$B, + "Alpha"=>$Alpha, + "Ticks"=>$Ticks, + "Weight"=>$Weight + ); + if ( $CaptionBox ) { + $this->drawFilledRectangle( + $StartX, + $YPos, + $EndX, + $YPos+$CaptionHeight, + array( + "R"=>$CaptionFillR, + "G"=>$CaptionFillG, + "B"=>$CaptionFillB, + "BorderR"=>$CaptionBorderR, + "BorderG"=>$CaptionBorderG, + "BorderB"=>$CaptionBorderB, + "Alpha"=>$CaptionFillAlpha + ) + ); + } + $this->drawLine( + $StartX+2, + $YPos+($CaptionHeight/2), + $EndX-2, + $YPos+($CaptionHeight/2), + $CaptionSettings + ); + } else { + $this->drawFilledRectangle( + $this->GraphAreaX1-$CaptionWidth+$XMargin-$CaptionMargin, + $YPos, + $this->GraphAreaX1-$CaptionMargin+$XMargin, + $YPos+$CaptionHeight, + array( + "R"=>$R, + "G"=>$G, + "B"=>$B, + "BorderR"=>$CaptionBorderR, + "BorderG"=>$CaptionBorderG, + "BorderB"=>$CaptionBorderB + ) + ); + } + } + + if ( $XDivs == 0 ) { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; + } else { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; + } + $X = $this->GraphAreaX1 + $XMargin; + + $TopY = $YPos + ($CaptionHeight/2) - ($DerivativeHeight/2); + $BottomY = $YPos + ($CaptionHeight/2) + ($DerivativeHeight/2); + + $StartX = floor($this->GraphAreaX1+$XMargin); + $EndX = floor($this->GraphAreaX2-$XMargin); + + if ( $DrawBackground ) { + $this->drawFilledRectangle( + $StartX-1, + $TopY-1, + $EndX+1, + $BottomY+1, + array( + "R"=>$BackgroundR, + "G"=>$BackgroundG, + "B"=>$BackgroundB, + "Alpha"=>$BackgroundAlpha + ) + ); + } + if ( $DrawBorder ) { + $this->drawRectangle( + $StartX-1, + $TopY-1, + $EndX+1, + $BottomY+1, + array( + "R"=>$BorderR, + "G"=>$BorderG, + "B"=>$BorderB, + "Alpha"=>$BorderAlpha + ) + ); + } + + if ( !is_array($PosArray) ) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + + $RestoreShadow = $this->Shadow; + $this->Shadow = false; + + /* Determine the Max slope index */ + $LastX = null; + $LastY = null; + $MinSlope = 0; + $MaxSlope = 1; + foreach($PosArray as $Key => $Y) { + if ( $Y != VOID && $LastX != null ) { + $Slope = ($LastY - $Y); + if ( $Slope > $MaxSlope ) { + $MaxSlope = $Slope; + } if ( $Slope < $MinSlope ) { + $MinSlope = $Slope; + } + } + + if ( $Y == VOID ) { + $LastX = null; + $LastY = null; + } else { + $LastX = $X; + $LastY = $Y; + } + } + + $LastX = null; + $LastY = null; + $LastColor = null; + foreach($PosArray as $Key => $Y) { + if ( $Y != VOID && $LastY != null ) { + $Slope = ($LastY - $Y); + + if ( $Slope >= 0 ) { + $SlopeIndex = (100 / $MaxSlope) * $Slope; + $R = (($PositiveSlopeEndR - $PositiveSlopeStartR)/100)*$SlopeIndex+$PositiveSlopeStartR; + $G = (($PositiveSlopeEndG - $PositiveSlopeStartG)/100)*$SlopeIndex+$PositiveSlopeStartG; + $B = (($PositiveSlopeEndB - $PositiveSlopeStartB)/100)*$SlopeIndex+$PositiveSlopeStartB; + } elseif ( $Slope < 0 ) { + $SlopeIndex = (100 / abs($MinSlope)) * abs($Slope); + $R = (($NegativeSlopeEndR - $NegativeSlopeStartR)/100)*$SlopeIndex+$NegativeSlopeStartR; + $G = (($NegativeSlopeEndG - $NegativeSlopeStartG)/100)*$SlopeIndex+$NegativeSlopeStartG; + $B = (($NegativeSlopeEndB - $NegativeSlopeStartB)/100)*$SlopeIndex+$NegativeSlopeStartB; + } + + $Color = array("R"=>$R,"G"=>$G,"B"=>$B); + + if ( $ShadedSlopeBox && $LastColor != null ) {// && $Slope != 0 + $GradientSettings = array( + "StartR"=>$LastColor["R"], + "StartG"=>$LastColor["G"], + "StartB"=>$LastColor["B"], + "EndR"=>$R, + "EndG"=>$G, + "EndB"=>$B + ); + $this->drawGradientArea( + $LastX, + $TopY, + $X, + $BottomY, + DIRECTION_HORIZONTAL, + $GradientSettings + ); + } elseif ( !$ShadedSlopeBox || $LastColor == null ) { // || $Slope == 0 + $this->drawFilledRectangle( + floor($LastX), + $TopY, + floor($X), + $BottomY, + $Color + ); + } + $LastColor = $Color; + } + + if ( $Y == VOID ) { + $LastY = null; + + } else { + $LastX = $X; + $LastY = $Y; + } + + $X = $X + $XStep; + } + + $YPos = $YPos + $CaptionHeight + $SerieSpacing; + } else { + if ( $Caption ) { + $StartY = floor($this->GraphAreaY1-$CaptionWidth+$XMargin-$CaptionMargin); + $EndY = floor($this->GraphAreaY1-$CaptionMargin+$XMargin); + if ( $CaptionLine ) { + $CaptionSettings = array( + "R"=>$R, + "G"=>$G, + "B"=>$B, + "Alpha"=>$Alpha, + "Ticks"=>$Ticks, + "Weight"=>$Weight + ); + if ( $CaptionBox ) { + $this->drawFilledRectangle( + $XPos, + $StartY, + $XPos+$CaptionHeight, + $EndY, + array( + "R"=>$CaptionFillR, + "G"=>$CaptionFillG, + "B"=>$CaptionFillB, + "BorderR"=>$CaptionBorderR, + "BorderG"=>$CaptionBorderG, + "BorderB"=>$CaptionBorderB, + "Alpha"=>$CaptionFillAlpha + ) + ); + } + $this->drawLine( + $XPos+($CaptionHeight/2), + $StartY+2, + $XPos+($CaptionHeight/2), + $EndY-2, + $CaptionSettings + ); + } else { + $this->drawFilledRectangle( + $XPos, + $StartY, + $XPos+$CaptionHeight, + $EndY, + array( + "R"=>$R, + "G"=>$G, + "B"=>$B, + "BorderR"=>$CaptionBorderR, + "BorderG"=>$CaptionBorderG, + "BorderB"=>$CaptionBorderB + ) + ); + } + } + + + if ( $XDivs == 0 ) { + $XStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; + } else { + $XStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; + } + $Y = $this->GraphAreaY1 + $XMargin; + + $TopX = $XPos + ($CaptionHeight/2) - ($DerivativeHeight/2); + $BottomX = $XPos + ($CaptionHeight/2) + ($DerivativeHeight/2); + + $StartY = floor($this->GraphAreaY1+$XMargin); + $EndY = floor($this->GraphAreaY2-$XMargin); + + if ( $DrawBackground ) { + $this->drawFilledRectangle( + $TopX-1, + $StartY-1, + $BottomX+1, + $EndY+1, + array( + "R"=>$BackgroundR, + "G"=>$BackgroundG, + "B"=>$BackgroundB, + "Alpha"=>$BackgroundAlpha + ) + ); + } + if ( $DrawBorder ) { + $this->drawRectangle( + $TopX-1, + $StartY-1, + $BottomX+1, + $EndY+1, + array( + "R"=>$BorderR, + "G"=>$BorderG, + "B"=>$BorderB, + "Alpha"=>$BorderAlpha + ) + ); + } + + if ( !is_array($PosArray) ) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + + $RestoreShadow = $this->Shadow; + $this->Shadow = false; + + /* Determine the Max slope index */ + $LastX = null; + $LastY = null; + $MinSlope = 0; + $MaxSlope = 1; + foreach($PosArray as $Key => $X) { + if ( $X != VOID && $LastX != null ) { + $Slope = ($X - $LastX); + if ( $Slope > $MaxSlope ) { + $MaxSlope = $Slope; + } + if ( $Slope < $MinSlope ) { + $MinSlope = $Slope; + } + } + + if ( $X == VOID ) { + $LastX = null; + } else { + $LastX = $X; + } + } + + $LastX = null; + $LastY = null; + $LastColor = null; + foreach($PosArray as $Key => $X) { + if ( $X != VOID && $LastX != null ) { + $Slope = ($X - $LastX); + + if ( $Slope >= 0 ) { + $SlopeIndex = (100 / $MaxSlope) * $Slope; + $R = (($PositiveSlopeEndR - $PositiveSlopeStartR)/100)*$SlopeIndex+$PositiveSlopeStartR; + $G = (($PositiveSlopeEndG - $PositiveSlopeStartG)/100)*$SlopeIndex+$PositiveSlopeStartG; + $B = (($PositiveSlopeEndB - $PositiveSlopeStartB)/100)*$SlopeIndex+$PositiveSlopeStartB; + } elseif ( $Slope < 0 ) { + $SlopeIndex = (100 / abs($MinSlope)) * abs($Slope); + $R = (($NegativeSlopeEndR - $NegativeSlopeStartR)/100)*$SlopeIndex+$NegativeSlopeStartR; + $G = (($NegativeSlopeEndG - $NegativeSlopeStartG)/100)*$SlopeIndex+$NegativeSlopeStartG; + $B = (($NegativeSlopeEndB - $NegativeSlopeStartB)/100)*$SlopeIndex+$NegativeSlopeStartB; + } + + $Color = array("R"=>$R,"G"=>$G,"B"=>$B); + + if ( $ShadedSlopeBox && $LastColor != null ) { + $GradientSettings = array( + "StartR"=>$LastColor["R"], + "StartG"=>$LastColor["G"], + "StartB"=>$LastColor["B"], + "EndR"=>$R, + "EndG"=>$G, + "EndB"=>$B + ); + + $this->drawGradientArea( + $TopX, + $LastY, + $BottomX, + $Y, + DIRECTION_VERTICAL, + $GradientSettings + ); + } elseif ( !$ShadedSlopeBox || $LastColor == null ) { + $this->drawFilledRectangle( + $TopX, + floor($LastY), + $BottomX, + floor($Y), + $Color + ); + } + $LastColor = $Color; + } + + if ( $X == VOID ) { + $LastX = null; + } else { + $LastX = $X; + $LastY = $Y; + } + + $Y = $Y + $XStep; + } + + $XPos = $XPos + $CaptionHeight + $SerieSpacing; + } + $this->Shadow = $RestoreShadow; + } + } + } + + /** + * Draw the line of best fit + * @param type $Format + */ + public function drawBestFit($Format="") + { + $OverrideTicks = isset($Format["Ticks"]) ? $Format["Ticks"] : null; + $OverrideR = isset($Format["R"]) ? $Format["R"] : VOID; + $OverrideG = isset($Format["G"]) ? $Format["G"] : VOID; + $OverrideB = isset($Format["B"]) ? $Format["B"] : VOID; + $OverrideAlpha = isset($Format["Alpha"]) ? $Format["Alpha"] : VOID; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + + foreach($Data["Series"] as $SerieName => $Serie) { + if ($Serie["isDrawable"] == true && $SerieName != $Data["Abscissa"]) { + if ( $OverrideR != VOID && $OverrideG != VOID && $OverrideB != VOID ) { + $R = $OverrideR; + $G = $OverrideG; + $B = $OverrideB; + } else { + $R = $Serie["Color"]["R"]; + $G = $Serie["Color"]["G"]; + $B = $Serie["Color"]["B"]; + } + if ( $OverrideTicks == null ) { + $Ticks = $Serie["Ticks"]; + } else { + $Ticks = $OverrideTicks; + } + if ( $OverrideAlpha == VOID ) { + $Alpha = $Serie["Color"]["Alpha"]; + } else { + $Alpha = $OverrideAlpha; + } + + $Color = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks); + + $AxisID = $Serie["Axis"]; + $PosArray = $this->scaleComputeY( + $Serie["Data"], + array("AxisID"=>$Serie["Axis"]) + ); + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) { + if ( $XDivs == 0 ) { $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; + } else { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; + } + $X = $this->GraphAreaX1 + $XMargin; + + if ( !is_array($PosArray) ) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + $Sxy = 0; + $Sx = 0; + $Sy = 0; + $Sxx = 0; + foreach($PosArray as $Key => $Y) { + if ( $Y != VOID ) { + $Sxy = $Sxy + $X*$Y; + $Sx = $Sx + $X; + $Sy = $Sy + $Y; + $Sxx = $Sxx + $X*$X; + } + + $X = $X + $XStep; + } + $n = count($this->DataSet->stripVOID($PosArray)); //$n = count($PosArray); + $M = (($n*$Sxy)-($Sx*$Sy)) / (($n*$Sxx)-($Sx*$Sx)); + $B = (($Sy)-($M*$Sx))/($n); + + $X1 = $this->GraphAreaX1 + $XMargin; + $Y1 = $M * $X1 + $B; + $X2 = $this->GraphAreaX2 - $XMargin; + $Y2 = $M * $X2 + $B; + + if ( $Y1 < $this->GraphAreaY1 ) { + $X1 = $X1 + ($this->GraphAreaY1-$Y1); + $Y1 = $this->GraphAreaY1; + } + if ( $Y1 > $this->GraphAreaY2 ) { + $X1 = $X1 + ($Y1-$this->GraphAreaY2); + $Y1 = $this->GraphAreaY2; + } + if ( $Y2 < $this->GraphAreaY1 ) { + $X2 = $X2 - ($this->GraphAreaY1-$Y2); + $Y2 = $this->GraphAreaY1; + } + if ( $Y2 > $this->GraphAreaY2 ) { + $X2 = $X2 - ($Y2-$this->GraphAreaY2); + $Y2 = $this->GraphAreaY2; + } + + $this->drawLine($X1,$Y1,$X2,$Y2,$Color); + } else { + if ( $XDivs == 0 ) { + $YStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; + } else { + $YStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; + } + $Y = $this->GraphAreaY1 + $XMargin; + + if ( !is_array($PosArray) ) { + $Value = $PosArray; + $PosArray = ""; + $PosArray[0] = $Value; + } + $Sxy = 0; + $Sx = 0; + $Sy = 0; + $Sxx = 0; + foreach($PosArray as $Key => $X) { + if ( $X != VOID ) { + $Sxy = $Sxy + $X*$Y; + $Sx = $Sx + $Y; + $Sy = $Sy + $X; + $Sxx = $Sxx + $Y*$Y; + } + + $Y = $Y + $YStep; + } + $n = count($this->DataSet->stripVOID($PosArray)); //$n = count($PosArray); + $M = (($n*$Sxy)-($Sx*$Sy)) / (($n*$Sxx)-($Sx*$Sx)); + $B = (($Sy)-($M*$Sx))/($n); + + $Y1 = $this->GraphAreaY1 + $XMargin; + $X1 = $M * $Y1 + $B; + $Y2 = $this->GraphAreaY2 - $XMargin; + $X2 = $M * $Y2 + $B; + + if ( $X1 < $this->GraphAreaX1 ) { + $Y1 = $Y1 + ($this->GraphAreaX1-$X1); $X1 = $this->GraphAreaX1; + } + if ( $X1 > $this->GraphAreaX2 ) { + $Y1 = $Y1 + ($X1-$this->GraphAreaX2); $X1 = $this->GraphAreaX2; + } + if ( $X2 < $this->GraphAreaX1 ) { + $Y2 = $Y2 - ($this->GraphAreaY1-$X2); $X2 = $this->GraphAreaX1; + } + if ( $X2 > $this->GraphAreaX2 ) { + $Y2 = $Y2 - ($X2-$this->GraphAreaX2); $X2 = $this->GraphAreaX2; + } + + $this->drawLine($X1,$Y1,$X2,$Y2,$Color); + } + } + } + } + + /** + * Write labels + * @param type $SeriesName + * @param type $Indexes + * @param type $Format + */ + public function writeLabel($SeriesName,$Indexes,$Format="") + { + $OverrideTitle = isset($Format["OverrideTitle"]) ? $Format["OverrideTitle"] : null; + $ForceLabels = isset($Format["ForceLabels"]) ? $Format["ForceLabels"] : null; + $DrawPoint = isset($Format["DrawPoint"]) ? $Format["DrawPoint"] : LABEL_POINT_BOX; + $DrawVerticalLine = isset($Format["DrawVerticalLine"]) ? $Format["DrawVerticalLine"] : false; + $VerticalLineR = isset($Format["VerticalLineR"]) ? $Format["VerticalLineR"] : 0; + $VerticalLineG = isset($Format["VerticalLineG"]) ? $Format["VerticalLineG"] : 0; + $VerticalLineB = isset($Format["VerticalLineB"]) ? $Format["VerticalLineB"] : 0; + $VerticalLineAlpha = isset($Format["VerticalLineAlpha"]) ? $Format["VerticalLineAlpha"] : 40; + $VerticalLineTicks = isset($Format["VerticalLineTicks"]) ? $Format["VerticalLineTicks"] : 2; + + $Data = $this->DataSet->getData(); + list($XMargin,$XDivs) = $this->scaleGetXSettings(); + + if ( !is_array($Indexes) ) { $Index = $Indexes; $Indexes = ""; $Indexes[] = $Index; } + if ( !is_array($SeriesName) ) { $SerieName = $SeriesName; $SeriesName = ""; $SeriesName[] = $SerieName; } + if ( $ForceLabels != null && !is_array($ForceLabels) ) { $ForceLabel = $ForceLabels; $ForceLabels = ""; $ForceLabels[] = $ForceLabel; } + + foreach ($Indexes as $Key => $Index) { + $Series = ""; + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) { + if ( $XDivs == 0 ) { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1)/4; + } else { + $XStep = ($this->GraphAreaX2-$this->GraphAreaX1-$XMargin*2)/$XDivs; + } + $X = $this->GraphAreaX1 + $XMargin + $Index * $XStep; + + if ( $DrawVerticalLine ) { + $this->drawLine( + $X, + $this->GraphAreaY1+$Data["YMargin"], + $X, + $this->GraphAreaY2-$Data["YMargin"], + array( + "R"=>$VerticalLineR, + "G"=>$VerticalLineG, + "B"=>$VerticalLineB, + "Alpha"=>$VerticalLineAlpha, + "Ticks"=>$VerticalLineTicks + ) + ); + } + + $MinY = $this->GraphAreaY2; + foreach ($SeriesName as $iKey => $SerieName) { + if ( isset($Data["Series"][$SerieName]["Data"][$Index]) ) { + $AxisID = $Data["Series"][$SerieName]["Axis"]; + $XAxisMode = $Data["XAxisDisplay"]; + $XAxisFormat = $Data["XAxisFormat"]; + $XAxisUnit = $Data["XAxisUnit"]; + $AxisMode = $Data["Axis"][$AxisID]["Display"]; + $AxisFormat = $Data["Axis"][$AxisID]["Format"]; + $AxisUnit = $Data["Axis"][$AxisID]["Unit"]; + + if (isset($Data["Abscissa"]) + && isset($Data["Series"][$Data["Abscissa"]]["Data"][$Index]) + ) { + $XLabel = $this->scaleFormat( + $Data["Series"][$Data["Abscissa"]]["Data"][$Index], + $XAxisMode, + $XAxisFormat, + $XAxisUnit + ); + } else { + $XLabel = ""; + } + if ( $OverrideTitle != null) { + $Description = $OverrideTitle; + } elseif ( count($SeriesName) == 1 ) { + $Description = $Data["Series"][$SerieName]["Description"]." - ".$XLabel; + } elseif (isset($Data["Abscissa"]) + && isset($Data["Series"][$Data["Abscissa"]]["Data"][$Index]) + ) { + $Description = $XLabel; + } + $Serie = ""; + $Serie["R"] = $Data["Series"][$SerieName]["Color"]["R"]; + $Serie["G"] = $Data["Series"][$SerieName]["Color"]["G"]; + $Serie["B"] = $Data["Series"][$SerieName]["Color"]["B"]; + $Serie["Alpha"] = $Data["Series"][$SerieName]["Color"]["Alpha"]; + + if (count($SeriesName) == 1 + && isset($Data["Series"][$SerieName]["XOffset"]) + ) { + $SerieOffset = $Data["Series"][$SerieName]["XOffset"]; + } else { + $SerieOffset = 0; + } + $Value = $Data["Series"][$SerieName]["Data"][$Index]; + if ( $Value == VOID ) { + $Value = "NaN"; + } + + if ( $ForceLabels != null ) { + $Caption = isset($ForceLabels[$Key]) ? $ForceLabels[$Key] : "Not set"; + } else { + $Caption = $this->scaleFormat($Value,$AxisMode,$AxisFormat,$AxisUnit); + } + + if ( $this->LastChartLayout == CHART_LAST_LAYOUT_STACKED ) { + if ( $Value >=0 ) { + $LookFor = "+"; + } else { + $LookFor = "-"; + } + + $Value = 0; + $Done = false; + foreach($Data["Series"] as $Name => $SerieLookup) { + if ( $SerieLookup["isDrawable"] == true + && $Name != $Data["Abscissa"] + && !$Done + ) { + if (isset($Data["Series"][$Name]["Data"][$Index]) + && $Data["Series"][$Name]["Data"][$Index] != VOID + ) { + if ($Data["Series"][$Name]["Data"][$Index] >= 0 && $LookFor == "+" ) { + $Value = $Value + $Data["Series"][$Name]["Data"][$Index]; + } + if ($Data["Series"][$Name]["Data"][$Index] < 0 && $LookFor == "-" ) { + $Value = $Value - $Data["Series"][$Name]["Data"][$Index]; + } + if ($Name == $SerieName ) { + $Done = true; + } + } + } + } + } + + $X = floor($this->GraphAreaX1 + $XMargin + $Index * $XStep + $SerieOffset); + $Y = floor($this->scaleComputeY($Value,array("AxisID"=>$AxisID))); + + if ($Y < $MinY) { $MinY = $Y; } + + if ( $DrawPoint == LABEL_POINT_CIRCLE ) { + $this->drawFilledCircle( + $X, + $Y, + 3, + array( + "R"=>255, + "G"=>255, + "B"=>255, + "BorderR"=>0, + "BorderG"=>0, + "BorderB"=>0 + ) + ); + } elseif ( $DrawPoint == LABEL_POINT_BOX ) { + $this->drawFilledRectangle( + $X-2, + $Y-2, + $X+2, + $Y+2, + array( + "R"=>255, + "G"=>255, + "B"=>255, + "BorderR"=>0, + "BorderG"=>0, + "BorderB"=>0 + ) + ); + } + $Series[] = array("Format"=>$Serie,"Caption"=>$Caption); + } + } + $this->drawLabelBox($X,$MinY-3,$Description,$Series,$Format); + } else { + if ( $XDivs == 0 ) { + $XStep = ($this->GraphAreaY2-$this->GraphAreaY1)/4; + } else { + $XStep = ($this->GraphAreaY2-$this->GraphAreaY1-$XMargin*2)/$XDivs; + } + $Y = $this->GraphAreaY1 + $XMargin + $Index * $XStep; + + if ( $DrawVerticalLine ) { + $this->drawLine( + $this->GraphAreaX1+$Data["YMargin"], + $Y, + $this->GraphAreaX2-$Data["YMargin"], + $Y, + array( + "R"=>$VerticalLineR, + "G"=>$VerticalLineG, + "B"=>$VerticalLineB, + "Alpha"=>$VerticalLineAlpha, + "Ticks"=>$VerticalLineTicks + ) + ); + } + + $MinX = $this->GraphAreaX2; + foreach ($SeriesName as $Key => $SerieName) { + if (isset($Data["Series"][$SerieName]["Data"][$Index])) { + $AxisID = $Data["Series"][$SerieName]["Axis"]; + $XAxisMode = $Data["XAxisDisplay"]; + $XAxisFormat = $Data["XAxisFormat"]; + $XAxisUnit = $Data["XAxisUnit"]; + $AxisMode = $Data["Axis"][$AxisID]["Display"]; + $AxisFormat = $Data["Axis"][$AxisID]["Format"]; + $AxisUnit = $Data["Axis"][$AxisID]["Unit"]; + + if (isset($Data["Abscissa"]) + && isset($Data["Series"][$Data["Abscissa"]]["Data"][$Index]) + ) { + $XLabel = $this->scaleFormat( + $Data["Series"][$Data["Abscissa"]]["Data"][$Index], + $XAxisMode, + $XAxisFormat, + $XAxisUnit + ); + } else { + $XLabel = ""; + } + if ( $OverrideTitle != null) { + $Description = $OverrideTitle; + } elseif (count($SeriesName) == 1 ) { + if (isset($Data["Abscissa"]) + && isset($Data["Series"][$Data["Abscissa"]]["Data"][$Index]) + ) { + $Description = $Data["Series"][$SerieName]["Description"]." - ".$XLabel; + } + } elseif (isset($Data["Abscissa"]) + && isset($Data["Series"][$Data["Abscissa"]]["Data"][$Index]) + ) { + $Description = $XLabel; + } + $Serie = ""; + if ( isset($Data["Extended"]["Palette"][$Index] ) ) { + $Serie["R"] = $Data["Extended"]["Palette"][$Index]["R"]; + $Serie["G"] = $Data["Extended"]["Palette"][$Index]["G"]; + $Serie["B"] = $Data["Extended"]["Palette"][$Index]["B"]; + $Serie["Alpha"] = $Data["Extended"]["Palette"][$Index]["Alpha"]; + } else { + $Serie["R"] = $Data["Series"][$SerieName]["Color"]["R"]; + $Serie["G"] = $Data["Series"][$SerieName]["Color"]["G"]; + $Serie["B"] = $Data["Series"][$SerieName]["Color"]["B"]; + $Serie["Alpha"] = $Data["Series"][$SerieName]["Color"]["Alpha"]; + } + + if (count($SeriesName) == 1 + && isset($Data["Series"][$SerieName]["XOffset"])) { + $SerieOffset = $Data["Series"][$SerieName]["XOffset"]; + } else { + $SerieOffset = 0; + } + + $Value = $Data["Series"][$SerieName]["Data"][$Index]; + if ( $ForceLabels != null ) { + $Caption = isset($ForceLabels[$Key]) ? $ForceLabels[$Key] : "Not set"; + } else { + $Caption = $this->scaleFormat($Value,$AxisMode,$AxisFormat,$AxisUnit); + } + if ( $Value == VOID ) { + $Value = "NaN"; + } + + if ( $this->LastChartLayout == CHART_LAST_LAYOUT_STACKED ) { + if ( $Value >=0 ) { + $LookFor = "+"; + } else { + $LookFor = "-"; + } + + $Value = 0; + $Done = false; + foreach($Data["Series"] as $Name => $SerieLookup) { + if ( $SerieLookup["isDrawable"] == true && $Name != $Data["Abscissa"] && !$Done ) { + if (isset($Data["Series"][$Name]["Data"][$Index]) + && $Data["Series"][$Name]["Data"][$Index] != VOID + ) { + if ($Data["Series"][$Name]["Data"][$Index] >= 0 && $LookFor == "+" ) { + $Value = $Value + $Data["Series"][$Name]["Data"][$Index]; + } + if ($Data["Series"][$Name]["Data"][$Index] < 0 && $LookFor == "-" ) { + $Value = $Value - $Data["Series"][$Name]["Data"][$Index]; + } + if ($Name == $SerieName ) { + $Done = true; + } + } + } + } + } + + $X = floor($this->scaleComputeY($Value,array("AxisID"=>$AxisID))); + $Y = floor($this->GraphAreaY1 + $XMargin + $Index * $XStep + $SerieOffset); + + if ($X < $MinX) { + $MinX = $X; + } + + if ( $DrawPoint == LABEL_POINT_CIRCLE ) { + $this->drawFilledCircle( + $X, + $Y, + 3, + array( + "R"=>255, + "G"=>255, + "B"=>255, + "BorderR"=>0, + "BorderG"=>0, + "BorderB"=>0 + ) + ); + } elseif ( $DrawPoint == LABEL_POINT_BOX ) { + $this->drawFilledRectangle( + $X-2, + $Y-2, + $X+2, + $Y+2, + array( + "R"=>255, + "G"=>255, + "B"=>255, + "BorderR"=>0, + "BorderG"=>0, + "BorderB"=>0 + ) + ); + } + $Series[] = array("Format"=>$Serie,"Caption"=>$Caption); + } + } + $this->drawLabelBox($MinX,$Y-3,$Description,$Series,$Format); + } + } + } + + /** + * Draw a label box + * @param type $X + * @param type $Y + * @param type $Title + * @param type $Captions + * @param type $Format + */ + public function drawLabelBox($X,$Y,$Title,$Captions,$Format="") + { + $NoTitle = isset($Format["NoTitle"]) ? $Format["NoTitle"] : null; + $BoxWidth = isset($Format["BoxWidth"]) ? $Format["BoxWidth"] : 50; + $DrawSerieColor = isset($Format["DrawSerieColor"]) ? $Format["DrawSerieColor"] : true; + $SerieR = isset($Format["SerieR"]) ? $Format["SerieR"] : null; + $SerieG = isset($Format["SerieG"]) ? $Format["SerieG"] : null; + $SerieB = isset($Format["SerieB"]) ? $Format["SerieB"] : null; + $SerieAlpha = isset($Format["SerieAlpha"]) ? $Format["SerieAlpha"] : null; + $SerieBoxSize = isset($Format["SerieBoxSize"]) ? $Format["SerieBoxSize"] : 6; + $SerieBoxSpacing = isset($Format["SerieBoxSpacing"]) ? $Format["SerieBoxSpacing"] : 4; + $VerticalMargin = isset($Format["VerticalMargin"]) ? $Format["VerticalMargin"] : 10; + $HorizontalMargin = isset($Format["HorizontalMargin"]) ? $Format["HorizontalMargin"] : 8; + $R = isset($Format["R"]) ? $Format["R"] : $this->FontColorR; + $G = isset($Format["G"]) ? $Format["G"] : $this->FontColorG; + $B = isset($Format["B"]) ? $Format["B"] : $this->FontColorB; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : $this->FontColorA; + $FontName = isset($Format["FontName"]) + ? $this->loadFont($Format["FontName"], 'fonts') + : $this->FontName; + $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->FontSize; + $TitleMode = isset($Format["TitleMode"]) ? $Format["TitleMode"] : LABEL_TITLE_NOBACKGROUND; + $TitleR = isset($Format["TitleR"]) ? $Format["TitleR"] : $R; + $TitleG = isset($Format["TitleG"]) ? $Format["TitleG"] : $G; + $TitleB = isset($Format["TitleB"]) ? $Format["TitleB"] : $B; + $TitleAlpha = isset($Format["TitleAlpha"]) ? $Format["TitleAlpha"] : 100; + $TitleBackgroundR = isset($Format["TitleBackgroundR"]) ? $Format["TitleBackgroundR"] : 0; + $TitleBackgroundG = isset($Format["TitleBackgroundG"]) ? $Format["TitleBackgroundG"] : 0; + $TitleBackgroundB = isset($Format["TitleBackgroundB"]) ? $Format["TitleBackgroundB"] : 0; + $TitleBackgroundAlpha = isset($Format["TitleBackgroundAlpha"]) ? $Format["TitleBackgroundAlpha"] : 100; + $GradientStartR = isset($Format["GradientStartR"]) ? $Format["GradientStartR"] : 255; + $GradientStartG = isset($Format["GradientStartG"]) ? $Format["GradientStartG"] : 255; + $GradientStartB = isset($Format["GradientStartB"]) ? $Format["GradientStartB"] : 255; + $GradientEndR = isset($Format["GradientEndR"]) ? $Format["GradientEndR"] : 220; + $GradientEndG = isset($Format["GradientEndG"]) ? $Format["GradientEndG"] : 220; + $GradientEndB = isset($Format["GradientEndB"]) ? $Format["GradientEndB"] : 220; + $BoxAlpha = isset($Format["BoxAlpha"]) ? $Format["BoxAlpha"] : 100; + + if ( !$DrawSerieColor ) { + $SerieBoxSize = 0; + $SerieBoxSpacing = 0; + } + + $TxtPos = $this->getTextBox($X,$Y,$FontName,$FontSize,0,$Title); + $TitleWidth = ($TxtPos[1]["X"] - $TxtPos[0]["X"])+$VerticalMargin*2; + $TitleHeight = ($TxtPos[0]["Y"] - $TxtPos[2]["Y"]); + + if ( $NoTitle ) { + $TitleWidth = 0; + $TitleHeight = 0; + } + + $CaptionWidth = 0; + $CaptionHeight = -$HorizontalMargin; + foreach($Captions as $Key =>$Caption) { + $TxtPos = $this->getTextBox( + $X, + $Y, + $FontName, + $FontSize, + 0, + $Caption["Caption"] + ); + $CaptionWidth = max( + $CaptionWidth, + ($TxtPos[1]["X"] - $TxtPos[0]["X"])+$VerticalMargin*2 + ); + $CaptionHeight = $CaptionHeight + + max( + ($TxtPos[0]["Y"] - $TxtPos[2]["Y"]), + ($SerieBoxSize+2) + ) + + $HorizontalMargin; + } + + if ( $CaptionHeight <= 5 ) { + $CaptionHeight = $CaptionHeight + $HorizontalMargin/2; + } + + if ( $DrawSerieColor ) { + $CaptionWidth = $CaptionWidth + $SerieBoxSize + $SerieBoxSpacing; + } + + $BoxWidth = max($BoxWidth,$TitleWidth,$CaptionWidth); + + $XMin = $X - 5 - floor(($BoxWidth-10) / 2); + $XMax = $X + 5 + floor(($BoxWidth-10) / 2); + + $RestoreShadow = $this->Shadow; + if ( $this->Shadow == true ) { + $this->Shadow = false; + + $Poly = ""; + $Poly[] = $X+$this->ShadowX; + $Poly[] = $Y+$this->ShadowX; + $Poly[] = $X+5+$this->ShadowX; + $Poly[] = $Y-5+$this->ShadowX; + $Poly[] = $XMax+$this->ShadowX; + $Poly[] = $Y-5+$this->ShadowX; + + if ( $NoTitle ) { + $Poly[] = $XMax+$this->ShadowX; + $Poly[] = $Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*2+$this->ShadowX; + $Poly[] = $XMin+$this->ShadowX; + $Poly[] = $Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*2+$this->ShadowX; + } else { + $Poly[] = $XMax+$this->ShadowX; + $Poly[] = $Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*3+$this->ShadowX; + $Poly[] = $XMin+$this->ShadowX; + $Poly[] = $Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*3+$this->ShadowX; + } + + $Poly[] = $XMin+$this->ShadowX; + $Poly[] = $Y-5+$this->ShadowX; + $Poly[] = $X-5+$this->ShadowX; + $Poly[] = $Y-5+$this->ShadowX; + $this->drawPolygon( + $Poly, + array( + "R"=>$this->ShadowR, + "G"=>$this->ShadowG, + "B"=>$this->ShadowB, + "Alpha"=>$this->Shadowa + ) + ); + } + + /* Draw the background */ + $GradientSettings = array( + "StartR"=>$GradientStartR, + "StartG"=>$GradientStartG, + "StartB"=>$GradientStartB, + "EndR"=>$GradientEndR, + "EndG"=>$GradientEndG, + "EndB"=>$GradientEndB, + "Alpha"=>$BoxAlpha + ); + if ( $NoTitle ) { + $this->drawGradientArea( + $XMin, + $Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*2, + $XMax, + $Y-6, + DIRECTION_VERTICAL, + $GradientSettings + ); + } else { + $this->drawGradientArea( + $XMin, + $Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*3, + $XMax, + $Y-6, + DIRECTION_VERTICAL, + $GradientSettings + ); + } + $Poly = ""; + $Poly[] = $X; + $Poly[] = $Y; + $Poly[] = $X-5; + $Poly[] = $Y-5; + $Poly[] = $X+5; + $Poly[] = $Y-5; + $this->drawPolygon( + $Poly, + array( + "R"=>$GradientEndR, + "G"=>$GradientEndG, + "B"=>$GradientEndB, + "Alpha"=>$BoxAlpha, + "NoBorder"=>true + ) + ); + + /* Outer border */ + $OuterBorderColor = $this->allocateColor($this->Picture,100,100,100,$BoxAlpha); + imageline($this->Picture,$XMin,$Y-5,$X-5,$Y-5,$OuterBorderColor); + imageline($this->Picture,$X,$Y,$X-5,$Y-5,$OuterBorderColor); + imageline($this->Picture,$X,$Y,$X+5,$Y-5,$OuterBorderColor); + imageline($this->Picture,$X+5,$Y-5,$XMax,$Y-5,$OuterBorderColor); + if ( $NoTitle ) { + imageline($this->Picture,$XMin,$Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*2,$XMin,$Y-5,$OuterBorderColor); + imageline($this->Picture,$XMax,$Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*2,$XMax,$Y-5,$OuterBorderColor); + imageline($this->Picture,$XMin,$Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*2,$XMax,$Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*2,$OuterBorderColor); + } else { + imageline($this->Picture,$XMin,$Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*3,$XMin,$Y-5,$OuterBorderColor); + imageline($this->Picture,$XMax,$Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*3,$XMax,$Y-5,$OuterBorderColor); + imageline($this->Picture,$XMin,$Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*3,$XMax,$Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*3,$OuterBorderColor); + } + + /* Inner border */ + $InnerBorderColor = $this->allocateColor($this->Picture,255,255,255,$BoxAlpha); + imageline($this->Picture,$XMin+1,$Y-6,$X-5,$Y-6,$InnerBorderColor); + imageline($this->Picture,$X,$Y-1,$X-5,$Y-6,$InnerBorderColor); + imageline($this->Picture,$X,$Y-1,$X+5,$Y-6,$InnerBorderColor); + imageline($this->Picture,$X+5,$Y-6,$XMax-1,$Y-6,$InnerBorderColor); + if ( $NoTitle ) { + imageline($this->Picture,$XMin+1,$Y-4-$TitleHeight-$CaptionHeight-$HorizontalMargin*2,$XMin+1,$Y-6,$InnerBorderColor); + imageline($this->Picture,$XMax-1,$Y-4-$TitleHeight-$CaptionHeight-$HorizontalMargin*2,$XMax-1,$Y-6,$InnerBorderColor); + imageline($this->Picture,$XMin+1,$Y-4-$TitleHeight-$CaptionHeight-$HorizontalMargin*2,$XMax-1,$Y-4-$TitleHeight-$CaptionHeight-$HorizontalMargin*2,$InnerBorderColor); + } else { + imageline($this->Picture,$XMin+1,$Y-4-$TitleHeight-$CaptionHeight-$HorizontalMargin*3,$XMin+1,$Y-6,$InnerBorderColor); + imageline($this->Picture,$XMax-1,$Y-4-$TitleHeight-$CaptionHeight-$HorizontalMargin*3,$XMax-1,$Y-6,$InnerBorderColor); + imageline($this->Picture,$XMin+1,$Y-4-$TitleHeight-$CaptionHeight-$HorizontalMargin*3,$XMax-1,$Y-4-$TitleHeight-$CaptionHeight-$HorizontalMargin*3,$InnerBorderColor); + } + + /* Draw the separator line */ + if ( $TitleMode == LABEL_TITLE_NOBACKGROUND && !$NoTitle ) { + $YPos = $Y-7-$CaptionHeight-$HorizontalMargin-$HorizontalMargin/2; + $XMargin = $VerticalMargin / 2; + $this->drawLine( + $XMin+$XMargin, + $YPos+1, + $XMax-$XMargin, + $YPos+1, + array( + "R"=>$GradientEndR, + "G"=>$GradientEndG, + "B"=>$GradientEndB, + "Alpha"=>$BoxAlpha + ) + ); + $this->drawLine( + $XMin+$XMargin, + $YPos, + $XMax-$XMargin, + $YPos, + array( + "R"=>$GradientStartR, + "G"=>$GradientStartG, + "B"=>$GradientStartB, + "Alpha"=>$BoxAlpha + ) + ); + } elseif ( $TitleMode == LABEL_TITLE_BACKGROUND ) { + $this->drawFilledRectangle( + $XMin, + $Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin*3, + $XMax, + $Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin+$HorizontalMargin/2, + array( + "R"=>$TitleBackgroundR, + "G"=>$TitleBackgroundG, + "B"=>$TitleBackgroundB, + "Alpha"=>$BoxAlpha + ) + ); + imageline( + $this->Picture, + $XMin+1, + $Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin+$HorizontalMargin/2+1, + $XMax-1, + $Y-5-$TitleHeight-$CaptionHeight-$HorizontalMargin+$HorizontalMargin/2+1, + $InnerBorderColor + ); + } + + /* Write the description */ + if ( !$NoTitle ) + $this->drawText( + $XMin+$VerticalMargin, + $Y-7-$CaptionHeight-$HorizontalMargin*2, + $Title, + array( + "Align"=>TEXT_ALIGN_BOTTOMLEFT, + "R"=>$TitleR, + "G"=>$TitleG, + "B"=>$TitleB + ) + ); + + /* Write the value */ + $YPos = $Y-5-$HorizontalMargin; + $XPos = $XMin+$VerticalMargin+$SerieBoxSize+$SerieBoxSpacing; + foreach($Captions as $Key => $Caption) { + $CaptionTxt = $Caption["Caption"]; + $TxtPos = $this->getTextBox($XPos,$YPos,$FontName,$FontSize,0,$CaptionTxt); + $CaptionHeight = ($TxtPos[0]["Y"] - $TxtPos[2]["Y"]); + + /* Write the serie color if needed */ + if ( $DrawSerieColor ) { + $BoxSettings = array( + "R"=>$Caption["Format"]["R"], + "G"=>$Caption["Format"]["G"], + "B"=>$Caption["Format"]["B"], + "Alpha"=>$Caption["Format"]["Alpha"], + "BorderR"=>0, + "BorderG"=>0, + "BorderB"=>0 + ); + $this->drawFilledRectangle( + $XMin+$VerticalMargin, + $YPos-$SerieBoxSize, + $XMin+$VerticalMargin+$SerieBoxSize, + $YPos, + $BoxSettings + ); + } + + $this->drawText($XPos,$YPos,$CaptionTxt,array("Align"=>TEXT_ALIGN_BOTTOMLEFT)); + + $YPos = $YPos - $CaptionHeight - $HorizontalMargin; + } + + $this->Shadow = $RestoreShadow; + } + + /** + * Draw a basic shape + * @param type $X + * @param type $Y + * @param type $Shape + * @param type $PlotSize + * @param type $PlotBorder + * @param type $BorderSize + * @param type $R + * @param type $G + * @param type $B + * @param type $Alpha + * @param type $BorderR + * @param type $BorderG + * @param type $BorderB + * @param type $BorderAlpha + */ + public function drawShape( + $X, + $Y, + $Shape, + $PlotSize, + $PlotBorder, + $BorderSize, + $R, + $G, + $B, + $Alpha, + $BorderR, + $BorderG, + $BorderB, + $BorderAlpha + ) { + if ( $Shape == SERIE_SHAPE_FILLEDCIRCLE ) { + if ( $PlotBorder ) { $this->drawFilledCircle($X,$Y,$PlotSize+$BorderSize,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha)); } + $this->drawFilledCircle($X,$Y,$PlotSize,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + } elseif ( $Shape == SERIE_SHAPE_FILLEDSQUARE ) { + if ( $PlotBorder ) { $this->drawFilledRectangle($X-$PlotSize-$BorderSize,$Y-$PlotSize-$BorderSize,$X+$PlotSize+$BorderSize,$Y+$PlotSize+$BorderSize,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha)); } + $this->drawFilledRectangle($X-$PlotSize,$Y-$PlotSize,$X+$PlotSize,$Y+$PlotSize,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + } elseif ( $Shape == SERIE_SHAPE_FILLEDTRIANGLE ) { + if ( $PlotBorder ) { + $Pos = ""; $Pos[]=$X; $Pos[]=$Y-$PlotSize-$BorderSize; $Pos[]=$X-$PlotSize-$BorderSize; $Pos[]=$Y+$PlotSize+$BorderSize; $Pos[]=$X+$PlotSize+$BorderSize; $Pos[]=$Y+$PlotSize+$BorderSize; + $this->drawPolygon($Pos,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha)); + } + + $Pos = ""; $Pos[]=$X; $Pos[]=$Y-$PlotSize; $Pos[]=$X-$PlotSize; $Pos[]=$Y+$PlotSize; $Pos[]=$X+$PlotSize; $Pos[]=$Y+$PlotSize; + $this->drawPolygon($Pos,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + } elseif ( $Shape == SERIE_SHAPE_TRIANGLE ) { + $this->drawLine($X,$Y-$PlotSize,$X-$PlotSize,$Y+$PlotSize,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + $this->drawLine($X-$PlotSize,$Y+$PlotSize,$X+$PlotSize,$Y+$PlotSize,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + $this->drawLine($X+$PlotSize,$Y+$PlotSize,$X,$Y-$PlotSize,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + } elseif ( $Shape == SERIE_SHAPE_SQUARE ) { + $this->drawRectangle($X-$PlotSize,$Y-$PlotSize,$X+$PlotSize,$Y+$PlotSize,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + } elseif ( $Shape == SERIE_SHAPE_CIRCLE ) { + $this->drawCircle($X,$Y,$PlotSize,$PlotSize,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + } elseif ( $Shape == SERIE_SHAPE_DIAMOND ) { + $Pos = ""; $Pos[]=$X-$PlotSize; $Pos[]=$Y; $Pos[]=$X; $Pos[]=$Y-$PlotSize; $Pos[]=$X+$PlotSize; $Pos[]=$Y; $Pos[]=$X; $Pos[]=$Y+$PlotSize; + $this->drawPolygon($Pos,array("NoFill"=>true,"BorderR"=>$R,"BorderG"=>$G,"BorderB"=>$B,"BorderAlpha"=>$Alpha)); + } elseif ( $Shape == SERIE_SHAPE_FILLEDDIAMOND ) { + if ( $PlotBorder ) { + $Pos = ""; $Pos[]=$X-$PlotSize-$BorderSize; $Pos[]=$Y; $Pos[]=$X; $Pos[]=$Y-$PlotSize-$BorderSize; $Pos[]=$X+$PlotSize+$BorderSize; $Pos[]=$Y; $Pos[]=$X; $Pos[]=$Y+$PlotSize+$BorderSize; + $this->drawPolygon($Pos,array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha)); + } + + $Pos = ""; $Pos[]=$X-$PlotSize; $Pos[]=$Y; $Pos[]=$X; $Pos[]=$Y-$PlotSize; $Pos[]=$X+$PlotSize; $Pos[]=$Y; $Pos[]=$X; $Pos[]=$Y+$PlotSize; + $this->drawPolygon($Pos,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha)); + } + } + + /** + * + * @param type $Points + * @param type $Format + * @return type + */ + public function drawPolygonChart($Points,$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; + $NoFill = isset($Format["NoFill"]) ? $Format["NoFill"] : false; + $NoBorder = isset($Format["NoBorder"]) ? $Format["NoBorder"] : false; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $R; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $G; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $B; + $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : $Alpha / 2; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : null; + $Threshold = isset($Format["Threshold"]) ? $Format["Threshold"] : null; + + if ( $Surrounding != null ) { + $BorderR = $R+$Surrounding; + $BorderG = $G+$Surrounding; + $BorderB = $B+$Surrounding; + } + + $RestoreShadow = $this->Shadow; + $this->Shadow = false; + + $AllIntegers = true; + for($i=0;$i<=count($Points)-2;$i=$i+2) { + if ( $this->getFirstDecimal($Points[$i+1]) != 0 ) { + $AllIntegers = false; + } + } + + /* Convert polygon to segments */ + $Segments = ""; + for ($i=2;$i<=count($Points)-2;$i=$i+2) { + $Segments[] = array( + "X1"=>$Points[$i-2], + "Y1"=>$Points[$i-1], + "X2"=>$Points[$i], + "Y2"=>$Points[$i+1] + ); + } + $Segments[] = array( + "X1"=>$Points[$i-2], + "Y1"=>$Points[$i-1], + "X2"=>$Points[0], + "Y2"=>$Points[1] + ); + + /* Simplify straight lines */ + $Result = ""; + $inHorizon = false; + $LastX = VOID; + foreach($Segments as $Key => $Pos) { + if ( $Pos["Y1"] != $Pos["Y2"] ) { + if ( $inHorizon ) { + $inHorizon = false; + $Result[] = array( + "X1"=>$LastX, + "Y1"=>$Pos["Y1"], + "X2"=>$Pos["X1"], + "Y2"=>$Pos["Y1"] + ); + } + + $Result[] = array( + "X1"=>$Pos["X1"], + "Y1"=>$Pos["Y1"], + "X2"=>$Pos["X2"], + "Y2"=>$Pos["Y2"] + ); + } else { + if ( !$inHorizon ) { + $inHorizon = true; + $LastX = $Pos["X1"]; + } + } + } + $Segments = $Result; + + /* Do we have something to draw */ + if ( $Segments == "" ) { + return(0); + } + + /* For segments debugging purpose */ + //foreach($Segments as $Key => $Pos) + // echo $Pos["X1"].",".$Pos["Y1"].",".$Pos["X2"].",".$Pos["Y2"]."\r\n"; + + /* Find out the min & max Y boundaries */ + $MinY = OUT_OF_SIGHT; $MaxY = OUT_OF_SIGHT; + foreach($Segments as $Key => $Coords) { + if ($MinY == OUT_OF_SIGHT || $MinY > min($Coords["Y1"],$Coords["Y2"])) { + $MinY = min($Coords["Y1"],$Coords["Y2"]); + } + if ($MaxY == OUT_OF_SIGHT || $MaxY < max($Coords["Y1"],$Coords["Y2"])) { + $MaxY = max($Coords["Y1"],$Coords["Y2"]); + } + } + + if ( $AllIntegers ) { + $YStep = 1; + } else { + $YStep = .5; + } + + $MinY = floor($MinY); + $MaxY = floor($MaxY); + + /* Scan each Y lines */ + $DefaultColor = $this->allocateColor($this->Picture,$R,$G,$B,$Alpha); + $DebugLine = 0; + $DebugColor = $this->allocateColor($this->Picture,255,0,0,100); + + $MinY = floor($MinY); + $MaxY = floor($MaxY); + $YStep = 1; + + if ( !$NoFill ) { + //if ( $DebugLine ) { $MinY = $DebugLine; $MaxY = $DebugLine; } + for ($Y=$MinY;$Y<=$MaxY;$Y=$Y+$YStep) { + $Intersections = ""; + $LastSlope = null; + $RestoreLast = "-"; + foreach($Segments as $Key => $Coords) { + $X1 = $Coords["X1"]; + $X2 = $Coords["X2"]; + $Y1 = $Coords["Y1"]; + $Y2 = $Coords["Y2"]; + + if (min($Y1,$Y2) <= $Y && max($Y1,$Y2) >= $Y) { + if ( $Y1 == $Y2 ) { + $X = $X1; + } else { + $X = $X1 + ( ($Y-$Y1)*$X2 - ($Y-$Y1)*$X1 ) / ($Y2-$Y1); + } + + $X = floor($X); + + if ( $X2 == $X1 ) { + $Slope = "!"; + } else { + $SlopeC = ($Y2 - $Y1) / ($X2 - $X1); + if( $SlopeC == 0 ) { + $Slope = "="; + } elseif( $SlopeC > 0 ) { + $Slope = "+"; + } elseif ( $SlopeC < 0 ) { + $Slope = "-"; + } + } + + if ( !is_array($Intersections) ) { + $Intersections[] = $X; + } elseif( !in_array($X,$Intersections) ) { + $Intersections[] = $X; + } elseif( in_array($X,$Intersections) ) { + if ($Y == $DebugLine) { + echo $Slope."/".$LastSlope."(".$X.") "; + } + + if ( $Slope == "=" && $LastSlope == "-" ) { + $Intersections[] = $X; + } + if ( $Slope != $LastSlope && $LastSlope != "!" && $LastSlope != "=" ) { + $Intersections[] = $X; + } + if ( $Slope != $LastSlope && $LastSlope == "!" && $Slope == "+" ) { + $Intersections[] = $X; + } + } + + if (is_array($Intersections) + && in_array($X,$Intersections) + && $LastSlope == "=" + && ($Slope == "-" ) + ) { + $Intersections[] = $X; + + } + + $LastSlope = $Slope; + } + } + if ( $RestoreLast != "-" ) { + $Intersections[] = $RestoreLast; + echo "@".$Y."\r\n"; + } + + if ( is_array($Intersections) ) { + sort($Intersections); + + if ($Y == $DebugLine) { + print_r($Intersections); + } + + /* Remove null plots */ + $Result = ""; + for($i=0;$i<=count($Intersections)-1;$i=$i+2) { + if (isset($Intersections[$i+1])) { + if ( $Intersections[$i] != $Intersections[$i+1] ) { + $Result[] = $Intersections[$i]; + $Result[] = $Intersections[$i+1]; + } + } + } + + if ( is_array($Result) ) { + $Intersections = $Result; + + $LastX = OUT_OF_SIGHT; + foreach($Intersections as $Key => $X) { + if ( $LastX == OUT_OF_SIGHT ) { + $LastX = $X; + } elseif ( $LastX != OUT_OF_SIGHT ) { + if ( $this->getFirstDecimal($LastX) > 1 ) { + $LastX++; + } + + $Color = $DefaultColor; + if ( $Threshold != null ) { + foreach($Threshold as $Key => $Parameters) { + if ($Y <= $Parameters["MinX"] + && $Y >= $Parameters["MaxX"] + ) { + if ( isset($Parameters["R"]) ) { + $R = $Parameters["R"]; + } else { + $R = 0; + } + if ( isset($Parameters["G"]) ) { + $G = $Parameters["G"]; + } else { + $G = 0; + } + if ( isset($Parameters["B"]) ) { + $B = $Parameters["B"]; + } else { + $B = 0; + } + if ( isset($Parameters["Alpha"]) ) { + $Alpha = $Parameters["Alpha"]; + } else { + $Alpha = 100; + } + $Color = $this->allocateColor( + $this->Picture,$R,$G,$B,$Alpha + ); + } + } + } + + imageline($this->Picture,$LastX,$Y,$X,$Y,$Color); + + if ( $Y == $DebugLine) { + imageline($this->Picture,$LastX,$Y,$X,$Y,$DebugColor); + } + + $LastX = OUT_OF_SIGHT; + } + } + } + } + } + } + + /* Draw the polygon border, if required */ + if ( !$NoBorder) { + foreach($Segments as $Key => $Coords) { + $this->drawLine( + $Coords["X1"], + $Coords["Y1"], + $Coords["X2"], + $Coords["Y2"], + array( + "R"=>$BorderR, + "G"=>$BorderG, + "B"=>$BorderB, + "Alpha"=>$BorderAlpha, + "Threshold"=>$Threshold + ) + ); + } + } + + $this->Shadow = $RestoreShadow; + } + + /** + * Return the abscissa margin + * @param type $Data + * @return type + */ + public function getAbscissaMargin($Data) + { + foreach($Data["Axis"] as $AxisID => $Values) { + if ( $Values["Identity"] == AXIS_X ) { + return($Values["Margin"]); + } + } + return(0); + } +} diff --git a/vendor/szymach/c-pchart/src/Classes/pImage.php b/vendor/szymach/c-pchart/src/Classes/pImage.php new file mode 100644 index 0000000000..84c4eeac79 --- /dev/null +++ b/vendor/szymach/c-pchart/src/Classes/pImage.php @@ -0,0 +1,764 @@ +FontName = $this->loadFont($this->FontName, 'fonts'); + + $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 + * @param type $Enabled + * @param type $Format + */ + public 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 + * @param type $X1 + * @param type $Y1 + * @param type $X2 + * @param type $Y2 + * @return type + */ + public 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 + * @return type + */ + public function getWidth() + { + return($this->XSize); + } + + /** + * Return the heigth of the picture + * @return type + */ + public function getHeight() + { + return($this->YSize); + } + + /** + * Render the picture to a file + * @param type $FileName + */ + public 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 + * @param type $BrowserExpire + */ + public 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 + * @param type $FileName + */ + public function autoOutput($FileName="output.png") + { + if (php_sapi_name() == "cli") { + $this->Render($FileName); + } else { + $this->Stroke(); + } + } + + /** + * Return the length between two points + * @param type $X1 + * @param type $Y1 + * @param type $X2 + * @param type $Y2 + * @return type + */ + public 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 + * @param type $X1 + * @param type $Y1 + * @param type $X2 + * @param type $Y2 + * @return type + */ + public 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 + * @param type $X + * @param type $Y + * @param type $FontName + * @param type $FontSize + * @param type $Angle + * @param type $Text + * @return type + */ + public function getTextBox_deprecated($X,$Y,$FontName,$FontSize,$Angle,$Text) + { + $FontName = $this->loadFont($FontName, 'fonts'); + $Size = imagettfbbox($FontSize,$Angle,$FontName,$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); + } + + /** + * Return the surrounding box of text area + * @param type $X + * @param type $Y + * @param type $FontName + * @param type $FontSize + * @param type $Angle + * @param type $Text + * @return type + */ + public function getTextBox($X,$Y,$FontName,$FontSize,$Angle,$Text) + { + $FontName = $this->loadFont($FontName, 'fonts'); + $coords = imagettfbbox($FontSize, 0, $FontName, $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 + * @param type $Format + */ + public 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 = $this->loadFont($FontName, 'fonts'); + } + if ($FontSize != null) { + $this->FontSize = $FontSize; + } + } + + /** + * Returns the 1st decimal values (used to correct AA bugs) + * @param type $Value + * @return type + */ + public 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 + * @param type $DataSet + */ + public function setDataSet(&$DataSet) + { $this->DataSet = $DataSet; } + + /** + * Print attached dataset contents to STDOUT + */ + public function printDataSet() + { print_r($this->DataSet); } + + /** + * Initialise the image map methods + * @param type $Name + * @param type $StorageMode + * @param type $UniqueID + * @param type $StorageFolder + */ + public 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 + * @param type $Type + * @param type $Plots + * @param type $Color + * @param type $Title + * @param type $Message + * @param type $HTMLEncode + */ + public 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("€","\u20AC",$Title); + $Title = htmlentities($Title,ENT_QUOTES,"ISO-8859-15"); + if ( $HTMLEncode ) { + $Message = htmlentities($Message,ENT_QUOTES,"ISO-8859-15"); + $Message = str_replace("<","<",$Message); + $Message = str_replace(">",">",$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 + * @param type $SerieName + * @param type $Values + * @return type + */ + public 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 + * @param type $OldTitle + * @param type $NewTitle + * @return type + */ + public 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 + * @param type $Title + * @param type $Values + * @return type + */ + public 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 + * @param type $Name + * @param type $StorageMode + * @param type $UniqueID + * @param type $StorageFolder + */ + public 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 + * @param type $R + * @param type $G + * @param type $B + * @return type + */ + public 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 + * @param type $Plots + * @return type + */ + public 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 + * @param type $X + * @param type $Y + * @param type $Width + * @param type $Height + * @param type $Format + */ + public 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); + } +} diff --git a/vendor/szymach/c-pchart/src/Classes/pIndicator.php b/vendor/szymach/c-pchart/src/Classes/pIndicator.php new file mode 100644 index 0000000000..dfd9912ac7 --- /dev/null +++ b/vendor/szymach/c-pchart/src/Classes/pIndicator.php @@ -0,0 +1,264 @@ +pChartObject = $pChartObject; + } + + /* Draw an indicator */ + public function draw($X,$Y,$Width,$Height,$Format="") + { + $Values = isset($Format["Values"]) ? $Format["Values"] : VOID; + $IndicatorSections = isset($Format["IndicatorSections"]) ? $Format["IndicatorSections"] : null; + $ValueDisplay = isset($Format["ValueDisplay"]) ? $Format["ValueDisplay"] : INDICATOR_VALUE_BUBBLE; + $SectionsMargin = isset($Format["SectionsMargin"]) ? $Format["SectionsMargin"] : 4; + $DrawLeftHead = isset($Format["DrawLeftHead"]) ? $Format["DrawLeftHead"] : true; + $DrawRightHead = isset($Format["DrawRightHead"]) ? $Format["DrawRightHead"] : true; + $HeadSize = isset($Format["HeadSize"]) ? $Format["HeadSize"] : floor($Height/4); + $TextPadding = isset($Format["TextPadding"]) ? $Format["TextPadding"] : 4; + $CaptionLayout = isset($Format["CaptionLayout"]) ? $Format["CaptionLayout"] : INDICATOR_CAPTION_EXTENDED; + $CaptionPosition = isset($Format["CaptionPosition"]) ? $Format["CaptionPosition"] : INDICATOR_CAPTION_INSIDE; + $CaptionColorFactor = isset($Format["CaptionColorFactor"]) ? $Format["CaptionColorFactor"] : null; + $CaptionR = isset($Format["CaptionR"]) ? $Format["CaptionR"] : 255; + $CaptionG = isset($Format["CaptionG"]) ? $Format["CaptionG"] : 255; + $CaptionB = isset($Format["CaptionB"]) ? $Format["CaptionB"] : 255; + $CaptionAlpha = isset($Format["CaptionAlpha"]) ? $Format["CaptionAlpha"] : 100; + $SubCaptionColorFactor = isset($Format["SubCaptionColorFactor"]) ? $Format["SubCaptionColorFactor"] : null; + $SubCaptionR = isset($Format["SubCaptionR"]) ? $Format["SubCaptionR"] : 50; + $SubCaptionG = isset($Format["SubCaptionG"]) ? $Format["SubCaptionG"] : 50; + $SubCaptionB = isset($Format["SubCaptionB"]) ? $Format["SubCaptionB"] : 50; + $SubCaptionAlpha = isset($Format["SubCaptionAlpha"]) ? $Format["SubCaptionAlpha"] : 100; + $ValueFontName = isset($Format["ValueFontName"]) ? $Format["ValueFontName"] : $this->pChartObject->FontName; + $ValueFontSize = isset($Format["ValueFontSize"]) ? $Format["ValueFontSize"] : $this->pChartObject->FontSize; + $CaptionFontName = isset($Format["CaptionFontName"]) ? $Format["CaptionFontName"] : $this->pChartObject->FontName; + $CaptionFontSize = isset($Format["CaptionFontSize"]) ? $Format["CaptionFontSize"] : $this->pChartObject->FontSize; + $Unit = isset($Format["Unit"]) ? $Format["Unit"] : ""; + + /* Convert the Values to display to an array if needed */ + if ( !is_array($Values) ) { + $Value = $Values; $Values = ""; + $Values[] = $Value; + } + + /* No section, let's die */ + if ( $IndicatorSections == null ) { + return(0); + } + + /* Determine indicator visual configuration */ + $OverallMin = $IndicatorSections[0]["End"]; $OverallMax = $IndicatorSections[0]["Start"]; + foreach ($IndicatorSections as $Key => $Settings) { + if ( $Settings["End"] > $OverallMax ) { $OverallMax = $Settings["End"]; } + if ( $Settings["Start"] < $OverallMin ) { $OverallMin = $Settings["Start"]; } + } + $RealWidth = $Width - (count($IndicatorSections)-1)*$SectionsMargin; + $XScale = $RealWidth / ($OverallMax-$OverallMin); + + $X1 = $X; $ValuesPos = ""; + foreach ($IndicatorSections as $Key => $Settings) { + $Color = array("R"=>$Settings["R"],"G"=>$Settings["G"],"B"=>$Settings["B"]); + $Caption = $Settings["Caption"]; + $SubCaption = $Settings["Start"]." - ".$Settings["End"]; + + $X2 = $X1 + ($Settings["End"] - $Settings["Start"]) * $XScale; + + if ( $Key == 0 && $DrawLeftHead ) { + $Poly = ""; + $Poly[] = $X1-1; + $Poly[] = $Y; + $Poly[] = $X1-1; + $Poly[] = $Y+$Height; + $Poly[] = $X1-1-$HeadSize; + $Poly[] = $Y+($Height/2); + $this->pChartObject->drawPolygon($Poly,$Color); + $this->pChartObject->drawLine($X1-2,$Y,$X1-2-$HeadSize,$Y+($Height/2),$Color); + $this->pChartObject->drawLine($X1-2,$Y+$Height,$X1-2-$HeadSize,$Y+($Height/2),$Color); + } + + /* Determine the position of the breaks */ + $Break = ""; + foreach($Values as $iKey => $Value) { + if ( $Value >= $Settings["Start"] && $Value <= $Settings["End"] ) { + $XBreak = $X1 + ($Value - $Settings["Start"]) * $XScale; + $ValuesPos[$Value] = $XBreak; + $Break[] = floor($XBreak); + } + } + + if ( $ValueDisplay == INDICATOR_VALUE_LABEL ) + { + if ( $Break == "" ) { + $this->pChartObject->drawFilledRectangle($X1,$Y,$X2,$Y+$Height,$Color); + } else { + sort($Break); + $Poly = ""; $Poly[] = $X1; $Poly[] = $Y; $LastPointWritten = false; + foreach($Break as $iKey => $Value) { + if ( $Value-5 >= $X1 ) { + $Poly[] = $Value-5; $Poly[] = $Y; + } elseif ($X1 - ($Value-5) > 0 ) { + $Offset = $X1 - ($Value-5); + $Poly = ""; $Poly[] = $X1; $Poly[] = $Y + $Offset; + } + + $Poly[] = $Value; $Poly[] = $Y+5; + + if ( $Value+5 <= $X2 ) { + $Poly[] = $Value+5; $Poly[] = $Y; + } elseif (($Value+5) > $X2 ) { + $Offset = ($Value+5) - $X2; + $Poly[] = $X2; $Poly[] = $Y + $Offset; + $LastPointWritten = true; + } + } + if ( !$LastPointWritten ) { + $Poly[] = $X2; $Poly[] = $Y; + } + $Poly[] = $X2; $Poly[] = $Y+$Height; + $Poly[] = $X1; $Poly[] = $Y+$Height; + + $this->pChartObject->drawPolygon($Poly,$Color); + } + } else { + $this->pChartObject->drawFilledRectangle($X1,$Y,$X2,$Y+$Height,$Color); + } + + if ( $Key == count($IndicatorSections)-1 && $DrawRightHead ) { + $Poly = ""; + $Poly[] = $X2+1; + $Poly[] = $Y; + $Poly[] = $X2+1; + $Poly[] = $Y+$Height; + $Poly[] = $X2+1+$HeadSize; + $Poly[] = $Y+($Height/2); + $this->pChartObject->drawPolygon($Poly,$Color); + $this->pChartObject->drawLine($X2+1,$Y,$X2+1+$HeadSize,$Y+($Height/2),$Color); + $this->pChartObject->drawLine($X2+1,$Y+$Height,$X2+1+$HeadSize,$Y+($Height/2),$Color); + } + + if ( $CaptionPosition == INDICATOR_CAPTION_INSIDE ) { + $TxtPos = $this->pChartObject->getTextBox($X1,$Y+$Height+$TextPadding,$CaptionFontName,$CaptionFontSize,0,$Caption); + $YOffset = ($TxtPos[0]["Y"] - $TxtPos[2]["Y"]) + $TextPadding; + + if ( $CaptionLayout == INDICATOR_CAPTION_EXTENDED ) { + $TxtPos = $this->pChartObject->getTextBox($X1,$Y+$Height+$TextPadding,$CaptionFontName,$CaptionFontSize,0,$SubCaption); + $YOffset = $YOffset + ($TxtPos[0]["Y"] - $TxtPos[2]["Y"]) + $TextPadding*2; + } + $XOffset = $TextPadding; + } else { + $YOffset = 0; + $XOffset = 0; + } + + if ( $CaptionColorFactor == null ) { + $CaptionColor = array( + "Align"=>TEXT_ALIGN_TOPLEFT, + "FontName"=>$CaptionFontName, + "FontSize"=>$CaptionFontSize, + "R"=>$CaptionR, + "G"=>$CaptionG, + "B"=>$CaptionB, + "Alpha"=>$CaptionAlpha + ); + } else { + $CaptionColor = array( + "Align"=>TEXT_ALIGN_TOPLEFT, + "FontName"=>$CaptionFontName, + "FontSize"=>$CaptionFontSize, + "R"=>$Settings["R"]+$CaptionColorFactor, + "G"=>$Settings["G"]+$CaptionColorFactor, + "B"=>$Settings["B"]+$CaptionColorFactor + ); + } + + if ( $SubCaptionColorFactor == null ) { + $SubCaptionColor = array( + "Align"=>TEXT_ALIGN_TOPLEFT, + "FontName"=>$CaptionFontName, + "FontSize"=>$CaptionFontSize, + "R"=>$SubCaptionR, + "G"=>$SubCaptionG, + "B"=>$SubCaptionB, + "Alpha"=>$SubCaptionAlpha + ); + } else { + $SubCaptionColor = array( + "Align"=>TEXT_ALIGN_TOPLEFT, + "FontName"=>$CaptionFontName, + "FontSize"=>$CaptionFontSize, + "R"=>$Settings["R"]+$SubCaptionColorFactor, + "G"=>$Settings["G"]+$SubCaptionColorFactor, + "B"=>$Settings["B"]+$SubCaptionColorFactor + ); + } + + $RestoreShadow = $this->pChartObject->Shadow; + $this->pChartObject->Shadow = false; + + if ( $CaptionLayout == INDICATOR_CAPTION_DEFAULT ) { + $this->pChartObject->drawText($X1,$Y+$Height+$TextPadding,$Caption,$CaptionColor); + } elseif ( $CaptionLayout == INDICATOR_CAPTION_EXTENDED ) { + $TxtPos = $this->pChartObject->getTextBox($X1,$Y+$Height+$TextPadding,$CaptionFontName,$CaptionFontSize,0,$Caption); + $CaptionHeight = $TxtPos[0]["Y"] - $TxtPos[2]["Y"]; + + $this->pChartObject->drawText($X1+$XOffset,$Y+$Height-$YOffset+$TextPadding,$Caption,$CaptionColor); + $this->pChartObject->drawText($X1+$XOffset,$Y+$Height-$YOffset+$CaptionHeight+$TextPadding*2,$SubCaption,$SubCaptionColor); + } + + $this->pChartObject->Shadow = $RestoreShadow; + + $X1 = $X2 + $SectionsMargin; + } + + $RestoreShadow = $this->pChartObject->Shadow; + $this->pChartObject->Shadow = false; + + foreach($Values as $Key => $Value) { + if ( $Value >= $OverallMin && $Value <= $OverallMax ) { + foreach ($IndicatorSections as $Key => $Settings) { + if ( $Value >= $Settings["Start"] && $Value <= $Settings["End"] ) { + $X1 = $ValuesPos[$Value]; //$X + $Key*$SectionsMargin + ($Value - $OverallMin) * $XScale; + + if ( $ValueDisplay == INDICATOR_VALUE_BUBBLE ) { + $TxtPos = $this->pChartObject->getTextBox($X1,$Y,$ValueFontName,$ValueFontSize,0,$Value.$Unit); + $Radius = floor(($TxtPos[1]["X"] - $TxtPos[0]["X"] + $TextPadding*4)/2); + + $this->pChartObject->drawFilledCircle($X1,$Y,$Radius+4,array("R"=>$Settings["R"]+20,"G"=>$Settings["G"]+20,"B"=>$Settings["B"]+20)); + $this->pChartObject->drawFilledCircle($X1,$Y,$Radius,array("R"=>255,"G"=>255,"B"=>255)); + + $TextSettings = array("Align"=>TEXT_ALIGN_MIDDLEMIDDLE,"FontName"=>$ValueFontName,"FontSize"=>$ValueFontSize); + $this->pChartObject->drawText($X1-1,$Y-1,$Value.$Unit,$TextSettings); + } elseif( $ValueDisplay == INDICATOR_VALUE_LABEL ) { + $Caption = ""; + $Caption[] = array("Format"=>array("R"=>$Settings["R"],"G"=>$Settings["G"],"B"=>$Settings["B"],"Alpha"=>100),"Caption"=>$Value.$Unit); + $this->pChartObject->drawLabelBox(floor($X1),floor($Y)+2,"Value - ".$Settings["Caption"],$Caption); + } + } + $X1 = $X2 + $SectionsMargin; + } + } + } + $this->pChartObject->Shadow = $RestoreShadow; + } +} diff --git a/vendor/szymach/c-pchart/src/Classes/pPie.php b/vendor/szymach/c-pchart/src/Classes/pPie.php new file mode 100644 index 0000000000..7988229c2f --- /dev/null +++ b/vendor/szymach/c-pchart/src/Classes/pPie.php @@ -0,0 +1,2049 @@ +pChartObject = $pChartObject; + + /* Cache the pData object reference */ + $this->pDataObject = $pDataObject; + } + + /** + * Draw a pie chart + * @param type $X + * @param type $Y + * @param type $Format + * @return type + */ + public 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 + * @param type $X + * @param type $Y + * @param type $Format + * @return type + */ + public 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;$ipChartObject->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; + } + /* Empty error handling */ + if ( isset($SliceAngle[$SliceID][1]) ) { + $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; + /* Empty error handling */ + if ( $Visible[$SliceID]["Start"] && isset($Plots[2])) { + $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 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; + } + + /* Empty error handling */ + if ( isset($SliceAngle[$SliceID][1]) ) { + $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;$jpChartObject->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 + * @param type $X + * @param type $Y + * @param type $Format + * @return type + */ + public 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 + * @param type $SliceID + * @param type $Format + */ + public 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 + * @param type $X + * @param type $Y + * @param type $Label + * @param type $Angle + * @param int $Settings + * @param type $Stacked + * @param type $Xc + * @param type $Yc + * @param type $Radius + * @param type $Reversed + */ + public 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 + * @param type $StartAngle + * @param type $EndAngle + * @param type $Offset + * @param type $Reversed + */ + public 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 + * @return type + */ + public 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 + * @param type $X + * @param type $Y + * @param type $Format + * @return type + */ + public 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 + * @param type $X + * @param type $Y + * @param type $Format + * @return type + */ + public 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 + * @param type $Data + * @return type + */ + public function arraySerialize($Data) + { + $Result = ""; + foreach($Data as $Key => $Value) { + if ($Result == "") { + $Result = floor($Value); + } else { + $Result = $Result.",".floor($Value); + } + } + + return($Result); + } + + /** + * Reverse an array + * @param type $Plots + * @return type + */ + public 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 + * @param type $Data + * @param type $Palette + * @param type $DataSerie + * @param type $AbscissaSerie + * @return type + */ + public 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 diff --git a/vendor/szymach/c-pchart/src/Classes/pRadar.php b/vendor/szymach/c-pchart/src/Classes/pRadar.php new file mode 100644 index 0000000000..92281f90c1 --- /dev/null +++ b/vendor/szymach/c-pchart/src/Classes/pRadar.php @@ -0,0 +1,887 @@ +pChartObject = $Object; + + $FixedMax = isset($Format["FixedMax"]) ? $Format["FixedMax"] : VOID; + $AxisR = isset($Format["AxisR"]) ? $Format["AxisR"] : 60; + $AxisG = isset($Format["AxisG"]) ? $Format["AxisG"] : 60; + $AxisB = isset($Format["AxisB"]) ? $Format["AxisB"] : 60; + $AxisAlpha = isset($Format["AxisAlpha"]) ? $Format["AxisAlpha"] : 50; + $AxisRotation = isset($Format["AxisRotation"]) ? $Format["AxisRotation"] : 0; + $DrawTicks = isset($Format["DrawTicks"]) ? $Format["DrawTicks"] : true; + $TicksLength = isset($Format["TicksLength"]) ? $Format["TicksLength"] : 2; + $DrawAxisValues = isset($Format["DrawAxisValues"]) ? $Format["DrawAxisValues"] : true; + $AxisBoxRounded = isset($Format["AxisBoxRounded"]) ? $Format["AxisBoxRounded"] : true; + $AxisFontName = isset($Format["AxisFontName"]) ? $Format["AxisFontName"] : $this->pChartObject->FontName; + $AxisFontSize = isset($Format["AxisFontSize"]) ? $Format["AxisFontSize"] : $this->pChartObject->FontSize; + $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : false; + $WriteValuesInBubble = isset($Format["WriteValuesInBubble"]) ? $Format["WriteValuesInBubble"] : true; + $ValueFontName = isset($Format["ValueFontName"]) ? $Format["ValueFontName"] : $this->pChartObject->FontName; + $ValueFontSize = isset($Format["ValueFontSize"]) ? $Format["ValueFontSize"] : $this->pChartObject->FontSize; + $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : 4; + $OuterBubbleRadius = isset($Format["OuterBubbleRadius"]) ? $Format["OuterBubbleRadius"] : 2; + $OuterBubbleR = isset($Format["OuterBubbleR"]) ? $Format["OuterBubbleR"] : VOID; + $OuterBubbleG = isset($Format["OuterBubbleG"]) ? $Format["OuterBubbleG"] : VOID; + $OuterBubbleB = isset($Format["OuterBubbleB"]) ? $Format["OuterBubbleB"] : VOID; + $OuterBubbleAlpha = isset($Format["OuterBubbleAlpha"]) ? $Format["OuterBubbleAlpha"] : 100; + $InnerBubbleR = isset($Format["InnerBubbleR"]) ? $Format["InnerBubbleR"] : 255; + $InnerBubbleG = isset($Format["InnerBubbleG"]) ? $Format["InnerBubbleG"] : 255; + $InnerBubbleB = isset($Format["InnerBubbleB"]) ? $Format["InnerBubbleB"] : 255; + $InnerBubbleAlpha = isset($Format["InnerBubbleAlpha"]) ? $Format["InnerBubbleAlpha"] : 100; + $DrawBackground = isset($Format["DrawBackground"]) ? $Format["DrawBackground"] : true; + $BackgroundR = isset($Format["BackgroundR"]) ? $Format["BackgroundR"] : 255; + $BackgroundG = isset($Format["BackgroundG"]) ? $Format["BackgroundG"] : 255; + $BackgroundB = isset($Format["BackgroundB"]) ? $Format["BackgroundB"] : 255; + $BackgroundAlpha = isset($Format["BackgroundAlpha"]) ? $Format["BackgroundAlpha"] : 50; + $BackgroundGradient = isset($Format["BackgroundGradient"]) ? $Format["BackgroundGradient"] : null; + $Layout = isset($Format["Layout"]) ? $Format["Layout"] : RADAR_LAYOUT_STAR; + $SegmentHeight = isset($Format["SegmentHeight"]) ? $Format["SegmentHeight"] : SEGMENT_HEIGHT_AUTO; + $Segments = isset($Format["Segments"]) ? $Format["Segments"] : 4; + $WriteLabels = isset($Format["WriteLabels"]) ? $Format["WriteLabels"] : true; + $SkipLabels = isset($Format["SkipLabels"]) ? $Format["SkipLabels"] : 1; + $LabelMiddle = isset($Format["LabelMiddle"]) ? $Format["LabelMiddle"] : false; + $LabelsBackground = isset($Format["LabelsBackground"]) ? $Format["LabelsBackground"] : true; + $LabelsBGR = isset($Format["LabelsBGR"]) ? $Format["LabelsBGR"] : 255; + $LabelsBGG = isset($Format["LabelsBGR"]) ? $Format["LabelsBGG"] : 255; + $LabelsBGB = isset($Format["LabelsBGR"]) ? $Format["LabelsBGB"] : 255; + $LabelsBGAlpha = isset($Format["LabelsBGAlpha"]) ? $Format["LabelsBGAlpha"] : 50; + $LabelPos = isset($Format["LabelPos"]) ? $Format["LabelPos"] : RADAR_LABELS_ROTATED; + $LabelPadding = isset($Format["LabelPadding"]) ? $Format["LabelPadding"] : 4; + $DrawPoints = isset($Format["DrawPoints"]) ? $Format["DrawPoints"] : true; + $PointRadius = isset($Format["PointRadius"]) ? $Format["PointRadius"] : 4; + $PointSurrounding = isset($Format["PointRadius"]) ? $Format["PointRadius"] : -30; + $DrawLines = isset($Format["DrawLines"]) ? $Format["DrawLines"] : true; + $LineLoopStart = isset($Format["LineLoopStart"]) ? $Format["LineLoopStart"] : true; + $DrawPoly = isset($Format["DrawPoly"]) ? $Format["DrawPoly"] : false; + $PolyAlpha = isset($Format["PolyAlpha"]) ? $Format["PolyAlpha"] : 40; + $FontSize = $Object->FontSize; + $X1 = $Object->GraphAreaX1; + $Y1 = $Object->GraphAreaY1; + $X2 = $Object->GraphAreaX2; + $Y2 = $Object->GraphAreaY2; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : false; + + /* Cancel default tick length if ticks not enabled */ + if ( $DrawTicks == false ) { + $TicksLength = 0; + } + + /* Data Processing */ + $Data = $Values->getData(); + $Palette = $Values->getPalette(); + + /* Catch the number of required axis */ + $LabelSerie = $Data["Abscissa"]; + if ( $LabelSerie != "" ) { + $Points = count($Data["Series"][$LabelSerie]["Data"]); + } else { + $Points = 0; + foreach($Data["Series"] as $SerieName => $DataArray) { + if ( count($DataArray["Data"]) > $Points ) { + $Points = count($DataArray["Data"]); + } + } + } + + /* Draw the axis */ + $CenterX = ($X2-$X1)/2 + $X1; + $CenterY = ($Y2-$Y1)/2 + $Y1; + + $EdgeHeight = min(($X2-$X1)/2,($Y2-$Y1)/2); + if ( $WriteLabels ) { + $EdgeHeight = $EdgeHeight - $FontSize - $LabelPadding - $TicksLength; + } + /* Determine the scale if set to automatic */ + if ( $SegmentHeight == SEGMENT_HEIGHT_AUTO) { + if ( $FixedMax != VOID ) { + $Max = $FixedMax; + } else { + $Max = 0; + foreach($Data["Series"] as $SerieName => $DataArray) { + if ( $SerieName != $LabelSerie ) { + if ( max($DataArray["Data"]) > $Max ) { + $Max = max($DataArray["Data"]); + } + } + } + } + $MaxSegments = $EdgeHeight/20; + $Scale = $Object->computeScale(0,$Max,$MaxSegments,array(1,2,5)); + + $Segments = $Scale["Rows"]; + $SegmentHeight = $Scale["RowHeight"]; + } + + if ( $LabelMiddle && $SkipLabels == 1 ) { + $Axisoffset = (360/$Points)/2; + } elseif ( $LabelMiddle && $SkipLabels != 1 ) { + $Axisoffset = (360/($Points/$SkipLabels))/2; + } elseif ( !$LabelMiddle ) { + $Axisoffset = 0; + } + + /* Background processing */ + if ( $DrawBackground ) { + $RestoreShadow = $Object->Shadow; + $Object->Shadow = false; + + if ($BackgroundGradient == null) { + if ( $Layout == RADAR_LAYOUT_STAR ) { + $Color = array("R"=>$BackgroundR,"G"=>$BackgroundG,"B"=>$BackgroundB,"Alpha"=>$BackgroundAlpha); + $PointArray = ""; + for($i=0;$i<=360;$i=$i+(360/$Points)) { + $PointArray[] = cos(deg2rad($i+$AxisRotation)) * $EdgeHeight + $CenterX; + $PointArray[] = sin(deg2rad($i+$AxisRotation)) * $EdgeHeight + $CenterY; + } + $Object->drawPolygon($PointArray,$Color); + } elseif ( $Layout == RADAR_LAYOUT_CIRCLE ) { + $Color = array("R"=>$BackgroundR,"G"=>$BackgroundG,"B"=>$BackgroundB,"Alpha"=>$BackgroundAlpha); + $Object->drawFilledCircle($CenterX,$CenterY,$EdgeHeight,$Color); + } + } else { + $GradientROffset = ($BackgroundGradient["EndR"] - $BackgroundGradient["StartR"]) / $Segments; + $GradientGOffset = ($BackgroundGradient["EndG"] - $BackgroundGradient["StartG"]) / $Segments; + $GradientBOffset = ($BackgroundGradient["EndB"] - $BackgroundGradient["StartB"]) / $Segments; + $GradientAlphaOffset = ($BackgroundGradient["EndAlpha"] - $BackgroundGradient["StartAlpha"]) / $Segments; + + if ( $Layout == RADAR_LAYOUT_STAR ) { + for ($j=$Segments;$j>=1;$j--) { + $Color = array( + "R"=>$BackgroundGradient["StartR"]+$GradientROffset*$j, + "G"=>$BackgroundGradient["StartG"]+$GradientGOffset*$j, + "B"=>$BackgroundGradient["StartB"]+$GradientBOffset*$j, + "Alpha"=>$BackgroundGradient["StartAlpha"]+$GradientAlphaOffset*$j + ); + $PointArray = ""; + + for($i=0;$i<=360;$i=$i+(360/$Points)) { + $PointArray[] = cos(deg2rad($i+$AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterX; + $PointArray[] = sin(deg2rad($i+$AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterY; + } + $Object->drawPolygon($PointArray,$Color); + } + } elseif ( $Layout == RADAR_LAYOUT_CIRCLE ) { + for($j=$Segments;$j>=1;$j--) { + $Color = array( + "R"=>$BackgroundGradient["StartR"]+$GradientROffset*$j, + "G"=>$BackgroundGradient["StartG"]+$GradientGOffset*$j, + "B"=>$BackgroundGradient["StartB"]+$GradientBOffset*$j, + "Alpha"=>$BackgroundGradient["StartAlpha"]+$GradientAlphaOffset*$j + ); + $Object->drawFilledCircle($CenterX,$CenterY,($EdgeHeight/$Segments)*$j,$Color); + } + } + } + $Object->Shadow = $RestoreShadow; + } + + /* Axis to axis lines */ + $Color = array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha); + $ColorDotted = array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha*.8, "Ticks"=>2); + if ( $Layout == RADAR_LAYOUT_STAR ) { + for($j=1;$j<=$Segments;$j++) { + for($i=0;$i<360;$i=$i+(360/$Points)) { + $EdgeX1 = cos(deg2rad($i+$AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterX; + $EdgeY1 = sin(deg2rad($i+$AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterY; + $EdgeX2 = cos(deg2rad($i+$AxisRotation+(360/$Points))) * ($EdgeHeight/$Segments)*$j + $CenterX; + $EdgeY2 = sin(deg2rad($i+$AxisRotation+(360/$Points))) * ($EdgeHeight/$Segments)*$j + $CenterY; + + $Object->drawLine($EdgeX1,$EdgeY1,$EdgeX2,$EdgeY2,$Color); + } + } + } elseif ( $Layout == RADAR_LAYOUT_CIRCLE ) { + for($j=1;$j<=$Segments;$j++) { + $Radius = ($EdgeHeight/$Segments)*$j; + $Object->drawCircle($CenterX,$CenterY,$Radius,$Radius,$Color); + } + } + + if ( $DrawAxisValues ) { + if ( $LabelsBackground ) { + $Options = array( + "DrawBox"=>true, + "Align"=>TEXT_ALIGN_MIDDLEMIDDLE, + "BoxR"=>$LabelsBGR, + "BoxG"=>$LabelsBGG, + "BoxB"=>$LabelsBGB, + "BoxAlpha"=>$LabelsBGAlpha + ); + } else { + $Options = array("Align"=>TEXT_ALIGN_MIDDLEMIDDLE); + } + if ( $AxisBoxRounded ) { + $Options["BoxRounded"] = true; + } + + $Options["FontName"] = $AxisFontName; + $Options["FontSize"] = $AxisFontSize; + + $Angle = 360 / ($Points*2); + for($j=1;$j<=$Segments;$j++) { + $Label = $j * $SegmentHeight; + + if ( $Layout == RADAR_LAYOUT_CIRCLE ) { + $EdgeX1 = cos(deg2rad($Angle+$AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterX; + $EdgeY1 = sin(deg2rad($Angle+$AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterY; + } elseif ( $Layout == RADAR_LAYOUT_STAR ) { + $EdgeX1 = cos(deg2rad($AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterX; + $EdgeY1 = sin(deg2rad($AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterY; + $EdgeX2 = cos(deg2rad((360 / $Points) + $AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterX; + $EdgeY2 = sin(deg2rad((360 / $Points) + $AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterY; + + $EdgeX1 = ($EdgeX2 - $EdgeX1)/2 + $EdgeX1; + $EdgeY1 = ($EdgeY2 - $EdgeY1)/2 + $EdgeY1; + } + + $Object->drawText($EdgeX1,$EdgeY1,$Label,$Options); + } + } + + /* Axis lines */ + $ID = 0; + for($i=0;$i<360;$i=$i+(360/$Points)) { + $EdgeX = cos(deg2rad($i+$AxisRotation)) * ($EdgeHeight+$TicksLength) + $CenterX; + $EdgeY = sin(deg2rad($i+$AxisRotation)) * ($EdgeHeight+$TicksLength) + $CenterY; + + if ($ID % $SkipLabels == 0) { + $Object->drawLine($CenterX,$CenterY,$EdgeX,$EdgeY,$Color); + } else { + $Object->drawLine($CenterX,$CenterY,$EdgeX,$EdgeY,$ColorDotted); + } + + if ( $WriteLabels ) { + $LabelX = cos(deg2rad($i+$AxisRotation+$Axisoffset)) * ($EdgeHeight+$LabelPadding+$TicksLength) + $CenterX; + $LabelY = sin(deg2rad($i+$AxisRotation+$Axisoffset)) * ($EdgeHeight+$LabelPadding+$TicksLength) + $CenterY; + + if ( $LabelSerie != "" ) { + $Label = isset($Data["Series"][$LabelSerie]["Data"][$ID]) ? $Data["Series"][$LabelSerie]["Data"][$ID] : ""; + } else { + $Label = $ID; + } + + if ($ID % $SkipLabels == 0) { + if ( $LabelPos == RADAR_LABELS_ROTATED ) { + $Object->drawText( + $LabelX, + $LabelY, + $Label, + array( + "Angle"=>(360-($i+$AxisRotation+$Axisoffset))-90, + "Align"=>TEXT_ALIGN_BOTTOMMIDDLE + ) + ); + } else { + if ( (floor($LabelX) == floor($CenterX)) && (floor($LabelY) < floor($CenterY)) ) { + $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE)); + } + if ( (floor($LabelX) > floor($CenterX)) && (floor($LabelY) < floor($CenterY)) ) { + $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_BOTTOMLEFT)); + } + if ( (floor($LabelX) > floor($CenterX)) && (floor($LabelY) == floor($CenterY)) ) { + $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_MIDDLELEFT)); + } + if ( (floor($LabelX) > floor($CenterX)) && (floor($LabelY) > floor($CenterY)) ) { + $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_TOPLEFT)); + } + if ( (floor($LabelX) < floor($CenterX)) && (floor($LabelY) < floor($CenterY)) ) { + $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_BOTTOMRIGHT)); + } + if ( (floor($LabelX) < floor($CenterX)) && (floor($LabelY) == floor($CenterY)) ) { + $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_MIDDLERIGHT)); + } + if ( (floor($LabelX) < floor($CenterX)) && (floor($LabelY) > floor($CenterY)) ) { + $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_TOPRIGHT)); + } + if ( (floor($LabelX) == floor($CenterX)) && (floor($LabelY) > floor($CenterY)) ) { + $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_TOPMIDDLE)); + } + } + } + } + $ID++; + } + + /* Compute the plots position */ + $ID = 0; $Plot = ""; + foreach($Data["Series"] as $SerieName => $DataS) { + if ( $SerieName != $LabelSerie ) { + $Color = array( + "R"=>$Palette[$ID]["R"], + "G"=>$Palette[$ID]["G"], + "B"=>$Palette[$ID]["B"], + "Alpha"=>$Palette[$ID]["Alpha"], + "Surrounding"=>$PointSurrounding + ); + foreach($DataS["Data"] as $Key => $Value) { + $Angle = (360/$Points) * $Key; + $Length = ($EdgeHeight/($Segments*$SegmentHeight))*$Value; + + $X = cos(deg2rad($Angle+$AxisRotation)) * $Length + $CenterX; + $Y = sin(deg2rad($Angle+$AxisRotation)) * $Length + $CenterY; + + $Plot[$ID][] = array($X,$Y,$Value); + + if ( $RecordImageMap ) { + $this->pChartObject->addToImageMap( + "CIRCLE", + floor($X).",".floor($Y).",".floor($PointRadius), + $this->pChartObject->toHTMLColor( + $Palette[$ID]["R"], + $Palette[$ID]["G"], + $Palette[$ID]["B"] + ), + $DataS["Description"], + $Data["Series"][$LabelSerie]["Data"][$Key]." = ".$Value + ); + } + } + $ID++; + } + } + + /* Draw all that stuff! */ + foreach($Plot as $ID => $Points) { + $Color = array( + "R"=>$Palette[$ID]["R"], + "G"=>$Palette[$ID]["G"], + "B"=>$Palette[$ID]["B"], + "Alpha"=>$Palette[$ID]["Alpha"], + "Surrounding"=>$PointSurrounding + ); + + /* Draw the polygons */ + if ( $DrawPoly ) { + if ($PolyAlpha != null) { + $Color = array( + "R"=>$Palette[$ID]["R"], + "G"=>$Palette[$ID]["G"], + "B"=>$Palette[$ID]["B"], + "Alpha"=>$PolyAlpha, + "Surrounding"=>$PointSurrounding + ); + } + $PointsArray = ""; + for ($i=0; $idrawPolygon($PointsArray,$Color); + } + + $Color = array( + "R"=>$Palette[$ID]["R"], + "G"=>$Palette[$ID]["G"], + "B"=>$Palette[$ID]["B"], + "Alpha"=>$Palette[$ID]["Alpha"], + "Surrounding"=>$PointSurrounding + ); + + /* Bubble and labels settings */ + $TextSettings = array( + "Align"=>TEXT_ALIGN_MIDDLEMIDDLE, + "FontName"=>$ValueFontName, + "FontSize"=>$ValueFontSize, + "R"=>$Palette[$ID]["R"], + "G"=>$Palette[$ID]["G"], + "B"=>$Palette[$ID]["B"] + ); + $InnerColor = array( + "R"=>$InnerBubbleR, + "G"=>$InnerBubbleG, + "B"=>$InnerBubbleB, + "Alpha"=>$InnerBubbleAlpha + ); + if ( $OuterBubbleR != VOID ) { + $OuterColor = array( + "R"=>$OuterBubbleR, + "G"=>$OuterBubbleG, + "B"=>$OuterBubbleB, + "Alpha"=>$OuterBubbleAlpha + ); + } else { + $OuterColor = array( + "R"=>$Palette[$ID]["R"]+20, + "G"=>$Palette[$ID]["G"]+20, + "B"=>$Palette[$ID]["B"]+20, + "Alpha"=>$Palette[$ID]["Alpha"] + ); + } + /* Loop to the starting points if asked */ + if ( $LineLoopStart && $DrawLines ) + $Object->drawLine( + $Points[count($Points)-1][0], + $Points[count($Points)-1][1], + $Points[0][0], + $Points[0][1], + $Color + ); + + /* Draw the lines & points */ + for ($i=0; $idrawLine( + $Points[$i][0], + $Points[$i][1], + $Points[$i+1][0], + $Points[$i+1][1], + $Color + ); + } + if ( $DrawPoints ) { + $Object->drawFilledCircle( + $Points[$i][0], + $Points[$i][1], + $PointRadius, + $Color + ); + } + if ( $WriteValuesInBubble && $WriteValues ) { + $TxtPos = $this->pChartObject->getTextBox( + $Points[$i][0], + $Points[$i][1], + $ValueFontName, + $ValueFontSize, + 0, + $Points[$i][2] + ); + $Radius = floor(($TxtPos[1]["X"] - $TxtPos[0]["X"] + $ValuePadding*2)/2); + + $this->pChartObject->drawFilledCircle( + $Points[$i][0], + $Points[$i][1], + $Radius+$OuterBubbleRadius, + $OuterColor + ); + $this->pChartObject->drawFilledCircle( + $Points[$i][0], + $Points[$i][1], + $Radius,$InnerColor + ); + } + + if ( $WriteValues ) + $this->pChartObject->drawText( + $Points[$i][0]-1, + $Points[$i][1]-1, + $Points[$i][2], + $TextSettings + ); + } + } + } + + + + /** + * Draw a radar chart + * @param type $Object + * @param type $Values + * @param type $Format + */ + public function drawPolar($Object,$Values,$Format="") + { + $this->pChartObject = $Object; + + $FixedMax = isset($Format["FixedMax"]) ? $Format["FixedMax"] : VOID; + $AxisR = isset($Format["AxisR"]) ? $Format["AxisR"] : 60; + $AxisG = isset($Format["AxisG"]) ? $Format["AxisG"] : 60; + $AxisB = isset($Format["AxisB"]) ? $Format["AxisB"] : 60; + $AxisAlpha = isset($Format["AxisAlpha"]) ? $Format["AxisAlpha"] : 50; + $AxisRotation = isset($Format["AxisRotation"]) ? $Format["AxisRotation"] : -90; + $DrawTicks = isset($Format["DrawTicks"]) ? $Format["DrawTicks"] : true; + $TicksLength = isset($Format["TicksLength"]) ? $Format["TicksLength"] : 2; + $DrawAxisValues = isset($Format["DrawAxisValues"]) ? $Format["DrawAxisValues"] : true; + $AxisBoxRounded = isset($Format["AxisBoxRounded"]) ? $Format["AxisBoxRounded"] : true; + $AxisFontName = isset($Format["FontName"]) ? $Format["FontName"] : $this->pChartObject->FontName; + $AxisFontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->pChartObject->FontSize; + $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : false; + $WriteValuesInBubble = isset($Format["WriteValuesInBubble"]) ? $Format["WriteValuesInBubble"] : true; + $ValueFontName = isset($Format["ValueFontName"]) ? $Format["ValueFontName"] : $this->pChartObject->FontName; + $ValueFontSize = isset($Format["ValueFontSize"]) ? $Format["ValueFontSize"] : $this->pChartObject->FontSize; + $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : 4; + $OuterBubbleRadius = isset($Format["OuterBubbleRadius"]) ? $Format["OuterBubbleRadius"] : 2; + $OuterBubbleR = isset($Format["OuterBubbleR"]) ? $Format["OuterBubbleR"] : VOID; + $OuterBubbleG = isset($Format["OuterBubbleG"]) ? $Format["OuterBubbleG"] : VOID; + $OuterBubbleB = isset($Format["OuterBubbleB"]) ? $Format["OuterBubbleB"] : VOID; + $OuterBubbleAlpha = isset($Format["OuterBubbleAlpha"]) ? $Format["OuterBubbleAlpha"] : 100; + $InnerBubbleR = isset($Format["InnerBubbleR"]) ? $Format["InnerBubbleR"] : 255; + $InnerBubbleG = isset($Format["InnerBubbleG"]) ? $Format["InnerBubbleG"] : 255; + $InnerBubbleB = isset($Format["InnerBubbleB"]) ? $Format["InnerBubbleB"] : 255; + $InnerBubbleAlpha = isset($Format["InnerBubbleAlpha"]) ? $Format["InnerBubbleAlpha"] : 100; + $DrawBackground = isset($Format["DrawBackground"]) ? $Format["DrawBackground"] : true; + $BackgroundR = isset($Format["BackgroundR"]) ? $Format["BackgroundR"] : 255; + $BackgroundG = isset($Format["BackgroundG"]) ? $Format["BackgroundG"] : 255; + $BackgroundB = isset($Format["BackgroundB"]) ? $Format["BackgroundB"] : 255; + $BackgroundAlpha = isset($Format["BackgroundAlpha"]) ? $Format["BackgroundAlpha"] : 50; + $BackgroundGradient= isset($Format["BackgroundGradient"]) ? $Format["BackgroundGradient"] : null; + $AxisSteps = isset($Format["AxisSteps"]) ? $Format["AxisSteps"] : 20; + $SegmentHeight = isset($Format["SegmentHeight"]) ? $Format["SegmentHeight"] : SEGMENT_HEIGHT_AUTO; + $Segments = isset($Format["Segments"]) ? $Format["Segments"] : 4; + $WriteLabels = isset($Format["WriteLabels"]) ? $Format["WriteLabels"] : true; + $LabelsBackground = isset($Format["LabelsBackground"]) ? $Format["LabelsBackground"] : true; + $LabelsBGR = isset($Format["LabelsBGR"]) ? $Format["LabelsBGR"] : 255; + $LabelsBGG = isset($Format["LabelsBGR"]) ? $Format["LabelsBGG"] : 255; + $LabelsBGB = isset($Format["LabelsBGR"]) ? $Format["LabelsBGB"] : 255; + $LabelsBGAlpha = isset($Format["LabelsBGAlpha"]) ? $Format["LabelsBGAlpha"] : 50; + $LabelPos = isset($Format["LabelPos"]) ? $Format["LabelPos"] : RADAR_LABELS_ROTATED; + $LabelPadding = isset($Format["LabelPadding"]) ? $Format["LabelPadding"] : 4; + $DrawPoints = isset($Format["DrawPoints"]) ? $Format["DrawPoints"] : true; + $PointRadius = isset($Format["PointRadius"]) ? $Format["PointRadius"] : 4; + $PointSurrounding = isset($Format["PointRadius"]) ? $Format["PointRadius"] : -30; + $DrawLines = isset($Format["DrawLines"]) ? $Format["DrawLines"] : true; + $LineLoopStart = isset($Format["LineLoopStart"]) ? $Format["LineLoopStart"] : false; + $DrawPoly = isset($Format["DrawPoly"]) ? $Format["DrawPoly"] : false; + $PolyAlpha = isset($Format["PolyAlpha"]) ? $Format["PolyAlpha"] : null; + $FontSize = $Object->FontSize; + $X1 = $Object->GraphAreaX1; + $Y1 = $Object->GraphAreaY1; + $X2 = $Object->GraphAreaX2; + $Y2 = $Object->GraphAreaY2; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : false; + + if ( $AxisBoxRounded ) { + $DrawAxisValues = true; + } + + /* Cancel default tick length if ticks not enabled */ + if ( $DrawTicks == false ) { + $TicksLength = 0; + } + + /* Data Processing */ + $Data = $Values->getData(); + $Palette = $Values->getPalette(); + + /* Catch the number of required axis */ + $LabelSerie = $Data["Abscissa"]; + if ( $LabelSerie != "" ) { + $Points = count($Data["Series"][$LabelSerie]["Data"]); + } else { + $Points = 0; + foreach($Data["Series"] as $SerieName => $DataArray) { + if ( count($DataArray["Data"]) > $Points ) { + $Points = count($DataArray["Data"]); + } + } + } + + /* Draw the axis */ + $CenterX = ($X2-$X1)/2 + $X1; + $CenterY = ($Y2-$Y1)/2 + $Y1; + + $EdgeHeight = min(($X2-$X1)/2,($Y2-$Y1)/2); + if ( $WriteLabels ) { + $EdgeHeight = $EdgeHeight - $FontSize - $LabelPadding - $TicksLength; + } + + /* Determine the scale if set to automatic */ + if ( $SegmentHeight == SEGMENT_HEIGHT_AUTO) { + if ( $FixedMax != VOID ) { + $Max = $FixedMax; + } else { + $Max = 0; + foreach($Data["Series"] as $SerieName => $DataArray) { + if ( $SerieName != $LabelSerie ) { + if ( max($DataArray["Data"]) > $Max ) { + $Max = max($DataArray["Data"]); + } + } + } + } + $MaxSegments = $EdgeHeight/20; + $Scale = $Object->computeScale(0,$Max,$MaxSegments,array(1,2,5)); + + $Segments = $Scale["Rows"]; + $SegmentHeight = $Scale["RowHeight"]; + } + + + /* Background processing */ + if ( $DrawBackground ) { + $RestoreShadow = $Object->Shadow; + $Object->Shadow = false; + + if ($BackgroundGradient == null) { + $Color = array("R"=>$BackgroundR,"G"=>$BackgroundG,"B"=>$BackgroundB,"Alpha"=>$BackgroundAlpha); + $Object->drawFilledCircle($CenterX,$CenterY,$EdgeHeight,$Color); + } else { + $GradientROffset = ($BackgroundGradient["EndR"] - $BackgroundGradient["StartR"]) / $Segments; + $GradientGOffset = ($BackgroundGradient["EndG"] - $BackgroundGradient["StartG"]) / $Segments; + $GradientBOffset = ($BackgroundGradient["EndB"] - $BackgroundGradient["StartB"]) / $Segments; + $GradientAlphaOffset = ($BackgroundGradient["EndAlpha"] - $BackgroundGradient["StartAlpha"]) / $Segments; + + for ($j=$Segments;$j>=1;$j--) { + $Color = array( + "R"=>$BackgroundGradient["StartR"]+$GradientROffset*$j, + "G"=>$BackgroundGradient["StartG"]+$GradientGOffset*$j, + "B"=>$BackgroundGradient["StartB"]+$GradientBOffset*$j, + "Alpha"=>$BackgroundGradient["StartAlpha"]+$GradientAlphaOffset*$j + ); + $Object->drawFilledCircle($CenterX,$CenterY,($EdgeHeight/$Segments)*$j,$Color); + } + } + $Object->Shadow = $RestoreShadow; + } + + /* Axis to axis lines */ + $Color = array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha); + for($j=1;$j<=$Segments;$j++) { + $Radius = ($EdgeHeight/$Segments)*$j; + $Object->drawCircle($CenterX,$CenterY,$Radius,$Radius,$Color); + } + + if ( $DrawAxisValues ) { + if ( $LabelsBackground ) { + $Options = array( + "DrawBox"=>true, + "Align"=>TEXT_ALIGN_MIDDLEMIDDLE, + "BoxR"=>$LabelsBGR, + "BoxG"=>$LabelsBGG, + "BoxB"=>$LabelsBGB, + "BoxAlpha"=>$LabelsBGAlpha + ); + } else { + $Options = array("Align"=>TEXT_ALIGN_MIDDLEMIDDLE); + } + + if ( $AxisBoxRounded ) { $Options["BoxRounded"] = true; } + + $Options["FontName"] = $AxisFontName; + $Options["FontSize"] = $AxisFontSize; + + $Angle = 360 / ($Points*2); + for($j=1;$j<=$Segments;$j++) { + $EdgeX1 = cos(deg2rad($Angle+$AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterX; + $EdgeY1 = sin(deg2rad($Angle+$AxisRotation)) * ($EdgeHeight/$Segments)*$j + $CenterY; + $Label = $j*$SegmentHeight; + + $Object->drawText($EdgeX1,$EdgeY1,$Label,$Options); + } + } + + /* Axis lines */ + $ID = 0; + for($i=0;$i<=359;$i=$i+$AxisSteps) { + $EdgeX = cos(deg2rad($i+$AxisRotation)) * ($EdgeHeight+$TicksLength) + $CenterX; + $EdgeY = sin(deg2rad($i+$AxisRotation)) * ($EdgeHeight+$TicksLength) + $CenterY; + + $Object->drawLine($CenterX,$CenterY,$EdgeX,$EdgeY,$Color); + + if ( $WriteLabels ) { + $LabelX = cos(deg2rad($i+$AxisRotation)) * ($EdgeHeight+$LabelPadding+$TicksLength) + $CenterX; + $LabelY = sin(deg2rad($i+$AxisRotation)) * ($EdgeHeight+$LabelPadding+$TicksLength) + $CenterY; + $Label = $i."°"; + + if ( $LabelPos == RADAR_LABELS_ROTATED ) { + $Object->drawText($LabelX,$LabelY,$Label,array("Angle"=>(360-$i),"Align"=>TEXT_ALIGN_BOTTOMMIDDLE)); + } else { + if ( (floor($LabelX) == floor($CenterX)) && (floor($LabelY) < floor($CenterY)) ) { + $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE)); + } + if ( (floor($LabelX) > floor($CenterX)) && (floor($LabelY) < floor($CenterY)) ) { + $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_BOTTOMLEFT)); + } + if ( (floor($LabelX) > floor($CenterX)) && (floor($LabelY) == floor($CenterY)) ) { + $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_MIDDLELEFT)); + } + if ( (floor($LabelX) > floor($CenterX)) && (floor($LabelY) > floor($CenterY)) ) { + $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_TOPLEFT)); + } + if ( (floor($LabelX) < floor($CenterX)) && (floor($LabelY) < floor($CenterY)) ) { + $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_BOTTOMRIGHT)); + } + if ( (floor($LabelX) < floor($CenterX)) && (floor($LabelY) == floor($CenterY)) ) { + $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_MIDDLERIGHT)); + } + if ( (floor($LabelX) < floor($CenterX)) && (floor($LabelY) > floor($CenterY)) ) { + $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_TOPRIGHT)); + } + if ( (floor($LabelX) == floor($CenterX)) && (floor($LabelY) > floor($CenterY)) ) { + $Object->drawText($LabelX,$LabelY,$Label,array("Align"=>TEXT_ALIGN_TOPMIDDLE)); + } + } + } + $ID++; + } + + /* Compute the plots position */ + $ID = 0; $Plot = ""; + foreach($Data["Series"] as $SerieName => $DataSet) { + if ( $SerieName != $LabelSerie ) { + $Color = array( + "R"=>$Palette[$ID]["R"], + "G"=>$Palette[$ID]["G"], + "B"=>$Palette[$ID]["B"], + "Alpha"=>$Palette[$ID]["Alpha"], + "Surrounding"=>$PointSurrounding + ); + foreach($DataSet["Data"] as $Key => $Value) { + $Angle = $Data["Series"][$LabelSerie]["Data"][$Key]; + $Length = ($EdgeHeight/($Segments*$SegmentHeight))*$Value; + + $X = cos(deg2rad($Angle+$AxisRotation)) * $Length + $CenterX; + $Y = sin(deg2rad($Angle+$AxisRotation)) * $Length + $CenterY; + + if ( $RecordImageMap ) { + $this->pChartObject->addToImageMap( + "CIRCLE",floor($X).",".floor($Y).",".floor($PointRadius), + $this->pChartObject->toHTMLColor( + $Palette[$ID]["R"], + $Palette[$ID]["G"], + $Palette[$ID]["B"] + ), + $DataSet["Description"], + $Data["Series"][$LabelSerie]["Data"][$Key]."° = ".$Value + ); + } + + $Plot[$ID][] = array($X,$Y,$Value); + } + $ID++; + } + } + + /* Draw all that stuff! */ + foreach($Plot as $ID => $Points) { + $Color = array( + "R"=>$Palette[$ID]["R"], + "G"=>$Palette[$ID]["G"], + "B"=>$Palette[$ID]["B"], + "Alpha"=>$Palette[$ID]["Alpha"], + "Surrounding"=>$PointSurrounding + ); + + /* Draw the polygons */ + if ( $DrawPoly ) { + if ($PolyAlpha != null) { + $Color = array( + "R"=>$Palette[$ID]["R"], + "G"=>$Palette[$ID]["G"], + "B"=>$Palette[$ID]["B"], + "Alpha"=>$PolyAlpha, + "Surrounding"=>$PointSurrounding + ); + } + $PointsArray = ""; + for ($i=0; $idrawPolygon($PointsArray,$Color); + } + + $Color = array( + "R"=>$Palette[$ID]["R"], + "G"=>$Palette[$ID]["G"], + "B"=>$Palette[$ID]["B"], + "Alpha"=>$Palette[$ID]["Alpha"], + "Surrounding"=>$PointSurrounding + ); + + /* Bubble and labels settings */ + $TextSettings = array( + "Align"=>TEXT_ALIGN_MIDDLEMIDDLE, + "FontName"=>$ValueFontName, + "FontSize"=>$ValueFontSize, + "R"=>$Palette[$ID]["R"], + "G"=>$Palette[$ID]["G"], + "B"=>$Palette[$ID]["B"] + ); + $InnerColor = array( + "R"=>$InnerBubbleR, + "G"=>$InnerBubbleG, + "B"=>$InnerBubbleB, + "Alpha"=>$InnerBubbleAlpha + ); + if ( $OuterBubbleR != VOID ) { + $OuterColor = array( + "R"=>$OuterBubbleR, + "G"=>$OuterBubbleG, + "B"=>$OuterBubbleB, + "Alpha"=>$OuterBubbleAlpha + ); + } else { + $OuterColor = array( + "R"=>$Palette[$ID]["R"]+20, + "G"=>$Palette[$ID]["G"]+20, + "B"=>$Palette[$ID]["B"]+20, + "Alpha"=>$Palette[$ID]["Alpha"] + ); + } + /* Loop to the starting points if asked */ + if ( $LineLoopStart && $DrawLines ) { + $Object->drawLine( + $Points[count($Points)-1][0], + $Points[count($Points)-1][1], + $Points[0][0], + $Points[0][1], + $Color + ); + } + /* Draw the lines & points */ + for ($i=0; $idrawLine( + $Points[$i][0], + $Points[$i][1], + $Points[$i+1][0], + $Points[$i+1][1], + $Color + ); + } + if ( $DrawPoints ) { + $Object->drawFilledCircle( + $Points[$i][0], + $Points[$i][1], + $PointRadius, + $Color + ); + } + if ( $WriteValuesInBubble && $WriteValues ) { + $TxtPos = $this->pChartObject->getTextBox( + $Points[$i][0], + $Points[$i][1], + $ValueFontName, + $ValueFontSize, + 0, + $Points[$i][2] + ); + $Radius = floor(($TxtPos[1]["X"] - $TxtPos[0]["X"] + $ValuePadding*2)/2); + + $this->pChartObject->drawFilledCircle($Points[$i][0],$Points[$i][1],$Radius+$OuterBubbleRadius,$OuterColor); + $this->pChartObject->drawFilledCircle($Points[$i][0],$Points[$i][1],$Radius,$InnerColor); + } + + if ( $WriteValues ) { + $this->pChartObject->drawText($Points[$i][0]-1,$Points[$i][1]-1,$Points[$i][2],$TextSettings); + } + } + } + } +} diff --git a/vendor/szymach/c-pchart/src/Classes/pScatter.php b/vendor/szymach/c-pchart/src/Classes/pScatter.php new file mode 100644 index 0000000000..2bf942c185 --- /dev/null +++ b/vendor/szymach/c-pchart/src/Classes/pScatter.php @@ -0,0 +1,2013 @@ +pChartObject = $pChartObject; + $this->pDataObject = $pDataObject; + } + + /* Prepare the scale */ + public function drawScatterScale($Format="") + { + $Mode = isset($Format["Mode"]) ? $Format["Mode"] : SCALE_MODE_FLOATING; + $Floating = isset($Format["Floating"]) ? $Format["Floating"] : false; + $XLabelsRotation = isset($Format["XLabelsRotation"]) ? $Format["XLabelsRotation"] : 90; + $MinDivHeight = isset($Format["MinDivHeight"]) ? $Format["MinDivHeight"] : 20; + $Factors = isset($Format["Factors"]) ? $Format["Factors"] : array(1,2,5); + $ManualScale = isset($Format["ManualScale"]) ? $Format["ManualScale"] : array("0"=>array("Min"=>-100,"Max"=>100)); + $XMargin = isset($Format["XMargin"]) ? $Format["XMargin"] : 0; + $YMargin = isset($Format["YMargin"]) ? $Format["YMargin"] : 0; + $ScaleSpacing = isset($Format["ScaleSpacing"]) ? $Format["ScaleSpacing"] : 15; + $InnerTickWidth = isset($Format["InnerTickWidth"]) ? $Format["InnerTickWidth"] : 2; + $OuterTickWidth = isset($Format["OuterTickWidth"]) ? $Format["OuterTickWidth"] : 2; + $DrawXLines = isset($Format["DrawXLines"]) ? $Format["DrawXLines"] : ALL; + $DrawYLines = isset($Format["DrawYLines"]) ? $Format["DrawYLines"] : ALL; + $GridTicks = isset($Format["GridTicks"]) ? $Format["GridTicks"] : 4; + $GridR = isset($Format["GridR"]) ? $Format["GridR"] : 255; + $GridG = isset($Format["GridG"]) ? $Format["GridG"] : 255; + $GridB = isset($Format["GridB"]) ? $Format["GridB"] : 255; + $GridAlpha = isset($Format["GridAlpha"]) ? $Format["GridAlpha"] : 40; + $AxisRo = isset($Format["AxisR"]) ? $Format["AxisR"] : 0; + $AxisGo = isset($Format["AxisG"]) ? $Format["AxisG"] : 0; + $AxisBo = isset($Format["AxisB"]) ? $Format["AxisB"] : 0; + $AxisAlpha = isset($Format["AxisAlpha"]) ? $Format["AxisAlpha"] : 100; + $TickRo = isset($Format["TickR"]) ? $Format["TickR"] : 0; + $TickGo = isset($Format["TickG"]) ? $Format["TickG"] : 0; + $TickBo = isset($Format["TickB"]) ? $Format["TickB"] : 0; + $TickAlpha = isset($Format["TickAlpha"]) ? $Format["TickAlpha"] : 100; + $DrawSubTicks = isset($Format["DrawSubTicks"]) ? $Format["DrawSubTicks"] : false; + $InnerSubTickWidth = isset($Format["InnerSubTickWidth"]) ? $Format["InnerSubTickWidth"] : 0; + $OuterSubTickWidth = isset($Format["OuterSubTickWidth"]) ? $Format["OuterSubTickWidth"] : 2; + $SubTickR = isset($Format["SubTickR"]) ? $Format["SubTickR"] : 255; + $SubTickG = isset($Format["SubTickG"]) ? $Format["SubTickG"] : 0; + $SubTickB = isset($Format["SubTickB"]) ? $Format["SubTickB"] : 0; + $SubTickAlpha = isset($Format["SubTickAlpha"]) ? $Format["SubTickAlpha"] : 100; + $XReleasePercent = isset($Format["XReleasePercent"]) ? $Format["XReleasePercent"] : 1; + $DrawArrows = isset($Format["DrawArrows"]) ? $Format["DrawArrows"] : false; + $ArrowSize = isset($Format["ArrowSize"]) ? $Format["ArrowSize"] : 8; + $CycleBackground = isset($Format["CycleBackground"]) ? $Format["CycleBackground"] : false; + $BackgroundR1 = isset($Format["BackgroundR1"]) ? $Format["BackgroundR1"] : 255; + $BackgroundG1 = isset($Format["BackgroundG1"]) ? $Format["BackgroundG1"] : 255; + $BackgroundB1 = isset($Format["BackgroundB1"]) ? $Format["BackgroundB1"] : 255; + $BackgroundAlpha1 = isset($Format["BackgroundAlpha1"]) ? $Format["BackgroundAlpha1"] : 10; + $BackgroundR2 = isset($Format["BackgroundR2"]) ? $Format["BackgroundR2"] : 230; + $BackgroundG2 = isset($Format["BackgroundG2"]) ? $Format["BackgroundG2"] : 230; + $BackgroundB2 = isset($Format["BackgroundB2"]) ? $Format["BackgroundB2"] : 230; + $BackgroundAlpha2 = isset($Format["BackgroundAlpha2"]) ? $Format["BackgroundAlpha2"] : 10; + + /* Check if we have at least both one X and Y axis */ + $GotXAxis = false; $GotYAxis = false; + foreach($this->pDataObject->Data["Axis"] as $AxisID => $AxisSettings) { + if ( $AxisSettings["Identity"] == AXIS_X ) { + $GotXAxis = true; + } + if ( $AxisSettings["Identity"] == AXIS_Y ) { + $GotYAxis = true; + } + } + if ( !$GotXAxis ) { + return(SCATTER_MISSING_X_SERIE); + } + if ( !$GotYAxis ) { + return(SCATTER_MISSING_Y_SERIE); + } + + /* Skip a NOTICE event in case of an empty array */ + if ( $DrawYLines == NONE ) { + $DrawYLines = array("zarma"=>"31"); + } + + $Data = $this->pDataObject->getData(); + + foreach($Data["Axis"] as $AxisID => $AxisSettings) { + if ( $AxisSettings["Identity"] == AXIS_X) { + $Width = $this->pChartObject->GraphAreaX2 - $this->pChartObject->GraphAreaX1 - $XMargin*2; + } else { + $Width = $this->pChartObject->GraphAreaY2 - $this->pChartObject->GraphAreaY1 - $YMargin*2; + } + + $AxisMin = ABSOLUTE_MAX; $AxisMax = OUT_OF_SIGHT; + if ( $Mode == SCALE_MODE_FLOATING ) { + foreach($Data["Series"] as $SerieID => $SerieParameter) { + if ($SerieParameter["Axis"] == $AxisID + && $Data["Series"][$SerieID]["isDrawable"] + ) { + $AxisMax = max($AxisMax,$Data["Series"][$SerieID]["Max"]); + $AxisMin = min($AxisMin,$Data["Series"][$SerieID]["Min"]); + } + } + $AutoMargin = (($AxisMax-$AxisMin)/100)*$XReleasePercent; + + $Data["Axis"][$AxisID]["Min"] = $AxisMin-$AutoMargin; + $Data["Axis"][$AxisID]["Max"] = $AxisMax+$AutoMargin; + } elseif ( $Mode == SCALE_MODE_MANUAL ) { + if (isset($ManualScale[$AxisID]["Min"]) + && isset($ManualScale[$AxisID]["Max"]) + ) { + $Data["Axis"][$AxisID]["Min"] = $ManualScale[$AxisID]["Min"]; + $Data["Axis"][$AxisID]["Max"] = $ManualScale[$AxisID]["Max"]; + } else { + throw new \Exception("Manual scale boundaries not set."); + } + } + + /* Full manual scale */ + if ( isset($ManualScale[$AxisID]["Rows"]) && isset($ManualScale[$AxisID]["RowHeight"]) ) { + $Scale = array( + "Rows"=>$ManualScale[$AxisID]["Rows"], + "RowHeight"=>$ManualScale[$AxisID]["RowHeight"], + "XMin"=>$ManualScale[$AxisID]["Min"], + "XMax"=>$ManualScale[$AxisID]["Max"] + ); + } else { + $MaxDivs = floor($Width/$MinDivHeight); + $Scale = $this->pChartObject->computeScale( + $Data["Axis"][$AxisID]["Min"], + $Data["Axis"][$AxisID]["Max"], + $MaxDivs, + $Factors, + $AxisID + ); + } + + $Data["Axis"][$AxisID]["Margin"] = $AxisSettings["Identity"] == AXIS_X ? $XMargin : $YMargin; + $Data["Axis"][$AxisID]["ScaleMin"] = $Scale["XMin"]; + $Data["Axis"][$AxisID]["ScaleMax"] = $Scale["XMax"]; + $Data["Axis"][$AxisID]["Rows"] = $Scale["Rows"]; + $Data["Axis"][$AxisID]["RowHeight"] = $Scale["RowHeight"]; + + if ( isset($Scale["Format"]) ) { + $Data["Axis"][$AxisID]["Format"] = $Scale["Format"]; + } + + if ( !isset($Data["Axis"][$AxisID]["Display"]) ) { + $Data["Axis"][$AxisID]["Display"] = null; + } + if ( !isset($Data["Axis"][$AxisID]["Format"]) ) { + $Data["Axis"][$AxisID]["Format"] = null; + } + if ( !isset($Data["Axis"][$AxisID]["Unit"]) ) { + $Data["Axis"][$AxisID]["Unit"] = null; + } + } + + /* Get the default font color */ + $FontColorRo = $this->pChartObject->FontColorR; + $FontColorGo = $this->pChartObject->FontColorG; + $FontColorBo = $this->pChartObject->FontColorB; + + /* Set the original boundaries */ + $AxisPos["L"] = $this->pChartObject->GraphAreaX1; + $AxisPos["R"] = $this->pChartObject->GraphAreaX2; + $AxisPos["T"] = $this->pChartObject->GraphAreaY1; + $AxisPos["B"] = $this->pChartObject->GraphAreaY2; + + foreach($Data["Axis"] as $AxisID => $AxisSettings) { + if ( isset($AxisSettings["Color"]) ) { + $AxisR = $AxisSettings["Color"]["R"]; + $AxisG = $AxisSettings["Color"]["G"]; + $AxisB = $AxisSettings["Color"]["B"]; + $TickR = $AxisSettings["Color"]["R"]; + $TickG = $AxisSettings["Color"]["G"]; + $TickB = $AxisSettings["Color"]["B"]; + $this->pChartObject->setFontProperties( + array( + "R"=>$AxisSettings["Color"]["R"], + "G"=>$AxisSettings["Color"]["G"], + "B"=>$AxisSettings["Color"]["B"] + ) + ); + } else { + $AxisR = $AxisRo; $AxisG = $AxisGo; $AxisB = $AxisBo; + $TickR = $TickRo; $TickG = $TickGo; $TickB = $TickBo; + $this->pChartObject->setFontProperties(array("R"=>$FontColorRo,"G"=>$FontColorGo,"B"=>$FontColorBo)); + } + + $LastValue = "w00t"; $ID = 1; + if ( $AxisSettings["Identity"] == AXIS_X ) { + if ( $AxisSettings["Position"] == AXIS_POSITION_BOTTOM ) { + if ( $XLabelsRotation == 0 ) { + $LabelAlign = TEXT_ALIGN_TOPMIDDLE; + $LabelOffset = 2; + } + if ( $XLabelsRotation > 0 && $XLabelsRotation < 190 ) { + $LabelAlign = TEXT_ALIGN_MIDDLERIGHT; + $LabelOffset = 5; + } + if ( $XLabelsRotation == 180 ) { + $LabelAlign = TEXT_ALIGN_BOTTOMMIDDLE; + $LabelOffset = 5; + } + if ( $XLabelsRotation > 180 && $XLabelsRotation < 360 ) { + $LabelAlign = TEXT_ALIGN_MIDDLELEFT; + $LabelOffset = 2; + } + + if ( $Floating ) { + $FloatingOffset = $YMargin; + $this->pChartObject->drawLine( + $this->pChartObject->GraphAreaX1+$AxisSettings["Margin"], + $AxisPos["B"], + $this->pChartObject->GraphAreaX2-$AxisSettings["Margin"], + $AxisPos["B"], + array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + } else { + $FloatingOffset = 0; + $this->pChartObject->drawLine( + $this->pChartObject->GraphAreaX1, + $AxisPos["B"], + $this->pChartObject->GraphAreaX2, + $AxisPos["B"], + array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + } + + if ( $DrawArrows ) { + $this->pChartObject->drawArrow( + $this->pChartObject->GraphAreaX2-$AxisSettings["Margin"], + $AxisPos["B"],$this->pChartObject->GraphAreaX2+($ArrowSize*2), + $AxisPos["B"], + array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize) + ); + } + + $Width = ($this->pChartObject->GraphAreaX2 - $this->pChartObject->GraphAreaX1) - $AxisSettings["Margin"]*2; + $Step = $Width / $AxisSettings["Rows"]; $SubTicksSize = $Step /2; $MaxBottom = $AxisPos["B"]; + $LastX = null; + for ($i=0;$i<=$AxisSettings["Rows"];$i++) { + $XPos = $this->pChartObject->GraphAreaX1 + $AxisSettings["Margin"] + $Step*$i; + $YPos = $AxisPos["B"]; + $Value = $this->pChartObject->scaleFormat( + $AxisSettings["ScaleMin"] + $AxisSettings["RowHeight"]*$i, + $AxisSettings["Display"], + $AxisSettings["Format"], + $AxisSettings["Unit"] + ); + + if ( $i%2 == 1 ) { + $BGColor = array( + "R"=>$BackgroundR1, + "G"=>$BackgroundG1, + "B"=>$BackgroundB1, + "Alpha"=>$BackgroundAlpha1 + ); + } else { + $BGColor = array( + "R"=>$BackgroundR2, + "G"=>$BackgroundG2, + "B"=>$BackgroundB2, + "Alpha"=>$BackgroundAlpha2 + ); + } + if ( $LastX != null + && $CycleBackground + && ( $DrawXLines == ALL || in_array($AxisID,$DrawXLines) ) + ) { + $this->pChartObject->drawFilledRectangle( + $LastX, + $this->pChartObject->GraphAreaY1+$FloatingOffset, + $XPos, + $this->pChartObject->GraphAreaY2-$FloatingOffset, + $BGColor + ); + } + + if ( $DrawXLines == ALL || in_array($AxisID,$DrawXLines) ) { + $this->pChartObject->drawLine( + $XPos, + $this->pChartObject->GraphAreaY1+$FloatingOffset, + $XPos, + $this->pChartObject->GraphAreaY2-$FloatingOffset, + array("R"=>$GridR,"G"=>$GridG,"B"=>$GridB,"Alpha"=>$GridAlpha,"Ticks"=>$GridTicks) + ); + } + if ( $DrawSubTicks && $i != $AxisSettings["Rows"] ) { + $this->pChartObject->drawLine( + $XPos+$SubTicksSize, + $YPos-$InnerSubTickWidth, + $XPos+$SubTicksSize, + $YPos+$OuterSubTickWidth, + array("R"=>$SubTickR,"G"=>$SubTickG,"B"=>$SubTickB,"Alpha"=>$SubTickAlpha) + ); + } + $this->pChartObject->drawLine( + $XPos, + $YPos-$InnerTickWidth, + $XPos, + $YPos+$OuterTickWidth, + array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha) + ); + $Bounds = $this->pChartObject->drawText( + $XPos, + $YPos+$OuterTickWidth+$LabelOffset, + $Value,array("Angle"=>$XLabelsRotation,"Align"=>$LabelAlign) + ); + $TxtBottom = $YPos+2+$OuterTickWidth+2+($Bounds[0]["Y"]-$Bounds[2]["Y"]); + $MaxBottom = max($MaxBottom,$TxtBottom); + + $LastX = $XPos; + } + + if ( isset($AxisSettings["Name"]) ) { + $YPos = $MaxBottom+2; + $XPos = $this->pChartObject->GraphAreaX1 + +($this->pChartObject->GraphAreaX2-$this->pChartObject->GraphAreaX1)/2; + $Bounds = $this->pChartObject->drawText( + $XPos, + $YPos, + $AxisSettings["Name"], + array("Align"=>TEXT_ALIGN_TOPMIDDLE) + ); + $MaxBottom = $Bounds[0]["Y"]; + + $this->pDataObject->Data["GraphArea"]["Y2"] = $MaxBottom + $this->pChartObject->FontSize; + } + + $AxisPos["B"] = $MaxBottom + $ScaleSpacing; + } elseif ( $AxisSettings["Position"] == AXIS_POSITION_TOP ) { + if ( $XLabelsRotation == 0 ) { + $LabelAlign = TEXT_ALIGN_BOTTOMMIDDLE; + $LabelOffset = 2; + } + if ( $XLabelsRotation > 0 && $XLabelsRotation < 190 ) { + $LabelAlign = TEXT_ALIGN_MIDDLELEFT; + $LabelOffset = 2; + } + if ( $XLabelsRotation == 180 ) { + $LabelAlign = TEXT_ALIGN_TOPMIDDLE; + $LabelOffset = 5; + } + if ( $XLabelsRotation > 180 && $SLabelxRotation < 360 ) { + $LabelAlign = TEXT_ALIGN_MIDDLERIGHT; + $LabelOffset = 5; + } + + if ( $Floating ) { + $FloatingOffset = $YMargin; + $this->pChartObject->drawLine( + $this->pChartObject->GraphAreaX1+$AxisSettings["Margin"], + $AxisPos["T"],$this->pChartObject->GraphAreaX2-$AxisSettings["Margin"], + $AxisPos["T"],array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + } else { + $FloatingOffset = 0; + $this->pChartObject->drawLine( + $this->pChartObject->GraphAreaX1, + $AxisPos["T"], + $this->pChartObject->GraphAreaX2, + $AxisPos["T"],array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + } + + if ( $DrawArrows ) { + $this->pChartObject->drawArrow( + $this->pChartObject->GraphAreaX2-$AxisSettings["Margin"], + $AxisPos["T"], + $this->pChartObject->GraphAreaX2+($ArrowSize*2), + $AxisPos["T"], + array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize) + ); + } + + $Width = ($this->pChartObject->GraphAreaX2 + - $this->pChartObject->GraphAreaX1) + - $AxisSettings["Margin"]*2; + $Step = $Width / $AxisSettings["Rows"]; + $SubTicksSize = $Step /2; + $MinTop = $AxisPos["T"]; + $LastX = null; + for ($i=0;$i<=$AxisSettings["Rows"];$i++) { + $XPos = $this->pChartObject->GraphAreaX1 + $AxisSettings["Margin"] + $Step*$i; + $YPos = $AxisPos["T"]; + $Value = $this->pChartObject->scaleFormat( + $AxisSettings["ScaleMin"] + $AxisSettings["RowHeight"]*$i, + $AxisSettings["Display"], + $AxisSettings["Format"], + $AxisSettings["Unit"] + ); + + if ( $i%2 == 1 ) { + $BGColor = array( + "R"=>$BackgroundR1, + "G"=>$BackgroundG1, + "B"=>$BackgroundB1, + "Alpha"=>$BackgroundAlpha1 + ); + } else { + $BGColor = array( + "R"=>$BackgroundR2, + "G"=>$BackgroundG2, + "B"=>$BackgroundB2, + "Alpha"=>$BackgroundAlpha2 + ); + } + if ( $LastX != null + && $CycleBackground + && ( $DrawXLines == ALL || in_array($AxisID,$DrawXLines) ) + ) { + $this->pChartObject->drawFilledRectangle( + $LastX, + $this->pChartObject->GraphAreaY1+$FloatingOffset, + $XPos, + $this->pChartObject->GraphAreaY2-$FloatingOffset, + $BGColor + ); + } + + if ( $DrawXLines == ALL || in_array($AxisID,$DrawXLines) ) { + $this->pChartObject->drawLine( + $XPos, + $this->pChartObject->GraphAreaY1+$FloatingOffset, + $XPos,$this->pChartObject->GraphAreaY2-$FloatingOffset, + array("R"=>$GridR,"G"=>$GridG,"B"=>$GridB,"Alpha"=>$GridAlpha,"Ticks"=>$GridTicks) + ); + } + + if ( $DrawSubTicks && $i != $AxisSettings["Rows"] ) { + $this->pChartObject->drawLine( + $XPos+$SubTicksSize, + $YPos-$OuterSubTickWidth, + $XPos+$SubTicksSize, + $YPos+$InnerSubTickWidth, + array("R"=>$SubTickR,"G"=>$SubTickG,"B"=>$SubTickB,"Alpha"=>$SubTickAlpha) + ); + } + $this->pChartObject->drawLine( + $XPos, + $YPos-$OuterTickWidth, + $XPos, + $YPos+$InnerTickWidth, + array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha) + ); + $Bounds = $this->pChartObject->drawText( + $XPos, + $YPos-$OuterTickWidth-$LabelOffset, + $Value, + array("Angle"=>$XLabelsRotation,"Align"=>$LabelAlign) + ); + $TxtBox = $YPos-$OuterTickWidth-4-($Bounds[0]["Y"]-$Bounds[2]["Y"]); + $MinTop = min($MinTop,$TxtBox); + + $LastX = $XPos; + } + + if ( isset($AxisSettings["Name"]) ) { + $YPos = $MinTop-2; + $XPos = $this->pChartObject->GraphAreaX1 + +($this->pChartObject->GraphAreaX2-$this->pChartObject->GraphAreaX1)/2; + $Bounds = $this->pChartObject->drawText( + $XPos, + $YPos, + $AxisSettings["Name"], + array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE) + ); + $MinTop = $Bounds[2]["Y"]; + + $this->pDataObject->Data["GraphArea"]["Y1"] = $MinTop; + } + + $AxisPos["T"] = $MinTop - $ScaleSpacing; + } + } elseif ( $AxisSettings["Identity"] == AXIS_Y ) { + if ( $AxisSettings["Position"] == AXIS_POSITION_LEFT ) { + + if ( $Floating ) { + $FloatingOffset = $XMargin; + $this->pChartObject->drawLine( + $AxisPos["L"], + $this->pChartObject->GraphAreaY1+$AxisSettings["Margin"], + $AxisPos["L"], + $this->pChartObject->GraphAreaY2-$AxisSettings["Margin"], + array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + } else { + $FloatingOffset = 0; + $this->pChartObject->drawLine( + $AxisPos["L"], + $this->pChartObject->GraphAreaY1, + $AxisPos["L"], + $this->pChartObject->GraphAreaY2, + array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + } + + if ( $DrawArrows ) { + $this->pChartObject->drawArrow( + $AxisPos["L"], + $this->pChartObject->GraphAreaY1+$AxisSettings["Margin"], + $AxisPos["L"], + $this->pChartObject->GraphAreaY1-($ArrowSize*2), + array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize) + ); + } + + $Height = ($this->pChartObject->GraphAreaY2 - $this->pChartObject->GraphAreaY1) - $AxisSettings["Margin"]*2; + $Step = $Height / $AxisSettings["Rows"]; $SubTicksSize = $Step /2; $MinLeft = $AxisPos["L"]; + $LastY = null; + for($i=0;$i<=$AxisSettings["Rows"];$i++) { + $YPos = $this->pChartObject->GraphAreaY2 - $AxisSettings["Margin"] - $Step*$i; + $XPos = $AxisPos["L"]; + $Value = $this->pChartObject->scaleFormat( + $AxisSettings["ScaleMin"] + $AxisSettings["RowHeight"]*$i, + $AxisSettings["Display"], + $AxisSettings["Format"], + $AxisSettings["Unit"] + ); + + if ( $i%2 == 1 ) { + $BGColor = array( + "R"=>$BackgroundR1, + "G"=>$BackgroundG1, + "B"=>$BackgroundB1, + "Alpha"=>$BackgroundAlpha1 + ); + } else { + $BGColor = array( + "R"=>$BackgroundR2, + "G"=>$BackgroundG2, + "B"=>$BackgroundB2, + "Alpha"=>$BackgroundAlpha2 + ); + } + if ($LastY != null + && $CycleBackground + && ( $DrawYLines == ALL || in_array($AxisID,$DrawYLines) ) + ) { + $this->pChartObject->drawFilledRectangle( + $this->pChartObject->GraphAreaX1+$FloatingOffset, + $LastY, + $this->pChartObject->GraphAreaX2-$FloatingOffset, + $YPos, + $BGColor + ); + } + + if (($YPos != $this->pChartObject->GraphAreaY1 + && $YPos != $this->pChartObject->GraphAreaY2) + && ($DrawYLines == ALL || in_array($AxisID,$DrawYLines) ) + ) { + $this->pChartObject->drawLine( + $this->pChartObject->GraphAreaX1+$FloatingOffset, + $YPos, + $this->pChartObject->GraphAreaX2-$FloatingOffset, + $YPos, + array("R"=>$GridR,"G"=>$GridG,"B"=>$GridB,"Alpha"=>$GridAlpha,"Ticks"=>$GridTicks) + ); + } + + if ( $DrawSubTicks && $i != $AxisSettings["Rows"] ) { + $this->pChartObject->drawLine($XPos-$OuterSubTickWidth,$YPos-$SubTicksSize,$XPos+$InnerSubTickWidth,$YPos-$SubTicksSize,array("R"=>$SubTickR,"G"=>$SubTickG,"B"=>$SubTickB,"Alpha"=>$SubTickAlpha)); + } + $this->pChartObject->drawLine($XPos-$OuterTickWidth,$YPos,$XPos+$InnerTickWidth,$YPos,array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha)); + $Bounds = $this->pChartObject->drawText($XPos-$OuterTickWidth-2,$YPos,$Value,array("Align"=>TEXT_ALIGN_MIDDLERIGHT)); + $TxtLeft = $XPos-$OuterTickWidth-2-($Bounds[1]["X"]-$Bounds[0]["X"]); + $MinLeft = min($MinLeft,$TxtLeft); + + $LastY = $YPos; + } + + if ( isset($AxisSettings["Name"]) ) { + $XPos = $MinLeft-2; + $YPos = $this->pChartObject->GraphAreaY1 + +($this->pChartObject->GraphAreaY2-$this->pChartObject->GraphAreaY1)/2; + $Bounds = $this->pChartObject->drawText( + $XPos, + $YPos, + $AxisSettings["Name"], + array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE, "Angle"=>90) + ); + $MinLeft = $Bounds[2]["X"]; + + $this->pDataObject->Data["GraphArea"]["X1"] = $MinLeft; + } + + $AxisPos["L"] = $MinLeft - $ScaleSpacing; + } elseif ( $AxisSettings["Position"] == AXIS_POSITION_RIGHT ) { + if ( $Floating ) { + $FloatingOffset = $XMargin; + $this->pChartObject->drawLine( + $AxisPos["R"], + $this->pChartObject->GraphAreaY1+$AxisSettings["Margin"], + $AxisPos["R"], + $this->pChartObject->GraphAreaY2-$AxisSettings["Margin"], + array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + } else { + $FloatingOffset = 0; + $this->pChartObject->drawLine( + $AxisPos["R"], + $this->pChartObject->GraphAreaY1, + $AxisPos["R"], + $this->pChartObject->GraphAreaY2, + array("R"=>$AxisR,"G"=>$AxisG,"B"=>$AxisB,"Alpha"=>$AxisAlpha) + ); + } + + if ( $DrawArrows ) { + $this->pChartObject->drawArrow( + $AxisPos["R"], + $this->pChartObject->GraphAreaY1+$AxisSettings["Margin"], + $AxisPos["R"],$this->pChartObject->GraphAreaY1-($ArrowSize*2), + array("FillR"=>$AxisR,"FillG"=>$AxisG,"FillB"=>$AxisB,"Size"=>$ArrowSize) + ); + } + + $Height = ($this->pChartObject->GraphAreaY2 - $this->pChartObject->GraphAreaY1) + - $AxisSettings["Margin"]*2; + $Step = $Height / $AxisSettings["Rows"]; + $SubTicksSize = $Step /2; $MaxLeft = $AxisPos["R"]; + $LastY = null; + for ($i=0;$i<=$AxisSettings["Rows"];$i++) { + $YPos = $this->pChartObject->GraphAreaY2 - $AxisSettings["Margin"] - $Step*$i; + $XPos = $AxisPos["R"]; + $Value = $this->pChartObject->scaleFormat( + $AxisSettings["ScaleMin"] + $AxisSettings["RowHeight"]*$i, + $AxisSettings["Display"], + $AxisSettings["Format"], + $AxisSettings["Unit"] + ); + + if ( $i%2 == 1 ) { + $BGColor = array( + "R"=>$BackgroundR1, + "G"=>$BackgroundG1, + "B"=>$BackgroundB1, + "Alpha"=>$BackgroundAlpha1 + ); + } else { + $BGColor = array( + "R"=>$BackgroundR2, + "G"=>$BackgroundG2, + "B"=>$BackgroundB2, + "Alpha"=>$BackgroundAlpha2 + ); + } + if ($LastY != null + && $CycleBackground + && ( $DrawYLines == ALL || in_array($AxisID,$DrawYLines) ) + ) { + $this->pChartObject->drawFilledRectangle( + $this->pChartObject->GraphAreaX1+$FloatingOffset, + $LastY, + $this->pChartObject->GraphAreaX2-$FloatingOffset, + $YPos, + $BGColor + ); + } + + if (($YPos != $this->pChartObject->GraphAreaY1 + && $YPos != $this->pChartObject->GraphAreaY2) + && ($DrawYLines == ALL || in_array($AxisID,$DrawYLines)) + ) { + $this->pChartObject->drawLine( + $this->pChartObject->GraphAreaX1+$FloatingOffset, + $YPos, + $this->pChartObject->GraphAreaX2-$FloatingOffset, + $YPos, + array("R"=>$GridR,"G"=>$GridG,"B"=>$GridB,"Alpha"=>$GridAlpha,"Ticks"=>$GridTicks) + ); + } + + if ( $DrawSubTicks && $i != $AxisSettings["Rows"] ) { + $this->pChartObject->drawLine( + $XPos-$InnerSubTickWidth, + $YPos-$SubTicksSize, + $XPos+$OuterSubTickWidth, + $YPos-$SubTicksSize, + array("R"=>$SubTickR,"G"=>$SubTickG,"B"=>$SubTickB,"Alpha"=>$SubTickAlpha) + ); + } + $this->pChartObject->drawLine( + $XPos-$InnerTickWidth, + $YPos, + $XPos+$OuterTickWidth, + $YPos, + array("R"=>$TickR,"G"=>$TickG,"B"=>$TickB,"Alpha"=>$TickAlpha) + ); + $Bounds = $this->pChartObject->drawText( + $XPos+$OuterTickWidth+2, + $YPos, + $Value, + array("Align"=>TEXT_ALIGN_MIDDLELEFT) + ); + $TxtLeft = $XPos+$OuterTickWidth+2+($Bounds[1]["X"]-$Bounds[0]["X"]); + $MaxLeft = max($MaxLeft,$TxtLeft); + + $LastY = $YPos; + } + + if ( isset($AxisSettings["Name"]) ) { + $XPos = $MaxLeft+6; + $YPos = $this->pChartObject->GraphAreaY1 + + ($this->pChartObject->GraphAreaY2-$this->pChartObject->GraphAreaY1)/2; + $Bounds = $this->pChartObject->drawText( + $XPos, + $YPos, + $AxisSettings["Name"], + array("Align"=>TEXT_ALIGN_BOTTOMMIDDLE,"Angle"=>270) + ); + $MaxLeft = $Bounds[2]["X"]; + + $this->pDataObject->Data["GraphArea"]["X2"] = $MaxLeft + $this->pChartObject->FontSize; + } + + $AxisPos["R"] = $MaxLeft + $ScaleSpacing; + } + } + } + + $this->pDataObject->saveAxisConfig($Data["Axis"]); + } + + /** + * Draw a scatter plot chart + * @param type $Format + */ + public function drawScatterPlotChart($Format=null) + { + $PlotSize = isset($Format["PlotSize"]) ? $Format["PlotSize"] : 3; + $PlotBorder = isset($Format["PlotBorder"]) ? $Format["PlotBorder"] : false; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 250; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 250; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 250; + $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : 30; + $BorderSize = isset($Format["BorderSize"]) ? $Format["BorderSize"] : 1; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : null; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : false; + $ImageMapTitle = isset($Format["ImageMapTitle"]) ? $Format["ImageMapTitle"] : null; + $ImageMapPrecision = isset($Format["ImageMapPrecision"]) ? $Format["ImageMapPrecision"] : 2; + + $Data = $this->pDataObject->getData(); + $Palette = $this->pDataObject->getPalette(); + + $BorderColor = array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha); + + foreach($Data["ScatterSeries"] as $Key => $Series) { + if ( $Series["isDrawable"] == true ) { + $SerieX = $Series["X"]; + $SerieValuesX = $Data["Series"][$SerieX]["Data"]; + $SerieXAxis = $Data["Series"][$SerieX]["Axis"]; + $SerieY = $Series["Y"]; + $SerieValuesY = $Data["Series"][$SerieY]["Data"]; + $SerieYAxis = $Data["Series"][$SerieY]["Axis"]; + + if ( $ImageMapTitle == null ) { + $Description = $Data["Series"][$Series["X"]]["Description"] + ." / ".$Data["Series"][$Series["Y"]]["Description"]; + } else { + $Description = $ImageMapTitle; + } + + if ( isset($Series["Picture"]) && $Series["Picture"] != "" ) { + $Picture = $Series["Picture"]; + list($PicWidth,$PicHeight,$PicType) = $this->pChartObject->getPicInfo($Picture); + } else { + $Picture = null; + } + + $PosArrayX = $this->getPosArray($SerieValuesX,$SerieXAxis); + if ( !is_array($PosArrayX) ) { + $Value = $PosArrayX; + $PosArrayX = ""; + $PosArrayX[0] = $Value; + } + $PosArrayY = $this->getPosArray($SerieValuesY,$SerieYAxis); + if ( !is_array($PosArrayY) ) { + $Value = $PosArrayY; + $PosArrayY = ""; + $PosArrayY[0] = $Value; + } + + $Color = array( + "R"=>$Series["Color"]["R"], + "G"=>$Series["Color"]["G"], + "B"=>$Series["Color"]["B"], + "Alpha"=>$Series["Color"]["Alpha"] + ); + + foreach($PosArrayX as $Key => $Value) { + $X = $Value; + $Y = $PosArrayY[$Key]; + + if ( $X != VOID && $Y != VOID ) { + $RealValue = round( + $Data["Series"][$Series["X"]]["Data"][$Key],2)." / " + .round($Data["Series"][$Series["Y"]]["Data"][$Key], + 2 + ); + if ($RecordImageMap ) { + $this->pChartObject->addToImageMap( + "CIRCLE", + floor($X).",".floor($Y).",".floor($PlotSize+$BorderSize), + $this->pChartObject->toHTMLColor( + $Series["Color"]["R"], + $Series["Color"]["G"], + $Series["Color"]["B"] + ), + $Description, + $RealValue + ); + } + + if( isset($Series["Shape"]) ) { + $this->pChartObject->drawShape( + $X, + $Y, + $Series["Shape"], + $PlotSize, + $PlotBorder, + $BorderSize, + $Series["Color"]["R"], + $Series["Color"]["G"], + $Series["Color"]["B"], + $Series["Color"]["Alpha"], + $BorderR, + $BorderG, + $BorderB, + $BorderAlpha + ); + } elseif ( $Picture == null ) { + if ( $PlotBorder ) { + $this->pChartObject->drawFilledCircle($X,$Y,$PlotSize+$BorderSize,$BorderColor); + } + $this->pChartObject->drawFilledCircle($X,$Y,$PlotSize,$Color); + } else { + $this->pChartObject->drawFromPicture($PicType,$Picture,$X-$PicWidth/2,$Y-$PicHeight/2); + } + } + } + } + } + } + + /** + * Draw a scatter line chart + * @param type $Format + */ + public function drawScatterLineChart($Format=null) + { + $Data = $this->pDataObject->getData(); + $Palette = $this->pDataObject->getPalette(); + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : false; + $ImageMapTitle = isset($Format["ImageMapTitle"]) ? $Format["ImageMapTitle"] : null; + $ImageMapPlotSize = isset($Format["ImageMapPlotSize"]) ? $Format["ImageMapPlotSize"] : 10; + $ImageMapPrecision = isset($Format["ImageMapPrecision"]) ? $Format["ImageMapPrecision"] : 2; + + /* Parse all the series to draw */ + foreach($Data["ScatterSeries"] as $Key => $Series) { + if ( $Series["isDrawable"] == true ) { + $SerieX = $Series["X"]; + $SerieValuesX = $Data["Series"][$SerieX]["Data"]; + $SerieXAxis = $Data["Series"][$SerieX]["Axis"]; + $SerieY = $Series["Y"]; + $SerieValuesY = $Data["Series"][$SerieY]["Data"]; + $SerieYAxis = $Data["Series"][$SerieY]["Axis"]; + $Ticks = $Series["Ticks"]; + $Weight = $Series["Weight"]; + + if ($ImageMapTitle == null ) { + $Description = $Data["Series"][$Series["X"]]["Description"] + ." / ".$Data["Series"][$Series["Y"]]["Description"]; + } else { + $Description = $ImageMapTitle; + } + + $PosArrayX = $this->getPosArray($SerieValuesX,$SerieXAxis); + if (!is_array($PosArrayX) ) { + $Value = $PosArrayX; + $PosArrayX = ""; + $PosArrayX[0] = $Value; + } + $PosArrayY = $this->getPosArray($SerieValuesY,$SerieYAxis); + if (!is_array($PosArrayY) ) { + $Value = $PosArrayY; + $PosArrayY = ""; + $PosArrayY[0] = $Value; + } + + $Color = array( + "R"=>$Series["Color"]["R"], + "G"=>$Series["Color"]["G"], + "B"=>$Series["Color"]["B"], + "Alpha"=>$Series["Color"]["Alpha"] + ); + if ( $Ticks != 0 ) { + $Color["Ticks"] = $Ticks; + } + if ( $Weight != 0 ) { + $Color["Weight"] = $Weight; + } + + $LastX = VOID; $LastY = VOID; + foreach($PosArrayX as $Key => $Value) { + $X = $Value; $Y = $PosArrayY[$Key]; + + if ( $X != VOID && $Y != VOID ) { + $RealValue = round($Data["Series"][$Series["X"]]["Data"][$Key],2) + ." / ".round($Data["Series"][$Series["Y"]]["Data"][$Key],2); + if ( $RecordImageMap ) { + $this->pChartObject->addToImageMap( + "CIRCLE", + floor($X).",".floor($Y).",".$ImageMapPlotSize, + $this->pChartObject->toHTMLColor( + $Series["Color"]["R"], + $Series["Color"]["G"], + $Series["Color"]["B"] + ), + $Description, + $RealValue + ); + } + } + + if ( $X != VOID && $Y != VOID && $LastX != VOID && $LastY != VOID) { + $this->pChartObject->drawLine($LastX,$LastY,$X,$Y,$Color); + } + $LastX = $X; $LastY = $Y; + } + } + } + } + + /** + * Draw a scatter spline chart + * @param type $Format + */ + public function drawScatterSplineChart($Format=null) + { + $Data = $this->pDataObject->getData(); + $Palette = $this->pDataObject->getPalette(); + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : false; + $ImageMapTitle = isset($Format["ImageMapTitle"]) ? $Format["ImageMapTitle"] : null; + $ImageMapPlotSize = isset($Format["ImageMapPlotSize"]) ? $Format["ImageMapPlotSize"] : 10; + $ImageMapPrecision = isset($Format["ImageMapPrecision"]) ? $Format["ImageMapPrecision"] : 2; + + foreach($Data["ScatterSeries"] as $Key => $Series) { + if ( $Series["isDrawable"] == true ) { + $SerieX = $Series["X"]; + $SerieValuesX = $Data["Series"][$SerieX]["Data"]; + $SerieXAxis = $Data["Series"][$SerieX]["Axis"]; + $SerieY = $Series["Y"]; + $SerieValuesY = $Data["Series"][$SerieY]["Data"]; + $SerieYAxis = $Data["Series"][$SerieY]["Axis"]; + $Ticks = $Series["Ticks"]; + $Weight = $Series["Weight"]; + + if ( $ImageMapTitle == null ) { + $Description = $Data["Series"][$Series["X"]]["Description"] + ." / ".$Data["Series"][$Series["Y"]]["Description"]; + } else { + $Description = $ImageMapTitle; + } + + $PosArrayX = $this->getPosArray($SerieValuesX,$SerieXAxis); + if ( !is_array($PosArrayX) ) { + $Value = $PosArrayX; + $PosArrayX = ""; + $PosArrayX[0] = $Value; + } + $PosArrayY = $this->getPosArray($SerieValuesY,$SerieYAxis); + if ( !is_array($PosArrayY) ) { + $Value = $PosArrayY; + $PosArrayY = ""; + $PosArrayY[0] = $Value; + } + + $SplineSettings = array( + "R"=>$Series["Color"]["R"], + "G"=>$Series["Color"]["G"], + "B"=>$Series["Color"]["B"], + "Alpha"=>$Series["Color"]["Alpha"] + ); + if ($Ticks != 0) { + $SplineSettings["Ticks"] = $Ticks; + } + if ($Weight != 0) { + $SplineSettings["Weight"] = $Weight; + } + + $LastX = VOID; + $LastY = VOID; + $WayPoints = ""; + $Forces = ""; + foreach($PosArrayX as $Key => $Value) { + $X = $Value; $Y = $PosArrayY[$Key]; + $Force = $this->pChartObject->getLength($LastX,$LastY,$X,$Y)/5; + + if ( $X != VOID && $Y != VOID ) { + $RealValue = round($Data["Series"][$Series["X"]]["Data"][$Key],2) + ." / ".round($Data["Series"][$Series["Y"]]["Data"][$Key],2); + if ($RecordImageMap) { + $this->pChartObject->addToImageMap( + "CIRCLE", + floor($X).",".floor($Y).",".$ImageMapPlotSize, + $this->pChartObject->toHTMLColor( + $Series["Color"]["R"], + $Series["Color"]["G"], + $Series["Color"]["B"] + ), + $Description, + $RealValue + ); + } + } + + if ( $X != VOID && $Y != VOID ) { + $WayPoints[] = array($X,$Y); + $Forces[] = $Force; + } + + if ( $Y == VOID || $X == VOID ) { + $SplineSettings["Forces"] = $Forces; + $this->pChartObject->drawSpline($WayPoints,$SplineSettings); + $WayPoints = ""; + $Forces = ""; + } + + $LastX = $X; + $LastY = $Y; + } + $SplineSettings["Forces"] = $Forces; + $this->pChartObject->drawSpline($WayPoints,$SplineSettings); + } + } + } + + /** + * Return the scaled plot position + * @param type $Values + * @param type $AxisID + * @return type + */ + public function getPosArray($Values,$AxisID) + { + $Data = $this->pDataObject->getData(); + + if ( !is_array($Values) ) { + $Values = array($Values); + } + + if ( $Data["Axis"][$AxisID]["Identity"] == AXIS_X ) { + $Height = ($this->pChartObject->GraphAreaX2 + - $this->pChartObject->GraphAreaX1) + - $Data["Axis"][$AxisID]["Margin"]*2; + $ScaleHeight = $Data["Axis"][$AxisID]["ScaleMax"] + - $Data["Axis"][$AxisID]["ScaleMin"]; + $Step = $Height / $ScaleHeight; + + $Result = ""; + foreach($Values as $Key => $Value) { + if ( $Value == VOID ) { + $Result[] = VOID; + } else { + $Result[] = $this->pChartObject->GraphAreaX1 + + $Data["Axis"][$AxisID]["Margin"] + + ($Step * ($Value-$Data["Axis"][$AxisID]["ScaleMin"])); + } + } + + if ( count($Result) == 1 ) { + return($Result[0]); + } else { + return($Result); + } + } else { + $Height = ($this->pChartObject->GraphAreaY2 + - $this->pChartObject->GraphAreaY1) + - $Data["Axis"][$AxisID]["Margin"]*2; + $ScaleHeight = $Data["Axis"][$AxisID]["ScaleMax"] - $Data["Axis"][$AxisID]["ScaleMin"]; + $Step = $Height / $ScaleHeight; + + $Result = ""; + foreach($Values as $Key => $Value) { + if ( $Value == VOID ) { + $Result[] = VOID; + } else { + $Result[] = $this->pChartObject->GraphAreaY2 + - $Data["Axis"][$AxisID]["Margin"] + - ($Step * ($Value-$Data["Axis"][$AxisID]["ScaleMin"])); + } + } + + if ( count($Result) == 1 ) { + return($Result[0]); + } else { + return($Result); + } + } + } + + /** + * Draw the legend of the active series + * @param type $X + * @param type $Y + * @param type $Format + */ + public function drawScatterLegend($X,$Y,$Format="") + { + $Family = isset($Format["Family"]) ? $Format["Family"] : LEGEND_FAMILY_BOX; + $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; + $BoxWidth = isset($Format["BoxWidth"]) ? $Format["BoxWidth"] : 5; + $BoxHeight = isset($Format["BoxHeight"]) ? $Format["BoxHeight"] : 5; + $IconAreaWidth = isset($Format["IconAreaWidth"]) ? $Format["IconAreaWidth"] : $BoxWidth; + $IconAreaHeight = isset($Format["IconAreaHeight"]) ? $Format["IconAreaHeight"] : $BoxHeight; + $XSpacing = isset($Format["XSpacing"]) ? $Format["XSpacing"] : 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; + } + + $Data = $this->pDataObject->getData(); + + foreach($Data["ScatterSeries"] as $Key => $Series) { + if ( $Series["isDrawable"] == true && isset($Series["Picture"])) { + list($PicWidth,$PicHeight) = $this->pChartObject->getPicInfo($Series["Picture"]); + if ( $IconAreaWidth < $PicWidth ) { + $IconAreaWidth = $PicWidth; + } + if ( $IconAreaHeight < $PicHeight ) { + $IconAreaHeight = $PicHeight; + } + } + } + + $YStep = max($this->pChartObject->FontSize,$IconAreaHeight) + 5; + $XStep = $IconAreaWidth + 5; + $XStep = $XSpacing; + + $Boundaries = ""; + $Boundaries["L"] = $X; + $Boundaries["T"] = $Y; + $Boundaries["R"] = 0; + $Boundaries["B"] = 0; + $vY = $Y; + $vX = $X; + foreach($Data["ScatterSeries"] as $Key => $Series) { + if ( $Series["isDrawable"] == true ) { + if ( $Mode == LEGEND_VERTICAL ) { + $BoxArray = $this->pChartObject->getTextBox( + $vX+$IconAreaWidth+4, + $vY+$IconAreaHeight/2, + $FontName, + $FontSize, + 0, + $Series["Description"] + ); + + if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$IconAreaHeight/2 ) { + $Boundaries["T"] = $BoxArray[2]["Y"]+$IconAreaHeight/2; + } + if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { + $Boundaries["R"] = $BoxArray[1]["X"]+2; + } + if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$IconAreaHeight/2 ) { + $Boundaries["B"] = $BoxArray[1]["Y"]+2+$IconAreaHeight/2; + } + + $Lines = preg_split("/\n/",$Series["Description"]); + $vY = $vY + max($this->pChartObject->FontSize*count($Lines),$IconAreaHeight) + 5; + } elseif ( $Mode == LEGEND_HORIZONTAL ) { + $Lines = preg_split("/\n/",$Series["Description"]); + $Width = ""; + foreach($Lines as $Key => $Value) { + $BoxArray = $this->pChartObject->getTextBox( + $vX+$IconAreaWidth+6, + $Y+$IconAreaHeight/2+(($this->pChartObject->FontSize+3)*$Key), + $FontName, + $FontSize, + 0, + $Value + ); + + if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$IconAreaHeight/2 ) { + $Boundaries["T"] = $BoxArray[2]["Y"]+$IconAreaHeight/2; + } + if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { + $Boundaries["R"] = $BoxArray[1]["X"]+2; + } + if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$IconAreaHeight/2 ) { + $Boundaries["B"] = $BoxArray[1]["Y"]+2+$IconAreaHeight/2; + } + + $Width[] = $BoxArray[1]["X"]; + } + $vX=max($Width)+$XStep; + } + } + } + $vY=$vY-$YStep; $vX=$vX-$XStep; + + $TopOffset = $Y - $Boundaries["T"]; + if ( $Boundaries["B"]-($vY+$IconAreaHeight) < $TopOffset ) { + $Boundaries["B"] = $vY+$IconAreaHeight+$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->Shadow = false; + foreach($Data["ScatterSeries"] as $Key => $Series) { + if ( $Series["isDrawable"] == true ) { + $R = $Series["Color"]["R"]; + $G = $Series["Color"]["G"]; + $B = $Series["Color"]["B"]; + $Ticks = $Series["Ticks"]; + $Weight = $Series["Weight"]; + + if ( isset($Series["Picture"]) ) { + $Picture = $Series["Picture"]; + list($PicWidth,$PicHeight) = $this->pChartObject->getPicInfo($Picture); + $PicX = $X+$IconAreaWidth/2; $PicY = $Y+$IconAreaHeight/2; + + $this->pChartObject->drawFromPNG($PicX-$PicWidth/2,$PicY-$PicHeight/2,$Picture); + } else { + if ( $Family == LEGEND_FAMILY_BOX ) { + if ( $BoxWidth != $IconAreaWidth ) { + $XOffset = floor(($IconAreaWidth-$BoxWidth)/2); + } else { + $XOffset = 0; + } + if ( $BoxHeight != $IconAreaHeight ) { + $YOffset = floor(($IconAreaHeight-$BoxHeight)/2); + } else { + $YOffset = 0; + } + + $this->pChartObject->drawFilledRectangle( + $X+1+$XOffset, + $Y+1+$YOffset, + $X+$BoxWidth+$XOffset+1, + $Y+$BoxHeight+1+$YOffset, + array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>20) + ); + $this->pChartObject->drawFilledRectangle( + $X+$XOffset, + $Y+$YOffset, + $X+$BoxWidth+$XOffset, + $Y+$BoxHeight+$YOffset, + array("R"=>$R,"G"=>$G,"B"=>$B,"Surrounding"=>20) + ); + } elseif ( $Family == LEGEND_FAMILY_CIRCLE ) { + $this->pChartObject->drawFilledCircle( + $X+1+$IconAreaWidth/2, + $Y+1+$IconAreaHeight/2, + min($IconAreaHeight/2,$IconAreaWidth/2), + array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>20) + ); + $this->pChartObject->drawFilledCircle( + $X+$IconAreaWidth/2, + $Y+$IconAreaHeight/2, + min($IconAreaHeight/2,$IconAreaWidth/2), + array("R"=>$R,"G"=>$G,"B"=>$B,"Surrounding"=>20) + ); + } elseif ( $Family == LEGEND_FAMILY_LINE ) { + $this->pChartObject->drawLine( + $X+1, + $Y+1+$IconAreaHeight/2, + $X+1+$IconAreaWidth, + $Y+1+$IconAreaHeight/2, + array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>20,"Ticks"=>$Ticks,"Weight"=>$Weight) + ); + $this->pChartObject->drawLine( + $X, + $Y+$IconAreaHeight/2, + $X+$IconAreaWidth, + $Y+$IconAreaHeight/2, + array("R"=>$R,"G"=>$G,"B"=>$B,"Ticks"=>$Ticks,"Weight"=>$Weight) + ); + } + } + + if ( $Mode == LEGEND_VERTICAL ) { + $Lines = preg_split("/\n/",$Series["Description"]); + foreach($Lines as $Key => $Value) { + $this->pChartObject->drawText( + $X+$IconAreaWidth+4, + $Y+$IconAreaHeight/2+(($this->pChartObject->FontSize+3)*$Key), + $Value,array("R"=>$FontR,"G"=>$FontG,"B"=>$FontB,"Align"=>TEXT_ALIGN_MIDDLELEFT) + ); + } + $Y=$Y+max($this->pChartObject->FontSize*count($Lines),$IconAreaHeight) + 5; + } elseif ( $Mode == LEGEND_HORIZONTAL ) { + $Lines = preg_split("/\n/",$Series["Description"]); + $Width = ""; + foreach($Lines as $Key => $Value) { + $BoxArray = $this->pChartObject->drawText( + $X+$IconAreaWidth+4, + $Y+$IconAreaHeight/2+(($this->pChartObject->FontSize+3)*$Key), + $Value,array("R"=>$FontR,"G"=>$FontG,"B"=>$FontB,"Align"=>TEXT_ALIGN_MIDDLELEFT) + ); + $Width[] = $BoxArray[1]["X"]; + } + $X=max($Width)+2+$XStep; + } + } + } + + $this->Shadow = $RestoreShadow; + } + + /** + * Get the legend box size + * @param type $Format + * @return type + */ + public function getScatterLegendSize($Format="") + { + $FontName = isset($Format["FontName"]) ? $Format["FontName"] : $this->pChartObject->FontName; + $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->pChartObject->FontSize; + $BoxSize = isset($Format["BoxSize"]) ? $Format["BoxSize"] : 5; + $Margin = isset($Format["Margin"]) ? $Format["Margin"] : 5; + $Style = isset($Format["Style"]) ? $Format["Style"] : LEGEND_ROUND; + $Mode = isset($Format["Mode"]) ? $Format["Mode"] : LEGEND_VERTICAL; + + $YStep = max($this->pChartObject->FontSize,$BoxSize) + 5; + $XStep = $BoxSize + 5; + + $X=100; $Y=100; + + $Data = $this->pDataObject->getData(); + + foreach($Data["ScatterSeries"] as $Key => $Series) { + if ( $Series["isDrawable"] == true && isset($Series["Picture"])) { + list($PicWidth,$PicHeight) = $this->pChartObject->getPicInfo($Series["Picture"]); + if ( $IconAreaWidth < $PicWidth ) { + $IconAreaWidth = $PicWidth; + } + if ( $IconAreaHeight < $PicHeight ) { + $IconAreaHeight = $PicHeight; + } + } + } + + $YStep = max($this->pChartObject->FontSize,$IconAreaHeight) + 5; + $XStep = $IconAreaWidth + 5; + $XStep = $XSpacing; + + $Boundaries = ""; + $Boundaries["L"] = $X; + $Boundaries["T"] = $Y; + $Boundaries["R"] = 0; + $Boundaries["B"] = 0; + $vY = $Y; + $vX = $X; + foreach($Data["ScatterSeries"] as $Key => $Series) { + if ( $Series["isDrawable"] == true ) { + if ( $Mode == LEGEND_VERTICAL ) { + $BoxArray = $this->pChartObject->getTextBox( + $vX+$IconAreaWidth+4, + $vY+$IconAreaHeight/2, + $FontName, + $FontSize, + 0, + $Series["Description"] + ); + + if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$IconAreaHeight/2 ) { + $Boundaries["T"] = $BoxArray[2]["Y"]+$IconAreaHeight/2; + } + if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { + $Boundaries["R"] = $BoxArray[1]["X"]+2; + } + if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$IconAreaHeight/2 ) { + $Boundaries["B"] = $BoxArray[1]["Y"]+2+$IconAreaHeight/2; + } + + $Lines = preg_split("/\n/",$Series["Description"]); + $vY = $vY + max($this->pChartObject->FontSize*count($Lines),$IconAreaHeight) + 5; + } elseif ( $Mode == LEGEND_HORIZONTAL ) { + $Lines = preg_split("/\n/",$Series["Description"]); + $Width = ""; + foreach($Lines as $Key => $Value) { + $BoxArray = $this->pChartObject->getTextBox( + $vX+$IconAreaWidth+6, + $Y+$IconAreaHeight/2+(($this->pChartObject->FontSize+3)*$Key), + $FontName, + $FontSize, + 0, + $Value + ); + + if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$IconAreaHeight/2 ) { + $Boundaries["T"] = $BoxArray[2]["Y"]+$IconAreaHeight/2; + } + if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { + $Boundaries["R"] = $BoxArray[1]["X"]+2; + } + if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$IconAreaHeight/2 ) { + $Boundaries["B"] = $BoxArray[1]["Y"]+2+$IconAreaHeight/2; + } + + $Width[] = $BoxArray[1]["X"]; + } + $vX=max($Width)+$XStep; + } + } + } + $vY=$vY-$YStep; + $vX=$vX-$XStep; + + $TopOffset = $Y - $Boundaries["T"]; + if ( $Boundaries["B"]-($vY+$BoxSize) < $TopOffset ) { + $Boundaries["B"] = $vY+$BoxSize+$TopOffset; + } + + $Width = ($Boundaries["R"]+$Margin) - ($Boundaries["L"]-$Margin); + $Height = ($Boundaries["B"]+$Margin) - ($Boundaries["T"]-$Margin); + + return(array("Width"=>$Width,"Height"=>$Height)); + } + + /** + * Draw the line of best fit + * @param type $Format + */ + public function drawScatterBestFit($Format="") + { + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : 0; + + $Data = $this->pDataObject->getData(); + + foreach($Data["ScatterSeries"] as $Key => $Series) { + if ( $Series["isDrawable"] == true ) { + $SerieX = $Series["X"]; + $SerieValuesX = $Data["Series"][$SerieX]["Data"]; + $SerieXAxis = $Data["Series"][$SerieX]["Axis"]; + $SerieY = $Series["Y"]; + $SerieValuesY = $Data["Series"][$SerieY]["Data"]; + $SerieYAxis = $Data["Series"][$SerieY]["Axis"]; + + $Color = array( + "R"=>$Series["Color"]["R"], + "G"=>$Series["Color"]["G"], + "B"=>$Series["Color"]["B"], + "Alpha"=>$Series["Color"]["Alpha"] + ); + $Color["Ticks"] = $Ticks; + + $PosArrayX = $Data["Series"][$Series["X"]]["Data"]; + $PosArrayY = $Data["Series"][$Series["Y"]]["Data"]; + + $Sxy = 0; + $Sx = 0; + $Sy = 0; + $Sxx = 0; + foreach($PosArrayX as $Key => $Value) { + $X = $Value; + $Y = $PosArrayY[$Key]; + + $Sxy = $Sxy + $X*$Y; + $Sx = $Sx + $X; + $Sy = $Sy + $Y; + $Sxx = $Sxx + $X*$X; + } + + $n = count($PosArrayX); + + if ((($n*$Sxx) == ($Sx*$Sx))) { + $X1 = $this->getPosArray($Data["Axis"][$SerieXAxis]["ScaleMin"],$SerieXAxis); + $X2 = $X1; + $Y1 = $this->pChartObject->GraphAreaY1; + $Y2 = $this->pChartObject->GraphAreaY2; + } else { + $M = (($n*$Sxy)-($Sx*$Sy)) / (($n*$Sxx)-($Sx*$Sx)); + $B = (($Sy)-($M*$Sx))/($n); + + $X1 = $this->getPosArray($Data["Axis"][$SerieXAxis]["ScaleMin"],$SerieXAxis); + $Y1 = $this->getPosArray($M * $Data["Axis"][$SerieXAxis]["ScaleMin"] + $B,$SerieYAxis); + $X2 = $this->getPosArray($Data["Axis"][$SerieXAxis]["ScaleMax"],$SerieXAxis); + $Y2 = $this->getPosArray($M * $Data["Axis"][$SerieXAxis]["ScaleMax"] + $B,$SerieYAxis); + + $RealM = -($Y2-$Y1)/($X2-$X1); + + if ( $Y1 < $this->pChartObject->GraphAreaY1 ) { + $X1 = $X1 + ($this->pChartObject->GraphAreaY1-$Y1/$RealM); + $Y1 = $this->pChartObject->GraphAreaY1; + } + if ( $Y1 > $this->pChartObject->GraphAreaY2 ) { + $X1 = $X1 + ($Y1-$this->pChartObject->GraphAreaY2)/$RealM; + $Y1 = $this->pChartObject->GraphAreaY2; + } + if ( $Y2 < $this->pChartObject->GraphAreaY1 ) { + $X2 = $X2 - ($this->pChartObject->GraphAreaY1-$Y2)/$RealM; + $Y2 = $this->pChartObject->GraphAreaY1; + } + if ( $Y2 > $this->pChartObject->GraphAreaY2 ) { + $X2 = $X2 - ($Y2-$this->pChartObject->GraphAreaY2)/$RealM; + $Y2 = $this->pChartObject->GraphAreaY2; + } + } + + $this->pChartObject->drawLine($X1,$Y1,$X2,$Y2,$Color); + } + } + } + + /** + * + * @param type $ScatterSerieID + * @param type $Points + * @param type $Format + * @return type + */ + public function writeScatterLabel($ScatterSerieID,$Points,$Format="") + { + $OverrideTitle = isset($Format["OverrideTitle"]) ? $Format["OverrideTitle"] : null; + $DrawPoint = isset($Format["DrawPoint"]) ? $Format["DrawPoint"] : LABEL_POINT_BOX; + $Decimals = isset($Format["Decimals"]) ? $Format["Decimals"] : null; + + $Data = $this->pDataObject->getData(); + $Palette = $this->pDataObject->getPalette(); + + if ( !is_array($Points) ) { + $Point = $Points; + $Points = ""; + $Points[0] = $Point; + } + + if ( !isset($Data["ScatterSeries"][$ScatterSerieID]) ) { + return(0); + } + $Series = $Data["ScatterSeries"][$ScatterSerieID]; + + $SerieX = $Series["X"]; + $SerieValuesX = $Data["Series"][$SerieX]["Data"]; + $SerieXAxis = $Data["Series"][$SerieX]["Axis"]; + + $SerieY = $Series["Y"]; + $SerieValuesY = $Data["Series"][$SerieY]["Data"]; + $SerieYAxis = $Data["Series"][$SerieY]["Axis"]; + + $PosArrayX = $this->getPosArray($SerieValuesX,$SerieXAxis); + if ( !is_array($PosArrayX) ) { + $Value = $PosArrayX; + $PosArrayX = ""; + $PosArrayX[0] = $Value; + } + $PosArrayY = $this->getPosArray($SerieValuesY,$SerieYAxis); + if ( !is_array($PosArrayY) ) { + $Value = $PosArrayY; + $PosArrayY = ""; + $PosArrayY[0] = $Value; + } + + foreach($Points as $Key => $Point) { + if ( isset($PosArrayX[$Point]) && isset($PosArrayY[$Point]) ) { + $X = floor($PosArrayX[$Point]); + $Y = floor($PosArrayY[$Point]); + + if ( $DrawPoint == LABEL_POINT_CIRCLE ) { + $this->pChartObject->drawFilledCircle( + $X, + $Y, + 3, + array("R"=>255,"G"=>255,"B"=>255,"BorderR"=>0,"BorderG"=>0,"BorderB"=>0) + ); + } elseif ( $DrawPoint == LABEL_POINT_BOX ) { + $this->pChartObject->drawFilledRectangle( + $X-2, + $Y-2, + $X+2, + $Y+2, + array("R"=>255,"G"=>255,"B"=>255,"BorderR"=>0,"BorderG"=>0,"BorderB"=>0) + ); + } + $Serie = ""; + $Serie["R"] = $Series["Color"]["R"]; + $Serie["G"] = $Series["Color"]["G"]; + $Serie["B"] = $Series["Color"]["B"]; + $Serie["Alpha"] = $Series["Color"]["Alpha"]; + + $XAxisMode = $Data["Axis"][$SerieXAxis]["Display"]; + $XAxisFormat = $Data["Axis"][$SerieXAxis]["Format"]; + $XAxisUnit = $Data["Axis"][$SerieXAxis]["Unit"]; + if ( $Decimals == null ) { + $XValue = $SerieValuesX[$Point]; + } else { + $XValue = round($SerieValuesX[$Point],$Decimals); + } + $XValue = $this->pChartObject->scaleFormat($XValue,$XAxisMode,$XAxisFormat,$XAxisUnit); + + $YAxisMode = $Data["Axis"][$SerieYAxis]["Display"]; + $YAxisFormat = $Data["Axis"][$SerieYAxis]["Format"]; + $YAxisUnit = $Data["Axis"][$SerieYAxis]["Unit"]; + if ( $Decimals == null ) { + $YValue = $SerieValuesY[$Point]; + } else { + $YValue = round($SerieValuesY[$Point],$Decimals); + } + $YValue = $this->pChartObject->scaleFormat($YValue,$YAxisMode,$YAxisFormat,$YAxisUnit); + + $Caption = $XValue." / ".$YValue; + + if ( isset($Series["Description"]) ) { + $Description = $Series["Description"]; + } else { + $Description = "No description"; + } + $Series = ""; + $Series[] = array("Format"=>$Serie,"Caption"=>$Caption); + + $this->pChartObject->drawLabelBox($X,$Y-3,$Description,$Series,$Format); + } + } + } + + /** + * Draw a Scatter threshold + * @param type $Value + * @param type $Format + * @return type + */ + public function drawScatterThreshold($Value,$Format="") + { + $AxisID = isset($Format["AxisID"]) ? $Format["AxisID"] : 0; + $R = isset($Format["R"]) ? $Format["R"] : 255; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 50; + $Weight = isset($Format["Weight"]) ? $Format["Weight"] : null; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : 3; + $Wide = isset($Format["Wide"]) ? $Format["Wide"] : false; + $WideFactor = isset($Format["WideFactor"]) ? $Format["WideFactor"] : 5; + $WriteCaption = isset($Format["WriteCaption"]) ? $Format["WriteCaption"] : false; + $Caption = isset($Format["Caption"]) ? $Format["Caption"] : null; + $CaptionAlign = isset($Format["CaptionAlign"]) ? $Format["CaptionAlign"] : CAPTION_LEFT_TOP; + $CaptionOffset = isset($Format["CaptionOffset"]) ? $Format["CaptionOffset"] : 10; + $CaptionR = isset($Format["CaptionR"]) ? $Format["CaptionR"] : 255; + $CaptionG = isset($Format["CaptionG"]) ? $Format["CaptionG"] : 255; + $CaptionB = isset($Format["CaptionB"]) ? $Format["CaptionB"] : 255; + $CaptionAlpha = isset($Format["CaptionAlpha"]) ? $Format["CaptionAlpha"] : 100; + $DrawBox = isset($Format["DrawBox"]) ? $Format["DrawBox"] : true; + $DrawBoxBorder = isset($Format["DrawBoxBorder"]) ? $Format["DrawBoxBorder"] : false; + $BorderOffset = isset($Format["BorderOffset"]) ? $Format["BorderOffset"] : 5; + $BoxRounded = isset($Format["BoxRounded"]) ? $Format["BoxRounded"] : true; + $RoundedRadius = isset($Format["RoundedRadius"]) ? $Format["RoundedRadius"] : 3; + $BoxR = isset($Format["BoxR"]) ? $Format["BoxR"] : 0; + $BoxG = isset($Format["BoxG"]) ? $Format["BoxG"] : 0; + $BoxB = isset($Format["BoxB"]) ? $Format["BoxB"] : 0; + $BoxAlpha = isset($Format["BoxAlpha"]) ? $Format["BoxAlpha"] : 20; + $BoxSurrounding = isset($Format["BoxSurrounding"]) ? $Format["BoxSurrounding"] : ""; + $BoxBorderR = isset($Format["BoxBorderR"]) ? $Format["BoxBorderR"] : 255; + $BoxBorderG = isset($Format["BoxBorderG"]) ? $Format["BoxBorderG"] : 255; + $BoxBorderB = isset($Format["BoxBorderB"]) ? $Format["BoxBorderB"] : 255; + $BoxBorderAlpha = isset($Format["BoxBorderAlpha"]) ? $Format["BoxBorderAlpha"] : 100; + + $CaptionSettings = array( + "DrawBox"=>$DrawBox, + "DrawBoxBorder"=>$DrawBoxBorder, + "BorderOffset"=>$BorderOffset, + "BoxRounded"=>$BoxRounded, + "RoundedRadius"=>$RoundedRadius, + "BoxR"=>$BoxR, + "BoxG"=>$BoxG, + "BoxB"=>$BoxB, + "BoxAlpha"=>$BoxAlpha, + "BoxSurrounding"=>$BoxSurrounding, + "BoxBorderR"=>$BoxBorderR, + "BoxBorderG"=>$BoxBorderG, + "BoxBorderB"=>$BoxBorderB, + "BoxBorderAlpha"=>$BoxBorderAlpha, + "R"=>$CaptionR, + "G"=>$CaptionG, + "B"=>$CaptionB, + "Alpha"=>$CaptionAlpha + ); + + if ( $Caption == null ) { + $Caption = $Value; + } + + $Data = $this->pDataObject->getData(); + + if ( !isset($Data["Axis"][$AxisID]) ) { + return(-1); + } + + if ( $Data["Axis"][$AxisID]["Identity"] == AXIS_Y ) { + $X1 = $this->pChartObject->GraphAreaX1 + $Data["Axis"][$AxisID]["Margin"]; + $X2 = $this->pChartObject->GraphAreaX2 - $Data["Axis"][$AxisID]["Margin"]; + $Y = $this->getPosArray($Value,$AxisID); + + $this->pChartObject->drawLine( + $X1, + $Y, + $X2, + $Y, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Weight"=>$Weight) + ); + + if ( $Wide ) { + $this->pChartObject->drawLine( + $X1, + $Y-1, + $X2, + $Y-1, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks) + ); + $this->pChartObject->drawLine( + $X1, + $Y+1, + $X2, + $Y+1, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks) + ); + } + + if ( $WriteCaption ) { + if ( $CaptionAlign == CAPTION_LEFT_TOP ) { + $X = $this->pChartObject->GraphAreaX1 + $Data["Axis"][$AxisID]["Margin"] + $CaptionOffset; + $CaptionSettings["Align"] = TEXT_ALIGN_MIDDLELEFT; + } else { + $X = $this->pChartObject->GraphAreaX2 - $Data["Axis"][$AxisID]["Margin"] - $CaptionOffset; + $CaptionSettings["Align"] = TEXT_ALIGN_MIDDLERIGHT; + } + $this->pChartObject->drawText($X,$Y,$Caption,$CaptionSettings); + } + + return(array("Y"=>$Y)); + } elseif ( $Data["Axis"][$AxisID]["Identity"] == AXIS_X ) { + $X = $this->getPosArray($Value,$AxisID); + $Y1 = $this->pChartObject->GraphAreaY1 + $Data["Axis"][$AxisID]["Margin"]; + $Y2 = $this->pChartObject->GraphAreaY2 - $Data["Axis"][$AxisID]["Margin"]; + + $this->pChartObject->drawLine( + $X, + $Y1, + $X, + $Y2, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks,"Weight"=>$Weight) + ); + + if ( $Wide ) { + $this->pChartObject->drawLine( + $X-1, + $Y1, + $X-1, + $Y2, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks) + ); + $this->pChartObject->drawLine( + $X+1, + $Y1, + $X+1, + $Y2, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha/$WideFactor,"Ticks"=>$Ticks) + ); + } + + if ( $WriteCaption ) { + if ( $CaptionAlign == CAPTION_LEFT_TOP ) { + $Y = $this->pChartObject->GraphAreaY1 + $Data["Axis"][$AxisID]["Margin"] + $CaptionOffset; + $CaptionSettings["Align"] = TEXT_ALIGN_TOPMIDDLE; + } else { + $Y = $this->pChartObject->GraphAreaY2 - $Data["Axis"][$AxisID]["Margin"] - $CaptionOffset; + $CaptionSettings["Align"] = TEXT_ALIGN_BOTTOMMIDDLE; + } + + $CaptionSettings["Align"] = TEXT_ALIGN_TOPMIDDLE; + $this->pChartObject->drawText($X,$Y,$Caption,$CaptionSettings); + } + + return(array("X"=>$X)); + } + } + + /** + * Draw a Scatter threshold area + * @param type $Value1 + * @param type $Value2 + * @param type $Format + * @return type + */ + public function drawScatterThresholdArea($Value1,$Value2,$Format="") + { + $AxisID = isset($Format["AxisID"]) ? $Format["AxisID"] : 0; + $R = isset($Format["R"]) ? $Format["R"] : 255; + $G = isset($Format["G"]) ? $Format["G"] : 0; + $B = isset($Format["B"]) ? $Format["B"] : 0; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 20; + $Border = isset($Format["Border"]) ? $Format["Border"] : true; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : $R; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : $G; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : $B; + $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : $Alpha + 20; + $BorderTicks = isset($Format["BorderTicks"]) ? $Format["BorderTicks"] : 2; + $AreaName = isset($Format["AreaName"]) ? $Format["AreaName"] : "La ouate de phoque"; //null; + $NameAngle = isset($Format["NameAngle"]) ? $Format["NameAngle"] : ZONE_NAME_ANGLE_AUTO; + $NameR = isset($Format["NameR"]) ? $Format["NameR"] : 255; + $NameG = isset($Format["NameG"]) ? $Format["NameG"] : 255; + $NameB = isset($Format["NameB"]) ? $Format["NameB"] : 255; + $NameAlpha = isset($Format["NameAlpha"]) ? $Format["NameAlpha"] : 100; + $DisableShadowOnArea = isset($Format["DisableShadowOnArea"]) ? $Format["DisableShadowOnArea"] : true; + + if ($Value1 > $Value2) { + list($Value1, $Value2) = array($Value2, $Value1); + } + + $RestoreShadow = $this->pChartObject->Shadow; + if ( $DisableShadowOnArea && $this->pChartObject->Shadow ) { + $this->pChartObject->Shadow = false; + } + + if ($BorderAlpha >100) { + $BorderAlpha = 100; + } + + $Data = $this->pDataObject->getData(); + + if ( !isset($Data["Axis"][$AxisID]) ) { + return(-1); + } + + if ( $Data["Axis"][$AxisID]["Identity"] == AXIS_X ) { + $Y1 = $this->pChartObject->GraphAreaY1 + $Data["Axis"][$AxisID]["Margin"]; + $Y2 = $this->pChartObject->GraphAreaY2 - $Data["Axis"][$AxisID]["Margin"]; + $X1 = $this->getPosArray($Value1,$AxisID); + $X2 = $this->getPosArray($Value2,$AxisID); + + if ( $X1 <= $this->pChartObject->GraphAreaX1 ) { + $X1 = $this->pChartObject->GraphAreaX1+$Data["Axis"][$AxisID]["Margin"]; + } + if ( $X2 >= $this->pChartObject->GraphAreaX2 ) { + $X2 = $this->pChartObject->GraphAreaX2-$Data["Axis"][$AxisID]["Margin"]; + } + + $this->pChartObject->drawFilledRectangle( + $X1, + $Y1, + $X2, + $Y2, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha) + ); + + if ( $Border ) { + $this->pChartObject->drawLine( + $X1, + $Y1, + $X1, + $Y2, + array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$BorderTicks) + ); + $this->pChartObject->drawLine( + $X2, + $Y1, + $X2, + $Y2, + array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$BorderTicks) + ); + } + + if ( $AreaName != null ) { + $XPos = ($X2-$X1)/2 + $X1; + $YPos = ($Y2-$Y1)/2 + $Y1; + + if ( $NameAngle == ZONE_NAME_ANGLE_AUTO ) { + $TxtPos = $this->pChartObject->getTextBox( + $XPos, + $YPos, + $this->pChartObject->FontName, + $this->pChartObject->FontSize, + 0, + $AreaName + ); + $TxtWidth = $TxtPos[1]["X"] - $TxtPos[0]["X"]; + if ( abs($X2 - $X1) > $TxtWidth ) { + $NameAngle = 0; + } else { + $NameAngle = 90; + } + } + $this->pChartObject->Shadow = $RestoreShadow; + $this->pChartObject->drawText( + $XPos, + $YPos, + $AreaName, + array( + "R"=>$NameR, + "G"=>$NameG, + "B"=>$NameB, + "Alpha"=>$NameAlpha, + "Angle"=>$NameAngle, + "Align"=>TEXT_ALIGN_MIDDLEMIDDLE + ) + ); + if ( $DisableShadowOnArea ) { + $this->pChartObject->Shadow = false; + } + } + + $this->pChartObject->Shadow = $RestoreShadow; + return(array("X1"=>$X1,"X2"=>$X2)); + } elseif ( $Data["Axis"][$AxisID]["Identity"] == AXIS_Y ) { + $X1 = $this->pChartObject->GraphAreaX1 + $Data["Axis"][$AxisID]["Margin"]; + $X2 = $this->pChartObject->GraphAreaX2 - $Data["Axis"][$AxisID]["Margin"]; + $Y1 = $this->getPosArray($Value1,$AxisID); + $Y2 = $this->getPosArray($Value2,$AxisID); + + if ( $Y1 >= $this->pChartObject->GraphAreaY2 ) { + $Y1 = $this->pChartObject->GraphAreaY2-$Data["Axis"][$AxisID]["Margin"]; + } + if ( $Y2 <= $this->pChartObject->GraphAreaY1 ) { + $Y2 = $this->pChartObject->GraphAreaY1+$Data["Axis"][$AxisID]["Margin"]; + } + + $this->pChartObject->drawFilledRectangle( + $X1, + $Y1, + $X2, + $Y2, + array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha) + ); + + if ( $Border ) { + $this->pChartObject->drawLine( + $X1, + $Y1, + $X2, + $Y1, + array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$BorderTicks) + ); + $this->pChartObject->drawLine( + $X1, + $Y2, + $X2, + $Y2, + array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha,"Ticks"=>$BorderTicks) + ); + } + + if ( $AreaName != null ) { + $XPos = ($X2-$X1)/2 + $X1; + $YPos = ($Y2-$Y1)/2 + $Y1; + + $this->pChartObject->Shadow = $RestoreShadow; + $this->pChartObject->drawText( + $YPos, + $XPos, + $AreaName, + array("R"=>$NameR,"G"=>$NameG,"B"=>$NameB,"Alpha"=>$NameAlpha,"Angle"=>0,"Align"=>TEXT_ALIGN_MIDDLEMIDDLE) + ); + if ( $DisableShadowOnArea ) { + $this->Shadow = false; + } + } + + $this->pChartObject->Shadow = $RestoreShadow; + return(array("Y1"=>$Y1,"Y2"=>$Y2)); + } + } +} \ No newline at end of file diff --git a/vendor/szymach/c-pchart/src/Classes/pSplit.php b/vendor/szymach/c-pchart/src/Classes/pSplit.php new file mode 100644 index 0000000000..f3fa06c694 --- /dev/null +++ b/vendor/szymach/c-pchart/src/Classes/pSplit.php @@ -0,0 +1,143 @@ +pChartObject = $Object; + + $Spacing = isset($Format["Spacing"]) ? $Format["Spacing"] : 20; + $TextPadding = isset($Format["TextPadding"]) ? $Format["TextPadding"] : 2; + $TextPos = isset($Format["TextPos"]) ? $Format["TextPos"] : TEXT_POS_TOP; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : null; + $Force = isset($Format["Force"]) ? $Format["Force"] : 70; + $Segments = isset($Format["Segments"]) ? $Format["Segments"] : 15; + $FontSize = $Object->FontSize; + $X1 = $Object->GraphAreaX1; + $Y1 = $Object->GraphAreaY1; + $X2 = $Object->GraphAreaX2; + $Y2 = $Object->GraphAreaY2; + + /* Data Processing */ + $Data = $Values->getData(); + $Palette = $Values->getPalette(); + + $LabelSerie = $Data["Abscissa"]; + $DataSerie = ""; + + foreach($Data["Series"] as $SerieName => $Value) { + if ( $SerieName != $LabelSerie && $DataSerie == "" ) { + $DataSerie = $SerieName; + } + } + + $DataSerieSum = array_sum($Data["Series"][$DataSerie]["Data"]); + $DataSerieCount = count($Data["Series"][$DataSerie]["Data"]); + + /* Scale Processing */ + if ( $TextPos == TEXT_POS_RIGHT ) { + $YScale = (($Y2-$Y1) - (($DataSerieCount+1)*$Spacing)) / $DataSerieSum; + } else { + $YScale = (($Y2-$Y1) - ($DataSerieCount*$Spacing)) / $DataSerieSum; + } + $LeftHeight = $DataSerieSum * $YScale; + + /* Re-compute graph width depending of the text mode choosen */ + if ( $TextPos == TEXT_POS_RIGHT ) { + $MaxWidth = 0; + foreach($Data["Series"][$LabelSerie]["Data"] as $Key => $Label) { + $Boundardies = $Object->getTextBox(0,0,$Object->FontName,$Object->FontSize,0,$Label); + if ( $Boundardies[1]["X"] > $MaxWidth ) { + $MaxWidth = $Boundardies[1]["X"] + $TextPadding*2; + } + } + $X2 = $X2 - $MaxWidth; + } + + /* Drawing */ + $LeftY = ((($Y2-$Y1) / 2) + $Y1) - ($LeftHeight/2); + $RightY = $Y1; + $VectorX = (($X2-$X1) / 2); + + foreach($Data["Series"][$DataSerie]["Data"] as $Key => $Value) { + if ( isset($Data["Series"][$LabelSerie]["Data"][$Key]) ) { + $Label = $Data["Series"][$LabelSerie]["Data"][$Key]; + } else { + $Label = "-"; + } + $LeftY1 = $LeftY; + $LeftY2 = $LeftY + $Value * $YScale; + + $RightY1 = $RightY + $Spacing; + $RightY2 = $RightY + $Spacing + $Value * $YScale; + + $Settings = array( + "R"=>$Palette[$Key]["R"], + "G"=>$Palette[$Key]["G"], + "B"=>$Palette[$Key]["B"], + "Alpha"=>$Palette[$Key]["Alpha"], + "NoDraw"=>true, + "Segments"=>$Segments, + "Surrounding"=>$Surrounding + ); + + $PolyGon = ""; + + $Angle = $Object->getAngle($X2,$RightY1,$X1,$LeftY1); + $VectorX1 = cos(deg2rad($Angle+90)) * $Force + ($X2-$X1)/2 + $X1; + $VectorY1 = sin(deg2rad($Angle+90)) * $Force + ($RightY1-$LeftY1)/2 + $LeftY1; + $VectorX2 = cos(deg2rad($Angle-90)) * $Force + ($X2-$X1)/2 + $X1; + $VectorY2 = sin(deg2rad($Angle-90)) * $Force + ($RightY1-$LeftY1)/2 + $LeftY1; + + $Points = $Object->drawBezier($X1,$LeftY1,$X2,$RightY1,$VectorX1,$VectorY1,$VectorX2,$VectorY2,$Settings); + foreach($Points as $Key => $Pos) { + $PolyGon[] = $Pos["X"]; + $PolyGon[] = $Pos["Y"]; + } + + $Angle = $Object->getAngle($X2,$RightY2,$X1,$LeftY2); + $VectorX1 = cos(deg2rad($Angle+90)) * $Force + ($X2-$X1)/2 +$X1; + $VectorY1 = sin(deg2rad($Angle+90)) * $Force + ($RightY2-$LeftY2)/2 + $LeftY2; + $VectorX2 = cos(deg2rad($Angle-90)) * $Force + ($X2-$X1)/2 +$X1; + $VectorY2 = sin(deg2rad($Angle-90)) * $Force + ($RightY2-$LeftY2)/2 + $LeftY2; + + $Points = $Object->drawBezier($X1,$LeftY2,$X2,$RightY2,$VectorX1,$VectorY1,$VectorX2,$VectorY2,$Settings); + $Points = array_reverse($Points); + foreach($Points as $Key => $Pos) { + $PolyGon[] = $Pos["X"]; + $PolyGon[] = $Pos["Y"]; + } + + $Object->drawPolygon($PolyGon,$Settings); + + if ( $TextPos == TEXT_POS_RIGHT ) { + $Object->drawText($X2+$TextPadding,($RightY2-$RightY1)/2+$RightY1,$Label,array("Align"=>TEXT_ALIGN_MIDDLELEFT)); + } else { + $Object->drawText($X2,$RightY1-$TextPadding,$Label,array("Align"=>TEXT_ALIGN_BOTTOMRIGHT)); + } + $LeftY = $LeftY2; + $RightY = $RightY2; + } + } +} \ No newline at end of file diff --git a/vendor/szymach/c-pchart/src/Classes/pSpring.php b/vendor/szymach/c-pchart/src/Classes/pSpring.php new file mode 100644 index 0000000000..d01fa2cff6 --- /dev/null +++ b/vendor/szymach/c-pchart/src/Classes/pSpring.php @@ -0,0 +1,1051 @@ +Data = ""; + $this->Links = ""; + + /* Set nodes defaults */ + $this->Default["R"] = 255; + $this->Default["G"] = 255; + $this->Default["B"] = 255; + $this->Default["Alpha"] = 100; + $this->Default["BorderR"] = 0; + $this->Default["BorderG"] = 0; + $this->Default["BorderB"] = 0; + $this->Default["BorderAlpha"] = 100; + $this->Default["Surrounding"] = null; + $this->Default["BackgroundR"] = 255; + $this->Default["BackgroundG"] = 255; + $this->Default["BackgroundB"] = 255; + $this->Default["BackgroundAlpha"] = 0; + $this->Default["Force"] = 1; + $this->Default["NodeType"] = NODE_TYPE_FREE; + $this->Default["Size"] = 5; + $this->Default["Shape"] = NODE_SHAPE_CIRCLE; + $this->Default["FreeZone"] = 40; + $this->Default["LinkR"] = 0; + $this->Default["LinkG"] = 0; + $this->Default["LinkB"] = 0; + $this->Default["LinkAlpha"] = 0; + + $this->Labels["Type"] = LABEL_CLASSIC; + $this->Labels["R"] = 0; + $this->Labels["G"] = 0; + $this->Labels["B"] = 0; + $this->Labels["Alpha"] = 100; + + $this->AutoComputeFreeZone = false; + } + + /** + * Set default links options + * @param type $Settings + */ + public function setLinkDefaults($Settings="") + { + if ( isset($Settings["R"]) ) { + $this->Default["LinkR"] = $Settings["R"]; + } + if ( isset($Settings["G"]) ) { + $this->Default["LinkG"] = $Settings["G"]; + } + if ( isset($Settings["B"]) ) { + $this->Default["LinkB"] = $Settings["B"]; + } + if ( isset($Settings["Alpha"]) ) { + $this->Default["LinkAlpha"] = $Settings["Alpha"]; + } + } + + /** + * Set default links options + * @param type $Settings + */ + public function setLabelsSettings($Settings="") + { + if ( isset($Settings["Type"]) ) { + $this->Labels["Type"] = $Settings["Type"]; + } + if ( isset($Settings["R"]) ) { + $this->Labels["R"] = $Settings["R"]; + } + if ( isset($Settings["G"]) ) { + $this->Labels["G"] = $Settings["G"]; + } + if ( isset($Settings["B"]) ) { + $this->Labels["B"] = $Settings["B"]; + } + if ( isset($Settings["Alpha"]) ) { + $this->Labels["Alpha"] = $Settings["Alpha"]; + } + } + + /** + * Auto compute the FreeZone size based on the number of connections + */ + public function autoFreeZone() + { + /* Check connections reciprocity */ + foreach($this->Data as $Key => $Settings) { + if ( isset($Settings["Connections"]) ) { + $this->Data[$Key]["FreeZone"] = count($Settings["Connections"])*10 + 20; + } else { + $this->Data[$Key]["FreeZone"] = 20; + } + } + } + + /** + * Set link properties + * @param type $FromNode + * @param type $ToNode + * @param type $Settings + * @return type + */ + public function linkProperties($FromNode,$ToNode,$Settings) + { + if ( !isset($this->Data[$FromNode]) ) { + return(0); + } + if ( !isset($this->Data[$ToNode]) ){ + return(0); + } + + $R = isset($Settings["R"]) ? $Settings["R"] : 0; + $G = isset($Settings["G"]) ? $Settings["G"] : 0; + $B = isset($Settings["B"]) ? $Settings["B"] : 0; + $Alpha = isset($Settings["Alpha"]) ? $Settings["Alpha"] : 100; + $Name = isset($Settings["Name"]) ? $Settings["Name"] : null; + $Ticks = isset($Settings["Ticks"]) ? $Settings["Ticks"] : null; + + $this->Links[$FromNode][$ToNode]["R"] = $R; + $this->Links[$ToNode][$FromNode]["R"] = $R; + $this->Links[$FromNode][$ToNode]["G"] = $G; + $this->Links[$ToNode][$FromNode]["G"] = $G; + $this->Links[$FromNode][$ToNode]["B"] = $B; + $this->Links[$ToNode][$FromNode]["B"] = $B; + $this->Links[$FromNode][$ToNode]["Alpha"] = $Alpha; + $this->Links[$ToNode][$FromNode]["Alpha"] = $Alpha; + $this->Links[$FromNode][$ToNode]["Name"] = $Name; + $this->Links[$ToNode][$FromNode]["Name"] = $Name; + $this->Links[$FromNode][$ToNode]["Ticks"] = $Ticks; + $this->Links[$ToNode][$FromNode]["Ticks"] = $Ticks; + } + + /** + * + * @param type $Settings + */ + public function setNodeDefaults($Settings="") + { + if ( isset($Settings["R"]) ) { + $this->Default["R"] = $Settings["R"]; + } + if ( isset($Settings["G"]) ) { + $this->Default["G"] = $Settings["G"]; + } + if ( isset($Settings["B"]) ) { + $this->Default["B"] = $Settings["B"]; + } + if ( isset($Settings["Alpha"]) ) { + $this->Default["Alpha"] = $Settings["Alpha"]; + } + if ( isset($Settings["BorderR"]) ) { + $this->Default["BorderR"] = $Settings["BorderR"]; + } + if ( isset($Settings["BorderG"]) ) { + $this->Default["BorderG"] = $Settings["BorderG"]; + } + if ( isset($Settings["BorderB"]) ) { + $this->Default["BorderB"] = $Settings["BorderB"]; + } + if ( isset($Settings["BorderAlpha"]) ) { + $this->Default["BorderAlpha"] = $Settings["BorderAlpha"]; + } + if ( isset($Settings["Surrounding"]) ) { + $this->Default["Surrounding"] = $Settings["Surrounding"]; + } + if ( isset($Settings["BackgroundR"]) ) { + $this->Default["BackgroundR"] = $Settings["BackgroundR"]; + } + if ( isset($Settings["BackgroundG"]) ) { + $this->Default["BackgroundG"] = $Settings["BackgroundG"]; + } + if ( isset($Settings["BackgroundB"]) ) { + $this->Default["BackgroundB"] = $Settings["BackgroundB"]; + } + if ( isset($Settings["BackgroundAlpha"]) ) { + $this->Default["BackgroundAlpha"] = $Settings["BackgroundAlpha"]; + } + if ( isset($Settings["NodeType"]) ) { + $this->Default["NodeType"] = $Settings["NodeType"]; + } + if ( isset($Settings["Size"]) ) { + $this->Default["Size"] = $Settings["Size"]; + } + if ( isset($Settings["Shape"]) ) { + $this->Default["Shape"] = $Settings["Shape"]; + } + if ( isset($Settings["FreeZone"]) ) { + $this->Default["FreeZone"] = $Settings["FreeZone"]; + } + } + + /** + * Add a node + * @param type $NodeID + * @param type $Settings + * @return type + */ + public function addNode($NodeID,$Settings="") + { + /* if the node already exists, ignore */ + if (isset($this->Data[$NodeID])) { + return(0); + } + + $Name = isset($Settings["Name"]) ? $Settings["Name"] : "Node ".$NodeID; + $Connections = isset($Settings["Connections"]) ? $Settings["Connections"] : null; + + $R = isset($Settings["R"]) ? $Settings["R"] : $this->Default["R"]; + $G = isset($Settings["G"]) ? $Settings["G"] : $this->Default["G"]; + $B = isset($Settings["B"]) ? $Settings["B"] : $this->Default["B"]; + $Alpha = isset($Settings["Alpha"]) ? $Settings["Alpha"] : $this->Default["Alpha"]; + $BorderR = isset($Settings["BorderR"]) ? $Settings["BorderR"] : $this->Default["BorderR"]; + $BorderG = isset($Settings["BorderG"]) ? $Settings["BorderG"] : $this->Default["BorderG"]; + $BorderB = isset($Settings["BorderB"]) ? $Settings["BorderB"] : $this->Default["BorderB"]; + $BorderAlpha = isset($Settings["BorderAlpha"]) ? $Settings["BorderAlpha"] : $this->Default["BorderAlpha"]; + $Surrounding = isset($Settings["Surrounding"]) ? $Settings["Surrounding"] : $this->Default["Surrounding"]; + $BackgroundR = isset($Settings["BackgroundR"]) ? $Settings["BackgroundR"] : $this->Default["BackgroundR"]; + $BackgroundG = isset($Settings["BackgroundG"]) ? $Settings["BackgroundG"] : $this->Default["BackgroundG"]; + $BackgroundB = isset($Settings["BackgroundB"]) ? $Settings["BackgroundB"] : $this->Default["BackgroundB"]; + $BackgroundAlpha = isset($Settings["BackgroundAlpha"]) ? $Settings["BackgroundAlpha"] : $this->Default["BackgroundAlpha"]; + $Force = isset($Settings["Force"]) ? $Settings["Force"] : $this->Default["Force"]; + $NodeType = isset($Settings["NodeType"]) ? $Settings["NodeType"] : $this->Default["NodeType"]; + $Size = isset($Settings["Size"]) ? $Settings["Size"] : $this->Default["Size"]; + $Shape = isset($Settings["Shape"]) ? $Settings["Shape"] : $this->Default["Shape"]; + $FreeZone = isset($Settings["FreeZone"]) ? $Settings["FreeZone"] : $this->Default["FreeZone"]; + + if ( $Surrounding != null ) { + $BorderR = $R + $Surrounding; + $BorderG = $G + $Surrounding; + $BorderB = $B + $Surrounding; + } + + $this->Data[$NodeID]["R"] = $R; + $this->Data[$NodeID]["G"] = $G; + $this->Data[$NodeID]["B"] = $B; + $this->Data[$NodeID]["Alpha"] = $Alpha; + $this->Data[$NodeID]["BorderR"] = $BorderR; + $this->Data[$NodeID]["BorderG"] = $BorderG; + $this->Data[$NodeID]["BorderB"] = $BorderB; + $this->Data[$NodeID]["BorderAlpha"] = $BorderAlpha; + $this->Data[$NodeID]["BackgroundR"] = $BackgroundR; + $this->Data[$NodeID]["BackgroundG"] = $BackgroundG; + $this->Data[$NodeID]["BackgroundB"] = $BackgroundB; + $this->Data[$NodeID]["BackgroundAlpha"] = $BackgroundAlpha; + $this->Data[$NodeID]["Name"] = $Name; + $this->Data[$NodeID]["Force"] = $Force; + $this->Data[$NodeID]["Type"] = $NodeType; + $this->Data[$NodeID]["Size"] = $Size; + $this->Data[$NodeID]["Shape"] = $Shape; + $this->Data[$NodeID]["FreeZone"] = $FreeZone; + if ( $Connections != null ) { + if ( is_array($Connections ) ) { + foreach($Connections as $Key => $Value) { + $this->Data[$NodeID]["Connections"][] = $Value; + } + } else { + $this->Data[$NodeID]["Connections"][] = $Connections; + } + } + } + + /** + * Set color attribute for a list of nodes + * @param type $Nodes + * @param type $Settings + */ + public function setNodesColor($Nodes,$Settings="") + { + if ( is_array($Nodes) ) { + foreach ($Nodes as $Key => $NodeID) { + if (isset($this->Data[$NodeID]) ) { + if ( isset($Settings["R"]) ) { $this->Data[$NodeID]["R"] = $Settings["R"]; } + if ( isset($Settings["G"]) ) { $this->Data[$NodeID]["G"] = $Settings["G"]; } + if ( isset($Settings["B"]) ) { $this->Data[$NodeID]["B"] = $Settings["B"]; } + if ( isset($Settings["Alpha"]) ) { $this->Data[$NodeID]["Alpha"] = $Settings["Alpha"]; } + if ( isset($Settings["BorderR"]) ) { $this->Data[$NodeID]["BorderR"] = $Settings["BorderR"]; } + if ( isset($Settings["BorderG"]) ) { $this->Data[$NodeID]["BorderG"] = $Settings["BorderG"]; } + if ( isset($Settings["BorderB"]) ) { $this->Data[$NodeID]["BorderB"] = $Settings["BorderB"]; } + if ( isset($Settings["BorderAlpha"]) ) { $this->Data[$NodeID]["BorderAlpha"] = $Settings["BorderAlpha"]; } + if ( isset($Settings["Surrounding"]) ) { $this->Data[$NodeID]["BorderR"] = $this->Data[$NodeID]["R"] + $Settings["Surrounding"]; $this->Data[$NodeID]["BorderG"] = $this->Data[$NodeID]["G"] + $Settings["Surrounding"]; $this->Data[$NodeID]["BorderB"] = $this->Data[$NodeID]["B"] + $Settings["Surrounding"]; } + } + } + } else { + if ( isset($Settings["R"]) ) { $this->Data[$Nodes]["R"] = $Settings["R"]; } + if ( isset($Settings["G"]) ) { $this->Data[$Nodes]["G"] = $Settings["G"]; } + if ( isset($Settings["B"]) ) { $this->Data[$Nodes]["B"] = $Settings["B"]; } + if ( isset($Settings["Alpha"]) ) { $this->Data[$Nodes]["Alpha"] = $Settings["Alpha"]; } + if ( isset($Settings["BorderR"]) ) { $this->Data[$Nodes]["BorderR"] = $Settings["BorderR"]; } + if ( isset($Settings["BorderG"]) ) { $this->Data[$Nodes]["BorderG"] = $Settings["BorderG"]; } + if ( isset($Settings["BorderB"]) ) { $this->Data[$Nodes]["BorderB"] = $Settings["BorderB"]; } + if ( isset($Settings["BorderAlpha"]) ) { $this->Data[$Nodes]["BorderAlpha"] = $Settings["BorderAlpha"]; } + if ( isset($Settings["Surrounding"]) ) { $this->Data[$Nodes]["BorderR"] = $this->Data[$NodeID]["R"] + $Settings["Surrounding"]; $this->Data[$NodeID]["BorderG"] = $this->Data[$NodeID]["G"] + $Settings["Surrounding"]; $this->Data[$NodeID]["BorderB"] = $this->Data[$NodeID]["B"] + $Settings["Surrounding"]; } + } + } + + /** + * Returns all the nodes details + * @return type + */ + public function dumpNodes() + { + return($this->Data); + } + + /* Check if a connection exists and create it if required */ + public function checkConnection($SourceID, $TargetID) + { + if ( isset($this->Data[$SourceID]["Connections"]) ) { + foreach ($this->Data[$SourceID]["Connections"] as $Key => $ConnectionID) { + if ( $TargetID == $ConnectionID ) { + return true; + } + } + } + $this->Data[$SourceID]["Connections"][] = $TargetID; + } + + /** + * Get the median linked nodes position + * @param type $Key + * @param type $X + * @param type $Y + * @return type + */ + public function getMedianOffset($Key,$X,$Y) + { + $Cpt = 1; + if (isset($this->Data[$Key]["Connections"]) ) { + foreach($this->Data[$Key]["Connections"] as $ID => $NodeID) { + if (isset($this->Data[$NodeID]["X"]) + && isset($this->Data[$NodeID]["Y"]) + ) { + $X = $X + $this->Data[$NodeID]["X"]; + $Y = $Y + $this->Data[$NodeID]["Y"]; + $Cpt++; + } + } + } + return(array("X"=>$X/$Cpt,"Y"=>$Y/$Cpt)); + } + + /** + * Return the ID of the attached partner with the biggest weight + * @param type $Key + * @return type + */ + public function getBiggestPartner($Key) + { + if (!isset($this->Data[$Key]["Connections"]) ) { + return(""); + } + + $MaxWeight = 0; $Result = ""; + foreach($this->Data[$Key]["Connections"] as $Key => $PeerID) { + if ( $this->Data[$PeerID]["Weight"] > $MaxWeight ) { + $MaxWeight = $this->Data[$PeerID]["Weight"]; + $Result = $PeerID; + } + } + return($Result); + } + + /** + * Do the initial node positions computing pass + * @param type $Algorithm + */ + public function firstPass($Algorithm) + { + $CenterX = ($this->X2 - $this->X1) / 2 + $this->X1; + $CenterY = ($this->Y2 - $this->Y1) / 2 + $this->Y1; + + /* Check connections reciprocity */ + foreach($this->Data as $Key => $Settings) { + if ( isset($Settings["Connections"]) ) { + foreach($Settings["Connections"] as $ID => $ConnectionID) { + $this->checkConnection($ConnectionID,$Key); + } + } + } + + if ( $this->AutoComputeFreeZone ) { + $this->autoFreeZone(); + } + + /* Get the max number of connections */ + $MaxConnections = 0; + foreach ($this->Data as $Key => $Settings) { + if (isset($Settings["Connections"]) ) { + if ($MaxConnections < count($Settings["Connections"] ) ) { + $MaxConnections = count($Settings["Connections"]); + } + } + } + + if ( $Algorithm == ALGORITHM_WEIGHTED ) { + foreach($this->Data as $Key => $Settings) { + if ( $Settings["Type"] == NODE_TYPE_CENTRAL ) { + $this->Data[$Key]["X"] = $CenterX; + $this->Data[$Key]["Y"] = $CenterY; + } + if ( $Settings["Type"] == NODE_TYPE_FREE ) { + if ( isset($Settings["Connections"]) ) { + $Connections = count($Settings["Connections"]); + } else { + $Connections = 0; + } + + $Ring = $MaxConnections - $Connections; + $Angle = rand(0,360); + + $this->Data[$Key]["X"] = cos(deg2rad($Angle)) * ($Ring*$this->RingSize) + $CenterX; + $this->Data[$Key]["Y"] = sin(deg2rad($Angle)) * ($Ring*$this->RingSize) + $CenterY; + } + } + } elseif ( $Algorithm == ALGORITHM_CENTRAL ) { + /* Put a weight on each nodes */ + foreach($this->Data as $Key => $Settings) { + if ( isset($Settings["Connections"]) ) { + $this->Data[$Key]["Weight"] = count($Settings["Connections"]); + } else { + $this->Data[$Key]["Weight"] = 0; + } + } + + $MaxConnections = $MaxConnections + 1; + for ($i=$MaxConnections;$i>=0;$i--) { + foreach ($this->Data as $Key => $Settings) { + if ( $Settings["Type"] == NODE_TYPE_CENTRAL ) { + $this->Data[$Key]["X"] = $CenterX; + $this->Data[$Key]["Y"] = $CenterY; + } + if ( $Settings["Type"] == NODE_TYPE_FREE ) { + if ( isset($Settings["Connections"]) ) { + $Connections = count($Settings["Connections"]); + } else { + $Connections = 0; + } + + if ( $Connections == $i ) { + $BiggestPartner = $this->getBiggestPartner($Key); + if ( $BiggestPartner != "" ) { + $Ring = $this->Data[$BiggestPartner]["FreeZone"]; + $Weight = $this->Data[$BiggestPartner]["Weight"]; + $AngleDivision = 360 / $this->Data[$BiggestPartner]["Weight"]; + $Done = false; $Tries = 0; + while (!$Done && $Tries <= $Weight*2) { + $Tries++; + $Angle = floor(rand(0,$Weight)*$AngleDivision); + if (!isset($this->Data[$BiggestPartner]["Angular"][$Angle]) + || !isset($this->Data[$BiggestPartner]["Angular"]) + ) { + $this->Data[$BiggestPartner]["Angular"][$Angle] = $Angle; + $Done = true; + } + } + if ( !$Done ) { + $Angle = rand(0,360); + $this->Data[$BiggestPartner]["Angular"][$Angle] = $Angle; + } + + $X = cos(deg2rad($Angle)) * ($Ring) + $this->Data[$BiggestPartner]["X"]; + $Y = sin(deg2rad($Angle)) * ($Ring) + $this->Data[$BiggestPartner]["Y"]; + + $this->Data[$Key]["X"] = $X; + $this->Data[$Key]["Y"] = $Y; + } + } + } + } + } + } elseif ( $Algorithm == ALGORITHM_CIRCULAR ) { + $MaxConnections = $MaxConnections + 1; + for ($i=$MaxConnections;$i>=0;$i--) { + foreach ($this->Data as $Key => $Settings) { + if ( $Settings["Type"] == NODE_TYPE_CENTRAL ) { + $this->Data[$Key]["X"] = $CenterX; + $this->Data[$Key]["Y"] = $CenterY; + } + if ( $Settings["Type"] == NODE_TYPE_FREE ) { + if (isset($Settings["Connections"])) { + $Connections = count($Settings["Connections"]); + } else { + $Connections = 0; + } + + if ( $Connections == $i ) { + $Ring = $MaxConnections - $Connections; + $Angle = rand(0,360); + + $X = cos(deg2rad($Angle)) * ($Ring*$this->RingSize) + $CenterX; + $Y = sin(deg2rad($Angle)) * ($Ring*$this->RingSize) + $CenterY; + + $MedianOffset = $this->getMedianOffset($Key,$X,$Y); + + $this->Data[$Key]["X"] = $MedianOffset["X"]; + $this->Data[$Key]["Y"] = $MedianOffset["Y"]; + } + } + } + } + } elseif ( $Algorithm == ALGORITHM_RANDOM ) { + foreach($this->Data as $Key => $Settings) { + if ( $Settings["Type"] == NODE_TYPE_FREE ) { + $this->Data[$Key]["X"] = $CenterX + rand(-20,20); + $this->Data[$Key]["Y"] = $CenterY + rand(-20,20); + } + if ( $Settings["Type"] == NODE_TYPE_CENTRAL ) { + $this->Data[$Key]["X"] = $CenterX; + $this->Data[$Key]["Y"] = $CenterY; + } + } + } + } + + /** + * Compute one pass + */ + public function doPass() + { + /* Compute vectors */ + foreach($this->Data as $Key => $Settings) { + if ( $Settings["Type"] != NODE_TYPE_CENTRAL ) { + unset($this->Data[$Key]["Vectors"]); + + $X1 = $Settings["X"]; + $Y1 = $Settings["Y"]; + + /* Repulsion vectors */ + foreach($this->Data as $Key2 => $Settings2) { + if ( $Key != $Key2 ) { + $X2 = $this->Data[$Key2]["X"]; + $Y2 = $this->Data[$Key2]["Y"]; + $FreeZone = $this->Data[$Key2]["FreeZone"]; + + $Distance = $this->getDistance($X1,$Y1,$X2,$Y2); + $Angle = $this->getAngle($X1,$Y1,$X2,$Y2) + 180; + + /* Nodes too close, repulsion occurs */ + if ( $Distance < $FreeZone ) { + $Force = log(pow(2,$FreeZone-$Distance)); + if ( $Force > 1 ) { + $this->Data[$Key]["Vectors"][] = array( + "Type"=>"R", + "Angle"=>$Angle % 360, + "Force"=>$Force + ); + } + } + } + } + + /* Attraction vectors */ + if ( isset($Settings["Connections"]) ) { + foreach($Settings["Connections"] as $ID => $NodeID) { + if ( isset($this->Data[$NodeID]) ) { + $X2 = $this->Data[$NodeID]["X"]; + $Y2 = $this->Data[$NodeID]["Y"]; + $FreeZone = $this->Data[$Key2]["FreeZone"]; + + $Distance = $this->getDistance($X1,$Y1,$X2,$Y2); + $Angle = $this->getAngle($X1,$Y1,$X2,$Y2); + + if ( $Distance > $FreeZone ) { + $Force = log(($Distance-$FreeZone)+1); + } else { + $Force = log(($FreeZone-$Distance)+1); + ($Angle = $Angle + 180); + } + + if ( $Force > 1 ) { + $this->Data[$Key]["Vectors"][] = array( + "Type"=>"A", + "Angle"=>$Angle % 360, + "Force"=>$Force + ); + } + } + } + } + } + } + + /* Move the nodes accoding to the vectors */ + foreach($this->Data as $Key => $Settings) { + $X = $Settings["X"]; + $Y = $Settings["Y"]; + + if ( isset($Settings["Vectors"]) && $Settings["Type"] != NODE_TYPE_CENTRAL ) { + foreach($Settings["Vectors"] as $ID => $Vector) { + $Type = $Vector["Type"]; + $Force = $Vector["Force"]; + $Angle = $Vector["Angle"]; + $Factor = $Type == "A" ? $this->MagneticForceA : $this->MagneticForceR; + + $X = cos(deg2rad($Angle)) * $Force * $Factor + $X; + $Y = sin(deg2rad($Angle)) * $Force * $Factor + $Y; + } + } + + $this->Data[$Key]["X"] = $X; + $this->Data[$Key]["Y"] = $Y; + } + } + + /** + * + * @return type + */ + public function lastPass() + { + /* Put everything inside the graph area */ + foreach($this->Data as $Key => $Settings) { + $X = $Settings["X"]; + $Y = $Settings["Y"]; + + if ( $X < $this->X1 ) { $X = $this->X1; } + if ( $X > $this->X2 ) { $X = $this->X2; } + if ( $Y < $this->Y1 ) { $Y = $this->Y1; } + if ( $Y > $this->Y2 ) { $Y = $this->Y2; } + + $this->Data[$Key]["X"] = $X; + $this->Data[$Key]["Y"] = $Y; + } + + /* Dump all links */ + $Links = ""; + foreach($this->Data as $Key => $Settings) { + $X1 = $Settings["X"]; + $Y1 = $Settings["Y"]; + + if ( isset($Settings["Connections"]) ) { + foreach ($Settings["Connections"] as $ID => $NodeID) { + if ( isset($this->Data[$NodeID]) ) { + $X2 = $this->Data[$NodeID]["X"]; + $Y2 = $this->Data[$NodeID]["Y"]; + + $Links[] = array( + "X1"=>$X1, + "Y1"=>$Y1, + "X2"=>$X2, + "Y2"=>$Y2, + "Source"=>$Settings["Name"], + "Destination"=>$this->Data[$NodeID]["Name"] + ); + } + } + } + } + + /* Check collisions */ + $Conflicts = 0; + foreach($this->Data as $Key => $Settings) { + $X1 = $Settings["X"]; + $Y1 = $Settings["Y"]; + + if ( isset($Settings["Connections"]) ) { + foreach ($Settings["Connections"] as $ID => $NodeID) { + if ( isset($this->Data[$NodeID]) ) { + $X2 = $this->Data[$NodeID]["X"]; + $Y2 = $this->Data[$NodeID]["Y"]; + + foreach($Links as $IDLinks => $Link) { + $X3 = $Link["X1"]; + $Y3 = $Link["Y1"]; + $X4 = $Link["X2"]; + $Y4 = $Link["Y2"]; + + if ( !($X1 == $X3 && $X2 == $X4 && $Y1 == $Y3 && $Y2 == $Y4 ) ) { + if ( $this->intersect($X1,$Y1,$X2,$Y2,$X3,$Y3,$X4,$Y4) ) { + if ( $Link["Source"] != $Settings["Name"] + && $Link["Source"] != $this->Data[$NodeID]["Name"] + && $Link["Destination"] != $Settings["Name"] + && $Link["Destination"] != $this->Data[$NodeID]["Name"] + ) { + $Conflicts++; + } + } + } + } + } + } + } + } + return($Conflicts/2); + } + + /** + * Center the graph + */ + public function center() + { + /* Determine the real center */ + $TargetCenterX = ($this->X2 - $this->X1) / 2 + $this->X1; + $TargetCenterY = ($this->Y2 - $this->Y1) / 2 + $this->Y1; + + /* Get current boundaries */ + $XMin = $this->X2; $XMax = $this->X1; + $YMin = $this->Y2; $YMax = $this->Y1; + foreach($this->Data as $Key => $Settings) { + $X = $Settings["X"]; + $Y = $Settings["Y"]; + + if ( $X < $XMin) { $XMin = $X; } + if ( $X > $XMax) { $XMax = $X; } + if ( $Y < $YMin) { $YMin = $Y; } + if ( $Y > $YMax) { $YMax = $Y; } + } + $CurrentCenterX = ($XMax - $XMin) / 2 + $XMin; + $CurrentCenterY = ($YMax - $YMin) / 2 + $YMin; + + /* Compute the offset to apply */ + $XOffset = $TargetCenterX - $CurrentCenterX; + $YOffset = $TargetCenterY - $CurrentCenterY; + + /* Correct the points position */ + foreach($this->Data as $Key => $Settings) { + $this->Data[$Key]["X"] = $Settings["X"] + $XOffset; + $this->Data[$Key]["Y"] = $Settings["Y"] + $YOffset; + } + } + + /** + * Create the encoded string + * @param type $Object + * @param string $Settings + * @return type + */ + public function drawSpring($Object,$Settings="") + { + $this->pChartObject = $Object; + + $Pass = isset($Settings["Pass"]) ? $Settings["Pass"] : 50; + $Retries = isset($Settings["Retry"]) ? $Settings["Retry"] : 10; + $this->MagneticForceA = isset($Settings["MagneticForceA"]) ? $Settings["MagneticForceA"] : 1.5; + $this->MagneticForceR = isset($Settings["MagneticForceR"]) ? $Settings["MagneticForceR"] : 2; + $this->RingSize = isset($Settings["RingSize"]) ? $Settings["RingSize"] : 40; + $DrawVectors = isset($Settings["DrawVectors"]) ? $Settings["DrawVectors"] : false; + $DrawQuietZone = isset($Settings["DrawQuietZone"]) ? $Settings["DrawQuietZone"] : false; + $CenterGraph = isset($Settings["CenterGraph"]) ? $Settings["CenterGraph"] : true; + $TextPadding = isset($Settings["TextPadding"]) ? $Settings["TextPadding"] : 4; + $Algorithm = isset($Settings["Algorithm"]) ? $Settings["Algorithm"] : ALGORITHM_WEIGHTED; + + $FontSize = $Object->FontSize; + $this->X1 = $Object->GraphAreaX1; + $this->Y1 = $Object->GraphAreaY1; + $this->X2 = $Object->GraphAreaX2; + $this->Y2 = $Object->GraphAreaY2; + + $Conflicts = 1; + $Jobs = 0; $this->History["MinimumConflicts"] = -1; + while ($Conflicts != 0 && $Jobs < $Retries ) { + $Jobs++; + + /* Compute the initial settings */ + $this->firstPass($Algorithm); + + /* Apply the vectors */ + if ( $Pass > 0 ) { + for ($i=0; $i<=$Pass; $i++) { + $this->doPass(); + } + } + + $Conflicts = $this->lastPass(); + if ( $this->History["MinimumConflicts"] == -1 + || $Conflicts < $this->History["MinimumConflicts"] + ) { + $this->History["MinimumConflicts"] = $Conflicts; + $this->History["Result"] = $this->Data; + } + } + + $Conflicts = $this->History["MinimumConflicts"]; + $this->Data = $this->History["Result"]; + + if ( $CenterGraph ) { + $this->center(); + } + + /* Draw the connections */ + $Drawn = ""; + foreach($this->Data as $Key => $Settings) { + $X = $Settings["X"]; + $Y = $Settings["Y"]; + + if ( isset($Settings["Connections"]) ) { + foreach ($Settings["Connections"] as $ID => $NodeID) { + if (!isset($Drawn[$Key])) { + $Drawn[$Key] = ""; + } + if (!isset($Drawn[$NodeID])) { + $Drawn[$NodeID] = ""; + } + + if ( isset($this->Data[$NodeID]) + && !isset($Drawn[$Key][$NodeID]) + && !isset($Drawn[$NodeID][$Key]) + ) { + $Color = array( + "R"=>$this->Default["LinkR"], + "G"=>$this->Default["LinkG"], + "B"=>$this->Default["LinkB"], + "Alpha"=>$this->Default["Alpha"] + ); + + if ($this->Links != "" ) { + if (isset($this->Links[$Key][$NodeID]["R"])) { + $Color = array( + "R"=>$this->Links[$Key][$NodeID]["R"], + "G"=>$this->Links[$Key][$NodeID]["G"], + "B"=>$this->Links[$Key][$NodeID]["B"], + "Alpha"=>$this->Links[$Key][$NodeID]["Alpha"] + ); + } + + if ( isset($this->Links[$Key][$NodeID]["Ticks"])) { + $Color["Ticks"] = $this->Links[$Key][$NodeID]["Ticks"]; + } + } + + $X2 = $this->Data[$NodeID]["X"]; + $Y2 = $this->Data[$NodeID]["Y"]; + $this->pChartObject->drawLine($X,$Y,$X2,$Y2,$Color); + $Drawn[$Key][$NodeID] = true; + + if ( isset($this->Links) && $this->Links != "" ) { + if ( isset($this->Links[$Key][$NodeID]["Name"]) + || isset($this->Links[$NodeID][$Key]["Name"]) + ) { + $Name = isset($this->Links[$Key][$NodeID]["Name"]) ? $this->Links[$Key][$NodeID]["Name"] : $this->Links[$NodeID][$Key]["Name"]; + $TxtX = ($X2 - $X)/2 + $X; + $TxtY = ($Y2 - $Y)/2 + $Y; + + if ( $X <= $X2 ) { + $Angle = (360-$this->getAngle($X,$Y,$X2,$Y2)) % 360; + } else { + $Angle = (360-$this->getAngle($X2,$Y2,$X,$Y)) % 360; + } + $Settings = $Color; + $Settings["Angle"] = $Angle; + $Settings["Align"] = TEXT_ALIGN_BOTTOMMIDDLE; + $this->pChartObject->drawText($TxtX,$TxtY,$Name,$Settings); + } + } + } + } + } + } + + /* Draw the quiet zones */ + if ( $DrawQuietZone ) { + foreach($this->Data as $Key => $Settings) { + $X = $Settings["X"]; + $Y = $Settings["Y"]; + $FreeZone = $Settings["FreeZone"]; + + $this->pChartObject->drawFilledCircle( + $X, + $Y, + $FreeZone, + array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>2) + ); + } + } + + + /* Draw the nodes */ + foreach($this->Data as $Key => $Settings) { + $X = $Settings["X"]; + $Y = $Settings["Y"]; + $Name = $Settings["Name"]; + $FreeZone = $Settings["FreeZone"]; + $Shape = $Settings["Shape"]; + $Size = $Settings["Size"]; + + $Color = array( + "R"=>$Settings["R"], + "G"=>$Settings["G"], + "B"=>$Settings["B"], + "Alpha"=>$Settings["Alpha"], + "BorderR"=>$Settings["BorderR"], + "BorderG"=>$Settings["BorderG"], + "BorderB"=>$Settings["BorderB"], + "BorderApha"=>$Settings["BorderAlpha"] + ); + + if ( $Shape == NODE_SHAPE_CIRCLE ) { + $this->pChartObject->drawFilledCircle($X,$Y,$Size,$Color); + } elseif ( $Shape == NODE_SHAPE_TRIANGLE ) { + $Points = ""; + $Points[] = cos(deg2rad(270)) * $Size + $X; $Points[] = sin(deg2rad(270)) * $Size + $Y; + $Points[] = cos(deg2rad(45)) * $Size + $X; $Points[] = sin(deg2rad(45)) * $Size + $Y; + $Points[] = cos(deg2rad(135)) * $Size + $X; $Points[] = sin(deg2rad(135)) * $Size + $Y; + $this->pChartObject->drawPolygon($Points,$Color); + } elseif ( $Shape == NODE_SHAPE_SQUARE ) { + $Offset = $Size/2; $Size = $Size / 2; + $this->pChartObject->drawFilledRectangle($X-$Offset,$Y-$Offset,$X+$Offset,$Y+$Offset,$Color); + } + + if ( $Name != "" ) { + $LabelOptions = array( + "R"=>$this->Labels["R"], + "G"=>$this->Labels["G"], + "B"=>$this->Labels["B"], + "Alpha"=>$this->Labels["Alpha"] + ); + + if ( $this->Labels["Type"] == LABEL_LIGHT ) { + $LabelOptions["Align"] = TEXT_ALIGN_BOTTOMLEFT; + $this->pChartObject->drawText($X,$Y,$Name,$LabelOptions); + } elseif ( $this->Labels["Type"] == LABEL_CLASSIC ) { + $LabelOptions["Align"] = TEXT_ALIGN_TOPMIDDLE; + $LabelOptions["DrawBox"] = true; + $LabelOptions["BoxAlpha"] = 50; + $LabelOptions["BorderOffset"] = 4; + $LabelOptions["RoundedRadius"] = 3; + $LabelOptions["BoxRounded"] = true; + $LabelOptions["NoShadow"] = true; + + $this->pChartObject->drawText($X,$Y+$Size+$TextPadding,$Name,$LabelOptions); + } + } + } + + /* Draw the vectors */ + if ( $DrawVectors ) { + foreach($this->Data as $Key => $Settings) { + $X1 = $Settings["X"]; + $Y1 = $Settings["Y"]; + + if ( isset($Settings["Vectors"]) && $Settings["Type"] != NODE_TYPE_CENTRAL ) { + foreach($Settings["Vectors"] as $ID => $Vector) { + $Type = $Vector["Type"]; + $Force = $Vector["Force"]; + $Angle = $Vector["Angle"]; + $Factor = $Type == "A" ? $this->MagneticForceA : $this->MagneticForceR; + $Color = $Type == "A" ? array("FillR"=>255,"FillG"=>0,"FillB"=>0) : array("FillR"=>0,"FillG"=>255,"FillB"=>0); + + $X2 = cos(deg2rad($Angle)) * $Force * $Factor + $X1; + $Y2 = sin(deg2rad($Angle)) * $Force * $Factor + $Y1; + + $this->pChartObject->drawArrow($X1,$Y1,$X2,$Y2,$Color); + } + } + } + } + + return(array("Pass"=>$Jobs,"Conflicts"=>$Conflicts)); + } + + /** + * Return the distance between two points + * @param type $X1 + * @param type $Y1 + * @param type $X2 + * @param type $Y2 + * @return type + */ + public function getDistance($X1,$Y1,$X2,$Y2) + { + return (sqrt(($X2-$X1)*($X2-$X1)+($Y2-$Y1)*($Y2-$Y1))); + } + + /** + * Return the angle made by a line and the X axis + * @param type $X1 + * @param type $Y1 + * @param type $X2 + * @param type $Y2 + * @return type + */ + public 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)); + } + } + + /** + * + * @param type $X1 + * @param type $Y1 + * @param type $X2 + * @param type $Y2 + * @param type $X3 + * @param type $Y3 + * @param type $X4 + * @param type $Y4 + * @return boolean + */ + public function intersect($X1,$Y1,$X2,$Y2,$X3,$Y3,$X4,$Y4) + { + $A = (($X3 * $Y4 - $X4 * $Y3) * ($X1 - $X2) - ($X1 * $Y2 - $X2 * $Y1) * ($X3 - $X4)); + $B = (($Y1 - $Y2) * ($X3 - $X4) - ($Y3 - $Y4) * ($X1 - $X2)); + + if ( $B == 0 ) { + return false; + } + $Xi = $A / $B; + + $C = ($X1 - $X2); + if ( $C == 0 ) { + return false; + } + $Yi = $Xi * (($Y1 - $Y2)/$C) + (($X1 * $Y2 - $X2 * $Y1)/$C); + + if ( $Xi >= min($X1,$X2) && $Xi >= min($X3,$X4) && $Xi <= max($X1,$X2) && $Xi <= max($X3,$X4)) { + if ( $Yi >= min($Y1,$Y2) && $Yi >= min($Y3,$Y4) && $Yi <= max($Y1,$Y2) && $Yi <= max($Y3,$Y4)) { + return true; + } + } + + return false; + } +} diff --git a/vendor/szymach/c-pchart/src/Classes/pStock.php b/vendor/szymach/c-pchart/src/Classes/pStock.php new file mode 100644 index 0000000000..d772454204 --- /dev/null +++ b/vendor/szymach/c-pchart/src/Classes/pStock.php @@ -0,0 +1,405 @@ +pChartObject = $pChartObject; + $this->pDataObject = $pDataObject; + } + + /** + * Draw a stock chart + * @param type $Format + * @return type + */ + public function drawStockChart($Format="") + { + $SerieOpen = isset($Format["SerieOpen"]) ? $Format["SerieOpen"] : "Open"; + $SerieClose = isset($Format["SerieClose"]) ? $Format["SerieClose"] : "Close"; + $SerieMin = isset($Format["SerieMin"]) ? $Format["SerieMin"] : "Min"; + $SerieMax = isset($Format["SerieMax"]) ? $Format["SerieMax"] : "Max"; + $SerieMedian = isset($Format["SerieMedian"]) ? $Format["SerieMedian"] : null; + $LineWidth = isset($Format["LineWidth"]) ? $Format["LineWidth"] : 1; + $LineR = isset($Format["LineR"]) ? $Format["LineR"] : 0; + $LineG = isset($Format["LineG"]) ? $Format["LineG"] : 0; + $LineB = isset($Format["LineB"]) ? $Format["LineB"] : 0; + $LineAlpha = isset($Format["LineAlpha"]) ? $Format["LineAlpha"] : 100; + $ExtremityWidth = isset($Format["ExtremityWidth"]) ? $Format["ExtremityWidth"] : 1; + $ExtremityLength = isset($Format["ExtremityLength"]) ? $Format["ExtremityLength"] : 3; + $ExtremityR = isset($Format["ExtremityR"]) ? $Format["ExtremityR"] : 0; + $ExtremityG = isset($Format["ExtremityG"]) ? $Format["ExtremityG"] : 0; + $ExtremityB = isset($Format["ExtremityB"]) ? $Format["ExtremityB"] : 0; + $ExtremityAlpha = isset($Format["ExtremityAlpha"]) ? $Format["ExtremityAlpha"] : 100; + $BoxWidth = isset($Format["BoxWidth"]) ? $Format["BoxWidth"] : 8; + $BoxUpR = isset($Format["BoxUpR"]) ? $Format["BoxUpR"] : 188; + $BoxUpG = isset($Format["BoxUpG"]) ? $Format["BoxUpG"] : 224; + $BoxUpB = isset($Format["BoxUpB"]) ? $Format["BoxUpB"] : 46; + $BoxUpAlpha = isset($Format["BoxUpAlpha"]) ? $Format["BoxUpAlpha"] : 100; + $BoxUpSurrounding = isset($Format["BoxUpSurrounding"]) ? $Format["BoxUpSurrounding"] : null; + $BoxUpBorderR = isset($Format["BoxUpBorderR"]) ? $Format["BoxUpBorderR"] : $BoxUpR-20; + $BoxUpBorderG = isset($Format["BoxUpBorderG"]) ? $Format["BoxUpBorderG"] : $BoxUpG-20; + $BoxUpBorderB = isset($Format["BoxUpBorderB"]) ? $Format["BoxUpBorderB"] : $BoxUpB-20; + $BoxUpBorderAlpha = isset($Format["BoxUpBorderAlpha"]) ? $Format["BoxUpBorderAlpha"] : 100; + $BoxDownR = isset($Format["BoxDownR"]) ? $Format["BoxDownR"] : 224; + $BoxDownG = isset($Format["BoxDownG"]) ? $Format["BoxDownG"] : 100; + $BoxDownB = isset($Format["BoxDownB"]) ? $Format["BoxDownB"] : 46; + $BoxDownAlpha = isset($Format["BoxDownAlpha"]) ? $Format["BoxDownAlpha"] : 100; + $BoxDownSurrounding= isset($Format["BoxDownSurrounding"]) ? $Format["BoxDownSurrounding"] : null; + $BoxDownBorderR = isset($Format["BoxDownBorderR"]) ? $Format["BoxDownBorderR"] : $BoxDownR-20; + $BoxDownBorderG = isset($Format["BoxDownBorderG"]) ? $Format["BoxDownBorderG"] : $BoxDownG-20; + $BoxDownBorderB = isset($Format["BoxDownBorderB"]) ? $Format["BoxDownBorderB"] : $BoxDownB-20; + $BoxDownBorderAlpha= isset($Format["BoxDownBorderAlpha"]) ? $Format["BoxDownBorderAlpha"] : 100; + $ShadowOnBoxesOnly = isset($Format["ShadowOnBoxesOnly"]) ? $Format["ShadowOnBoxesOnly"] : true; + $MedianR = isset($Format["MedianR"]) ? $Format["MedianR"] : 255; + $MedianG = isset($Format["MedianG"]) ? $Format["MedianG"] : 0; + $MedianB = isset($Format["MedianB"]) ? $Format["MedianB"] : 0; + $MedianAlpha = isset($Format["MedianAlpha"]) ? $Format["MedianAlpha"] : 100; + $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : false; + $ImageMapTitle = isset($Format["ImageMapTitle"]) ? $Format["ImageMapTitle"] : "Stock Chart"; + + + /* Data Processing */ + $Data = $this->pDataObject->getData(); + $Palette = $this->pDataObject->getPalette(); + + if ( $BoxUpSurrounding != null ) { + $BoxUpBorderR = $BoxUpR + $BoxUpSurrounding; + $BoxUpBorderG = $BoxUpG + $BoxUpSurrounding; + $BoxUpBorderB = $BoxUpB + $BoxUpSurrounding; + } + if ( $BoxDownSurrounding != null ) { + $BoxDownBorderR = $BoxDownR + $BoxDownSurrounding; + $BoxDownBorderG = $BoxDownG + $BoxDownSurrounding; + $BoxDownBorderB = $BoxDownB + $BoxDownSurrounding; + } + + if ( $LineWidth != 1 ) { + $LineOffset = $LineWidth / 2; + } + $BoxOffset = $BoxWidth / 2; + + $Data = $this->pChartObject->DataSet->getData(); + list($XMargin,$XDivs) = $this->pChartObject->scaleGetXSettings(); + + if (!isset($Data["Series"][$SerieOpen]) + || !isset($Data["Series"][$SerieClose]) + || !isset($Data["Series"][$SerieMin]) + || !isset($Data["Series"][$SerieMax]) + ) { + return(STOCK_MISSING_SERIE); + } + $Plots = ""; + foreach($Data["Series"][$SerieOpen]["Data"] as $Key => $Value) { + $Point = ""; + if (isset($Data["Series"][$SerieClose]["Data"][$Key]) + || isset($Data["Series"][$SerieMin]["Data"][$Key]) + || isset($Data["Series"][$SerieMax]["Data"][$Key]) + ) { + $Point = array( + $Value, + $Data["Series"][$SerieClose]["Data"][$Key], + $Data["Series"][$SerieMin]["Data"][$Key], + $Data["Series"][$SerieMax]["Data"][$Key] + ); + } + if ($SerieMedian != null && isset($Data["Series"][$SerieMedian]["Data"][$Key]) ) { + $Point[] = $Data["Series"][$SerieMedian]["Data"][$Key]; + } + $Plots[] = $Point; + } + + $AxisID = $Data["Series"][$SerieOpen]["Axis"]; + $Mode = $Data["Axis"][$AxisID]["Display"]; + $Format = $Data["Axis"][$AxisID]["Format"]; + $Unit = $Data["Axis"][$AxisID]["Unit"]; + + $YZero = $this->pChartObject->scaleComputeY(0,array("AxisID"=>$AxisID)); + $XStep = ($this->pChartObject->GraphAreaX2-$this->pChartObject->GraphAreaX1-$XMargin*2)/$XDivs; + + $X = $this->pChartObject->GraphAreaX1 + $XMargin; + $Y = $this->pChartObject->GraphAreaY1 + $XMargin; + + $LineSettings = array("R"=>$LineR,"G"=>$LineG,"B"=>$LineB,"Alpha"=>$LineAlpha); + $ExtremitySettings = array("R"=>$ExtremityR,"G"=>$ExtremityG,"B"=>$ExtremityB,"Alpha"=>$ExtremityAlpha); + $BoxUpSettings = array( + "R"=>$BoxUpR, + "G"=>$BoxUpG, + "B"=>$BoxUpB, + "Alpha"=>$BoxUpAlpha, + "BorderR"=>$BoxUpBorderR, + "BorderG"=>$BoxUpBorderG, + "BorderB"=>$BoxUpBorderB, + "BorderAlpha"=>$BoxUpBorderAlpha + ); + $BoxDownSettings = array( + "R"=>$BoxDownR, + "G"=>$BoxDownG, + "B"=>$BoxDownB, + "Alpha"=>$BoxDownAlpha, + "BorderR"=>$BoxDownBorderR, + "BorderG"=>$BoxDownBorderG, + "BorderB"=>$BoxDownBorderB, + "BorderAlpha"=>$BoxDownBorderAlpha + ); + $MedianSettings = array("R"=>$MedianR,"G"=>$MedianG,"B"=>$MedianB,"Alpha"=>$MedianAlpha); + + foreach($Plots as $Key =>$Points) { + $PosArray = $this->pChartObject->scaleComputeY($Points,array("AxisID"=>$AxisID)); + + $Values = "Open :".$Data["Series"][$SerieOpen]["Data"][$Key] + . "
Close : ".$Data["Series"][$SerieClose]["Data"][$Key] + . "
Min : ".$Data["Series"][$SerieMin]["Data"][$Key] + . "
Max : ".$Data["Series"][$SerieMax]["Data"][$Key]."
"; + if ( $SerieMedian != null ) { + $Values = $Values."Median : ".$Data["Series"][$SerieMedian]["Data"][$Key]."
"; + } + if ( $PosArray[0] > $PosArray[1] ) { + $ImageMapColor = $this->pChartObject->toHTMLColor($BoxUpR,$BoxUpG,$BoxUpB); + } else { + $ImageMapColor = $this->pChartObject->toHTMLColor($BoxDownR,$BoxDownG,$BoxDownB); + } + + if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) { + if ( $YZero > $this->pChartObject->GraphAreaY2-1 ) { + $YZero = $this->pChartObject->GraphAreaY2-1; + } + if ( $YZero < $this->pChartObject->GraphAreaY1+1 ) { + $YZero = $this->pChartObject->GraphAreaY1+1; + } + + if ( $XDivs == 0 ) { + $XStep = 0; + } else { + $XStep = ($this->pChartObject->GraphAreaX2-$this->pChartObject->GraphAreaX1-$XMargin*2)/$XDivs; + } + + if ( $ShadowOnBoxesOnly ) { + $RestoreShadow = $this->pChartObject->Shadow; + $this->pChartObject->Shadow = false; + } + + if ( $LineWidth == 1 ) { + $this->pChartObject->drawLine($X,$PosArray[2],$X,$PosArray[3],$LineSettings); + } else { + $this->pChartObject->drawFilledRectangle($X-$LineOffset,$PosArray[2],$X+$LineOffset,$PosArray[3],$LineSettings); + } + + if ( $ExtremityWidth == 1 ) { + $this->pChartObject->drawLine($X-$ExtremityLength,$PosArray[2],$X+$ExtremityLength,$PosArray[2],$ExtremitySettings); + $this->pChartObject->drawLine($X-$ExtremityLength,$PosArray[3],$X+$ExtremityLength,$PosArray[3],$ExtremitySettings); + + if ( $RecordImageMap ) { + $this->pChartObject->addToImageMap( + "RECT", + floor($X-$ExtremityLength).",".floor($PosArray[2]) + .",".floor($X+$ExtremityLength)."," + .floor($PosArray[3]), + $ImageMapColor, + $ImageMapTitle, + $Values + ); + } + } else { + $this->pChartObject->drawFilledRectangle( + $X-$ExtremityLength, + $PosArray[2], + $X+$ExtremityLength, + $PosArray[2]-$ExtremityWidth, + $ExtremitySettings + ); + $this->pChartObject->drawFilledRectangle( + $X-$ExtremityLength, + $PosArray[3], + $X+$ExtremityLength, + $PosArray[3]+$ExtremityWidth, + $ExtremitySettings + ); + + if ( $RecordImageMap ) { + $this->pChartObject->addToImageMap( + "RECT", + floor($X-$ExtremityLength).",".floor($PosArray[2]-$ExtremityWidth) + .",".floor($X+$ExtremityLength)."," + .floor($PosArray[3]+$ExtremityWidth), + $ImageMapColor, + $ImageMapTitle, + $Values + ); + } + } + + if ( $ShadowOnBoxesOnly ) { + $this->pChartObject->Shadow = $RestoreShadow; + } + + if ( $PosArray[0] > $PosArray[1] ) { + $this->pChartObject->drawFilledRectangle( + $X-$BoxOffset, + $PosArray[0], + $X+$BoxOffset, + $PosArray[1], + $BoxUpSettings + ); + } else { + $this->pChartObject->drawFilledRectangle( + $X-$BoxOffset, + $PosArray[0], + $X+$BoxOffset, + $PosArray[1], + $BoxDownSettings + ); + } + + if ( isset($PosArray[4]) ) { + $this->pChartObject->drawLine( + $X-$ExtremityLength, + $PosArray[4], + $X+$ExtremityLength, + $PosArray[4], + $MedianSettings + ); + } + $X = $X + $XStep; + } elseif ( $Data["Orientation"] == SCALE_POS_TOPBOTTOM ) { + if ( $YZero > $this->pChartObject->GraphAreaX2-1 ) { + $YZero = $this->pChartObject->GraphAreaX2-1; + } + if ( $YZero < $this->pChartObject->GraphAreaX1+1 ) { + $YZero = $this->pChartObject->GraphAreaX1+1; + } + + if ( $XDivs == 0 ) { + $XStep = 0; + } else { + $XStep = ($this->pChartObject->GraphAreaY2-$this->pChartObject->GraphAreaY1-$XMargin*2)/$XDivs; + } + + if ( $LineWidth == 1 ) { + $this->pChartObject->drawLine($PosArray[2],$Y,$PosArray[3],$Y,$LineSettings); + } else { + $this->pChartObject->drawFilledRectangle( + $PosArray[2], + $Y-$LineOffset, + $PosArray[3], + $Y+$LineOffset, + $LineSettings + ); + } + if ( $ShadowOnBoxesOnly ) { + $RestoreShadow = $this->pChartObject->Shadow; + $this->pChartObject->Shadow = false; + } + + if ( $ExtremityWidth == 1 ) { + $this->pChartObject->drawLine( + $PosArray[2], + $Y-$ExtremityLength, + $PosArray[2], + $Y+$ExtremityLength, + $ExtremitySettings + ); + $this->pChartObject->drawLine( + $PosArray[3], + $Y-$ExtremityLength, + $PosArray[3], + $Y+$ExtremityLength, + $ExtremitySettings + ); + + if ( $RecordImageMap ) { + $this->pChartObject->addToImageMap( + "RECT", + floor($PosArray[2]).",".floor($Y-$ExtremityLength) + .",".floor($PosArray[3]).",".floor($Y+$ExtremityLength), + $ImageMapColor, + $ImageMapTitle, + $Values + ); + } + } else { + $this->pChartObject->drawFilledRectangle( + $PosArray[2], + $Y-$ExtremityLength, + $PosArray[2]-$ExtremityWidth, + $Y+$ExtremityLength, + $ExtremitySettings + ); + $this->pChartObject->drawFilledRectangle( + $PosArray[3], + $Y-$ExtremityLength, + $PosArray[3]+$ExtremityWidth, + $Y+$ExtremityLength, + $ExtremitySettings + ); + + if ( $RecordImageMap ) { + $this->pChartObject->addToImageMap( + "RECT", + floor($PosArray[2]-$ExtremityWidth)."," + .floor($Y-$ExtremityLength)."," + .floor($PosArray[3]+$ExtremityWidth)."," + .floor($Y+$ExtremityLength), + $ImageMapColor, + $ImageMapTitle, + $Values + ); + } + } + + if ( $ShadowOnBoxesOnly ) { + $this->pChartObject->Shadow = $RestoreShadow; + } + + if ( $PosArray[0] < $PosArray[1] ) { + $this->pChartObject->drawFilledRectangle( + $PosArray[0], + $Y-$BoxOffset, + $PosArray[1], + $Y+$BoxOffset, + $BoxUpSettings + ); + } else { + $this->pChartObject->drawFilledRectangle( + $PosArray[0], + $Y-$BoxOffset, + $PosArray[1], + $Y+$BoxOffset, + $BoxDownSettings + ); + } + if ( isset($PosArray[4]) ) { + $this->pChartObject->drawLine( + $PosArray[4], + $Y-$ExtremityLength, + $PosArray[4], + $Y+$ExtremityLength, + $MedianSettings + ); + } + $Y = $Y + $XStep; + } + } + } +} \ No newline at end of file diff --git a/vendor/szymach/c-pchart/src/Classes/pSurface.php b/vendor/szymach/c-pchart/src/Classes/pSurface.php new file mode 100644 index 0000000000..a0b7e0523f --- /dev/null +++ b/vendor/szymach/c-pchart/src/Classes/pSurface.php @@ -0,0 +1,392 @@ +pChartObject = $pChartObject; + $this->GridSize = 10; + $this->Points = ""; + } + + /** + * Define the grid size and initialise the 2D matrix + * @param type $XSize + * @param type $YSize + */ + public function setGrid($XSize=10,$YSize=10) + { + for ($X=0; $X<=$XSize; $X++) { + for ($Y=0; $Y<=$YSize; $Y++) { + $this->Points[$X][$Y]=UNKNOWN; + } + } + + $this->GridSizeX = $XSize; + $this->GridSizeY = $YSize; + } + + /** + * Add a point on the grid + * @param type $X + * @param type $Y + * @param type $Value + * @param type $Force + * @return type + */ + public function addPoint($X,$Y,$Value,$Force=TRUE) + { + if ( $X < 0 || $X >$this->GridSizeX ) { + return(0); + } + if ( $Y < 0 || $Y >$this->GridSizeY ) { + return(0); + } + + if ( $this->Points[$X][$Y] == UNKNOWN || $Force ) { + $this->Points[$X][$Y] = $Value; + } elseif ( $this->Points[$X][$Y] == UNKNOWN ) { + $this->Points[$X][$Y] = $Value; + } else { + $this->Points[$X][$Y] = ($this->Points[$X][$Y] + $Value)/2; + } + } + + /** + * Write the X labels + * @param type $Format + * @return type + */ + public function writeXLabels($Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : $this->pChartObject->FontColorR; + $G = isset($Format["G"]) ? $Format["G"] : $this->pChartObject->FontColorG; + $B = isset($Format["B"]) ? $Format["B"] : $this->pChartObject->FontColorB; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : $this->pChartObject->FontColorA; + $Angle = isset($Format["Angle"]) ? $Format["Angle"] : 0; + $Padding = isset($Format["Padding"]) ? $Format["Padding"] : 5; + $Position = isset($Format["Position"]) ? $Format["Position"] : LABEL_POSITION_TOP; + $Labels = isset($Format["Labels"]) ? $Format["Labels"] : null; + $CountOffset = isset($Format["CountOffset"]) ? $Format["CountOffset"] : 0; + + if ( $Labels != null && !is_array($Labels) ) { + $Label = $Labels; + $Labels = ""; + $Labels[] = $Label; + } + + $X0 = $this->pChartObject->GraphAreaX1; + $XSize = ($this->pChartObject->GraphAreaX2 - $this->pChartObject->GraphAreaX1) / ($this->GridSizeX+1); + + $Settings = array("Angle"=>$Angle,"R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha); + if ( $Position == LABEL_POSITION_TOP ) { + $YPos = $this->pChartObject->GraphAreaY1 - $Padding; + if ($Angle == 0 ) { $Settings["Align"] = TEXT_ALIGN_BOTTOMMIDDLE; } + if ($Angle != 0 ) { $Settings["Align"] = TEXT_ALIGN_MIDDLELEFT; } + } elseif ( $Position == LABEL_POSITION_BOTTOM ) { + $YPos = $this->pChartObject->GraphAreaY2 + $Padding; + if ($Angle == 0 ) { $Settings["Align"] = TEXT_ALIGN_TOPMIDDLE; } + if ($Angle != 0 ) { $Settings["Align"] = TEXT_ALIGN_MIDDLERIGHT; } + } else { + return(-1); + } + for ($X=0;$X<=$this->GridSizeX;$X++) { + $XPos = floor($X0+$X*$XSize + $XSize/2); + + if( $Labels == null || !isset($Labels[$X]) ) { + $Value = $X+$CountOffset; + } else { + $Value = $Labels[$X]; + } + $this->pChartObject->drawText($XPos,$YPos,$Value,$Settings); + } + } + + /** + * Write the Y labels + * @param type $Format + * @return type + */ + public function writeYLabels($Format="") + { + $R = isset($Format["R"]) ? $Format["R"] : $this->pChartObject->FontColorR; + $G = isset($Format["G"]) ? $Format["G"] : $this->pChartObject->FontColorG; + $B = isset($Format["B"]) ? $Format["B"] : $this->pChartObject->FontColorB; + $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : $this->pChartObject->FontColorA; + $Angle = isset($Format["Angle"]) ? $Format["Angle"] : 0; + $Padding = isset($Format["Padding"]) ? $Format["Padding"] : 5; + $Position = isset($Format["Position"]) ? $Format["Position"] : LABEL_POSITION_LEFT; + $Labels = isset($Format["Labels"]) ? $Format["Labels"] : null; + $CountOffset = isset($Format["CountOffset"]) ? $Format["CountOffset"] : 0; + + if ( $Labels != null && !is_array($Labels) ) { + $Label = $Labels; $Labels = ""; + $Labels[] = $Label; + } + + $Y0 = $this->pChartObject->GraphAreaY1; + $YSize = ($this->pChartObject->GraphAreaY2 - $this->pChartObject->GraphAreaY1) / ($this->GridSizeY+1); + + $Settings = array("Angle"=>$Angle,"R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha); + if ( $Position == LABEL_POSITION_LEFT ) { + $XPos = $this->pChartObject->GraphAreaX1 - $Padding; + $Settings["Align"] = TEXT_ALIGN_MIDDLERIGHT; + } elseif ( $Position == LABEL_POSITION_RIGHT ) { + $XPos = $this->pChartObject->GraphAreaX2 + $Padding; + $Settings["Align"] = TEXT_ALIGN_MIDDLELEFT; + } else { + return(-1); + } + for ($Y=0;$Y<=$this->GridSizeY;$Y++) { + $YPos = floor($Y0+$Y*$YSize + $YSize/2); + + if( $Labels == null || !isset($Labels[$Y]) ) { + $Value = $Y+$CountOffset; + } else { + $Value = $Labels[$Y]; + } + $this->pChartObject->drawText($XPos,$YPos,$Value,$Settings); + } + } + + /** + * Draw the area arround the specified Threshold + * @param type $Threshold + * @param type $Format + */ + public function drawContour($Threshold,$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; + $Ticks = isset($Format["Ticks"]) ? $Format["Ticks"] : 3; + $Padding = isset($Format["Padding"]) ? $Format["Padding"] : 0; + + $X0 = $this->pChartObject->GraphAreaX1; + $Y0 = $this->pChartObject->GraphAreaY1; + $XSize = ($this->pChartObject->GraphAreaX2 - $this->pChartObject->GraphAreaX1) / ($this->GridSizeX+1); + $YSize = ($this->pChartObject->GraphAreaY2 - $this->pChartObject->GraphAreaY1) / ($this->GridSizeY+1); + + $Color = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"Ticks"=>$Ticks); + + for ($X=0;$X<=$this->GridSizeX;$X++) { + for ($Y=0;$Y<=$this->GridSizeY;$Y++) { + $Value = $this->Points[$X][$Y]; + + if ( $Value != UNKNOWN && $Value != IGNORED && $Value >= $Threshold) { + $X1 = floor($X0+$X*$XSize)+$Padding; + $Y1 = floor($Y0+$Y*$YSize)+$Padding; + $X2 = floor($X0+$X*$XSize+$XSize); + $Y2 = floor($Y0+$Y*$YSize+$YSize); + + if ($X > 0 + && $this->Points[$X-1][$Y] != UNKNOWN + && $this->Points[$X-1][$Y] != IGNORED + && $this->Points[$X-1][$Y] < $Threshold + ) { + $this->pChartObject->drawLine($X1,$Y1,$X1,$Y2,$Color); + } + if ($Y > 0 + && $this->Points[$X][$Y-1] != UNKNOWN + && $this->Points[$X][$Y-1] != IGNORED + && $this->Points[$X][$Y-1] < $Threshold + ) { + $this->pChartObject->drawLine($X1,$Y1,$X2,$Y1,$Color); + } + if ($X < $this->GridSizeX + && $this->Points[$X+1][$Y] != UNKNOWN + && $this->Points[$X+1][$Y] != IGNORED + && $this->Points[$X+1][$Y] < $Threshold + ) { + $this->pChartObject->drawLine($X2,$Y1,$X2,$Y2,$Color); + } + if ($Y < $this->GridSizeY + && $this->Points[$X][$Y+1] != UNKNOWN + && $this->Points[$X][$Y+1] != IGNORED + && $this->Points[$X][$Y+1] < $Threshold + ) { + $this->pChartObject->drawLine($X1,$Y2,$X2,$Y2,$Color); + } + } + } + } + } + + /** + * Draw the surface chart + * @param type $Format + */ + public function drawSurface($Format="") + { + $Palette = isset($Format["Palette"]) ? $Format["Palette"] : null; + $ShadeR1 = isset($Format["ShadeR1"]) ? $Format["ShadeR1"] : 77; + $ShadeG1 = isset($Format["ShadeG1"]) ? $Format["ShadeG1"] : 205; + $ShadeB1 = isset($Format["ShadeB1"]) ? $Format["ShadeB1"] : 21; + $ShadeA1 = isset($Format["ShadeA1"]) ? $Format["ShadeA1"] : 40; + $ShadeR2 = isset($Format["ShadeR2"]) ? $Format["ShadeR2"] : 227; + $ShadeG2 = isset($Format["ShadeG2"]) ? $Format["ShadeG2"] : 135; + $ShadeB2 = isset($Format["ShadeB2"]) ? $Format["ShadeB2"] : 61; + $ShadeA2 = isset($Format["ShadeA2"]) ? $Format["ShadeA2"] : 100; + $Border = isset($Format["Border"]) ? $Format["Border"] : false; + $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 0; + $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 0; + $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 0; + $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : -1; + $Padding = isset($Format["Padding"]) ? $Format["Padding"] : 1; + + $X0 = $this->pChartObject->GraphAreaX1; + $Y0 = $this->pChartObject->GraphAreaY1; + $XSize = ($this->pChartObject->GraphAreaX2 - $this->pChartObject->GraphAreaX1) / ($this->GridSizeX+1); + $YSize = ($this->pChartObject->GraphAreaY2 - $this->pChartObject->GraphAreaY1) / ($this->GridSizeY+1); + + for($X=0;$X<=$this->GridSizeX;$X++) { + for($Y=0;$Y<=$this->GridSizeY;$Y++) { + $Value = $this->Points[$X][$Y]; + + if ( $Value != UNKNOWN && $Value != IGNORED ) { + $X1 = floor($X0+$X*$XSize)+$Padding; + $Y1 = floor($Y0+$Y*$YSize)+$Padding; + $X2 = floor($X0+$X*$XSize+$XSize); + $Y2 = floor($Y0+$Y*$YSize+$YSize); + + if ( $Palette != null ) { + if ( isset($Palette[$Value]) && isset($Palette[$Value]["R"]) ) { + $R = $Palette[$Value]["R"]; + } else { + $R = 0; + } + + if ( isset($Palette[$Value]) && isset($Palette[$Value]["G"]) ) { + $G = $Palette[$Value]["G"]; + } else { + $G = 0; + } + + if ( isset($Palette[$Value]) && isset($Palette[$Value]["B"]) ) { + $B = $Palette[$Value]["B"]; + } else { + $B = 0; + } + if ( isset($Palette[$Value]) && isset($Palette[$Value]["Alpha"]) ) { + $Alpha = $Palette[$Value]["Alpha"]; + } else { + $Alpha = 1000; + } + } else { + $R = (($ShadeR2-$ShadeR1)/100)*$Value + $ShadeR1; + $G = (($ShadeG2-$ShadeG1)/100)*$Value + $ShadeG1; + $B = (($ShadeB2-$ShadeB1)/100)*$Value + $ShadeB1; + $Alpha = (($ShadeA2-$ShadeA1)/100)*$Value + $ShadeA1; + } + + $Settings = array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha); + if ( $Border ) { + $Settings["BorderR"] = $BorderR; + $Settings["BorderG"] = $BorderG; + $Settings["BorderB"] = $BorderB; + } + if ( $Surrounding != -1 ) { + $Settings["BorderR"] = $R+$Surrounding; + $Settings["BorderG"] = $G+$Surrounding; + $Settings["BorderB"] = $B+$Surrounding; + } + + $this->pChartObject->drawFilledRectangle($X1,$Y1,$X2-1,$Y2-1,$Settings); + } + } + } + } + + /** + * Compute the missing points + */ + public function computeMissing() + { + $Missing = ""; + for ($X=0;$X<=$this->GridSizeX;$X++) { + for ($Y=0;$Y<=$this->GridSizeY;$Y++) { + if ( $this->Points[$X][$Y] == UNKNOWN ) { + $Missing[] = $X.",".$Y; + } + } + } + shuffle($Missing); + + foreach($Missing as $Key => $Pos) { + $Pos = preg_split("/,/",$Pos); + $X = $Pos[0]; + $Y = $Pos[1]; + + if ( $this->Points[$X][$Y] == UNKNOWN ) { + $NearestNeighbor = $this->getNearestNeighbor($X,$Y); + + $Value = 0; $Points = 0; + for ($Xi=$X-$NearestNeighbor;$Xi<=$X+$NearestNeighbor;$Xi++) { + for ($Yi=$Y-$NearestNeighbor;$Yi<=$Y+$NearestNeighbor;$Yi++) { + if ($Xi >=0 + && $Yi >= 0 + && $Xi <= $this->GridSizeX + && $Yi <= $this->GridSizeY + && $this->Points[$Xi][$Yi] != UNKNOWN + && $this->Points[$Xi][$Yi] != IGNORED + ) { + $Value = $Value + $this->Points[$Xi][$Yi]; $Points++; + } + } + } + + if ( $Points != 0 ) { + $this->Points[$X][$Y] = $Value / $Points; + } + } + } + } + + /** + * Return the nearest Neighbor distance of a point + * @param type $Xp + * @param type $Yp + * @return type + */ + public function getNearestNeighbor($Xp,$Yp) + { + $Nearest = UNKNOWN; + for ($X=0;$X<=$this->GridSizeX;$X++) { + for ($Y=0;$Y<=$this->GridSizeY;$Y++) { + if ( $this->Points[$X][$Y] != UNKNOWN && $this->Points[$X][$Y] != IGNORED ) { + $DistanceX = max($Xp,$X)-min($Xp,$X); + $DistanceY = max($Yp,$Y)-min($Yp,$Y); + $Distance = max($DistanceX,$DistanceY); + if ( $Distance < $Nearest || $Nearest == UNKNOWN ) { + $Nearest = $Distance; + } + } + } + } + return($Nearest); + } +} \ No newline at end of file diff --git a/vendor/szymach/c-pchart/src/Resources/data/128B.db b/vendor/szymach/c-pchart/src/Resources/data/128B.db new file mode 100644 index 0000000000..8c73cdddcf --- /dev/null +++ b/vendor/szymach/c-pchart/src/Resources/data/128B.db @@ -0,0 +1,107 @@ +0;32;11011001100 +1;33;11001101100 +2;34;11001100110 +3;35;10010011000 +4;36;10010001100 +5;37;10001001100 +6;38;10011001000 +7;39;10011000100 +8;40;10001100100 +9;41;11001001000 +10;42;11001000100 +11;43;11000100100 +12;44;10110011100 +13;45;10011011100 +14;46;10011001110 +15;47;10111001100 +16;48;10011101100 +17;49;10011100110 +18;50;11001110010 +19;51;11001011100 +20;52;11001001110 +21;53;11011100100 +22;54;11001110100 +23;55;11101101110 +24;56;11101001100 +25;57;11100101100 +26;58;11100100110 +27;59;11101100100 +28;60;11100110100 +29;61;11100110010 +30;62;11011011000 +31;63;11011000110 +32;64;11000110110 +33;65;10100011000 +34;66;10001011000 +35;67;10001000110 +36;68;10110001000 +37;69;10001101000 +38;70;10001100010 +39;71;11010001000 +40;72;11000101000 +41;73;11000100010 +42;74;10110111000 +43;75;10110001110 +44;76;10001101110 +45;77;10111011000 +46;78;10111000110 +47;79;10001110110 +48;80;11101110110 +49;81;11010001110 +50;82;11000101110 +51;83;11011101000 +52;84;11011100010 +53;85;11011101110 +54;86;11101011000 +55;87;11101000110 +56;88;11100010110 +57;89;11101101000 +58;90;11101100010 +59;91;11100011010 +60;92;11101111010 +61;93;11001000010 +62;94;11110001010 +63;95;10100110000 +64;96;10100001100 +65;97;10010110000 +66;98;10010000110 +67;99;10000101100 +68;100;10000100110 +69;101;10110010000 +70;102;10110000100 +71;103;10011010000 +72;104;10011000010 +73;105;10000110100 +74;106;10000110010 +75;107;11000010010 +76;108;11001010000 +77;109;11110111010 +78;110;11000010100 +79;111;10001111010 +80;112;10100111100 +81;113;10010111100 +82;114;10010011110 +83;115;10111100100 +84;116;10011110100 +85;117;10011110010 +86;118;11110100100 +87;119;11110010100 +88;120;11110010010 +89;121;11011011110 +90;122;11011110110 +91;123;11110110110 +92;124;10101111000 +93;125;10100011110 +94;126;10001011110 +95;200;10111101000 +96;201;10111100010 +97;202;11110101000 +98;203;11110100010 +99;204;10111011110 +100;205;10111101110 +101;206;11101011110 +102;207;11110101110 +103;208;11010000100 +104;209;11010010000 +105;210;11010011100 +106;211;1100011101011 \ No newline at end of file diff --git a/vendor/szymach/c-pchart/src/Resources/data/39.db b/vendor/szymach/c-pchart/src/Resources/data/39.db new file mode 100644 index 0000000000..3857ed7536 --- /dev/null +++ b/vendor/szymach/c-pchart/src/Resources/data/39.db @@ -0,0 +1,44 @@ +0;101001101101 +1;110100101011 +2;101100101011 +3;110110010101 +4;101001101011 +5;110100110101 +6;101100110101 +7;101001011011 +8;110100101101 +9;101100101101 +A;110101001011 +B;101101001011 +C;110110100101 +D;101011001011 +E;110101100101 +F;101101100101 +G;101010011011 +H;110101001101 +I;101101001101 +J;101011001101 +K;110101010011 +L;101101010011 +M;110110101001 +N;101011010011 +O;110101101001 +P;101101101001 +Q;101010110011 +R;110101011001 +S;101101011001 +T;101011011001 +U;110010101011 +V;100110101011 +W;110011010101 +X;100101101011 +Y;110010110101 +Z;100110110101 +-;100101011011 +.;110010101101 + ;100110101101 +$;100100100101 +/;100100101001 ++;100101001001 +%;101001001001 +*;100101101101 \ No newline at end of file diff --git a/vendor/szymach/c-pchart/src/Resources/data/constants.php b/vendor/szymach/c-pchart/src/Resources/data/constants.php new file mode 100644 index 0000000000..814058c4fa --- /dev/null +++ b/vendor/szymach/c-pchart/src/Resources/data/constants.php @@ -0,0 +1,208 @@ +checkChartType($chartType); + $className = $this->namespace.'p'.ucfirst($chartType); + if (!class_exists($className)) { + throw new \Exception('The requested chart class does not exist!'); + } + return new $className($pChartObject, $pDataObject); + } + + /** + * Checks if the requested chart type is created via one of the methods in + * the pDraw class, instead through a seperate class. If a method in pDraw + * exists, an exception with proper information is thrown. + * + * @param string $chartType + * @throws \Exception + */ + private function checkChartType($chartType) + { + $methods = array( + 'draw'.ucfirst($chartType).'Chart', + 'draw'.ucfirst($chartType) + ); + foreach ($methods as $method) { + if (method_exists($this->namespace.'pImage', $method)) { + throw new \Exception( + 'The requested chart is not a seperate class, to draw it you' + . ' need to call the "'.$method.'" method on the pImage object' + . ' after populating it with data!' + . ' Check the documentation on library\'s website for details.' + ); + } + } + } + + /** + * Creates a new pData class with an option to pass the data to form a serie. + * + * @param array $points - points to be added to serie + * @param string $serieName - name of the serie + * @return pData + */ + public function newData(array $points = array(), $serieName = "Serie1") + { + $className = $this->namespace.'pData'; + $data = new $className(); + if (count($points) > 0) { + $data->addPoints($points, $serieName); + } + return $data; + } + + /** + * Create a new pImage class. It requires the size of axes to be properly + * constructed. + * + * @param integer $XSize - length of the X axis + * @param integer $YSize - length of the Y axis + * @param pData $DataSet - pData class populated with points + * @param boolean $TransparentBackground + * @return pImage + */ + public function newImage( + $XSize, + $YSize, + \CpChart\Classes\pData $DataSet = null, + $TransparentBackground = false + ) { + $className = $this->namespace.'pImage'; + return new $className( + $XSize, + $YSize, + $DataSet, + $TransparentBackground + ); + } + + /** + * Create one of the pBarcode classes. Only the number is required (39 or 128), + * the class name is contructed on the fly. Passing the constructor's parameters + * is also available, but not mandatory. + * + * @param string $number - number identifing the pBarcode class ("39" or "128") + * @param string $BasePath - optional path for the file containing the class data + * @param boolean $EnableMOD43 + * @return pBarcode(39|128) + * @throws \Exception + */ + public function getBarcode($number, $BasePath = "", $EnableMOD43 = false) + { + if ($number != "39" && $number != "128") { + throw new \Exception( + 'The barcode class for the provided number does not exist!' + ); + } + $className = $this->namespace."pBarcode".$number; + return new $className($BasePath, $EnableMOD43); + } +}