Chart-Clicker-2.90000755000765000024 013024411235 13441 5ustar00gphatstaff000000000000README100644000765000024 56013024411235 14363 0ustar00gphatstaff000000000000Chart-Clicker-2.90 This archive contains the distribution Chart-Clicker, version 2.90: Powerful, extensible charting. This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. This README file was generated by Dist::Zilla::Plugin::Readme v6.008. Changes100644000765000024 5017513024411235 15045 0ustar00gphatstaff000000000000Chart-Clicker-2.90Revision history for Perl extension Chart::Clicker. 2.90 Dec 14 2016 2.89 Dec 14 2016 2.88 Mar 31 2014 2.87 Jan 24 2014 - Implement divvy strategies with tick_division_type (rbt) 2.83 Jun 21 2012 - Remove a duplicate file (Thanks Jotam) 2.82 Jun 19 2012 - Remove accidental label border (Thanks Eric Busto) 2.81 Mar 19 2012 - Don't throw away old data on add_data($hashref) (pozorvlak) 2.80 Mar 5 2012 - Minor POD updates. 2.78 Feb 15 2012 - Add lots of POD. 2.77 Feb 13 2012 - Fix synopsis of Axis (Thanks Gisbert W. Selke, RT #74951) - Default Axis' format to %s to fix it from blowing up (Thanks Gisbert W. Selke, RT #74950) 2.76 Dec 14 2011 - Fix syntax error in example (Alexx Roche) 2.75 Dec 5 2011 - Add Graphics::Primitive::Cairo dep (thanks TEEJAY) 2.74 Nov 13 2011 - POD fixes 2.73 Nov 4 2011 - Fix busted images in renderers. 2.72 Sep 5 2011 - Remove documentation for data method and replace it with rendered data method. 2.71 Aug 25 2011 - Fix busted images. (Fixes RT #70376) - Fix typo in ColorAllocator synopsis (Matthias Bloch) 2.70 Aug 7 2011 - Add more examples in the Tutorial (mpeters) - Convert to Dist::Zilla & Pod::Weaver - Add some missing documentation found in Pod::Weaver conversion - Removed a lot of useless () - Take numbers off test names - Remove stillborn HeatMap renderer - Remove some useless tests - Use done_tests - Add get_value_for_key to Series - Fix name of get_all_series_keys in POD - Add get_series_values_for_key to DataSet - Change DataSet::get_series_values to return an arrayref - Fix an issue where series whose keys don't match cause weird StackedBar results (Fixes RT #57372) - Adjust Axis to honor existing minimum_width and minimum_height set on itself (Addresses RT #60279) - Add Note to StackedArea regarding the same problem mentioned in RT #57372 2.69 - Add note about CentOS. 2.68 - Remove add_to_markers stuff in docs, as it's bogus. That functionality is in the context. _ Remove boolean attribute that determines if a Plot has any markers to be drawn, as it was always true. Remove check of said attribute since it was always true. 2.67 - Axis now calls "super" at the end of it's finalize. This way if there is a callback it's called at the end, as advertised 2.66 - Nudge edge tick labels closer in based on their bounding box (Rod Taylor, RT #60603) - Skip "zero" values in Bar and Stacked bar. This prevents drawing hairline bars if the value of the series element is equal to the baseline of the range axis. 2.65 - Fix warning in Glass related to newer Moose deprecation warnings. 2.64 - POD fixes (Jonathan Yu, RT #56287 and #57317) 2.63 - Make DataSet and StackedBar more tolerant of missing values (Rod Taylor, RT #57259) 2.62 - More POD fixes 2.61 - Add bar_width attribute to Bar and StackedBar renderers for choosing your own bar width. - Remove unnecessary type declaration from Axis - POD errors (spotted by Ricardo Signes) - Add POD 'whatis' entries (RT #56287, Jonathan Yu) - Update README (RT #56396, Jonathan Yu) - Add missing dependency on Test::Exception (RT #56398, Jonathan Yu) 2.60 March 20, 2010 - Add gradient_reverse attribute to Pie renderer for reverse the direction of the gradient (Carl Chambers) - Add starting_angle attribute to Pie rather than hardcoding it to -90 (Carl Chambers) - Refactor some Pie internals to not use $self->{VAR} (Carl Chambers) 2.59 - Correct POD in PolarArea - Add max_size and min_size to Series::Size - Bump some dependencies - Add PolarArea example to Clicker.pm POD - Remove some unnecessary imports from Context and clean up some code - Add Math::Gradient dep - Fix POD typos in tutorial (Thanks Franz Bräuer) - Make Data::Series->range a lazy_build attribute - Rearrange tests - Add gradient_color to Pie renderer 2.58 January 25, 2010 - POD fixes 2.57 January 24, 2010 - Add PolarArea renderer - Clean up some Pie POD 2.56 - Fix tests that tested removed methods. (Thanks Christoper Bottoms) 2.55 - Add add_pair method to Series - Add repository metadata to Makefile.PL (Thanks cpanservice) 2.54 - Values added via add_data will now be part of the same DataSet, this may have caused some odd results with additive renderers - Remove some unused tick attributes and code associated with them - Add skip_range to Axis 2.53 - Fix bad default opacity in Bar renderer - Fix syntax error from method name typo in share-axes example 2.52 - Add contains method to Range - Redo POD to use an ATTRIBUTES section - Tutorial updates (Thanks Philip Chung) 2.51 - POD improvement for creating other formats. 2.50 - POD fix (Thanks Brian Cassidy) 2.49 - POD fixes - Image Updates 2.48 - Fix image URLs 2.47 - Fix busted add_data changes in 2.46 - Better add_data POD 2.46 - Use native Moose type traits rather than MX::AttributeHelpers - Allow Series to be instantiated with a HashRef - Deprecate data method in favor of rendered_data 2.45 - Document the ->draw,->data method for getting back a scalar - Add date-axis.pl example - Improve error message when keys != values - Add POD images (Thanks to Gagor Szabo and Bruno Vecchi) - Bump Cairo driver version - Bar Renderer fixes: - When bars ran below baseline, brush width wasn't taken into account - When only one series was present, bars below baseline were offset to the left unecessarily 2.44 - Add add_data method - Fix long-standing bug tripped when adding multiple datasets that use the same renderer. 2.43 - Fix typo in Axis Synopsis (thanks Michael Stapelberg) 2.42 - Add Legend::Tabular - Remove unused LegendItem 2.41 - Add title/title_position 2.40 - Tutorial update 2.39 - Adjust data range test - Add Clicker->set_renderer (Thanks castaway!) - Add Clicker->write_output to replace draw; write; 2.38 - Change the manner in which ticks are generated. Uses the lower and upper of the Axis' range then evenly divides the middle. - Adjust the location of an Axis' tick if that tick is equal to the lower or upper of the Axis' range. Allows top and bottom ticks to be drawn without overflowing the drawable area. 2.37 - Properly import croak so failures are reported without generating an exception (thanks omega!) 2.36 - Fix some weird 'padding' in ranges and in Axis marking, fixes datasets with ranges less than 1. 2.35 - Legend - Depend on Layout::Manager 0.29 and adjust Legend to use - Remove lots of random crap from Legend that wasn't being used - Ditch Clicker's BUILD method for prepare-time work wrt plot & legend addition - Add has_name predicate to Series and use it in Legend - Bar - Fix overlap in borders - Fix stroking of translucent bars - Only stroke bars if their opacity is < 1 and the brush width > 0 2.34 - Clean up some unnecessary POD - Add shape_brush to Point renderer - Add first cut of tutorial 2.33 - Rename share_axis_width to share_axes_with - Throw a useful error when there is no data, thanks Dave Hayes 2.32 - Dependency bumps - Trim out some unnecessary includes and code - Fix busted bubble renderer scaling - Allow multiple series with CandleStick - Removed UPGRADING POD, it's long past time to have done that - Fix Area & StackedArea's POD - Make StackedArea a subclass of Area - Fix contributor POD being all on one line 2.31 - Fix slight miscalculation in X position of "negative" bar renderer bars. - Simplify bar width calculation when using fudged axis ranges. 2.30 - Fix misnamed class in POD for Marker (Thanks bricas!) - Fix error in example/simple.pl - Fix completely busted Marker implementation (fix colors & range positioning) - Add lazily constructed marker_overlay attribute to Clicker - Document Marker properly 2.29 - Fix broken bar_padding computation in Bar renderer - Skip some math when no ticks are visible in an Axis 2.28 - Fix problems in dist due to quoting 2.27 - Fix shape positions when line renderer is additive - Add pie example 2.26 - Use min/max functions from List::Util rather than rolling my own - Refactor Series internals to more easily facilitate subclasses - Add HighLow series - Add CandleStick renderer 2.25 - Add some new examples: Multiple-Axes, Multiple-Renderers and Shared-Axes - Add Context->share_axes_with method for convenience - Add font attribute to OverAxis decoration 2.24 - Add label_font and tick_font attributes to Axis for changing each individually. 2.23 - Don't uselessly add a Fill op to a Line renderer w/no shape - Properly handle the shape_brush attribute in the Line renderer - Remove default background_color from Plot 2.22 - Line renderer will now stack if additive attribute is true. 2.21 - More clever color allocator that attempts to space out colors at even hue spacings for predictable color schemes that are more pleasing and contrast enough to be easily differentiated. - Bump Graphics::Color dep for color allocator test 2.20 - Remove ghostly " - 5" that was fucking up additive ranges - Clamp Area "fade" gradients to the top of their areas, not the top of the plot - Add tick_label_color to Axis - Add label_color to Axis - Use real gray rather than translucent gray for grid to get rid of composited "joint" spots at line intersections - Add StackedArea renderer - Fix some errors in examples 2.19 - Move some subs around in Clicker.pm, to no effect. - Take out some C-style loops because they apparently offend a loud majority of #moose (groditi and phaylon) - Hide border of "hidden" Axis - Set the type of Series keys & values to ArrayRef[Num] from ArrayRef - Fix 01-data-series.t which had an error in it. Yay type checking! - Remove some useless, commented out code 2.18 - Fix Line's shape attribute, which didn't do a damn thing - Draw Line's shapes in a separate loop so that the path works right - Remove Chart::Clicker::Shape - Add OverAxis Decoration - Add Clicker->over_decorations for adding decorations "over" the renderers - POD overhaul - Remove some long-commented-out code. 2.17 - POD fixes - Split Grid's brush into two separate attributes: range_brush and domain_brush - Set an Axis' padding to 5 at the time it is created, zero it out in prepare if hidden. This lets us remove some crufty code from Clicker.pm - Set a default color on the Axis' brush - Document Axis' tick_label_angle - Separate Grid's line drawing into two operations so that each brush can affect the output - Remove color from Grid, use each brush to set range/domain color separately - Remove some useless code from Plot - Add grid_over flag to Clicker.pm to allow grid over/under control - Rejigger Axis code so that each Axis' brush size affects it's border - Adjust paddings a bit. 2.16 - Add Axis->tick_label_angle for rotating tick label - Add requirement for Math::Trig - Bump some deps 2.15 - Fix META.yml - Add some POD to describe why NOT having a default context makes Clicker shit on itself. - Fix linear gradient in Area renderer. 2.14 - Add examples directory - Don't add padding if axes are hidden. - Fix gradients in Area renderer 2.13 - Remove some old code (was already commented out) 2.12 - Fix POD bug (thanks Jay Shirley) - Axis::DateTime: get this working again, albeit a bit gimped - Move pod tests to t/author 2.11 - Fix multiple-prepare bug 2.10 - Use new Grapics::Primitive APIs 2.09 - Remove Moose Coverage dependency 2.08 - Keep up with Graphics::Primitive API changes 2.07 - Bump Graphics::Primitive dep to 0.28 and make appropriate changes to Fill operations. 2.06 - Axis: Add stagger flag 2.05 - Axis: Fix busted labels when using labels & values together 2.04 - Fix bug in top-horizontal axes 2.03 - Oops again, bump Cairo driver version 2.02 - Ooops, bump version dependencies properly 2.01 - Remove label rotation on vertical axes due to problems with Graphics::Primitive - Depend on Graphics::Primitive 0.25 and make necessary API changes 2.0.0 - Pretty up some un-Moosey behaviour - Add Bubble renderer and Series::Size - Add PostScript and PDF support - Use Graphics::Primitive - Add show_range and show_domain flags to Grid - Make Range's span inclusive - Add lots of convenient methods via MooseX::AttributeHelpers - Get rid of all indirect method calls (ewww!) - Fix broken bar renderer alignment - Rename Renderer::Base to just Renderer - Stop baselining axes by default, it breaks stuff. - Abandon $CC_* position/orientation junk for Moose roles with strings - Move out lots of generic functionality to new modules - Add context support - Ignore duplicate axes - Change Axis 'visible' attribute to 'hidden' to avoid clashing with Layout::Manager - Axis' ticks attribute now yields the correct number of ticks, not -1 - Horizontal axes' tick labels now align their baselines properly - Make axes position independent, as they were intended 1.4.2 - Packaging fixes. 1.4.1 - Add fudge_amount attribute to Axis, defaulting to .1, that tells Clicker how much to fudge the amount upper and lower values of the range. - Fix drawing-insets test index mistype - Fix range baseline throwing Moose errors on undef - Fix broken layout test 1.4.0 - Add 'baseline' attribute to Axis - Fix incorrect coloring of text on customized axes - Add tick_labels to axis and make use of it in Simple - Make axes and labels cope with dropped letters (e.g 'y' or 'j') properly - Mooseify renderer options (the 'options' method is no longer used) - Allow many objects with a color to be set with just the name ('black' rather than 'new Chart::Clicker::Drawing::Color'...) - Fix warnings in tests - Line render shapes default to filled, shape_stroke provides method for old method of doing strokes. 1.3.0 - Fix broken Bar renderer - Add hide_axes and hide_grid to Simple - StackedBar renderer - 'additive' renderer attribute - combine the 'combined' range of a DataSet for additive renderers - Fix bug when setting range max/min to 0 - Real SVG support - Add 'format' attribute to Clicker constructor 1.2.2 - Fix broken Axis::DateTime - Fix broken type for Simple's renderer - Fix busted Bar renderer 1.2.1 _ Remove unused and un-required dependency 1.2.0 - Add Pie renderer. - Moose 1.1.8 Sat Sep 1 10:38:01 - Remove lots of ()-> - Try and make some things faster after watching dprofpp output - Fix format accessor in Axis::DateTime - Fix bug in Component::inside_width - Add shape to line renderer 1.1.7 Thu Aug 30 20:43:21 - Add time_zone to Axis::DateTime (thanks Johannes Hoerburger) - Add test for formatter and document inheritance 1.1.6 Fri Mar 09 18:24:12 2007 - Remove Mac OS X specific files (thanks jshirley) 1.1.5 Sat Feb 24 12:48:03 2007 - Return 1 for 0 span ranges. (thanks Daniel Kasak) 1.1.4 Wed Jan 02 09:31:21 2007 - Add Chart::Clicker::Simple - Fix bug in ColorAllocator's constructor - Fix bug in Bar Renderer for full-height bars - Remove default border from Plot - Doc cleanups - Code cleanups 1.1.3 Sun Oct 22 10:53:23 2006 - Add SVG support (thanks Torsten Schoenfeld) - Teach write() how to handle different formats. - Update docs 1.1.2 Sat Oct 21 12:16:51 2006 - Add labels to Axes (thanks Torsten Schoenfeld) - Add error accessor to Series (thanks Torsten Schoenfeld) - Add Measurement Renderer (thanks Torsten Schoenfeld) 1.1.1 Sun Sep 17 19:10:17 2006 - Documentation updates - Fix Axis::DateTime's rendering 1.1.0 Thu Sep 14 20:06:37 2006 - Remove (range|domain)_markers from Chart::Clicker - Fix rendering of Axis grid lines by using Axis mark() - Fix Series with keys given in constructor - Add Marker support via Data::Marker and Plot's use of Decoration::MarkerOverlay - Make pseudo-smart date stuff in DateTime 1.0.7 Tue Sep 12 20:12:34 2006 - Adjust Axis to make subclassing better - Add Axis::DateTime 1.0.6 Sometime - Make the stroke an option (and off by default) of Bar - Add max and min methods to Data::Range - Fix Area renderer only showing a single series - Take a stab at improving the Legend's rendering - Add mark() to Axis for positioning values - Adjust renderers to use Axis->mark() for positioning - Fix rendering of mutiple series in Bar renderer 1.0.5 Tue Sep 5 19:31:24 2006 - Fix broken charting of axes not based on zero lower ranges. - Reverse fade color stops - Use the lower on the range for Axis tick values - Add Glass decoration - Adjust Renderers to not take a 'min' value 1.0.4 Thu Aug 31 21:45:37 2006 - Remove disclaimer about using File::Temp - Fix completely broken domain axis values 1.0.3 Tue Aug 15 19:13:12 2006 - Ditch File::Temp for write_to_png_stream from Cairo 1.0.2 Thu Aug 10 19:18:11 2006 - Fix broken X axis for all Renderers (reported by Peter Hicks) 1.0.1 Wed Aug 09 20:28:42 2006 - Remove print of file size in png() - Update examples in Chart::Clicker POD - Allow setting of series in constructor or DataSet - Allow setting of range in Axis constructor (was overwritten) - Fix constructor of Series to use Class::Accessor - Document ticks() in Axis 1.0.0 Sometime - Don't draw on undefined surfaces returned from Components - Remove 'above' crap - Increase 'divvy' to ticks + 1 and only set it if it's undefined - Don't outright skip if an Axis is invisible, just skip the part when we are drawing. - Add format() to Axis for formatting tick values. 0.9.7 Mon Jun 12 00:00:00 2006 - Don't draw invisible axes - Expose the number of ticks for the axis. - Fix area renderer being off by 1.5 on first point 0.9.6 Thu Jun 8 00:12:54 2006 - I totally forgot to document... 0.9.3 Mon May 22 11:24:31 2006 - Layout based rendering. - Documentation updates - Labels 0.9.1 Wed May 10 10:12:09 2006 - Clicker is now a Container - Add CC_CENTER - Add Container - Add Component 0.9.0 Tue May 9 01:30:19 2006 - Axis labels - Get Axes working and add Axis positioning - Set all values to 0 by default in Insets - Rename constants CC_* and add TOP, BOTTOM, LEFT and RIGHT for Axis positioning. - Add Chart::Clicker::Drawing for some common constants - Move HORIZONTAL and VERTICAL to C:C::Drawing as constants - Eliminate extraneous drawing ops (paints) from Plot - Use an Inset to keep up with 'shrinkage' of inner surface in Plot - Enhance Axis with height, orientation, per, tick_values, and width and prepare method that calculates required space. - Remove prepare() from Renderer::Base and move most of the arguments to the render() method. - Rework Renderers to use the domain and range axes for the values they need for rendering. - 'inline' marker drawing - Add divvy() to Range. - Have Grid use 'main' domain and range axes for it's values. - Remove reference to a C:Clicker::prepare sub in the docs 0.2.4 Thu May 4 00:30:19 2006 - Shapes - Use Shapes for Point Renderer 0.2.3 Wed May 3 23:15:09 2006 - Bring Makefile.PL and MANIFEST up to speed - Legends! - Stop hard-coding output file - Fix bugs in color allocation - A solemn promise to tag this version so I can do svn diffs... 0.2.2 No clue - I forget 0.2.1 Tue Apr 25 23:53:21 2006 - Update Bar renderer to divide available spots between all series - Use ColorAllocator in renderers - Add ColorAllocator - Create the Drawing namespace 0.2.0 Sun Apr 23 08:09:34 2006 0.1.0 Thu Apr 20 01:12:09 2006 - Add Border and Stroke - Use Class::Accessor - Chart->background_color() - Plot->background_color() - Chart::Point 0.0.4 Tue Apr 18 23:22:12 2006 - Add Color and use it for Markers 0.0.3 Fri Apr 14 13:34:43 2006 - Add Grid decoration and move mass marker creation there for grid. 0.0.2 Fri Apr 14 12:13:10 2006 - Get Markers working 0.0.1 Tue Apr 11 20:30:16 2006 - original version LICENSE100644000765000024 4366013024411235 14560 0ustar00gphatstaff000000000000Chart-Clicker-2.90This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. Terms of the Perl programming language system itself a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" --- The GNU General Public License, Version 1, February 1989 --- This software is Copyright (c) 2016 by Cory G Watson. This is free software, licensed under: The GNU General Public License, Version 1, February 1989 GNU GENERAL PUBLIC LICENSE Version 1, February 1989 Copyright (C) 1989 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The license agreements of most software companies try to keep users at the mercy of those companies. By contrast, our General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. The General Public License applies to the Free Software Foundation's software and to any other program whose authors commit to using it. You can use it for your programs, too. When we speak of free software, we are referring to freedom, not price. Specifically, the General Public License is designed to make sure that you have the freedom to give away or sell copies of free software, 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of a such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must tell them their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any work containing the Program or a portion of it, either verbatim or with modifications. Each licensee is addressed as "you". 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this General Public License and to the absence of any warranty; and give any other recipients of the Program a copy of this General Public License along with the Program. You may charge a fee for the physical act of transferring a copy. 2. You may modify your copy or copies of the Program or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above, provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains the Program or any part thereof, either with or without modifications, to be licensed at no charge to all third parties under the terms of this General Public License (except that you may choose to grant warranty protection to some or all third parties, at your option). c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the simplest and most usual way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this General Public License. d) You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. Mere aggregation of another independent work with the Program (or its derivative) on a volume of a storage or distribution medium does not bring the other work under the scope of these terms. 3. You may copy and distribute the Program (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 1 and 2 above provided that you also do one of the following: a) accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Paragraphs 1 and 2 above; or, b) accompany it with a written offer, valid for at least three years, to give any third party free (except for a nominal charge for the cost of distribution) a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Paragraphs 1 and 2 above; or, c) accompany it with the information you received as to where the corresponding source code may be obtained. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form alone.) Source code for a work means the preferred form of the work for making modifications to it. For an executable file, complete source code means all the source code for all modules it contains; but, as a special exception, it need not include source code for modules which are standard libraries that accompany the operating system on which the executable file runs, or for standard header files or definitions files that accompany that operating system. 4. You may not copy, modify, sublicense, distribute or transfer the Program except as expressly provided under this General Public License. Any attempt otherwise to copy, modify, sublicense, distribute or transfer the Program is void, and will automatically terminate your rights to use the Program under this License. However, parties who have received copies, or rights to use copies, from you under this General Public License will not have their licenses terminated so long as such parties remain in full compliance. 5. By copying, distributing or modifying the Program (or any work based on the Program) you indicate your acceptance of this license to do so, and all its terms and conditions. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. 7. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of the license which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the license, you may choose any version ever published by the Free Software Foundation. 8. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. END OF TERMS AND CONDITIONS Appendix: 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 humanity, 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 convey 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) 19yy 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 1, 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19xx name of author Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (a program to direct compilers to make passes at assemblers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice That's all there is to it! --- The Artistic License 1.0 --- This software is Copyright (c) 2016 by Cory G Watson. This is free software, licensed under: The Artistic License 1.0 The Artistic License Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: - "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. - "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. - "Copyright Holder" is whoever is named in the copyright or copyrights for the package. - "You" is you, if you're thinking about copying or distributing this Package. - "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) - "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as ftp.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. 7. C or perl subroutines supplied by you and linked into this Package shall not be considered part of this Package. 8. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End t000755000765000024 013024411235 13625 5ustar00gphatstaff000000000000Chart-Clicker-2.90axis.t100644000765000024 153613024411235 15123 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; BEGIN { use_ok('Chart::Clicker::Axis'); } my $label = 'Foo'; # Exact tick_division_type by default my $axis = Chart::Clicker::Axis->new( label => $label, orientation => 'vertical', position => 'left' ); cmp_ok($axis->format_value(100), 'eq', '100', 'format_value (default format test)'); ok($axis->label eq $label, 'label'); ok($axis->show_ticks, 'Default show_ticks'); ok($axis->visible, 'Default visible'); my $showticks = 0; $axis->show_ticks($showticks); ok($axis->show_ticks == $showticks, 'show_ticks'); my $vis = 0; $axis->visible($vis); ok($axis->visible == $vis, 'visible'); ok(defined($axis->range), 'Has range'); my $lower = 0; my $upper = 100; $axis->range->lower($lower); $axis->range->upper($upper); ok($axis->range->lower == $lower, 'Lower value'); ok($axis->range->upper == $upper, 'Upper value'); done_testing; META.yml100644000765000024 363113024411235 14776 0ustar00gphatstaff000000000000Chart-Clicker-2.90--- abstract: 'Powerful, extensible charting.' author: - 'Cory G Watson ' build_requires: Test::Exception: '0' Test::Fatal: '0' Test::More: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 0 generated_by: 'Dist::Zilla version 6.008, CPAN::Meta::Converter version 2.150005' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Chart-Clicker requires: Carp: '0' Class::Load: '0' Color::Scheme: '0' DateTime: '0' DateTime::Set: '0' English: '0' Geometry::Primitive::Arc: '0' Geometry::Primitive::Circle: '0' Geometry::Primitive::Point: '0' Graphics::Color::RGB: '0' Graphics::Primitive::Border: '0' Graphics::Primitive::Brush: '0' Graphics::Primitive::Canvas: '0' Graphics::Primitive::Component: '0' Graphics::Primitive::Container: '0' Graphics::Primitive::Driver::Cairo: '0' Graphics::Primitive::Font: '0' Graphics::Primitive::Insets: '0' Graphics::Primitive::Operation::Fill: '0' Graphics::Primitive::Operation::Stroke: '0' Graphics::Primitive::Oriented: '0' Graphics::Primitive::Paint::Gradient::Linear: '0' Graphics::Primitive::Paint::Gradient::Radial: '0' Graphics::Primitive::Paint::Solid: '0' Graphics::Primitive::Path: '0' Graphics::Primitive::TextBox: '0' Layout::Manager::Absolute: '0' Layout::Manager::Axis: '0' Layout::Manager::Compass: '0' Layout::Manager::Flow: '0' Layout::Manager::Grid: '0' Layout::Manager::Single: '0' List::Util: '0' Math::Trig: '0' Moose: '0' Moose::Role: '0' Moose::Util: '0' Moose::Util::TypeConstraints: '0' POSIX: '0' Scalar::Util: '0' constant: '0' strict: '0' warnings: '0' resources: bugtracker: https://github.com/gphat/chart-clicker/issues homepage: https://github.com/gphat/chart-clicker repository: https://github.com/gphat/chart-clicker.git version: '2.90' x_serialization_backend: 'YAML::Tiny version 1.69' MANIFEST100644000765000024 527513024411235 14664 0ustar00gphatstaff000000000000Chart-Clicker-2.90# This file was automatically generated by Dist::Zilla::Plugin::Manifest v6.008. Changes LICENSE MANIFEST META.json META.yml Makefile.PL README README.mkdn example/annotation.pl example/area.pl example/bar.pl example/bubble.pl example/candlestick.pl example/date-axis.pl example/heatmap.pl example/line-and-shape.pl example/line.pl example/multiple-axes.pl example/multiple-renderers.pl example/overaxis-bar.pl example/pie.pl example/point.pl example/share-axes.pl example/simple.pl example/skip_range.pl example/sparkline.pl example/stackedarea.pl example/stackedbar.pl example/tabularlegend.pl example/tufte-whitegrid.pl inc/ChClDistMakeMaker.pm lib/Chart/Clicker.pm lib/Chart/Clicker/Axis.pm lib/Chart/Clicker/Axis/DateTime.pm lib/Chart/Clicker/Axis/DivisionType.pm lib/Chart/Clicker/Axis/DivisionType/Exact.pm lib/Chart/Clicker/Axis/DivisionType/LinearExpandGraph.pm lib/Chart/Clicker/Axis/DivisionType/LinearRounded.pm lib/Chart/Clicker/Component.pm lib/Chart/Clicker/Container.pm lib/Chart/Clicker/Context.pm lib/Chart/Clicker/Data/DataSet.pm lib/Chart/Clicker/Data/Marker.pm lib/Chart/Clicker/Data/Range.pm lib/Chart/Clicker/Data/Series.pm lib/Chart/Clicker/Data/Series/HighLow.pm lib/Chart/Clicker/Data/Series/Size.pm lib/Chart/Clicker/Decoration.pm lib/Chart/Clicker/Decoration/Annotation.pm lib/Chart/Clicker/Decoration/Glass.pm lib/Chart/Clicker/Decoration/Grid.pm lib/Chart/Clicker/Decoration/Legend.pm lib/Chart/Clicker/Decoration/Legend/Tabular.pm lib/Chart/Clicker/Decoration/MarkerOverlay.pm lib/Chart/Clicker/Decoration/OverAxis.pm lib/Chart/Clicker/Decoration/Plot.pm lib/Chart/Clicker/Drawing/ColorAllocator.pm lib/Chart/Clicker/Positioned.pm lib/Chart/Clicker/Renderer.pm lib/Chart/Clicker/Renderer/Area.pm lib/Chart/Clicker/Renderer/Bar.pm lib/Chart/Clicker/Renderer/Bubble.pm lib/Chart/Clicker/Renderer/CandleStick.pm lib/Chart/Clicker/Renderer/Line.pm lib/Chart/Clicker/Renderer/Pie.pm lib/Chart/Clicker/Renderer/Point.pm lib/Chart/Clicker/Renderer/PolarArea.pm lib/Chart/Clicker/Renderer/StackedArea.pm lib/Chart/Clicker/Renderer/StackedBar.pm lib/Chart/Clicker/Tutorial.pm t/add-data.t t/author-pod-syntax.t t/author-synopsis.t t/axis-datetime.t t/axis-division-rounded.t t/axis.t t/basic.t t/context.t t/data-dataset.t t/data-marker.t t/data-range.t t/datetime.t t/decoration-color_allocator.t t/decoration-glass.t t/decoration-grid.t t/decoration-legend.t t/decoration-markeroverlay.t t/decoration-plot.t t/decoration.t t/drawing-colorallocator.t t/example.t t/invisible.t t/renderer-area.t t/renderer-bar.t t/renderer-base.t t/renderer-bubble.t t/renderer-candlestick.t t/renderer-line.t t/renderer-pie.t t/renderer-point.t t/same-axes-ctx.t t/series/highlow.t t/series/series.t t/series/size.t t/simple-ctx.t t/xt/pod.t basic.t100644000765000024 153113024411235 15233 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; BEGIN { use_ok('Chart::Clicker'); use_ok('Chart::Clicker::Renderer::Bar'); use_ok('Chart::Clicker::Renderer::Line'); } my $chart = Chart::Clicker->new({ width => 100, height => 50 }); ok(defined($chart), 'new Chart'); isa_ok($chart, 'Chart::Clicker', 'isa Chart'); cmp_ok($chart->width, '==', 100, 'width'); cmp_ok($chart->height, '==', 50, 'height'); $chart->set_renderer(Chart::Clicker::Renderer::Bar->new); isa_ok($chart->get_context('default')->renderer, 'Chart::Clicker::Renderer::Bar', 'set_renderer'); $chart->set_renderer(Chart::Clicker::Renderer::Line->new, 'default'); isa_ok($chart->get_context('default')->renderer, 'Chart::Clicker::Renderer::Line', 'set_renderer'); eval { $chart->set_renderer(Chart::Clicker::Renderer::Bar->new, 'foo'); }; ok(defined($@), 'non-existant context blew up'); done_testing;META.json100644000765000024 623013024411235 15144 0ustar00gphatstaff000000000000Chart-Clicker-2.90{ "abstract" : "Powerful, extensible charting.", "author" : [ "Cory G Watson " ], "dynamic_config" : 0, "generated_by" : "Dist::Zilla version 6.008, CPAN::Meta::Converter version 2.150005", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Chart-Clicker", "prereqs" : { "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "develop" : { "requires" : { "Test::Pod" : "1.41", "Test::Synopsis" : "0" } }, "runtime" : { "requires" : { "Carp" : "0", "Class::Load" : "0", "Color::Scheme" : "0", "DateTime" : "0", "DateTime::Set" : "0", "English" : "0", "Geometry::Primitive::Arc" : "0", "Geometry::Primitive::Circle" : "0", "Geometry::Primitive::Point" : "0", "Graphics::Color::RGB" : "0", "Graphics::Primitive::Border" : "0", "Graphics::Primitive::Brush" : "0", "Graphics::Primitive::Canvas" : "0", "Graphics::Primitive::Component" : "0", "Graphics::Primitive::Container" : "0", "Graphics::Primitive::Driver::Cairo" : "0", "Graphics::Primitive::Font" : "0", "Graphics::Primitive::Insets" : "0", "Graphics::Primitive::Operation::Fill" : "0", "Graphics::Primitive::Operation::Stroke" : "0", "Graphics::Primitive::Oriented" : "0", "Graphics::Primitive::Paint::Gradient::Linear" : "0", "Graphics::Primitive::Paint::Gradient::Radial" : "0", "Graphics::Primitive::Paint::Solid" : "0", "Graphics::Primitive::Path" : "0", "Graphics::Primitive::TextBox" : "0", "Layout::Manager::Absolute" : "0", "Layout::Manager::Axis" : "0", "Layout::Manager::Compass" : "0", "Layout::Manager::Flow" : "0", "Layout::Manager::Grid" : "0", "Layout::Manager::Single" : "0", "List::Util" : "0", "Math::Trig" : "0", "Moose" : "0", "Moose::Role" : "0", "Moose::Util" : "0", "Moose::Util::TypeConstraints" : "0", "POSIX" : "0", "Scalar::Util" : "0", "constant" : "0", "strict" : "0", "warnings" : "0" } }, "test" : { "requires" : { "Test::Exception" : "0", "Test::Fatal" : "0", "Test::More" : "0" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/gphat/chart-clicker/issues" }, "homepage" : "https://github.com/gphat/chart-clicker", "repository" : { "type" : "git", "url" : "https://github.com/gphat/chart-clicker.git", "web" : "https://github.com/gphat/chart-clicker" } }, "version" : "2.90", "x_serialization_backend" : "Cpanel::JSON::XS version 3.0225" } xt000755000765000024 013024411235 14260 5ustar00gphatstaff000000000000Chart-Clicker-2.90/tpod.t100644000765000024 20113024411235 15340 0ustar00gphatstaff000000000000Chart-Clicker-2.90/t/xtuse Test::More; eval "use Test::Pod 1.00"; plan skip_all => "Test::Pod 1.00 requires for testing POD" if $@; all_pod_files_ok(); README.mkdn100644000765000024 2733513024411235 15364 0ustar00gphatstaff000000000000Chart-Clicker-2.90# NAME Chart::Clicker - Powerful, extensible charting. # VERSION version 2.90 # SYNOPSIS use Chart::Clicker; my $cc = Chart::Clicker->new; my @values = (42, 25, 86, 23, 2, 19, 103, 12, 54, 9); $cc->add_data('Sales', \@values); # alternately, you can add data one bit at a time... foreach my $v (@values) { $cc->add_data('Sales', $v); } # Or, if you want to specify the keys you can use a hashref my $data = { 12 => 123, 13 => 341, 14 => 1241 }; $cc->add_data('Sales', $data); $cc->write_output('foo.png'); # DESCRIPTION Chart::Clicker aims to be a powerful, extensible charting package that creates really pretty output. Charts can be saved in png, svg, pdf and postscript format. Clicker leverages the power of Graphics::Primitive to create snazzy graphics without being tied to specific backend. You may want to begin with [Chart::Clicker::Tutorial](https://metacpan.org/pod/Chart::Clicker::Tutorial). # EXAMPLES For code examples see the examples repository on GitHub: [http://github.com/gphat/chart-clicker-examples/](http://github.com/gphat/chart-clicker-examples/) # FEATURES ## Renderers Clicker supports the following renderers: - **Line** - **StackedLine** - **Bar** - **StackedBar** - **Area** - **StackedArea** - **Bubble** - **CandleStick** - **Point** - **Pie** - **PolarArea** # ADDING DATA The synopsis shows the simple way to add data. my @values = (42, 25, 86, 23, 2, 19, 103, 12, 54, 9); foreach my $v (@values) { $cc->add_data('Sales', $v); } This is a convenience method provided to make simple cases much simpler. Adding multiple Series to a chart is as easy as changing the name argument of `add_data`. Each unique first argument will result in a separate series. See the docs for `add_data` to learn more. If you'd like to use the more advanced features of Clicker you'll need to shake off this simple method and build Series & DataSets explicitly. use Chart::Clicker::Data::Series; use Chart::Clicker::Data::DataSet; ... my $series = Chart::Clicker::Data::Series->new( keys => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ], values => [ 42, 25, 86, 23, 2, 19, 103, 12, 54, 9 ], ); my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series ]); $cc->add_to_datasets($ds); This used to be the only way to add data, but repeated requests to make the common case easier resulted in the inclusion of `add_data`. # CONTEXTS The normal use case for a chart is a couple of datasets on the same axes. Sometimes you want to chart one or more datasets on different axes. A common need for this is when you are comparing two datasets of vastly different scale such as the number of employees in an office (1-10) to monthly revenues (10s of thousands). On a normal chart the number of employees would show up as a flat line at the bottom of the chart. To correct this, Clicker has contexts. A context is a pair of axes, a renderer and a name. The name is the 'key' by which you will refer to the context. my $context = Chart::Clicker::Context->new( name => 'sales' ); $clicker->add_to_contexts($context); $dataset->context('sales'); $clicker->add_to_datasets($dataset); New contexts provide a fresh domain and range axis and default to a Line renderer. **Caveat**: Clicker expects that the default context (identified by the string "default") will always be present. It is from this context that some of Clicker's internals draw their values. You should use the default context unless you need more than one, in which case you should use "default" as the base context. # FORMATS & OUTPUT Clicker supports PNG, SVG, PDF and PostScript output. To change your output type, specificy it when you create your Clicker object: my $cc = Chart::Clicker->new(format => 'pdf', ...); # ... $cc->write_output('chart.pdf'); If you are looking to get a scalar of the output for use with HTTP or similar things, you can use: # ... make your chart $cc->draw; my $image_data = $cc->rendered_data; If you happen to be using Catalyst then take a look at [Catalyst::View::Graphics::Primitive](https://metacpan.org/pod/Catalyst::View::Graphics::Primitive). # ATTRIBUTES ## background\_color Set/Get the background [color](https://metacpan.org/pod/Graphics::Color::RGB). Defaults to white. ## border Set/Get the [border](https://metacpan.org/pod/Graphics::Primitive::Border). ## color\_allocator Set/Get the [color\_allocator](https://metacpan.org/pod/Chart::Clicker::Drawing::ColorAllocator) for this chart. ## contexts Set/Get the [contexts](https://metacpan.org/pod/Chart::Clicker::Context) for this chart. ## datasets Get/Set the datasets for this chart. ## driver Set/Get the [driver](https://metacpan.org/pod/Graphics::Primitive::Driver) used to render this Chart. Defaults to [Graphics::Primitive::Driver::Cairo](https://metacpan.org/pod/Graphics::Primitive::Driver::Cairo). ## format Get the format for this Chart. Required in the constructor. Must be on of Png, Pdf, Ps or Svg. ## plot\_mode Fast or slow plot mode. When in fast mode, data elements that are deemed to be superfluous or invisible will not be drawn. Default is 'slow' ## grid\_over Flag controlling if the grid is rendered **over** the data. Defaults to 0. You probably want to set the grid's background color to an alpha of 0 if you enable this flag. ## height Set/Get the height. Defaults to 300. ## layout\_manager Set/Get the layout manager. Defaults to [Layout::Manager::Compass](https://metacpan.org/pod/Layout::Manager::Compass). ## legend Set/Get the [legend](https://metacpan.org/pod/Chart::Clicker::Decoration::Legend) that will be used with this chart. ## legend\_position The position the legend will be added. Should be one of north, south, east, west or center as required by [Layout::Manager::Compass](https://metacpan.org/pod/Layout::Manager::Compass). ## marker\_overlay Set/Get the [marker overlay](https://metacpan.org/pod/Chart::Clicker::Decoration::MarkerOverlay) object that will be used if this chart has markers. This is lazily constructed to save time. ## over\_decorations Set/Get an arrayref of "over decorations", or things that are drawn OVER the chart. This is an advanced feature. See `overaxis-bar.pl` in the examples. ## padding Set/Get the [padding](https://metacpan.org/pod/Graphics::Primitive::Insets). Defaults to 3px on all sides. ## plot Set/Get the [plot](https://metacpan.org/pod/Chart::Clicker::Decoration::Plot) on which things are drawn. ## subgraphs You can add "child" graphs to this one via `add_subgraph`. These must be Chart::Clicker objects and they will be added to the bottom of the existing chart. This is a rather esoteric feature. ## title Set/Get the title component for this chart. This is a [Graphics::Primitive::TextBox](https://metacpan.org/pod/Graphics::Primitive::TextBox), not a string. To set the title of a chart you should access the TextBox's `text` method. $cc->title->text('A Title!'); $cc->title->font->size(20); # etc, etc If the title has text then it is added to the chart in the position specified by `title_position`. You should consult the documentation for [Graphics::Primitive::TextBox](https://metacpan.org/pod/Graphics::Primitive::TextBox) for things like padding and text rotation. If you are adding it to the top and want some padding between it and the plot, you can: $cc->title->padding->bottom(5); ## title\_position The position the title will be added. Should be one of north, south, east, west or center as required by [Layout::Manager::Compass](https://metacpan.org/pod/Layout::Manager::Compass). Note that if no angle is set for the title then it will be changed to \-1.5707 if the title position is east or west. ## width Set/Get the width. Defaults to 500. # METHODS ## context\_count Get a count of contexts. ## context\_names Get a list of context names. ## delete\_context ($name) Remove the context with the specified name. ## get\_context ($name) Get the context with the specified name ## set\_context ($name, $context) Set a context of the specified name. ## add\_to\_datasets Add the specified dataset (or arrayref of datasets) to the chart. ## dataset\_count Get a count of datasets. ## get\_dataset ($index) Get the dataset at the specified index. ## rendered\_data Returns the data for this chart as a scalar. Suitable for 'streaming' to a client. ## add\_to\_over\_decorations Add an over decoration to the list. ## get\_over\_decoration ($index) Get the over decoration at the specified index. ## over\_decoration\_count Get a count of over decorations. ## add\_to\_contexts Add the specified context to the chart. ## add\_subgraph Add a subgraph to this chart. ## draw Draw this chart. ## get\_datasets\_for\_context Returns an arrayref containing all datasets for the given context. Used by renderers to get a list of datasets to chart. ## add\_data ($name, $data) Convenience method for adding data to the chart. Can be called one of three ways. - **scalar** Passing a name and a scalar will append the scalar data to that series' data. $cc->add_data('Sales', 1234); $cc->add_data('Sales', 1235); This will result in a Series named 'Sales' with two values. - **arrayref** Passing a name and an arrayref works much the same as the scalar method discussed above, but appends the supplied arrayref to the existing one. It may be mixed with the scalar method. $cc->add_data('Sales', \@some_sales); $cc->add_data('Sales', \@some_more_sales); # This works still! $cc->add_data('Sales', 1234); - **hashref** This allows you to pass both keys and values in all at once. $cc->add_data('Sales', { 2009 => 1234, 2010 => 1235 }); # appends to last call $cc->add_data('Sales', { 2011 => 1234, 2012 => 1235 }); You may call the hashref version after the scalar or arrayref versions, but you may not add a scalar or arrayref after adding a hashref (as it's not clear what indices should be used for the new data). ## set\_renderer ($renderer\_object, \[ $context \]); Sets the renderer on the specified context. If no context is provided then 'default' is assumed. ## write This method is passed through to the underlying driver. It is only necessary that you call this if you manually called `draw` beforehand. You likely want to use `write_output`. ## write\_output ($path) Write the chart output to the specified location. Output is written in the format provided to the constructor (which defaults to Png). Internally calls `draw` for you. If you use this method, do not call `draw` first! $c->write_output('/path/to/the.png'); ## inside\_width Get the width available in this container after taking away space for insets and borders. ## inside\_height Get the height available in this container after taking away space for insets and borders. # ISSUES WITH CENTOS I've had numerous reports of problems with Chart::Clicker when using CentOS. This problem has usually be solved by updating the version of cairo. I've had reports that upgrading to at least cairo-1.8.8-3 makes thinks work properly. I hesitate to provide any other data with this because it may get out of date fast. If you have trouble feel free to drop me an email and I'll tell you what I know. # CONTRIBUTORS Many thanks to the individuals who have contributed various bits: Ash Berlin Brian Cassidy Guillermo Roditi Torsten Schoenfeld Yuval Kogman # SOURCE Chart::Clicker is on github: http://github.com/gphat/chart-clicker/tree/master # AUTHOR Cory G Watson # COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. context.t100644000765000024 26513024411235 15621 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; BEGIN { use_ok('Chart::Clicker::Context'); } my $c = Chart::Clicker::Context->new(name => 'default'); cmp_ok($c->name, 'eq', $c->name, 'name'); done_testing;example.t100644000765000024 255413024411235 15613 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; use Chart::Clicker::Data::Series; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Marker; use Chart::Clicker::Renderer::Point; BEGIN { use_ok('Chart::Clicker'); } my $cc = Chart::Clicker->new; isa_ok($cc, 'Chart::Clicker'); my $series = Chart::Clicker::Data::Series->new( keys => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ], values => [ 42, 25, 86, 23, 2, 19, 103, 12, 54, 9 ], ); my $series2 = Chart::Clicker::Data::Series->new( keys => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ], values => [ 67, 15, 6, 90, 11, 45, 83, 11, 9, 101 ], ); my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series, $series2 ]); $cc->add_to_datasets($ds); my $ctx = $cc->get_context('default'); my $mark = Chart::Clicker::Data::Marker->new(key => 5, key2 => 6); $mark->brush->color(Graphics::Color::RGB->new(red => 1, green => 0, blue => 0, alpha => 1)); $mark->inside_color(Graphics::Color::RGB->new(red => .5, green => .5, blue => .5, alpha => .5)); $ctx->add_marker($mark); my $mark2 = Chart::Clicker::Data::Marker->new(value => 40, value2 => 60); $mark2->brush->color(Graphics::Color::RGB->new(red => 1, green => 0, blue => 0, alpha => 1)); $mark2->inside_color(Graphics::Color::RGB->new(red => .5, green => .5, blue => .5, alpha => .5)); $ctx->add_marker($mark2); $cc->draw; my $data = $cc->rendered_data; ok(defined($data), 'data'); done_testing;Makefile.PL100644000765000024 776113024411235 15507 0ustar00gphatstaff000000000000Chart-Clicker-2.90# This Makefile.PL for Chart-Clicker was generated by # inc::ChClDistMakeMaker # and Dist::Zilla::Plugin::MakeMaker::Awesome 0.38. # Don't edit it but the dist.ini and plugins used to construct it. use strict; use warnings; use ExtUtils::MakeMaker; my %WriteMakefileArgs = ( "ABSTRACT" => "Powerful, extensible charting.", "AUTHOR" => "Cory G Watson ", "CONFIGURE_REQUIRES" => { "ExtUtils::MakeMaker" => 0 }, "DISTNAME" => "Chart-Clicker", "LICENSE" => "perl", "NAME" => "Chart::Clicker", "PREREQ_PM" => { "Carp" => 0, "Class::Load" => 0, "Color::Scheme" => 0, "DateTime" => 0, "DateTime::Set" => 0, "English" => 0, "Geometry::Primitive::Arc" => 0, "Geometry::Primitive::Circle" => 0, "Geometry::Primitive::Point" => 0, "Graphics::Color::RGB" => 0, "Graphics::Primitive::Border" => 0, "Graphics::Primitive::Brush" => 0, "Graphics::Primitive::Canvas" => 0, "Graphics::Primitive::Component" => 0, "Graphics::Primitive::Container" => 0, ($^O eq 'MSWin32'?"Graphics::Primitive::Driver::GD":"Graphics::Primitive::Driver::Cairo") => 0, "Graphics::Primitive::Font" => 0, "Graphics::Primitive::Insets" => 0, "Graphics::Primitive::Operation::Fill" => 0, "Graphics::Primitive::Operation::Stroke" => 0, "Graphics::Primitive::Oriented" => 0, "Graphics::Primitive::Paint::Gradient::Linear" => 0, "Graphics::Primitive::Paint::Gradient::Radial" => 0, "Graphics::Primitive::Paint::Solid" => 0, "Graphics::Primitive::Path" => 0, "Graphics::Primitive::TextBox" => 0, "Layout::Manager::Absolute" => 0, "Layout::Manager::Axis" => 0, "Layout::Manager::Compass" => 0, "Layout::Manager::Flow" => 0, "Layout::Manager::Grid" => 0, "Layout::Manager::Single" => 0, "List::Util" => 0, "Math::Trig" => 0, "Moose" => 0, "Moose::Role" => 0, "Moose::Util" => 0, "Moose::Util::TypeConstraints" => 0, "POSIX" => 0, "Scalar::Util" => 0, "constant" => 0, "strict" => 0, "warnings" => 0 }, "TEST_REQUIRES" => { "Test::Exception" => 0, "Test::Fatal" => 0, "Test::More" => 0 }, "VERSION" => "2.90", "test" => { "TESTS" => "t/*.t t/series/*.t t/xt/*.t" } ); my %FallbackPrereqs = ( "Carp" => 0, "Class::Load" => 0, "Color::Scheme" => 0, "DateTime" => 0, "DateTime::Set" => 0, "English" => 0, "Geometry::Primitive::Arc" => 0, "Geometry::Primitive::Circle" => 0, "Geometry::Primitive::Point" => 0, "Graphics::Color::RGB" => 0, "Graphics::Primitive::Border" => 0, "Graphics::Primitive::Brush" => 0, "Graphics::Primitive::Canvas" => 0, "Graphics::Primitive::Component" => 0, "Graphics::Primitive::Container" => 0, "Graphics::Primitive::Driver::Cairo" => 0, "Graphics::Primitive::Font" => 0, "Graphics::Primitive::Insets" => 0, "Graphics::Primitive::Operation::Fill" => 0, "Graphics::Primitive::Operation::Stroke" => 0, "Graphics::Primitive::Oriented" => 0, "Graphics::Primitive::Paint::Gradient::Linear" => 0, "Graphics::Primitive::Paint::Gradient::Radial" => 0, "Graphics::Primitive::Paint::Solid" => 0, "Graphics::Primitive::Path" => 0, "Graphics::Primitive::TextBox" => 0, "Layout::Manager::Absolute" => 0, "Layout::Manager::Axis" => 0, "Layout::Manager::Compass" => 0, "Layout::Manager::Flow" => 0, "Layout::Manager::Grid" => 0, "Layout::Manager::Single" => 0, "List::Util" => 0, "Math::Trig" => 0, "Moose" => 0, "Moose::Role" => 0, "Moose::Util" => 0, "Moose::Util::TypeConstraints" => 0, "POSIX" => 0, "Scalar::Util" => 0, "Test::Exception" => 0, "Test::Fatal" => 0, "Test::More" => 0, "constant" => 0, "strict" => 0, "warnings" => 0 ); unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) { delete $WriteMakefileArgs{TEST_REQUIRES}; delete $WriteMakefileArgs{BUILD_REQUIRES}; $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs; } delete $WriteMakefileArgs{CONFIGURE_REQUIRES} unless eval { ExtUtils::MakeMaker->VERSION(6.52) }; WriteMakefile(%WriteMakefileArgs); add-data.t100644000765000024 605313024411235 15615 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse strict; use Test::More; use Test::Fatal; use Chart::Clicker; my @values = (42, 25, 86, 23, 2, 19, 103, 12, 54, 9); my @keys = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10); { my $cc = Chart::Clicker->new; foreach my $v (@values) { $cc->add_data('Sales', $v); } $cc->draw; is_deeply($cc->datasets->[0]->series->[0]->values, \@values, 'add_data scalar values'); ok(defined($cc->rendered_data), 'rendered'); } { my $cc = Chart::Clicker->new; my @vals1 = (42, 25, 86, 23, 2); my @vals2 = (19, 103, 12, 54, 9); $cc->add_data('Sales', \@vals1); $cc->add_data('Sales', \@vals2); $cc->draw; is_deeply($cc->datasets->[0]->series->[0]->values, \@values, 'add_data arrayref values'); ok(defined($cc->rendered_data), 'rendered'); } { my $cc = Chart::Clicker->new; my $hashref = { 1 => 42, 2 => 25, 3 => 86, 4 => 23, 5 => 2, 6 => 19, 7 => 103, 8 => 12, 9 => 54, 10 => 9 }; $cc->add_data('Sales', $hashref); $cc->draw; is_deeply($cc->datasets->[0]->series->[0]->values, \@values, 'add_data hashref values'); ok(defined($cc->rendered_data), 'rendered'); } { my $cc = Chart::Clicker->new; my $hashref1 = { 1 => 42, 4 => 23, 6 => 19, 7 => 103, }; my $hashref2 = { 5 => 2, 2 => 25, 3 => 86, 8 => 12, 9 => 54, 10 => 9 }; $cc->add_data('Sales', $hashref1); $cc->add_data('Sales', $hashref2); $cc->draw; is_deeply($cc->datasets->[0]->series->[0]->values, \@values, 'add_data multiple hashref values'); ok(defined($cc->rendered_data), 'rendered'); } { my $cc = Chart::Clicker->new; my @vals = (42, 25, 86, 23); my $hashref2 = { 5 => 2, 6 => 19, 7 => 103, 8 => 12, 9 => 54, 10 => 9 }; $cc->add_data('Sales', \@vals); $cc->add_data('Sales', $hashref2); $cc->draw; is_deeply($cc->datasets->[0]->series->[0]->values, \@values, 'add_data arrayref followed by hashref'); ok(defined($cc->rendered_data), 'rendered'); } { my $cc = Chart::Clicker->new; my $hashref = { 1 => 42, 2 => 25, 3 => 86, 4 => 23, 5 => 2, }; my @vals = (19, 103, 12, 54, 9); like( exception { $cc->add_data('Sales', $hashref); $cc->add_data('Sales', \@vals); }, qr/Can't add arrayref data after adding hashrefs/, "Exception thrown if arrayref data added after hashref data", ); } { my $cc = Chart::Clicker->new; my $hashref = { 1 => 42, 2 => 25, 3 => 86, 4 => 23, 5 => 2, }; my $val = 19; like( exception { $cc->add_data('Sales', $hashref); $cc->add_data('Sales', $val); }, qr/Can't add scalar data after adding hashrefs/, "Exception thrown if scalar data added after hashref data", ); } done_testing; datetime.t100644000765000024 304113024411235 15744 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; use Chart::Clicker::Data::Series; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Marker; use Chart::Clicker::Renderer::Point; use Chart::Clicker::Axis::DateTime; BEGIN { use_ok('Chart::Clicker'); } my $cc = Chart::Clicker->new; isa_ok($cc, 'Chart::Clicker'); my $now = time; my $hour = 3600; my @values = (42, 25, 86, 23, 2, 19, 103, 12, 54, 9); my $vcount = scalar(@values); my $series = Chart::Clicker::Data::Series->new; for my $i (0 .. $vcount) { $series->add_to_keys($now - ($hour * ($vcount - $i))); $series->add_to_values($values[$i - 1]); } # $series->add_to_keys(time - 3600); # $series->add_to_values(50); my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series ]); $cc->add_to_datasets($ds); my $ctx = $cc->get_context('default'); $ctx->domain_axis(Chart::Clicker::Axis::DateTime->new(position => 'bottom', orientation => 'horizontal')); my $mark = Chart::Clicker::Data::Marker->new(key => 5, key2 => 6); $mark->brush->color(Graphics::Color::RGB->new(red => 1, green => 0, blue => 0, alpha => 1)); $mark->inside_color(Graphics::Color::RGB->new(red => .5, green => .5, blue => .5, alpha => .5)); $ctx->add_marker($mark); my $mark2 = Chart::Clicker::Data::Marker->new(value => 40, value2 => 60); $mark2->brush->color(Graphics::Color::RGB->new(red => 1, green => 0, blue => 0, alpha => 1)); $mark2->inside_color(Graphics::Color::RGB->new(red => .5, green => .5, blue => .5, alpha => .5)); $ctx->add_marker($mark2); $cc->draw; my $data = $cc->rendered_data; ok(defined($data), 'data'); done_testing;invisible.t100644000765000024 170213024411235 16136 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; use Chart::Clicker::Data::Series; use Chart::Clicker::Data::Series::Size; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Renderer::Point; BEGIN { use_ok('Chart::Clicker'); } my $cc = Chart::Clicker->new; isa_ok($cc, 'Chart::Clicker'); my $series = Chart::Clicker::Data::Series->new( keys => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ], values => [ 42, 25, 86, 23, 2, 19, 103, 12, 54, 9 ], ); my $series2 = Chart::Clicker::Data::Series->new( keys => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ], values => [ 67, 15, 6, 90, 11, 45, 83, 11, 9, 101 ], ); my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series, $series2 ]); $cc->add_to_datasets($ds); my $def = $cc->get_context('default'); $def->range_axis->hidden(1); $cc->draw; cmp_ok($cc->plot->origin->x, '==', 4, 'plot origin x'); cmp_ok($cc->plot->origin->y, '==', 4, 'plot origin y'); my $data = $cc->rendered_data; ok(defined($data), 'data'); done_testing;example000755000765000024 013024411235 15015 5ustar00gphatstaff000000000000Chart-Clicker-2.90bar.pl100644000765000024 255213024411235 16262 0ustar00gphatstaff000000000000Chart-Clicker-2.90/example#!/usr/bin/perl use strict; use Chart::Clicker; use Chart::Clicker::Context; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Marker; use Chart::Clicker::Data::Series; use Chart::Clicker::Renderer::Bar; use Geometry::Primitive::Rectangle; use Graphics::Color::RGB; my $cc = Chart::Clicker->new(width => 500, height => 250); my @hours = qw( 1 2 3 4 5 6 7 8 9 10 11 12 ); my @bw1 = qw( 5.8 5.0 4.9 4.8 4.5 4.25 3.5 2.9 2.5 1.8 .9 .8 ); my @bw2 = qw( .7 1.1 1.7 2.5 3.0 4.5 5.0 4.9 4.7 4.8 4.2 4.4 ); my @bw3 = qw( .3 1.4 1.2 1.5 4.0 3.5 2.0 1.9 2.7 4.2 3.2 1.1 ); my $series1 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw1, ); my $series2 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw2, ); my $series3 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw3, ); my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series1, $series2, $series3 ]); $cc->add_to_datasets($ds); my $def = $cc->get_context('default'); my $area = Chart::Clicker::Renderer::Bar->new(opacity => .6); $area->brush->width(3); $def->renderer($area); $def->range_axis->tick_values([qw(1 3 5)]); $def->range_axis->format('%d'); $def->domain_axis->tick_values([qw(2 4 6 8 10)]); $def->domain_axis->format('%d'); $def->domain_axis->fudge_amount(.05); $cc->write_output('foo.png'); pie.pl100644000765000024 246613024411235 16277 0ustar00gphatstaff000000000000Chart-Clicker-2.90/example#!/usr/bin/perl use strict; use Chart::Clicker; use Chart::Clicker::Context; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Marker; use Chart::Clicker::Data::Series; use Chart::Clicker::Renderer::Pie; use Geometry::Primitive::Rectangle; use Graphics::Color::RGB; my $cc = Chart::Clicker->new(width => 300, height => 250); my $series1 = Chart::Clicker::Data::Series->new( keys => [ 1, 2, 3 ], values => [ 1, 2, 3 ], ); my $series2 = Chart::Clicker::Data::Series->new( keys => [ 1, 2, 3], values => [ 1, 1, 3 ], ); my $series3 = Chart::Clicker::Data::Series->new( keys => [ 1, 2, 3], values => [ 1, 2, 1 ], ); my $series4 = Chart::Clicker::Data::Series->new( keys => [ 1, 2, 3], values => [ 1, 2, 3 ], ); my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series1, $series2, $series3, $series4 ]); $cc->add_to_datasets($ds); my $defctx = $cc->get_context('default'); my $ren = Chart::Clicker::Renderer::Pie->new; $ren->border_color(Graphics::Color::RGB->new(red => 0, green => 0, blue => 0)); $ren->brush->width(2); $ren->gradient_color(Graphics::Color::RGB->new(red => 1, green => 1, blue => 1, alpha => .3)); $defctx->renderer($ren); $defctx->domain_axis->hidden(1); $defctx->range_axis->hidden(1); $cc->plot->grid->visible(0); $cc->write_output('foo.png'); data-range.t100644000765000024 343013024411235 16155 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; BEGIN { use_ok('Chart::Clicker::Data::Range'); } my $range = Chart::Clicker::Data::Range->new({ lower => 0, upper => 10 }); ok(defined($range), 'new Chart::Clicker::Data::Range'); isa_ok($range, 'Chart::Clicker::Data::Range', 'isa Chart::Clicker::Data::Range'); cmp_ok($range->lower, '==', 0, 'Lower'); cmp_ok($range->upper, '==', 10, 'Upper'); cmp_ok($range->span, '==', 10, 'span'); ok($range->contains(0), 'range contains 0'); ok($range->contains(5), 'range contains 5'); ok($range->contains(10), 'range contains 10'); ok(!$range->contains(11), 'range does not contain 11'); $range->combine(Chart::Clicker::Data::Range->new({ lower => 3, upper => 15 })); cmp_ok($range->lower, '==', 0, 'Combine 1: Lower stays'); cmp_ok($range->upper, '==', 15, 'Combine 1: Upper moves'); $range->combine(Chart::Clicker::Data::Range->new({ lower => -1, upper => 5 })); cmp_ok($range->lower, '==', -1, 'Combine 2: Lower moves'); cmp_ok($range->upper, '==', 15, 'Combine 2: Upper stays'); my $range2 = Chart::Clicker::Data::Range->new({ lower => 1, upper => 10 }); my $max = 11; $range2->max($max); cmp_ok($range2->upper, '==', $max, 'Upper == max'); my $min = 3; $range2->min($min); cmp_ok($range2->lower, '==', $min, 'Lower == min'); cmp_ok($range2->span, '==', ($max - $min), 'Span == (max - min)'); $range2->combine(Chart::Clicker::Data::Range->new({ lower => -1, upper => 50 })); cmp_ok($range2->upper, '==', $max, 'Upper == max after combine'); cmp_ok($range2->lower, '==', $min, 'Lower == min after combine'); my $range3 = Chart::Clicker::Data::Range->new; $range3->combine(Chart::Clicker::Data::Range->new({ lower => 3, upper => 15 })); cmp_ok($range3->lower, '==', 3, 'Undefined range, combine check lower'); cmp_ok($range3->upper, '==', 15, 'Undefined range, combine check upper'); done_testing;decoration.t100644000765000024 25313024411235 16261 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; BEGIN { use_ok('Chart::Clicker::Decoration'); } my $dec = Chart::Clicker::Decoration->new; isa_ok($dec, 'Chart::Clicker::Decoration'); done_testing;simple-ctx.t100644000765000024 273513024411235 16246 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; use Chart::Clicker::Data::Series; use Chart::Clicker::Data::Series::Size; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Renderer::Point; BEGIN { use_ok('Chart::Clicker'); } my $cc = Chart::Clicker->new; isa_ok($cc, 'Chart::Clicker'); my $series = Chart::Clicker::Data::Series->new( keys => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ], values => [ 42, 25, 86, 23, 2, 19, 103, 12, 54, 9 ], ); my $series2 = Chart::Clicker::Data::Series->new( keys => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ], values => [ 67, 15, 6, 90, 11, 45, 83, 11, 9, 101 ], ); my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series ]); my $sales = Chart::Clicker::Context->new(name => 'sales', renderer => Chart::Clicker::Renderer::Point->new); $cc->add_to_contexts($sales); my $ds2 = Chart::Clicker::Data::DataSet->new(series => [ $series2 ]); $ds2->context('sales'); $cc->add_to_datasets($ds, $ds2); $cc->draw; my $lrange = $cc->get_context('default')->range_axis; my $bdomain = $cc->get_context('default')->domain_axis; cmp_ok($lrange->position, 'eq', 'left', 'first range axis position'); cmp_ok($bdomain->position, 'eq', 'bottom', 'first domain axis position'); my $rrange = $cc->get_context('sales')->range_axis; my $tdomain = $cc->get_context('sales')->domain_axis; cmp_ok($rrange->position, 'eq', 'right', 'second range axis position'); cmp_ok($tdomain->position, 'eq', 'top', 'second domain axis position'); ok(defined($cc->rendered_data), 'data'); done_testing;area.pl100644000765000024 250613024411235 16425 0ustar00gphatstaff000000000000Chart-Clicker-2.90/example#!/usr/bin/perl use strict; use Chart::Clicker; use Chart::Clicker::Context; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Marker; use Chart::Clicker::Data::Series; use Chart::Clicker::Renderer::Area; use Geometry::Primitive::Rectangle; use Graphics::Color::RGB; my $cc = Chart::Clicker->new(width => 500, height => 250); my @hours = qw( 1 2 3 4 5 6 7 8 9 10 11 12 ); my @bw1 = qw( 5.8 5.0 4.9 4.8 4.5 4.25 3.5 2.9 2.5 1.8 .9 .8 ); my @bw2 = qw( .7 1.1 1.7 2.5 3.0 4.5 5.0 4.9 4.7 4.8 4.2 4.4 ); my @bw3 = qw( .3 1.4 1.2 1.5 4.0 3.5 2.0 1.9 2.7 4.2 3.2 1.1 ); my $series1 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw1, ); my $series2 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw2, ); my $series3 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw3, ); my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series1, $series2, $series3 ]); $cc->add_to_datasets($ds); my $def = $cc->get_context('default'); my $area = Chart::Clicker::Renderer::Area->new(opacity => .6); $area->brush->width(3); $def->renderer($area); $def->range_axis->tick_values([qw(1 3 5)]); $def->range_axis->format('%d'); $def->domain_axis->tick_values([qw(2 4 6 8 10)]); $def->domain_axis->format('%d'); $cc->write_output('foo.png'); line.pl100644000765000024 150013024411235 16435 0ustar00gphatstaff000000000000Chart-Clicker-2.90/example#!/usr/bin/perl use strict; use Chart::Clicker; use Chart::Clicker::Renderer::Line; my $cc = Chart::Clicker->new(width => 500, height => 250); my @bw1 = qw( 5.8 5.0 4.9 4.8 4.5 4.25 3.5 2.9 2.5 1.8 .9 .8 ); my @bw2 = qw( .7 1.1 1.7 2.5 3.0 4.5 5.0 4.9 4.7 4.8 4.2 4.4 ); my @bw3 = qw( .3 1.4 1.2 1.5 4.0 3.5 2.0 1.9 2.7 4.2 3.2 1.1 ); foreach my $d (@bw1) { $cc->add_data('Series 0', $d); } foreach my $d (@bw2) { $cc->add_data('Series 1', $d); } foreach my $d (@bw3) { $cc->add_data('Series 2', $d); } my $def = $cc->get_context('default'); my $ren = Chart::Clicker::Renderer::Line->new; $ren->brush->width(3); $def->range_axis->tick_values([qw(1 5 9)]); $def->range_axis->format('%d'); $def->domain_axis->tick_values([qw(2 4 6 8 10)]); $def->domain_axis->format('%d'); $cc->write_output('foo.png'); data-marker.t100644000765000024 72313024411235 16324 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; BEGIN { use_ok('Chart::Clicker::Data::Marker'); } my $marker = Chart::Clicker::Data::Marker->new; ok(defined($marker), 'new Chart::Clicker::Data::Marker'); isa_ok($marker, 'Chart::Clicker::Data::Marker', 'isa Chart::Data::Marker'); cmp_ok($marker->inside_color->red, '==', 0, 'Default Inside Color Red'); cmp_ok($marker->color->red, '==', 0, 'Default Color Red'); isa_ok($marker->brush, 'Graphics::Primitive::Brush', 'Default Brush'); done_testing;series000755000765000024 013024411235 15117 5ustar00gphatstaff000000000000Chart-Clicker-2.90/tsize.t100644000765000024 117413024411235 16421 0ustar00gphatstaff000000000000Chart-Clicker-2.90/t/seriesuse Test::More; BEGIN { use_ok('Chart::Clicker::Data::Series::Size'); } my $series = Chart::Clicker::Data::Series::Size->new; ok(defined($series), 'new Chart::Clicker::Data::Series::Size'); isa_ok($series, 'Chart::Clicker::Data::Series::Size'); my @values = (1, 2, 10); my @keys = (1, 2, 3); my @sizes = (3, 6); $series->values(\@values); $series->keys(\@keys); $series->sizes(\@sizes); cmp_ok($series->size_count, '==', 2, '2 sizes'); $series->add_to_sizes(5); cmp_ok($series->size_count, '==', 3, '3 sizes'); cmp_ok($series->max_size, '==', 6, 'get_max_size'); cmp_ok($series->min_size, '==', 3, 'get_min_size'); done_testing;point.pl100644000765000024 245213024411235 16646 0ustar00gphatstaff000000000000Chart-Clicker-2.90/example#!/usr/bin/perl use strict; use Chart::Clicker; use Chart::Clicker::Context; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Marker; use Chart::Clicker::Data::Series; use Chart::Clicker::Renderer::Point; use Geometry::Primitive::Rectangle; use Graphics::Color::RGB; my $cc = Chart::Clicker->new(width => 500, height => 250); my @hours = qw( 1 2 3 4 5 6 7 8 9 10 11 12 ); my @bw1 = qw( 5.8 5.0 4.9 4.8 4.5 4.25 3.5 2.9 2.5 1.8 .9 .8 ); my @bw2 = qw( .7 1.1 1.7 2.5 3.0 4.5 5.0 4.9 4.7 4.8 4.2 4.4 ); my @bw3 = qw( .3 1.4 1.2 1.5 4.0 3.5 2.0 1.9 2.7 4.2 3.2 1.1 ); my $series1 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw1, ); my $series2 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw2, ); my $series3 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw3, ); my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series1, $series2, $series3 ]); $cc->add_to_datasets($ds); my $def = $cc->get_context('default'); my $ren = Chart::Clicker::Renderer::Point->new(size => 5); $def->renderer($ren); $def->range_axis->tick_values([qw(1 3 5)]); $def->range_axis->format('%d'); $def->domain_axis->tick_values([qw(2 4 6 8 10)]); $def->domain_axis->format('%d'); $cc->write_output('foo.png'); data-dataset.t100644000765000024 440113024411235 16505 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; BEGIN { use_ok('Chart::Clicker::Data::DataSet'); } BEGIN { use_ok('Chart::Clicker::Data::Series'); } my $dataset = Chart::Clicker::Data::DataSet->new; cmp_ok($dataset->context, 'eq', 'default', 'context'); ok(defined($dataset), 'new Chart::Clicker::Data::DataSet'); isa_ok($dataset, 'Chart::Clicker::Data::DataSet', 'isa Chart::Data::DataSet'); my $series = Chart::Clicker::Data::Series->new; my $name = 'Foo'; $series->name($name); $series->keys([1, 2, 3]); $series->values([4, 5, 6]); eval { $dataset->prepare }; ok($@, 'Fail on empty dataset'); my $series2 = Chart::Clicker::Data::Series->new; $series2->name('Second'); $series2->keys([1, 2, 4]); $series2->values([-1, 102, 12]); $dataset->add_to_series($series); cmp_ok($dataset->count, '==', 1, 'count is correct'); $dataset->add_to_series($series2); cmp_ok($dataset->count, '==', 2, 'count is correct'); $dataset->prepare; cmp_ok($dataset->largest_value_slice, '==', 107, 'largest_value_slice'); my $ds = $dataset->series; ok(defined($ds), 'Series set'); ok(defined($ds->[0]), '0th Series set'); ok(defined($ds->[0]->name eq $name), 'Name set on series'); cmp_ok($dataset->count, '==', 2, 'Series count'); cmp_ok($dataset->max_key_count, '==', 3, 'Max Keys'); cmp_ok($dataset->range->lower, '==', -1, 'Min Range'); cmp_ok($dataset->range->upper, '==', 102, 'Max Range'); cmp_ok($dataset->domain->lower, '==', 1, 'Min Domain'); cmp_ok($dataset->domain->upper, '==', 4, 'Max Domain'); is_deeply($dataset->get_series_values(0), [ 4, -1 ], 'get_series_values'); my @keys = $dataset->get_series_keys(2); cmp_ok($keys[0], '==', 3, 'key 0'); cmp_ok($keys[1], '==', 4, 'key 1'); cmp_ok(scalar(@keys), '==', 2, '2 keys for position 2'); { my $ds2 = Chart::Clicker::Data::DataSet->new; my $s1 = Chart::Clicker::Data::Series->new( keys => [1, 3, 5], values => [1, 3, 5] ); my $s2 = Chart::Clicker::Data::Series->new( keys => [1, 2, 5, 7], values => [2, 4, 8, 10] ); $ds2->add_to_series($s1); $ds2->add_to_series($s2); is_deeply($ds2->get_series_values_for_key(1), [ 1, 2 ], 'get_series_values_for_key where both series have key'); is_deeply($ds2->get_series_values_for_key(3), [ 3, undef ], 'get_series_values_for_key one series is missing key'); } done_testing;renderer-bar.t100644000765000024 33613024411235 16504 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; BEGIN { use_ok('Chart::Clicker::Renderer::Bar'); } my $rndr = Chart::Clicker::Renderer::Bar->new; ok(defined($rndr), 'new Bar Renderer'); isa_ok($rndr, 'Chart::Clicker::Renderer::Bar'); done_testing;renderer-pie.t100644000765000024 33613024411235 16515 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; BEGIN { use_ok('Chart::Clicker::Renderer::Pie'); } my $rndr = Chart::Clicker::Renderer::Pie->new; ok(defined($rndr), 'new Pie Renderer'); isa_ok($rndr, 'Chart::Clicker::Renderer::Pie'); done_testing;bubble.pl100644000765000024 270313024411235 16747 0ustar00gphatstaff000000000000Chart-Clicker-2.90/example#!/usr/bin/perl use strict; use Chart::Clicker; use Chart::Clicker::Context; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Marker; use Chart::Clicker::Data::Series::Size; use Chart::Clicker::Renderer::Bubble; use Geometry::Primitive::Rectangle; use Graphics::Color::RGB; my $cc = Chart::Clicker->new(width => 500, height => 250); my @hours = qw( 1 2 3 4 5 6 7 8 9 10 11 12 ); my @bw1 = qw( 5.8 5.0 4.9 4.8 4.5 4.25 3.5 2.9 2.5 1.8 .9 .8 ); my @bw2 = qw( .7 1.1 1.7 2.5 3.0 4.5 5.0 4.9 4.7 4.8 4.2 4.4 ); my @bw3 = qw( .3 1.4 1.2 1.5 4.0 3.5 2.0 1.9 2.7 4.2 3.2 1.1 ); my $series1 = Chart::Clicker::Data::Series::Size->new( keys => \@hours, values => \@bw1, sizes => [qw(1 2 3 4 5 6 7 8 7 6 5 2)] ); my $series2 = Chart::Clicker::Data::Series::Size->new( keys => \@hours, values => \@bw2, sizes => [qw(8 7 6 5 4 3 2 1 2 3 4 5)] ); my $series3 = Chart::Clicker::Data::Series::Size->new( keys => \@hours, values => \@bw3, sizes => [qw(2 3 4 5 6 7 7 6 5 4 3 2)] ); my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series1, $series2, $series3 ]); $cc->add_to_datasets($ds); my $def = $cc->get_context('default'); my $ren = Chart::Clicker::Renderer::Bubble->new; $def->renderer($ren); $def->range_axis->tick_values([qw(1 3 5)]); $def->range_axis->format('%d'); $def->domain_axis->tick_values([qw(2 4 6 8 10)]); $def->domain_axis->format('%d'); $cc->write_output('foo.png'); simple.pl100644000765000024 73513024411235 16770 0ustar00gphatstaff000000000000Chart-Clicker-2.90/example#!/usr/bin/perl use strict; use Chart::Clicker; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Series; my $cc = Chart::Clicker->new(width => 500, height => 400); my $series1 = Chart::Clicker::Data::Series->new( keys => [qw(1 2 3 4 5 6 7 8 9 10 11 12)], values => [qw(5.8 5.0 4.9 4.8 4.5 4.25 3.5 2.9 2.5 1.8 .9 .8)] ); my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series1 ]); $cc->add_to_datasets($ds); $cc->write_output('foo.png'); axis-datetime.t100644000765000024 122113024411235 16704 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; BEGIN { use_ok('Chart::Clicker::Axis::DateTime'); } my $a = Chart::Clicker::Axis::DateTime->new( position => 'left',format => '%H:%M:%S', orientation => 'vertical' ); isa_ok($a, 'Chart::Clicker::Axis::DateTime'); my $foo = $a->format_value(time); ok($foo =~ /\d+:\d+:\d/, 'Formatted Properly'); my $dt = DateTime->new( 'year' => 2007, 'month' => 8, 'day' => 30, 'hour' => 18, 'minute'=> 53, 'second'=> 00, 'time_zone' => 'America/Chicago' ); $a->time_zone('UTC'); my $formatted = $a->format_value($dt->epoch); cmp_ok($formatted, 'eq', '23:53:00', 'Proper formatting with timezone'); done_testing;renderer-area.t100644000765000024 34213024411235 16645 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; BEGIN { use_ok('Chart::Clicker::Renderer::Area'); } my $rndr = Chart::Clicker::Renderer::Area->new; ok(defined($rndr), 'new Area Renderer'); isa_ok($rndr, 'Chart::Clicker::Renderer::Area'); done_testing;renderer-base.t100644000765000024 31313024411235 16645 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; BEGIN { use_ok('Chart::Clicker::Renderer'); } my $rndr = Chart::Clicker::Renderer->new; ok(defined($rndr), 'new Renderer'); isa_ok($rndr, 'Chart::Clicker::Renderer'); done_testing;renderer-line.t100644000765000024 34213024411235 16664 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; BEGIN { use_ok('Chart::Clicker::Renderer::Line'); } my $rndr = Chart::Clicker::Renderer::Line->new; ok(defined($rndr), 'new Line Renderer'); isa_ok($rndr, 'Chart::Clicker::Renderer::Line'); done_testing;same-axes-ctx.t100644000765000024 275513024411235 16642 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; use Chart::Clicker::Data::Series; use Chart::Clicker::Data::Series::Size; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Renderer::Point; BEGIN { use_ok('Chart::Clicker'); } my $cc = Chart::Clicker->new; isa_ok($cc, 'Chart::Clicker'); my $series = Chart::Clicker::Data::Series->new( keys => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ], values => [ 42, 25, 86, 23, 2, 19, 103, 12, 54, 9 ], ); my $series2 = Chart::Clicker::Data::Series->new( keys => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ], values => [ 67, 15, 6, 90, 11, 45, 83, 11, 9, 101 ], ); my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series ]); my $sales = Chart::Clicker::Context->new( name => 'sales', domain_axis => $cc->get_context('default')->domain_axis ); $cc->add_to_contexts($sales); my $ds2 = Chart::Clicker::Data::DataSet->new(series => [ $series2 ]); $ds2->context('sales'); $cc->add_to_datasets($ds, $ds2); $cc->draw; my $lrange = $cc->get_context('default')->range_axis; my $bdomain = $cc->get_context('default')->domain_axis; cmp_ok($lrange->position, 'eq', 'left', 'first range axis position'); cmp_ok($bdomain->position, 'eq', 'bottom', 'first domain axis position'); my $rrange = $cc->get_context('sales')->range_axis; my $tdomain = $cc->get_context('sales')->domain_axis; cmp_ok($rrange->position, 'eq', 'right', 'second range axis position'); cmp_ok($tdomain->position, 'eq', 'bottom', 'second domain axis position'); ok(defined($cc->rendered_data), 'data'); done_testing;series.t100644000765000024 426713024411235 16747 0ustar00gphatstaff000000000000Chart-Clicker-2.90/t/seriesuse Test::More; BEGIN { use_ok('Chart::Clicker::Data::Series'); } my $series = Chart::Clicker::Data::Series->new; ok(defined($series), 'new Chart::Clicker::Data::Series'); isa_ok($series, 'Chart::Clicker::Data::Series'); my $name = 'Foo'; $series->name($name); ok($series->name eq $name, 'Name'); my @values = (1, 2, 10); $series->values(\@values); my $svals = $series->values; ok(defined($svals), 'Values set'); cmp_ok($values[0], '==', $svals->[0], 'Value 0'); cmp_ok($values[1], '==', $svals->[1], 'Value 1'); cmp_ok($values[2], '==', $svals->[2], 'Value 2'); eval { $series->prepare; }; ok(defined($@), 'Fail when keycount != valuecount'); my @keys = (1, 2, 3); $series->keys(\@keys); my $skeys = $series->keys; ok(defined($skeys), 'Keys set'); cmp_ok($keys[0], 'eq', $skeys->[0], 'Key 0'); cmp_ok($keys[1], 'eq', $skeys->[1], 'Key 1'); cmp_ok($keys[2], 'eq', $skeys->[2], 'Key 2'); eval {$series->prepare; }; ok(!$@, 'Series prepare'); cmp_ok($series->key_count, '==', @keys, 'Key Count'); cmp_ok($series->value_count, '==', @values, 'Value Count'); cmp_ok($series->range->lower, '==', $values[0], 'Minimum Value'); cmp_ok($series->range->upper, '==', $values[2], 'Maximum Value'); cmp_ok($series->range->span, '==', 9, 'Span'); my $fooseries = Chart::Clicker::Data::Series->new({ keys => [ 1, 2, 3, 4 ], values => [ 5, 6, 7, 14] }); $fooseries->prepare; cmp_ok($fooseries->keys->[0], '==', 1, 'Verify first key'); cmp_ok($fooseries->values->[0], '==', 5, 'Verify first value'); cmp_ok($fooseries->key_count, '==', 4, 'Verify key count'); cmp_ok($fooseries->range->span, '==', 9, 'Range'); my $broken_series = Chart::Clicker::Data::Series->new; $broken_series->prepare; eval { my $range = $broken_series->range; }; ok(defined($@), 'caught busted range calculation'); my $quickseries = Chart::Clicker::Data::Series->new({ 1 => 5, 2 => 6, 3 => 7, 4 => 8 }); is_deeply($quickseries->keys, [ 1, 2, 3, 4 ], 'keys'); is_deeply($quickseries->values, [ 5, 6, 7, 8 ], 'values'); my $oddseries = Chart::Clicker::Data::Series->new({ keys => [ 1, 3, 5, 7, 9 ], values => [ 10, 11, 12, 13, 14 ] }); cmp_ok($oddseries->get_value_for_key(3), '==', 11, 'get_value_for_key'); done_testing;heatmap.pl100644000765000024 270513024411235 17135 0ustar00gphatstaff000000000000Chart-Clicker-2.90/example#!/usr/bin/perl use strict; use Chart::Clicker; use Chart::Clicker::Context; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Marker; use Chart::Clicker::Data::Series::Size; use Chart::Clicker::Renderer::HeatMap; use Geometry::Primitive::Rectangle; use Graphics::Color::RGB; my $cc = Chart::Clicker->new(width => 500, height => 250); my @hours = qw( 1 2 3 4 5 6 7 8 9 10 11 12 ); my @bw1 = qw( 5.8 5.0 4.9 4.8 4.5 4.25 3.5 2.9 2.5 1.8 .9 .8 ); my @bw2 = qw( .7 1.1 1.7 2.5 3.0 4.5 5.0 4.9 4.7 4.8 4.2 4.4 ); my @bw3 = qw( .3 1.4 1.2 1.5 4.0 3.5 2.0 1.9 2.7 4.2 3.2 1.1 ); my $series1 = Chart::Clicker::Data::Series::Size->new( keys => \@hours, values => \@bw1, sizes => [qw(1 2 3 4 5 6 7 8 7 6 5 2)] ); my $series2 = Chart::Clicker::Data::Series::Size->new( keys => \@hours, values => \@bw2, sizes => [qw(8 7 6 5 4 3 2 1 2 3 4 5)] ); my $series3 = Chart::Clicker::Data::Series::Size->new( keys => \@hours, values => \@bw3, sizes => [qw(2 3 4 5 6 7 7 6 5 4 3 2)] ); my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series1, $series2, $series3 ]); $cc->add_to_datasets($ds); my $def = $cc->get_context('default'); my $ren = Chart::Clicker::Renderer::HeatMap->new; $def->renderer($ren); $def->range_axis->tick_values([qw(1 3 5)]); $def->range_axis->format('%d'); $def->domain_axis->tick_values([qw(2 4 6 8 10)]); $def->domain_axis->format('%d'); $cc->write_output('foo.png'); renderer-point.t100644000765000024 34613024411235 17072 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; BEGIN { use_ok('Chart::Clicker::Renderer::Point'); } my $rndr = Chart::Clicker::Renderer::Point->new; ok(defined($rndr), 'new Point Renderer'); isa_ok($rndr, 'Chart::Clicker::Renderer::Point'); done_testing;highlow.t100644000765000024 140213024411235 17102 0ustar00gphatstaff000000000000Chart-Clicker-2.90/t/seriesuse Test::More; BEGIN { use_ok('Chart::Clicker::Data::Series::HighLow'); } my $series = Chart::Clicker::Data::Series::HighLow->new; ok(defined($series), 'new Chart::Clicker::Data::Series::HighLow'); isa_ok($series, 'Chart::Clicker::Data::Series::HighLow'); my $fooseries = Chart::Clicker::Data::Series::HighLow->new({ keys => [ 1, 2, 3, 4 ], highs => [ 11, 9, 12, 14 ], lows => [ 5, 1, 4, 12 ], opens => [ 4, 5, 6, 7 ], values => [ 5, 6, 7, 14 ], }); cmp_ok($fooseries->get_high(1), '==', 9, 'high 1'); cmp_ok($fooseries->get_low(1), '==', 1, 'low 1'); cmp_ok($fooseries->get_open(1), '==', 5, 'open 5'); my $range = $fooseries->range; cmp_ok($range->lower, '==', 1, 'range lower'); cmp_ok($range->upper, '==', 14, 'range upper'); done_testing;decoration-grid.t100644000765000024 27413024411235 17207 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; BEGIN { use_ok('Chart::Clicker::Decoration::Grid'); } my $dec = Chart::Clicker::Decoration::Grid->new; isa_ok($dec, 'Chart::Clicker::Decoration::Grid'); done_testing;decoration-plot.t100644000765000024 13113024411235 17230 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; BEGIN { use_ok('Chart::Clicker::Decoration::Plot'); } done_testing;renderer-bubble.t100644000765000024 35213024411235 17171 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; BEGIN { use_ok('Chart::Clicker::Renderer::Bubble'); } my $rndr = Chart::Clicker::Renderer::Bubble->new; ok(defined($rndr), 'new Bubble Renderer'); isa_ok($rndr, 'Chart::Clicker::Renderer::Bubble'); done_testing;author-synopsis.t100644000765000024 26213024411235 17321 0ustar00gphatstaff000000000000Chart-Clicker-2.90/t#!perl BEGIN { unless ($ENV{AUTHOR_TESTING}) { print qq{1..0 # SKIP these tests are for testing by the author\n}; exit } } use Test::Synopsis; all_synopsis_ok(); date-axis.pl100644000765000024 160313024411235 17371 0ustar00gphatstaff000000000000Chart-Clicker-2.90/example#!/usr/bin/perl use strict; use Chart::Clicker; use Chart::Clicker::Axis::DateTime; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Series; my $cc = Chart::Clicker->new(width => 500, height => 400); my $series1 = Chart::Clicker::Data::Series->new( values => [qw(1 2 3 4 5 6 7 8 9 10 11 12)], keys => [qw( 1257069600 1257156000 1257242400 1257328800 1257415200 1257501600 1257588000 1257674400 1257760800 1257847200 1257933600 1258020000 )] ); my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series1 ]); $cc->add_to_datasets($ds); my $def = $cc->get_context('default'); my $dtaxis = Chart::Clicker::Axis::DateTime->new( format => '%m/%d', position => 'bottom', orientation => 'horizontal' ); $def->domain_axis($dtaxis); $cc->write_output('foo.png');sparkline.pl100644000765000024 543313024411235 17507 0ustar00gphatstaff000000000000Chart-Clicker-2.90/example#!/usr/bin/perl use strict; use Chart::Clicker; use Chart::Clicker::Context; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Marker; use Chart::Clicker::Data::Series; use Chart::Clicker::Renderer::Point; use Geometry::Primitive::Rectangle; use Graphics::Color::RGB; my $cc = Chart::Clicker->new(width => 75, height => 18, format => 'png'); my $series = Chart::Clicker::Data::Series->new( keys => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24], values => [ 5.8, 5.0, 4.9, 4.8, 4.5, 4.25, 3.5, 2.9, 2.5, 1.8, .9, .8, .7, 1.1, 1.7, 2.5, 3.0, 4.5, 5.0, 4.9, 4.7, 4.8, 4.2, 4.4], ); my $series2 = Chart::Clicker::Data::Series->new( keys => [ 24 ], values => [ 4.4 ] ); my $series3 = Chart::Clicker::Data::Series->new( keys => [ 1, 13 ], values => [ 5.8, .7 ] ); my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series ]); $cc->add_to_datasets($ds); my $defctx = $cc->get_context('default'); my $highds = Chart::Clicker::Data::DataSet->new(series => [ $series2 ]); $cc->add_to_datasets($highds); my $highctx = Chart::Clicker::Context->new( name => 'high', renderer => Chart::Clicker::Renderer::Point->new( shape => Geometry::Primitive::Rectangle->new( width => 3, height => 3 ) ), range_axis => $defctx->range_axis, domain_axis => $defctx->domain_axis ); $cc->add_to_contexts($highctx); $highds->context('high'); # my $noteds = Chart::Clicker::Data::DataSet->new(series => [ $series3 ]); $cc->add_to_datasets($noteds); my $notectx = Chart::Clicker::Context->new( name => 'notable', renderer => Chart::Clicker::Renderer::Point->new( shape => Geometry::Primitive::Rectangle->new( width => 3, height => 3 ) ), range_axis => $defctx->range_axis, domain_axis => $defctx->domain_axis ); $cc->add_to_contexts($notectx); $noteds->context('notable'); my $grey = Graphics::Color::RGB->new( red => .36, green => .36, blue => .36, alpha => 1 ); my $red = Graphics::Color::RGB->new( red => 1, green => 0, blue => 0 ); my $blue = Graphics::Color::RGB->new( red => .2, green => .6, blue => 1 ); my $mark = Chart::Clicker::Data::Marker->new(value => 2, value2 => 4); $mark->brush->color( Graphics::Color::RGB->new(red => 0, green => 0, blue => 0, alpha => .15) ); $mark->inside_color( Graphics::Color::RGB->new(red => 0, green => 0, blue => 0, alpha => .15) ); $defctx->add_marker($mark); $cc->color_allocator->colors([ $grey, $red, $blue ]); $cc->plot->grid->visible(0); $cc->legend->visible(0); $cc->padding(2); $cc->border->width(0); $defctx->range_axis->hidden(1); $defctx->range_axis->fudge_amount(.2); $defctx->domain_axis->hidden(1); $defctx->domain_axis->fudge_amount(.1); $defctx->renderer->brush->width(1); $cc->write_output('foo.png')Chart000755000765000024 013024411235 15171 5ustar00gphatstaff000000000000Chart-Clicker-2.90/libClicker.pm100644000765000024 6302013024411235 17264 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chartpackage Chart::Clicker; $Chart::Clicker::VERSION = '2.90'; use Moose; extends 'Chart::Clicker::Container'; # ABSTRACT: Powerful, extensible charting. use Layout::Manager::Compass; use Graphics::Color::RGB; use Graphics::Primitive::Insets; use Graphics::Primitive::Border; #use Graphics::Primitive::Driver::Cairo; use Chart::Clicker::Context; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Series; use Chart::Clicker::Decoration::Legend; use Chart::Clicker::Decoration::MarkerOverlay; use Chart::Clicker::Decoration::Plot; use Chart::Clicker::Drawing::ColorAllocator; use Carp qw(croak); use Scalar::Util qw(refaddr); has '+background_color' => ( default => sub { Graphics::Color::RGB->new({ red => 1, green => 1, blue => 1, alpha => 1 }) } ); has '+border' => ( default => sub { my $b = Graphics::Primitive::Border->new; $b->color(Graphics::Color::RGB->new(red => 0, green => 0, blue => 0)); $b->width(1); return $b; } ); has 'color_allocator' => ( is => 'rw', isa => 'Chart::Clicker::Drawing::ColorAllocator', default => sub { Chart::Clicker::Drawing::ColorAllocator->new } ); has 'contexts' => ( traits => [ 'Hash' ], is => 'rw', isa => 'HashRef[Chart::Clicker::Context]', default => sub { { default => Chart::Clicker::Context->new(name => 'default') } }, handles => { 'set_context' => 'set', 'get_context' => 'get', 'context_names' => 'keys', 'context_count' => 'count', 'delete_context' => 'delete' } ); has '_data' => ( traits => [ 'Hash' ], is => 'rw', isa => 'HashRef[Str]', default => sub { {} } ); has 'datasets' => ( traits => [ 'Array' ], is => 'rw', isa => 'ArrayRef', default => sub { [] }, handles => { 'dataset_count' => 'count', 'add_to_datasets' => 'push', 'get_dataset' => 'get' } ); has 'driver' => ( is => 'rw', does => 'Graphics::Primitive::Driver', default => sub { my ($self) = @_; my $driver = $ENV{CHART_CLICKER_DEFAULT_DRIVER} || ($^O eq 'MSWin32'?"Graphics::Primitive::Driver::GD":"Graphics::Primitive::Driver::Cairo"); eval "require $driver;" or die "Cannot load driver $driver"; $driver->new( 'format' => $self->format, ) }, handles => { rendered_data => 'data', write => 'write' }, lazy => 1 ); has 'format' => ( is => 'rw', isa => 'Str', default => 'PNG' ); has 'plot_mode' => ( is => 'rw', isa => 'Str', default => 'slow' ); has 'grid_over' => ( is => 'rw', isa => 'Bool', default => 0 ); has '+height' => ( default => 300 ); has '+layout_manager' => ( default => sub { Layout::Manager::Compass->new } ); has 'legend' => ( is => 'rw', isa => 'Chart::Clicker::Decoration::Legend', default => sub { Chart::Clicker::Decoration::Legend->new( name => 'legend', ); } ); has 'legend_position' => ( is => 'rw', isa => 'Str', default => 's' ); has 'marker_overlay' => ( is => 'rw', isa => 'Chart::Clicker::Decoration::MarkerOverlay', lazy => 1, default => sub { Chart::Clicker::Decoration::MarkerOverlay->new } ); has 'over_decorations' => ( traits => [ 'Array' ], is => 'rw', isa => 'ArrayRef', default => sub { [] }, handles => { 'over_decoration_count' => 'count', 'add_to_over_decorations' => 'push', 'get_over_decoration' => 'get' } ); has '+padding' => ( default => sub { Graphics::Primitive::Insets->new( top => 3, bottom => 3, right => 3, left => 3 ) } ); has 'plot' => ( is => 'rw', isa => 'Chart::Clicker::Decoration::Plot', default => sub { Chart::Clicker::Decoration::Plot->new } ); has 'subgraphs' => ( is => 'rw', isa => 'ArrayRef', default => sub { [] }, predicate => 'has_subgraphs' ); has 'title' => ( is => 'rw', isa => 'Graphics::Primitive::TextBox', default => sub { Graphics::Primitive::TextBox->new( color => Graphics::Color::RGB->new( red => 0, green => 0, blue => 0), horizontal_alignment => 'center' ) } ); has 'title_position' => ( is => 'rw', isa => 'Str', default => 'n' ); has '+width' => ( default => 500 ); sub add_to_contexts { my ($self, $ctx) = @_; if(defined($self->get_context($ctx->name))) { croak("Context named '".$ctx->name."' already exists."); } $self->set_context($ctx->name, $ctx); } sub add_subgraph { my ($self, $graph) = @_; if (not ref $graph or not $graph->isa('Chart::Clicker')) { die('Sub-Graphs must be Chart::Clicker objects'); } push(@{$self->subgraphs}, $graph); } sub data { my ($self) = @_; print STDERR "WARNING: Calling 'data' to get image data is deprecated, please use rendered_data\n"; $self->rendered_data; } sub draw { my ($self) = @_; my $driver = $self->driver; $driver->prepare($self); $self->layout_manager->do_layout($self); $driver->finalize($self); $driver->draw($self); } sub get_datasets_for_context { my ($self, $name) = @_; my @dses; foreach my $ds (@{ $self->datasets }) { if($ds->context eq $name) { push(@dses, $ds); } } return \@dses; } sub add_data { my ($self, $name, $data) = @_; if(ref($data) eq 'ARRAY') { croak "Can't add arrayref data after adding hashrefs" if ref($self->_data->{$name}) eq 'HASH'; $self->_data->{$name} = [] unless defined($self->_data->{$name}); push(@{ $self->_data->{$name}}, @{ $data }); } elsif(ref($data) eq 'HASH') { if (!defined $self->_data->{$name}) { $self->_data->{$name} = {}; } elsif (ref($self->_data->{$name}) eq 'ARRAY') { my $old_data = $self->_data->{$name}; $self->_data->{$name} = {}; for my $i (0 .. @$old_data - 1) { $self->_data->{$name}{$i} = $old_data->[$i]; } } for my $key (keys %$data) { $self->_data->{$name}{$key} = $data->{$key}; } } else { croak "Can't add scalar data after adding hashrefs" if ref($self->_data->{$name}) eq 'HASH'; $self->_data->{$name} = [] unless defined($self->_data->{$name}); push(@{ $self->_data->{$name}}, $data); } } override('prepare', sub { my ($self, $driver) = @_; return if $self->prepared; if(scalar(keys(%{ $self->_data }))) { my $ds = Chart::Clicker::Data::DataSet->new; foreach my $name (keys(%{ $self->_data })) { my $vals = $self->_data->{$name}; if(ref($vals) eq 'ARRAY') { # This allows the user to add data as an array $ds->add_to_series( Chart::Clicker::Data::Series->new( name => $name, keys => [ 0..scalar(@{ $vals }) - 1 ], values => $vals ) ); } elsif(ref($vals) eq 'HASH') { # This allows the user to add data as a hashref my @keys = sort { $a <=> $b } keys %{ $vals }; my @values = (); foreach my $k (@keys) { push(@values, $vals->{$k}) } $ds->add_to_series( Chart::Clicker::Data::Series->new( name => $name, keys => \@keys, values => \@values ) ); } } $self->add_to_datasets($ds); } unless(scalar(@{ $self->components })) { $self->add_component($self->plot, 'c'); my $lp = lc($self->legend_position); if($self->legend->visible) { if(($lp =~ /^e/) || ($lp =~ /^w/)) { $self->legend->orientation('vertical'); } $self->add_component($self->legend, $self->legend_position); } # Add subgraphs if($self->has_subgraphs) { for my $subgraph (@{$self->subgraphs}) { $subgraph->border->width(0); $subgraph->padding(0); $self->add_component($subgraph, 'south'); } } if(defined($self->title->text)) { my $tp = $self->title_position; if(($tp =~ /^e/) || ($tp =~ /^w/)) { unless(defined($self->title->angle)) { $self->title->angle(-1.5707); } } $self->add_component($self->title, $tp); } } my $plot = $self->plot; $plot->clear_components; $plot->render_area->clear_components; # These two adds are here because the plot is too dependant on changes # in the axes and such to trust it across multiple prepares. Putting all # of this here made it easier to digest, although this has some codestink # to it... if($plot->grid->visible && !$self->grid_over) { $plot->render_area->add_component($plot->grid, 'c'); } $plot->render_area->add_component( $self->marker_overlay ); # Sentinels to control the side that the axes will be drawn on. my $dcount = 0; my $rcount = 0; # Hashes of axes & renderers we've already seen, as we don't want to add # them again... my %xaxes; my %yaxes; # A "seen" hash to prevent us from adding multiple renderers for the same # context. my %rends; my $dflt_ctx = $self->get_context('default'); die('Clicker must have a default context') unless defined($dflt_ctx); # Prepare the datasets and establish ranges for the axes. my $count = 0; foreach my $ds (@{ $self->datasets }) { unless($ds->count > 0) { die("Dataset $count is empty."); } $ds->prepare; my $ctx = $self->get_context($ds->context); unless(defined($ctx)) { $ctx = $dflt_ctx; } # Find our x axis and add it. my $xaxis = $ctx->domain_axis; unless(exists($xaxes{refaddr($xaxis)})) { $xaxis->range->combine($ds->domain); $xaxis->orientation('horizontal'); if($dcount % 2) { $xaxis->position('top'); $xaxis->border->bottom->width($xaxis->brush->width); } else { $xaxis->position('bottom'); $xaxis->border->top->width($xaxis->brush->width); } $xaxis->border->color($xaxis->color); $plot->add_component($xaxis, $xaxis->is_top ? 'n' : 's'); $xaxes{refaddr($xaxis)} = 1; $dcount++; } # Find our y axis and add it. my $yaxis = $ctx->range_axis; unless(exists($yaxes{refaddr($yaxis)})) { $yaxis->range->combine($ds->range); $yaxis->orientation('vertical'); if($rcount % 2) { $yaxis->position('right'); $yaxis->border->left->width($yaxis->brush->width); } else { $yaxis->position('left'); $yaxis->border->right->width($yaxis->brush->width); } $yaxis->border->color($yaxis->color); $plot->add_component($yaxis, $yaxis->is_left ? 'w' : 'e'); $rcount++; $yaxes{refaddr($yaxis)} = 1; } my $rend = $ctx->renderer; if($rend->additive) { $yaxis->range->upper($ds->largest_value_slice); } else { $yaxis->range->combine($ds->range); } # Only add this renderer to the chart if we haven't seen it already. unless(exists($rends{$ctx->name})) { $rend->context($ctx->name); $rend->clicker($self); $plot->render_area->add_component($rend, 'c'); $rends{$ctx->name} = $rend; } $count++; } if($plot->grid->visible && $self->grid_over) { $plot->grid->background_color->alpha(0); $plot->render_area->add_component($plot->grid, 'c'); } foreach my $c (@{ $self->components }) { $c->clicker($self) if $c->can('clicker'); } $plot->add_component($plot->render_area, 'c'); foreach my $oc (@{ $self->over_decorations }) { $plot->render_area->add_component($oc, 'c'); } super; }); sub set_renderer { my ($self, $renderer, $context) = @_; $context = 'default' unless defined($context); my $ctx = $self->get_context($context); die("Unknown context: '$context'") unless defined($ctx); $ctx->renderer($renderer); } sub write_output { my $self = shift; $self->draw; $self->write(@_); } __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker - Powerful, extensible charting. =head1 VERSION version 2.90 =head1 SYNOPSIS use Chart::Clicker; my $cc = Chart::Clicker->new; my @values = (42, 25, 86, 23, 2, 19, 103, 12, 54, 9); $cc->add_data('Sales', \@values); # alternately, you can add data one bit at a time... foreach my $v (@values) { $cc->add_data('Sales', $v); } # Or, if you want to specify the keys you can use a hashref my $data = { 12 => 123, 13 => 341, 14 => 1241 }; $cc->add_data('Sales', $data); $cc->write_output('foo.png'); =head1 DESCRIPTION Chart::Clicker aims to be a powerful, extensible charting package that creates really pretty output. Charts can be saved in png, svg, pdf and postscript format. Clicker leverages the power of Graphics::Primitive to create snazzy graphics without being tied to specific backend. You may want to begin with L. =head1 EXAMPLES For code examples see the examples repository on GitHub: L =head1 FEATURES =head2 Renderers Clicker supports the following renderers: =over 4 =item B =for HTML

Line Chart

=item B =for HTML

Stacked Line Chart

=item B =for HTML

Bar Chart

=item B =for HTML

Stacked Bar Chart

=item B =for HTML

Area Chart

=item B =for HTML

Stacked Area Chart

=item B =for HTML

Bubble Chart

=item B =for HTML

Candlestick Chart

=item B =for HTML

Point Chart

=item B =for HTML

Pie Chart

=item B =for HTML

Polar Area Chart

=back =head1 ADDING DATA The synopsis shows the simple way to add data. my @values = (42, 25, 86, 23, 2, 19, 103, 12, 54, 9); foreach my $v (@values) { $cc->add_data('Sales', $v); } This is a convenience method provided to make simple cases much simpler. Adding multiple Series to a chart is as easy as changing the name argument of C. Each unique first argument will result in a separate series. See the docs for C to learn more. If you'd like to use the more advanced features of Clicker you'll need to shake off this simple method and build Series & DataSets explicitly. use Chart::Clicker::Data::Series; use Chart::Clicker::Data::DataSet; ... my $series = Chart::Clicker::Data::Series->new( keys => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ], values => [ 42, 25, 86, 23, 2, 19, 103, 12, 54, 9 ], ); my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series ]); $cc->add_to_datasets($ds); This used to be the only way to add data, but repeated requests to make the common case easier resulted in the inclusion of C. =head1 CONTEXTS The normal use case for a chart is a couple of datasets on the same axes. Sometimes you want to chart one or more datasets on different axes. A common need for this is when you are comparing two datasets of vastly different scale such as the number of employees in an office (1-10) to monthly revenues (10s of thousands). On a normal chart the number of employees would show up as a flat line at the bottom of the chart. To correct this, Clicker has contexts. A context is a pair of axes, a renderer and a name. The name is the 'key' by which you will refer to the context. my $context = Chart::Clicker::Context->new( name => 'sales' ); $clicker->add_to_contexts($context); $dataset->context('sales'); $clicker->add_to_datasets($dataset); New contexts provide a fresh domain and range axis and default to a Line renderer. B: Clicker expects that the default context (identified by the string "default") will always be present. It is from this context that some of Clicker's internals draw their values. You should use the default context unless you need more than one, in which case you should use "default" as the base context. =head1 FORMATS & OUTPUT Clicker supports PNG, SVG, PDF and PostScript output. To change your output type, specificy it when you create your Clicker object: my $cc = Chart::Clicker->new(format => 'pdf', ...); # ... $cc->write_output('chart.pdf'); If you are looking to get a scalar of the output for use with HTTP or similar things, you can use: # ... make your chart $cc->draw; my $image_data = $cc->rendered_data; If you happen to be using Catalyst then take a look at L. =head1 ATTRIBUTES =head2 background_color Set/Get the background L. Defaults to white. =head2 border Set/Get the L. =head2 color_allocator Set/Get the L for this chart. =head2 contexts Set/Get the L for this chart. =head2 datasets Get/Set the datasets for this chart. =head2 driver Set/Get the L used to render this Chart. Defaults to L. =head2 format Get the format for this Chart. Required in the constructor. Must be on of Png, Pdf, Ps or Svg. =head2 plot_mode Fast or slow plot mode. When in fast mode, data elements that are deemed to be superfluous or invisible will not be drawn. Default is 'slow' =head2 grid_over Flag controlling if the grid is rendered B the data. Defaults to 0. You probably want to set the grid's background color to an alpha of 0 if you enable this flag. =head2 height Set/Get the height. Defaults to 300. =head2 layout_manager Set/Get the layout manager. Defaults to L. =head2 legend Set/Get the L that will be used with this chart. =head2 legend_position The position the legend will be added. Should be one of north, south, east, west or center as required by L. =head2 marker_overlay Set/Get the L object that will be used if this chart has markers. This is lazily constructed to save time. =head2 over_decorations Set/Get an arrayref of "over decorations", or things that are drawn OVER the chart. This is an advanced feature. See C in the examples. =head2 padding Set/Get the L. Defaults to 3px on all sides. =head2 plot Set/Get the L on which things are drawn. =head2 subgraphs You can add "child" graphs to this one via C. These must be Chart::Clicker objects and they will be added to the bottom of the existing chart. This is a rather esoteric feature. =head2 title Set/Get the title component for this chart. This is a L, not a string. To set the title of a chart you should access the TextBox's C method. $cc->title->text('A Title!'); $cc->title->font->size(20); # etc, etc If the title has text then it is added to the chart in the position specified by C. You should consult the documentation for L for things like padding and text rotation. If you are adding it to the top and want some padding between it and the plot, you can: $cc->title->padding->bottom(5); =head2 title_position The position the title will be added. Should be one of north, south, east, west or center as required by L. Note that if no angle is set for the title then it will be changed to -1.5707 if the title position is east or west. =head2 width Set/Get the width. Defaults to 500. =head1 METHODS =head2 context_count Get a count of contexts. =head2 context_names Get a list of context names. =head2 delete_context ($name) Remove the context with the specified name. =head2 get_context ($name) Get the context with the specified name =head2 set_context ($name, $context) Set a context of the specified name. =head2 add_to_datasets Add the specified dataset (or arrayref of datasets) to the chart. =head2 dataset_count Get a count of datasets. =head2 get_dataset ($index) Get the dataset at the specified index. =head2 rendered_data Returns the data for this chart as a scalar. Suitable for 'streaming' to a client. =head2 add_to_over_decorations Add an over decoration to the list. =head2 get_over_decoration ($index) Get the over decoration at the specified index. =head2 over_decoration_count Get a count of over decorations. =head2 add_to_contexts Add the specified context to the chart. =head2 add_subgraph Add a subgraph to this chart. =head2 draw Draw this chart. =head2 get_datasets_for_context Returns an arrayref containing all datasets for the given context. Used by renderers to get a list of datasets to chart. =head2 add_data ($name, $data) Convenience method for adding data to the chart. Can be called one of three ways. =over 4 =item B Passing a name and a scalar will append the scalar data to that series' data. $cc->add_data('Sales', 1234); $cc->add_data('Sales', 1235); This will result in a Series named 'Sales' with two values. =item B Passing a name and an arrayref works much the same as the scalar method discussed above, but appends the supplied arrayref to the existing one. It may be mixed with the scalar method. $cc->add_data('Sales', \@some_sales); $cc->add_data('Sales', \@some_more_sales); # This works still! $cc->add_data('Sales', 1234); =item B This allows you to pass both keys and values in all at once. $cc->add_data('Sales', { 2009 => 1234, 2010 => 1235 }); # appends to last call $cc->add_data('Sales', { 2011 => 1234, 2012 => 1235 }); You may call the hashref version after the scalar or arrayref versions, but you may not add a scalar or arrayref after adding a hashref (as it's not clear what indices should be used for the new data). =back =head2 set_renderer ($renderer_object, [ $context ]); Sets the renderer on the specified context. If no context is provided then 'default' is assumed. =head2 write This method is passed through to the underlying driver. It is only necessary that you call this if you manually called C beforehand. You likely want to use C. =head2 write_output ($path) Write the chart output to the specified location. Output is written in the format provided to the constructor (which defaults to Png). Internally calls C for you. If you use this method, do not call C first! $c->write_output('/path/to/the.png'); =head2 inside_width Get the width available in this container after taking away space for insets and borders. =head2 inside_height Get the height available in this container after taking away space for insets and borders. =head1 ISSUES WITH CENTOS I've had numerous reports of problems with Chart::Clicker when using CentOS. This problem has usually be solved by updating the version of cairo. I've had reports that upgrading to at least cairo-1.8.8-3 makes thinks work properly. I hesitate to provide any other data with this because it may get out of date fast. If you have trouble feel free to drop me an email and I'll tell you what I know. =head1 CONTRIBUTORS Many thanks to the individuals who have contributed various bits: Ash Berlin Brian Cassidy Guillermo Roditi Torsten Schoenfeld Yuval Kogman =head1 SOURCE Chart::Clicker is on github: http://github.com/gphat/chart-clicker/tree/master =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut decoration-glass.t100644000765000024 27713024411235 17376 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; BEGIN { use_ok('Chart::Clicker::Decoration::Glass'); } my $dec = Chart::Clicker::Decoration::Glass->new; isa_ok($dec, 'Chart::Clicker::Decoration::Glass'); done_testing;annotation.pl100644000765000024 635513024411235 17675 0ustar00gphatstaff000000000000Chart-Clicker-2.90/example#!/usr/bin/perl use strict; use Chart::Clicker; use Chart::Clicker::Context; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Marker; use Chart::Clicker::Data::Series; use Chart::Clicker::Decoration::Annotation; use Geometry::Primitive::Rectangle; use Geometry::Primitive::Point; use Graphics::Primitive::Border; use Graphics::Primitive::TextBox; use Graphics::Primitive::Insets; use Graphics::Color::RGB; my $cc = Chart::Clicker->new(width => 500, height => 400, format => 'png'); my @hours = qw( 1 2 3 4 5 6 7 8 9 10 11 12 ); my @bw1 = qw( 5.8 5.0 4.9 4.8 4.5 4.25 3.5 2.9 2.5 1.8 .9 .8 ); my @bw2 = qw( .7 1.1 1.7 2.5 3.0 4.5 5.0 4.9 4.7 4.8 4.2 4.4 ); my @bw3 = qw( .3 1.4 1.2 1.5 4.0 3.5 2.0 1.9 2.7 4.2 3.2 1.1 ); my $series1 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw1, ); my $series2 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw2, ); # We'll create a dataset with our first two series in it... my $ds = Chart::Clicker::Data::DataSet->new( series => [ $series1, $series2 ] ); # We'll put the third into it's own dataset so we can put it in a new context my $series3 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw3, ); my $ds1 = Chart::Clicker::Data::DataSet->new( series => [ $series3 ] ); # Create a new context my $other_context = Chart::Clicker::Context->new( name => 'other' ); # Set it's labels... $other_context->range_axis->label('Solor'); $other_context->domain_axis->label('Amet'); # Instruct the ds1 dataset to use the 'other' context. DataSets default to # the 'default' context. $ds1->context('other'); $cc->add_to_contexts($other_context); # Pretty stuff $cc->border->width(0); # Add the datasets to the chart $cc->add_to_datasets($ds); $cc->add_to_datasets($ds1); # Set some labels on the default context my $defctx = $cc->get_context('default'); $defctx->range_axis->label('Lorem'); $defctx->domain_axis->label('Ipsum'); $defctx->domain_axis->tick_label_angle(0.785398163); $defctx->renderer->brush->width(1); $cc->add_to_over_decorations( Chart::Clicker::Decoration::Annotation->new( key => $hours[2], value => $bw1[2], text => sprintf("value: %s", $bw1[2]), context => 'default', ) ); $cc->add_to_over_decorations( Chart::Clicker::Decoration::Annotation->new( key => $hours[4], value => $bw2[4], text => sprintf("(%s, %s)", $hours[4], $bw2[4]), context => 'default', padding => Graphics::Primitive::Insets->new( top => 5, bottom => 5, left => 5, right => 5, ), border => Graphics::Primitive::Border->new( color => Graphics::Color::RGB->from_hex_string('#000000'), width => 2, ), ) ); $cc->add_to_over_decorations( Chart::Clicker::Decoration::Annotation->new( key => $hours[9], value => $bw3[9], text => sprintf("(%s, %s)", $hours[9], $bw3[9]), context => 'other', background_color => Graphics::Color::RGB->from_hex_string('#000000'), color => Graphics::Color::RGB->from_hex_string('#ffffff'), offset => Geometry::Primitive::Point->new( x => 10, y => 0 ), ) ); $cc->write_output('foo.png'); share-axes.pl100644000765000024 431513024411235 17555 0ustar00gphatstaff000000000000Chart-Clicker-2.90/example#!/usr/bin/perl use strict; use Chart::Clicker; use Chart::Clicker::Context; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Marker; use Chart::Clicker::Data::Series; use Chart::Clicker::Renderer::Bar; use Geometry::Primitive::Rectangle; use Graphics::Color::RGB; my $cc = Chart::Clicker->new(width => 500, height => 400, format => 'png'); my @hours = qw( 1 2 3 4 5 6 7 8 9 10 11 12 ); my @bw1 = qw( 5.8 5.0 4.9 4.8 4.5 4.25 3.5 2.9 2.5 1.8 .9 .8 ); my @bw2 = qw( .7 1.1 1.7 2.5 3.0 4.5 5.0 4.9 4.7 4.8 4.2 4.4 ); my @bw3 = qw( .3 1.4 1.2 1.5 4.0 3.5 2.0 1.9 2.7 4.2 3.2 1.1 ); my $series1 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw1, ); my $series2 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw2, ); # We'll create a dataset with our first two series in it... my $ds = Chart::Clicker::Data::DataSet->new( series => [ $series1, $series2 ] ); # We'll put the third into it's own dataset so we can put it in a new context my $series3 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw3, ); my $ds1 = Chart::Clicker::Data::DataSet->new( series => [ $series3 ] ); # Create a new context # my $other_context = Chart::Clicker::Context->new( # name => 'other' # ); my $defctx = $cc->get_context('default'); # This line does the magic. It sets the other_context's axes to the same # ones used by the default. This gives us all the features of multiple # contexts, but without separate axes. # $other_context->share_axes_with($defctx); # Instruct the ds1 dataset to use the 'other' context. DataSets default to # the 'default' context. # $ds1->context('other'); # $cc->add_to_contexts($other_context); # Pretty stuff $cc->border->width(0); # Add the datasets to the chart $cc->add_to_datasets($ds); $cc->add_to_datasets($ds1); # Set some labels on the default context $defctx->range_axis->label('Lorem'); $defctx->domain_axis->label('Ipsum'); $defctx->domain_axis->tick_label_angle(0.785398163); # Here's the magic: You can set a renderer for any context. In this case # we'll change the default to a Bar. Voila! $defctx->renderer(Chart::Clicker::Renderer::Bar->new); $cc->write_output('foo.png'); skip_range.pl100644000765000024 224613024411235 17640 0ustar00gphatstaff000000000000Chart-Clicker-2.90/example#!/usr/bin/perl use strict; use Chart::Clicker; use Chart::Clicker::Renderer::Line; use Chart::Clicker::Data::Marker; my $cc = Chart::Clicker->new(width => 500, height => 250); my @bw1 = qw( 5 5 4 4 4 4 3 2 2 1 99 100 ); my @bw2 = qw( .7 1.1 1.7 2.5 3.0 4.5 15.0 4.9 4.7 4.8 4.2 4.4 ); my @bw3 = qw( .3 1.4 1.2 1.5 4.0 3.5 2.0 1.9 2.7 4.2 3.2 1.1 ); foreach my $d (@bw1) { $cc->add_data('Series 0', $d); } foreach my $d (@bw2) { $cc->add_data('Series 1', $d); } foreach my $d (@bw3) { $cc->add_data('Series 2', $d); } my $def = $cc->get_context('default'); my $ren = Chart::Clicker::Renderer::Line->new; $cc->get_context('default')->renderer($ren); $def->range_axis->skip_range(Chart::Clicker::Data::Range->new(lower => 20, upper => 70)); $def->domain_axis->tick_values([qw(10 20 30 40 50 60 70 80 90 100)]); $def->range_axis->format('%d'); $def->domain_axis->tick_values([qw(2 4 6 8 10)]); $def->domain_axis->format('%d'); my $skip_marker = Chart::Clicker::Data::Marker->new(value => 19.9, value2 => 70.1); $skip_marker->color( Graphics::Color::RGB->new(red => 0, green => 0, blue => 0) ); $def->add_marker($skip_marker); $cc->write_output('foo.png'); stackedbar.pl100644000765000024 257013024411235 17621 0ustar00gphatstaff000000000000Chart-Clicker-2.90/example#!/usr/bin/perl use strict; use Chart::Clicker; use Chart::Clicker::Context; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Marker; use Chart::Clicker::Data::Series; use Chart::Clicker::Renderer::StackedBar; use Geometry::Primitive::Rectangle; use Graphics::Color::RGB; my $cc = Chart::Clicker->new(width => 500, height => 250); my @hours = qw( 1 2 3 4 5 6 7 8 9 10 11 12 ); my @bw1 = qw( 5.8 5.0 4.9 4.8 4.5 4.25 3.5 2.9 2.5 1.8 .9 .8 ); my @bw2 = qw( .7 1.1 1.7 2.5 3.0 4.5 5.0 4.9 4.7 4.8 4.2 4.4 ); my @bw3 = qw( .3 1.4 1.2 1.5 4.0 3.5 2.0 1.9 2.7 4.2 3.2 1.1 ); my $series1 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw1, ); my $series2 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw2, ); my $series3 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw3, ); my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series1, $series2, $series3 ]); $cc->add_to_datasets($ds); my $def = $cc->get_context('default'); my $area = Chart::Clicker::Renderer::StackedBar->new(opacity => .6); $area->brush->width(3); $def->renderer($area); $def->range_axis->tick_values([qw(1 5 9)]); $def->range_axis->format('%d'); $def->domain_axis->tick_values([qw(2 4 6 8 10)]); $def->domain_axis->format('%d'); $def->domain_axis->fudge_amount(.05); $cc->write_output('foo.png'); decoration-legend.t100644000765000024 13313024411235 17512 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; BEGIN { use_ok('Chart::Clicker::Decoration::Legend'); } done_testing;author-pod-syntax.t100644000765000024 45413024411235 17543 0ustar00gphatstaff000000000000Chart-Clicker-2.90/t#!perl BEGIN { unless ($ENV{AUTHOR_TESTING}) { print qq{1..0 # SKIP these tests are for testing by the author\n}; exit } } # This file was automatically generated by Dist::Zilla::Plugin::PodSyntaxTests. use strict; use warnings; use Test::More; use Test::Pod 1.41; all_pod_files_ok(); candlestick.pl100644000765000024 315013024411235 17775 0ustar00gphatstaff000000000000Chart-Clicker-2.90/example#!/usr/bin/perl use strict; use Chart::Clicker; use Chart::Clicker::Context; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Marker; use Chart::Clicker::Data::Series::HighLow; use Chart::Clicker::Renderer::CandleStick; use Geometry::Primitive::Rectangle; use Graphics::Color::RGB; my $cc = Chart::Clicker->new(width => 500, height => 250); my $series1 = Chart::Clicker::Data::Series::HighLow->new( keys => [qw(1 2 3 4 5 6 7 8 9 10)], highs => [qw(5 9 7 8 8 9 5 4 7 9)], opens => [qw(3 5 4 6 4 8 4 1 1 6)], values => [qw(5 4 6 4 8 4 1 1 6 9)], lows => [qw(1 4 2 3 1 4 1 1 1 4)], ); my $series2 = Chart::Clicker::Data::Series::HighLow->new( keys => [qw(1 2 3 4 5 6 7 8 9 10)], highs => [qw(9 7 9 7 9 8 6 6 8 9)], opens => [qw(3 6 4 6 4 8 4 1 1 6)], values => [qw(6 4 6 4 8 4 1 1 6 9)], lows => [qw(3 4 2 3 3 4 1 1 1 4)], ); my $series3 = Chart::Clicker::Data::Series::HighLow->new( keys => [qw(1 2 3 4 5 6 7 8 9 10)], highs => [qw(8 8 5 4 3 8 9 9 6 4)], opens => [qw(3 7 3 2 1 2 7 9 5 2)], values => [qw(7 3 2 1 2 7 9 5 2 3)], lows => [qw(1 2 2 0 1 4 1 1 1 4)], ); my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series1, $series2, $series3 ]); $cc->add_to_datasets($ds); my $def = $cc->get_context('default'); my $ren = Chart::Clicker::Renderer::CandleStick->new; $def->renderer($ren); $def->range_axis->tick_values([qw(1 4 7)]); $def->range_axis->format('%d'); $def->domain_axis->fudge_amount(.05); $def->domain_axis->tick_values([qw(2 4 6 8 10)]); $def->domain_axis->format('%d'); $cc->write_output('foo.png'); stackedarea.pl100644000765000024 252413024411235 17764 0ustar00gphatstaff000000000000Chart-Clicker-2.90/example#!/usr/bin/perl use strict; use Chart::Clicker; use Chart::Clicker::Context; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Marker; use Chart::Clicker::Data::Series; use Chart::Clicker::Renderer::StackedArea; use Geometry::Primitive::Rectangle; use Graphics::Color::RGB; my $cc = Chart::Clicker->new(width => 500, height => 250); my @hours = qw( 1 2 3 4 5 6 7 8 9 10 11 12 ); my @bw1 = qw( 5.8 5.0 4.9 4.8 4.5 4.25 3.5 2.9 2.5 1.8 .9 .8 ); my @bw2 = qw( .7 1.1 1.7 2.5 3.0 4.5 5.0 4.9 4.7 4.8 4.2 4.4 ); my @bw3 = qw( .3 1.4 1.2 1.5 4.0 3.5 2.0 1.9 2.7 4.2 3.2 1.1 ); my $series1 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw1, ); my $series2 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw2, ); my $series3 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw3, ); my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series1, $series2, $series3 ]); $cc->add_to_datasets($ds); my $def = $cc->get_context('default'); my $area = Chart::Clicker::Renderer::StackedArea->new(opacity => .6); $area->brush->width(3); $def->renderer($area); $def->range_axis->tick_values([qw(1 5 9)]); $def->range_axis->format('%d'); $def->domain_axis->tick_values([qw(2 4 6 8 10)]); $def->domain_axis->format('%d'); $cc->write_output('foo.png'); overaxis-bar.pl100644000765000024 363213024411235 20120 0ustar00gphatstaff000000000000Chart-Clicker-2.90/example#!/usr/bin/perl use strict; use Chart::Clicker; use Chart::Clicker::Context; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Marker; use Chart::Clicker::Data::Series; use Chart::Clicker::Decoration::OverAxis; use Chart::Clicker::Renderer::Bar; use Geometry::Primitive::Rectangle; use Graphics::Color::RGB; my $cc = Chart::Clicker->new(width => 300, height => 150, format => 'png'); my @years = qw( 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 ); my @top = qw( 8 7 2 5 9 5 7 3 5 7 9 ); my @bottom = qw( -4 -2 -7 -9 -5 -7 -5 -5 -3 -9 -7 ); my $series = Chart::Clicker::Data::Series->new( keys => \@years, values => \@top, ); my $series2 = Chart::Clicker::Data::Series->new( keys => \@years, values => \@bottom, ); my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series, $series2 ]); $cc->add_to_datasets($ds); my $defctx = $cc->get_context('default'); my $grey = Graphics::Color::RGB->new( red => .36, green => .36, blue => .36, alpha => 1 ); my $red = Graphics::Color::RGB->new( red => .71, green => .71, blue => .71, alpha => 1 ); $cc->color_allocator->colors([ $grey, $red ]); $cc->border->width(0); $cc->background_color( Graphics::Color::RGB->new(red => .95, green => .94, blue => .92) ); $cc->plot->grid->visible(0); $cc->legend->visible(0); $defctx->renderer(Chart::Clicker::Renderer::Bar->new); $defctx->range_axis->baseline(0); $defctx->range_axis->hidden(1); $defctx->domain_axis->hidden(1); $defctx->domain_axis->fudge_amount(.1); $defctx->renderer->brush->width(1); $defctx->domain_axis->tick_values([qw(2000 2002 2004 2006 2008)]); $cc->add_to_over_decorations( Chart::Clicker::Decoration::OverAxis->new( context => 'default', border_color => Graphics::Color::RGB->new( red => .95, green => .94, blue => .92 ) ) ); $cc->write_output('foo.png');multiple-axes.pl100644000765000024 363313024411235 20310 0ustar00gphatstaff000000000000Chart-Clicker-2.90/example#!/usr/bin/perl use strict; use Chart::Clicker; use Chart::Clicker::Context; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Marker; use Chart::Clicker::Data::Series; use Geometry::Primitive::Rectangle; use Graphics::Color::RGB; my $cc = Chart::Clicker->new(width => 500, height => 400, format => 'png'); my @hours = qw( 1 2 3 4 5 6 7 8 9 10 11 12 ); my @bw1 = qw( 5.8 5.0 4.9 4.8 4.5 4.25 3.5 2.9 2.5 1.8 .9 .8 ); my @bw2 = qw( .7 1.1 1.7 2.5 3.0 4.5 5.0 4.9 4.7 4.8 4.2 4.4 ); my @bw3 = qw( .3 1.4 1.2 1.5 4.0 3.5 2.0 1.9 2.7 4.2 3.2 1.1 ); my $series1 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw1, ); my $series2 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw2, ); # We'll create a dataset with our first two series in it... my $ds = Chart::Clicker::Data::DataSet->new( series => [ $series1, $series2 ] ); # We'll put the third into it's own dataset so we can put it in a new context my $series3 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw3, ); my $ds1 = Chart::Clicker::Data::DataSet->new( series => [ $series3 ] ); # Create a new context my $other_context = Chart::Clicker::Context->new( name => 'other' ); # Set it's labels... $other_context->range_axis->label('Solor'); $other_context->domain_axis->label('Amet'); # Instruct the ds1 dataset to use the 'other' context. DataSets default to # the 'default' context. $ds1->context('other'); $cc->add_to_contexts($other_context); # Pretty stuff $cc->border->width(0); # Add the datasets to the chart $cc->add_to_datasets($ds); $cc->add_to_datasets($ds1); # Set some labels on the default context my $defctx = $cc->get_context('default'); $defctx->range_axis->label('Lorem'); $defctx->domain_axis->label('Ipsum'); $defctx->domain_axis->tick_label_angle(0.785398163); $defctx->renderer->brush->width(1); $cc->write_output('foo.png'); tabularlegend.pl100644000765000024 220413024411235 20321 0ustar00gphatstaff000000000000Chart-Clicker-2.90/example#!/usr/bin/perl use strict; use Chart::Clicker; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Series; use Chart::Clicker::Decoration::Legend::Tabular; use List::Util qw(max min); use Statistics::Basic qw(median mean); my $cc = Chart::Clicker->new(width => 500, height => 400); my $series1 = Chart::Clicker::Data::Series->new( keys => [qw(1 2 3 4 5 6 7 8 9 10 11 12)], values => [qw(5.8 5.0 4.9 4.8 4.5 4.25 3.5 2.9 2.5 1.8 .9 .8)] ); my $series2 = Chart::Clicker::Data::Series->new( keys => [qw(1 2 3 4 5 6 7 8 9 10 11 12)], values => [qw(8.5 0.5 9.4 8.4 5.4 2.5 5.3 9.2 5.2 8.1 1.9 1.8)] ); my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series1, $series2 ]); $cc->legend(Chart::Clicker::Decoration::Legend::Tabular->new( header => [ qw(Name Min Max Median Mean) ], data => [ [ min(@{ $series1->values }), max(@{ $series1->values }), median($series1->values)."", mean($series1->values)."" ], [ min(@{ $series2->values }), max(@{ $series2->values }), median($series2->values)."", mean($series2->values)."" ] ] )); $cc->add_to_datasets($ds); $cc->write_output('foo.png'); inc000755000765000024 013024411235 14133 5ustar00gphatstaff000000000000Chart-Clicker-2.90ChClDistMakeMaker.pm100644000765000024 72313024411235 20026 0ustar00gphatstaff000000000000Chart-Clicker-2.90/incpackage inc::ChClDistMakeMaker; use Moose; extends 'Dist::Zilla::Plugin::MakeMaker::Awesome'; around '_build_WriteMakefile_dump' => sub { my $orig = shift; my $self = shift; my $str =$self->$orig(); die "Graphics::Primitive::Driver::Cairo not found in Makefile.PL" unless $str =~ s/"Graphics::Primitive::Driver::Cairo"/(\$^O eq 'MSWin32'?"Graphics::Primitive::Driver::GD":"Graphics::Primitive::Driver::Cairo")/g; return $str; }; 1; renderer-candlestick.t100644000765000024 37613024411235 20230 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; BEGIN { use_ok('Chart::Clicker::Renderer::CandleStick'); } my $rndr = Chart::Clicker::Renderer::CandleStick->new; ok(defined($rndr), 'new CandleStick Renderer'); isa_ok($rndr, 'Chart::Clicker::Renderer::CandleStick'); done_testing;line-and-shape.pl100644000765000024 327113024411235 20302 0ustar00gphatstaff000000000000Chart-Clicker-2.90/example#!/usr/bin/perl use strict; use Chart::Clicker; use Chart::Clicker::Context; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Marker; use Chart::Clicker::Data::Series; use Chart::Clicker::Renderer::Line; use Geometry::Primitive::Circle; use Geometry::Primitive::Rectangle; use Graphics::Color::RGB; my $cc = Chart::Clicker->new(width => 500, height => 250, format => 'png'); my @hours = qw( 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 ); my @bw = qw( 5.8 5.0 4.9 4.8 4.5 4.25 3.5 2.9 2.5 1.8 .9 .8 .7 1.1 1.7 2.5 3.0 4.5 5.0 4.9 4.7 4.8 4.2 4.4 ); my $series = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw, ); my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series ]); $cc->add_to_datasets($ds); my $defctx = $cc->get_context('default'); my $grey = Graphics::Color::RGB->new( red => .36, green => .36, blue => .36, alpha => 1 ); $cc->background_color( # Graphics::Color::RGB->new(red => .95, green => .94, blue => .92) ); $cc->color_allocator->colors([ $grey ]); # $defctx->range_axis->label('FOOO'); $defctx->range_axis->fudge_amount(.2); #$defctx->domain_axis->hidden(1); # $defctx->domain_axis->label("WEEE"); $defctx->domain_axis->fudge_amount(.1); $defctx->domain_axis->tick_label_angle(0.785398163); $defctx->renderer(Chart::Clicker::Renderer::Line->new); $defctx->renderer->shape( Geometry::Primitive::Circle->new({ radius => 5, }) ); $defctx->renderer->shape_brush( Graphics::Primitive::Brush->new( width => 2, color => Graphics::Color::RGB->new(red => .9, green => .9, blue => .9, alpha => 1) ) ); $defctx->renderer->brush->width(2); $cc->write_output('foo.png'); Clicker000755000765000024 013024411235 16545 5ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/ChartAxis.pm100644000765000024 5051413024411235 20174 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clickerpackage Chart::Clicker::Axis; $Chart::Clicker::Axis::VERSION = '2.90'; use Moose; use Moose::Util; extends 'Chart::Clicker::Container'; with 'Chart::Clicker::Positioned'; # ABSTRACT: An X or Y Axis use Class::Load; use Chart::Clicker::Data::Range; use English qw(-no_match_vars); use Graphics::Color::RGB; use Graphics::Primitive::Font; use Layout::Manager::Absolute; use Math::Trig ':pi'; has 'tick_label_angle' => ( is => 'rw', isa => 'Num' ); has 'tick_division_type' => ( is => 'rw', isa => 'Str', default => 'Exact' ); # The above tick division type is loaded on the first call to divvy() has '_tick_division_type_loaded' => ( is => 'ro', isa => 'Bool', lazy_build => 1 ); has 'baseline' => ( is => 'rw', isa => 'Num', ); has 'brush' => ( is => 'rw', isa => 'Graphics::Primitive::Brush', default => sub { Graphics::Primitive::Brush->new( color => Graphics::Color::RGB->new( red => 1, green => 0, blue => 1, alpha => 1 ), width => 1 ) } ); has '+color' => ( default => sub { Graphics::Color::RGB->new({ red => 0, green => 0, blue => 0, alpha => 1 }) } ); has 'format' => ( is => 'rw', isa => 'Str|CodeRef', default => '%s' ); has 'fudge_amount' => ( is => 'rw', isa => 'Num', default => 0 ); has 'hidden' => ( is => 'rw', isa => 'Bool', default => 0 ); has 'label' => ( is => 'rw', isa => 'Str' ); has 'label_color' => ( is => 'rw', isa => 'Graphics::Color', default => sub { Graphics::Color::RGB->new({ red => 0, green => 0, blue => 0, alpha => 1 }) } ); has 'label_font' => ( is => 'rw', isa => 'Graphics::Primitive::Font', default => sub { Graphics::Primitive::Font->new } ); has '+layout_manager' => ( default => sub { Layout::Manager::Absolute->new }); has '+orientation' => ( required => 1 ); has '+position' => ( required => 1 ); has 'range' => ( is => 'rw', isa => 'Chart::Clicker::Data::Range', default => sub { Chart::Clicker::Data::Range->new } ); has 'show_ticks' => ( is => 'rw', isa => 'Bool', default => 1 ); has 'staggered' => ( is => 'rw', isa => 'Bool', default => 0 ); has 'skip_range' => ( is => 'rw', isa => 'Chart::Clicker::Data::Range', predicate => 'has_skip_range' ); has 'tick_font' => ( is => 'rw', isa => 'Graphics::Primitive::Font', default => sub { Graphics::Primitive::Font->new } ); has 'tick_label_color' => ( is => 'rw', isa => 'Graphics::Color', default => sub { Graphics::Color::RGB->new({ red => 0, green => 0, blue => 0, alpha => 1 }) } ); has 'tick_labels' => ( is => 'rw', isa => 'ArrayRef', ); has 'tick_values' => ( traits => [ 'Array' ], is => 'rw', isa => 'ArrayRef', default => sub { [] }, handles => { 'add_to_tick_values' => 'push', 'clear_tick_values' => 'clear', 'tick_value_count' => 'count' } ); has 'ticks' => ( is => 'rw', isa => 'Int', default => 6 ); sub BUILD { my ($self) = @_; $self->padding(3); } sub _build__tick_division_type_loaded { my $self = shift; # User modules are prefixed with a +. my $divisionTypeModule; my $extensionOf = 'Chart::Clicker::Axis::DivisionType'; if ( $self->tick_division_type =~ m/^\+(.*)$/xmisg ) { $divisionTypeModule = $1; } else { $divisionTypeModule = sprintf( '%s::%s', $extensionOf, $self->tick_division_type ); } # Try to load the DivisionType module. An error is thrown when the class is # not available or cannot be loaded Class::Load::load_class($divisionTypeModule); # Apply the newly loaded role to this class. Moose::Util::apply_all_roles( $self => $divisionTypeModule ); if ( not $self->does($extensionOf) ) { die("Module $divisionTypeModule does not extend $extensionOf"); } return 1; } override('prepare', sub { my ($self, $driver) = @_; $self->clear_components; # The BUILD method above establishes a 5px padding at instantiation time. # That saves us setting it elsewhere, but if 'hidden' feature is used, # then we have to unset the padding. hidden (as explained below) is # basically a hack as far as G:P is concerned to render an empty Axis. # We want it to render because we need it prepared for other elements # of the chart to work. if($self->hidden) { $self->padding(0); # Hide the border too, jic $self->border->width(0); } super; if($self->range->span == 0) { die('This axis has a span of 0, that\'s fatal!'); } if(defined($self->baseline)) { if($self->range->lower > $self->baseline) { $self->range->lower($self->baseline); } } else { $self->baseline($self->range->lower); } if($self->fudge_amount) { my $span = $self->range->span; my $lower = $self->range->lower; $self->range->lower($lower - abs($span * $self->fudge_amount)); my $upper = $self->range->upper; $self->range->upper($upper + ($span * $self->fudge_amount)); } if($self->show_ticks && !scalar(@{ $self->tick_values })) { $self->tick_values($self->divvy); } # Return now without setting a min height or width and allow # Layout::Manager to to set it for us, this is how we 'hide' return if $self->hidden; my $tfont = $self->tick_font; my $bheight = 0; my $bwidth = 0; # Determine all this once... much faster. my $i = 0; foreach my $val (@{ $self->tick_values }) { if($self->has_skip_range && $self->skip_range->contains($val)) { # If the label falls in inside the skip range, it's not to be # used at all. next; } my $label = $val; if(defined($self->tick_labels)) { if (defined $self->tick_labels->[$i]) { $label = $self->tick_labels->[$i]; } else { $label = ""; } } else { $label = $self->format_value($val); } my $tlabel = Graphics::Primitive::TextBox->new( text => $label, font => $tfont, color => $self->tick_label_color, ); if($self->tick_label_angle) { $tlabel->angle($self->tick_label_angle); } my $lay = $driver->get_textbox_layout($tlabel); $tlabel->prepare($driver); $tlabel->width($lay->width); $tlabel->height($lay->height); $bwidth = $tlabel->width if($tlabel->width > $bwidth); $bheight = $tlabel->height if($tlabel->height > $bheight); $self->add_component($tlabel); $i++; } my $big = $bheight; if($self->is_vertical) { $big = $bwidth; } my $label_width = 0; my $label_height = 0; if ($self->label) { my $label = Graphics::Primitive::TextBox->new( # angle => $angle, color => $self->label_color, name => 'label', font => $self->label_font, text => $self->label, width => $self->height, horizontal_align => 'center' ); $label->name('label'); $label->border->color(Graphics::Color::RGB->new(r => 0, g => 0, b => 0)); if($self->is_vertical) { if ($self->is_left) { $label->angle(-&pip2); } else { $label->angle(&pip2) } } $label->prepare($driver); $label->width($label->minimum_width); $label->height($label->minimum_height); $label_width = $label->width; $label_height = $label->height; $self->add_component($label); } if($self->is_vertical) { my $new_min_width = $self->outside_width + $big + $label_width; $self->minimum_width($new_min_width) if $new_min_width > $self->minimum_width; my $new_min_height = $self->outside_height + $big; $self->minimum_height($new_min_height) if $new_min_height > $self->minimum_height; } else { my $new_min_height = $self->outside_height + $big + $label_height; my $new_min_width = $self->outside_width + $big; $self->minimum_height($new_min_height) if $new_min_height > $self->minimum_height; $self->minimum_width($new_min_width) if $new_min_width > $self->minimum_width; if($self->staggered) { $self->minimum_height($self->minimum_height * 2); } } return 1; }); sub mark { my ($self, $span, $value) = @_; return undef if not defined $value; if($self->has_skip_range) { # We must completely ignore values that fall inside the skip range, # so we return an undef. return undef if $self->skip_range->contains($value); if($value > $self->skip_range->upper) { # If the value was outside the range, but above it then we must # be sure and substract the range we are skipping so that the # value will still fall on the chart. $value = $value - $self->skip_range->span; } } # 'caching' this here speeds things up. Calling after changing the # range would result in a messed up chart anyway... if(!defined($self->{LOWER})) { $self->{LOWER} = $self->range->lower; if($self->has_skip_range) { # If we have a skip range then the RSPAN is less the skip range's # span. $self->{RSPAN} = $self->range->span - $self->skip_range->span; } else { $self->{RSPAN} = $self->range->span; } } return ($span / $self->{RSPAN}) * ($value - $self->{LOWER} || 0); } override('finalize', sub { my ($self) = @_; if($self->hidden) { # Call the callback, just in case it matters. super; return; } my $x = 0; my $y = 0; my $width = $self->width; my $height = $self->height; my $ibb = $self->inside_bounding_box; my $iox = $ibb->origin->x; my $ioy = $ibb->origin->y; my $iwidth = $ibb->width; my $iheight = $ibb->height; if($self->is_left) { $x += $width; } elsif($self->is_right) { # nuffin } elsif($self->is_top) { $y += $height; } else { # nuffin } my $lower = $self->range->lower; my $upper = $self->range->upper; my @values = @{ $self->tick_values }; if($self->is_vertical) { my $comp_count = 0; for(0..$#values) { my $val = $values[$_]; my $mark = $self->mark($height, $val); next unless defined($mark); my $iy = $height - $mark; my $label = $self->get_component($comp_count); # Adjust text on the Y axis to fit when it is # too close to the edges my $standardYOrigin = $iy - ($label->height / 2); #my $lowerYOrigin = $iy - $label->height; my $lowerYOrigin = $ioy + $iheight - $label->height; my $upperYOrigin = $ioy; if($standardYOrigin >= $lowerYOrigin) { # The first label (being at the bottom) needs to be # skooched up a bit to fit. $label->origin->y($lowerYOrigin); } elsif($standardYOrigin <= $upperYOrigin) { # The last label (being at the top) can be positioned # exactly at the mark. $label->origin->y($upperYOrigin); } else { $label->origin->y($standardYOrigin); } if($self->is_left) { $label->origin->x($iox + $iwidth - $label->width); } else { $label->origin->x($iox); } # Keep track of how many components we've actually grabbed, since # we could be skipping any that are in a skip range. $comp_count++; } # Draw the label # FIXME Not working, rotated text labels... if($self->label) { my $label = $self->get_component($self->find_component('label')); if($self->is_left) { $label->origin->x($iox); $label->origin->y(($height - $label->height) / 2); } else { $label->origin->x($iox + $iwidth - $label->width); $label->origin->y(($height - $label->height) / 2); } } } else { # Draw a tick for each value. my $comp_count = 0; for(0..$#values) { my $val = $values[$_]; my $ix = $self->mark($width, $val); next unless defined($ix); my $label = $self->get_component($comp_count); my $bump = 0; if($self->staggered) { if($_ % 2) { $bump = $iheight / 2; } } # Adjust the X-origin value to ensure it is within the graph # and does not get snipped when too close to the edge. my $standardXOrigin = $ix - ($label->width / 1.8); my $lowerXOrigin = $iox; my $upperXOrigin = $iox + $iwidth - $label->width; if($standardXOrigin <= $lowerXOrigin) { $label->origin->x($lowerXOrigin); } elsif($standardXOrigin >= $upperXOrigin) { $label->origin->x($upperXOrigin); } else { $label->origin->x($standardXOrigin); } if($self->is_top) { $label->origin->y($ioy + $iheight - $label->height - $bump); } else { $label->origin->y($ioy + $bump); } # Keep track of how many components we've actually grabbed, since # we could be skipping any that are in a skip range. $comp_count++; } # Draw the label if($self->label) { my $label = $self->get_component($self->find_component('label')); my $ext = $self->{'label_extents_cache'}; if ($self->is_bottom) { $label->origin->x(($width - $label->width) / 2); $label->origin->y($height - $label->height - ($self->padding->bottom + $self->margins->bottom + $self->border->top->width ) ); } else { $label->origin->x(($width - $label->width) / 2); } } } super; }); sub format_value { my $self = shift; my $value = shift; my $format = $self->format; if($format) { if(ref($format) eq 'CODE') { return &$format($value); } else { return sprintf($format, $value); } } } sub divvy { my $self = shift; # Loads the divvy module once and only once # which implements _real_divvy() $self->_tick_division_type_loaded; return $self->_real_divvy(); } __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Axis - An X or Y Axis =head1 VERSION version 2.90 =head1 SYNOPSIS use Chart::Clicker::Axis; use Graphics::Primitive::Font; use Graphics::Primitive::Brush; my $axis = Chart::Clicker::Axis->new({ label_font => Graphics::Primitive::Font->new, orientation => 'vertical', position => 'left', brush => Graphics::Primitive::Brush->new, visible => 1, }); =head1 DESCRIPTION Chart::Clicker::Axis represents the plot of the chart. =head1 ATTRIBUTES =head2 height The height of the axis. =head2 width This axis' width. =head2 tick_label_angle The angle (in radians) to rotate the tick's labels. =head2 tick_division_type Selects the algorithm for dividing the graph axis into labelled ticks. The currently included algorithms are: L, L. You may write your own by providing a Moose Role which includes Role L and prefixing the module name with + when setting tick_division_type. Chart::Clicker::Axis->new(tick_division_type => '+MyApp::TickDivision'); This value should only be set once per axis. =head2 baseline The 'baseline' value of this axis. This is used by some renderers to change the way a value is marked. The Bar render, for instance, considers values below the base to be 'negative'. =head2 brush The brush for this axis. Expects a L. =head2 color The color of the axis' border. Expects a L object. Defaults to black. =head2 format The format to use for the axis values. If the format is a string then format is applied to each value 'tick' via sprintf. See sprintf perldoc for details! This is useful for situations where the values end up with repeating decimals. If the format is a coderef then that coderef will be executed and the value passed to it as an argument. my $nf = Number::Format->new; $default->domain_axis->format(sub { return $nf->format_number(shift); }); =head2 fudge_amount The amount to 'fudge' the span of this axis. You should supply a percentage (in decimal form) and the axis will grow at both ends by the supplied amount. This is useful when you want a bit of padding above and below the dataset. As an example, a fugdge_amount of .10 on an axis with a span of 10 to 50 would add 5 to the top and bottom of the axis. =head2 hidden This axis' hidden flag. If this is true then the Axis will not be drawn. =head2 label The label of the axis. =head2 label_color The color of the Axis' labels. Expects a L object. =head2 label_font The font used for the axis' label. Expects a L object. =head2 layout_manager Set/Get the Layout Manager. Defaults to L. =head2 orientation The orientation of this axis. See L. =head2 position The position of the axis on the chart. =head2 range The Range for this axis. Expects a L object. You may use this to explicitly set an upper and lower bound for the chart: $axis->range->max(1000); $axis->range->min(1); =head2 show_ticks If this is value is false then 'ticks' and their labels will not drawn for this axis. =head2 staggered If true, causes horizontally labeled axes to 'stagger' the labels so that half are at the top of the box and the other half are at the bottom. This makes long, overlapping labels less likely to overlap. It only does something useful with B labels. =head2 skip_range Allows you to specify a range of values that will be skipped completely on this axis. This is often used to trim a large, unremarkable section of data. If, for example, 50% of your values fall below 10 and 50% fall above 100 it is useless to bother charting the 10 to 100 range. Skipping it with this attribute will make for a much more useful chart, albeit somewhat visually skewed. $axis->skip_range(Chart::Clicker::Data::Range->new(lower => 10, upper => 100)); Note that B data points, including ticks, that fall inside the range specified will be completely ignored. =head2 tick_font The font used for the axis' ticks. Expects a L object. =head2 tick_label_color The color of the tick labels. Expects a L object. =head2 tick_labels The arrayref of labels to show for ticks on this Axis. This arrayref is consulted for every tick, in order. So placing a string at the zeroeth index will result in it being displayed on the zeroeth tick, etc, etc. =head2 tick_values The arrayref of values show as ticks on this Axis. =head2 ticks The number of 'ticks' to show. Setting this will divide the range on this axis by the specified value to establish tick values. This will have no effect if you specify tick_values. =head1 METHODS =head2 add_to_tick_values Add a value to the list of tick values. =head2 clear_tick_values Clear all tick values. =head2 tick_value_count Get a count of tick values. =head2 mark Given a span and a value, returns it's pixel position on this Axis. =head2 format_value Given a value, returns it formatted using this Axis' formatter. =head2 divvy Retrieves the divisions or ticks for the axis. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut axis-division-rounded.t100644000765000024 506613024411235 20405 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; BEGIN { use_ok('Chart::Clicker::Axis'); } my $label = 'Foo'; # Small Range { my $axis = Chart::Clicker::Axis->new( label => $label, orientation => 'vertical', position => 'left', tick_division_type => 'LinearRounded' ); ok( defined( $axis->range() ), 'Has range' ); $axis->range->lower(3); $axis->range->upper(105); is( $axis->ticks, '6', 'Default number of ticks' ); is_deeply( $axis->divvy(), [ 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 ], 'Nicely rounded tick values - medium scale' ); } # Larger Range { my $axis = Chart::Clicker::Axis->new( label => $label, orientation => 'vertical', position => 'left', tick_division_type => 'LinearRounded' ); $axis->range->lower(1); $axis->range->upper(999123421); is_deeply( $axis->divvy(), [ 0, 100000000, 200000000, 300000000, 400000000, 500000000, 600000000, 700000000, 800000000, 900000000, 1000000000], 'Nicely rounded tick values - large scale 5 ticks' ); } # Large range, small tick count { my $axis = Chart::Clicker::Axis->new( label => $label, orientation => 'vertical', position => 'left', tick_division_type => 'LinearRounded' ); $axis->range->lower(1); $axis->range->upper(999123421); $axis->ticks(3); is_deeply( $axis->divvy(), [ 0, 250000000, 500000000, 750000000, 1000000000 ], 'Nicely rounded tick values - large scale 3 ticks' ); } # Very small range below 1 { my $axis = Chart::Clicker::Axis->new( label => $label, orientation => 'vertical', position => 'left', tick_division_type => 'LinearRounded' ); $axis->range->lower(0.0072); $axis->range->upper(0.0078); $axis->ticks(3); is_deeply( $axis->divvy(), [ 0.0072, 0.0073, 0.0074, 0.0075, 0.0076, 0.0077, 0.0078 ], 'Nicely rounded tick values - large scale 3 ticks' ); } # Very small range above 1 { my $axis = Chart::Clicker::Axis->new( label => $label, orientation => 'vertical', position => 'left', tick_division_type => 'LinearRounded' ); $axis->range->lower(1.5672); $axis->range->upper(1.5679); $axis->ticks(4); is_deeply( $axis->divvy(), [ 1.5672, 1.5673, 1.5674, 1.5675, 1.5676, 1.5677, 1.5678, 1.5679 ], 'Nicely rounded tick values - large scale 3 ticks' ); } done_testing; tufte-whitegrid.pl100644000765000024 355413024411235 20634 0ustar00gphatstaff000000000000Chart-Clicker-2.90/example#!/usr/bin/perl use strict; use Chart::Clicker; use Chart::Clicker::Context; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Marker; use Chart::Clicker::Data::Series; use Chart::Clicker::Renderer::Point; use Geometry::Primitive::Rectangle; use Graphics::Color::RGB; my $cc = Chart::Clicker->new(width => 500, height => 200, format => 'png'); my @hours = qw( 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 ); my @bw = qw( 5.8 5.0 4.9 4.8 4.5 4.25 3.5 2.9 2.5 1.8 .9 .8 .7 1.1 1.7 2.5 3.0 4.5 5.0 4.9 4.7 4.8 4.2 4.4 ); my $series = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw, ); my $ds = Chart::Clicker::Data::DataSet->new(series => [ $series ]); $cc->add_to_datasets($ds); my $defctx = $cc->get_context('default'); my $grey = Graphics::Color::RGB->new( red => .36, green => .36, blue => .36, alpha => 1 ); $cc->color_allocator->colors([ $grey ]); $cc->grid_over(1); $cc->plot->grid->range_brush->width(5); $cc->plot->grid->show_domain(1); $cc->plot->grid->domain_brush->color( Graphics::Color::RGB->new(red => 0, green => 0, blue => 0, alpha => .10) ); $cc->legend->visible(0); $cc->border->width(0); $cc->background_color( Graphics::Color::RGB->new(red => .95, green => .94, blue => .92) ); $cc->plot->grid->range_brush->color( Graphics::Color::RGB->new(red => .95, green => .94, blue => .92) ); $cc->legend_position('n'); $defctx->range_axis->fudge_amount(.015); $defctx->range_axis->tick_values([qw(1 2 3 4 5)]); $defctx->range_axis->format('%d'); $defctx->domain_axis->brush->width(0); $defctx->domain_axis->tick_values([qw(3 6 9 12 15 18 21)]); $defctx->domain_axis->format('%d'); $defctx->domain_axis->fudge_amount(.015); $defctx->range_axis->brush->width(0); # $defctx->domain_axis->tick_label_angle(0.785398163); $defctx->renderer->brush->width(3); $cc->write_output('foo.png'); drawing-colorallocator.t100644000765000024 113713024411235 20624 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; use Graphics::Color::RGB; BEGIN { use_ok('Chart::Clicker::Drawing::ColorAllocator'); } my @seedcolors = ( Graphics::Color::RGB->new({ red => 0, green => 0, blue => 0, alpha => 1, name => 'black' }) ); my $ca = Chart::Clicker::Drawing::ColorAllocator->new({ colors => \@seedcolors }); isa_ok($ca, 'Chart::Clicker::Drawing::ColorAllocator'); my $shouldbeblack = $ca->next; ok(defined($shouldbeblack), 'Seeded color seems to be there'); cmp_ok($shouldbeblack->name, 'eq', 'black', 'Seeded color is black'); done_testing;Context.pm100644000765000024 557213024411235 20700 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clickerpackage Chart::Clicker::Context; $Chart::Clicker::Context::VERSION = '2.90'; use Moose; # ABSTRACT: A rendering context: Axes, Markers and a Renderer use Chart::Clicker::Axis; use Chart::Clicker::Renderer::Line; has 'domain_axis' => ( is => 'rw', isa => 'Chart::Clicker::Axis', default => sub { Chart::Clicker::Axis->new( orientation => 'horizontal', position => 'bottom', format => '%0.2f' ) } ); has 'markers' => ( traits => [ 'Array' ], is => 'rw', isa => 'ArrayRef[Chart::Clicker::Data::Marker]', default => sub { [] }, handles => { 'marker_count' => 'count', 'add_marker' => 'push' } ); has 'name' => ( is => 'rw', isa => 'Str', required => 1 ); has 'range_axis' => ( is => 'rw', isa => 'Chart::Clicker::Axis', default => sub { Chart::Clicker::Axis->new( orientation => 'vertical', position => 'left', format => '%0.2f' ) } ); has 'renderer' => ( is => 'rw', isa => 'Chart::Clicker::Renderer', default => sub { Chart::Clicker::Renderer::Line->new }, ); sub share_axes_with { my ($self, $other_context) = @_; $self->range_axis($other_context->range_axis); $self->domain_axis($other_context->domain_axis); } __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Context - A rendering context: Axes, Markers and a Renderer =head1 VERSION version 2.90 =head1 SYNOPSIS my $clicker = Chart::Clicker->new; my $context = Chart::Clicker::Context->new( name => 'Foo' ); $clicker->add_to_contexts('foo', $context); =head1 DESCRIPTION Contexts represent the way a dataset should be charted. Multiple contexts allow a chart with multiple renderers and axes. See the CONTEXTS section in L. =head2 renderer Set/get this context's renderer =head1 ATTRIBUTES =head2 domain_axis Set/get this context's domain L. =head2 markers An arrayref of Ls for this context. =head2 name Set/get this context's name =head2 range_axis Set/get this context's range L. =head1 METHODS =head2 add_marker Add a marker to this context. =head2 marker_count Get a count of markers in this context. =head2 share_axes_with ($other_context) Sets this context's axes to those of the supplied context. This is a convenience method for quickly sharing axes. It's simple doing: $self->range_axis($other_context->range_axis); $self->domain_axis($other_context->domain_axis); =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut decoration-markeroverlay.t100644000765000024 14213024411235 21137 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse Test::More; BEGIN { use_ok('Chart::Clicker::Decoration::MarkerOverlay'); } done_testing;multiple-renderers.pl100644000765000024 411113024411235 21331 0ustar00gphatstaff000000000000Chart-Clicker-2.90/example#!/usr/bin/perl use strict; use Chart::Clicker; use Chart::Clicker::Context; use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Marker; use Chart::Clicker::Data::Series; use Chart::Clicker::Renderer::Bar; use Geometry::Primitive::Rectangle; use Graphics::Color::RGB; my $cc = Chart::Clicker->new(width => 500, height => 400, format => 'png'); my @hours = qw( 1 2 3 4 5 6 7 8 9 10 11 12 ); my @bw1 = qw( 5.8 5.0 4.9 4.8 4.5 4.25 3.5 2.9 2.5 1.8 .9 .8 ); my @bw2 = qw( .7 1.1 1.7 2.5 3.0 4.5 5.0 4.9 4.7 4.8 4.2 4.4 ); my @bw3 = qw( .3 1.4 1.2 1.5 4.0 3.5 2.0 1.9 2.7 4.2 3.2 1.1 ); my $series1 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw1, ); my $series2 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw2, ); # We'll create a dataset with our first two series in it... my $ds = Chart::Clicker::Data::DataSet->new( series => [ $series1, $series2 ] ); # We'll put the third into it's own dataset so we can put it in a new context my $series3 = Chart::Clicker::Data::Series->new( keys => \@hours, values => \@bw3, ); my $ds1 = Chart::Clicker::Data::DataSet->new( series => [ $series3 ] ); # Create a new context my $other_context = Chart::Clicker::Context->new( name => 'other' ); # Set it's labels... $other_context->range_axis->label('Solor'); $other_context->domain_axis->label('Amet'); # Instruct the ds1 dataset to use the 'other' context. DataSets default to # the 'default' context. $ds1->context('other'); $cc->add_to_contexts($other_context); # Pretty stuff $cc->border->width(0); # Add the datasets to the chart $cc->add_to_datasets($ds); $cc->add_to_datasets($ds1); # Set some labels on the default context my $defctx = $cc->get_context('default'); $defctx->range_axis->label('Lorem'); $defctx->domain_axis->label('Ipsum'); $defctx->domain_axis->tick_label_angle(0.785398163); # Here's the magic: You can set a renderer for any context. In this case # we'll change the default to a Bar. Voila! $defctx->renderer(Chart::Clicker::Renderer::Bar->new); $cc->write_output('foo.png'); Renderer.pm100644000765000024 263213024411235 21014 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clickerpackage Chart::Clicker::Renderer; $Chart::Clicker::Renderer::VERSION = '2.90'; use Moose; extends 'Graphics::Primitive::Canvas'; # ABSTRACT: Base class for renderers has 'additive' => ( is => 'rw', isa => 'Bool', default => 0 ); has 'clicker' => ( is => 'rw', isa => 'Chart::Clicker', weak_ref => 1 ); has 'context' => ( is => 'rw', isa => 'Str' ); override('prepare', sub { my ($self) = @_; return 1; }); __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Renderer - Base class for renderers =head1 VERSION version 2.90 =head1 SYNOPSIS my $renderer = Chart::Clicker::Renderer::Foo->new; =head1 DESCRIPTION Chart::Clicker::Renderer represents the plot of the chart. =head1 ATTRIBUTES =head2 additive Read-only value that informs Clicker that this renderer uses the combined ranges of all the series it charts in total. Used for 'stacked' renderers like StackedBar, StackedArea and Line (which will stack if told to). Note: If you set a renderer to additive that B additive, this will produce wonky results. =head2 context The context to which this Renderer is attached. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Tutorial.pm100644000765000024 1321213024411235 21065 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clickerpackage Chart::Clicker::Tutorial; $Chart::Clicker::Tutorial::VERSION = '2.90'; # ABSTRACT: A Tutorial for using Chart::Clicker 1; __END__ =pod =head1 NAME Chart::Clicker::Tutorial - A Tutorial for using Chart::Clicker =head1 VERSION version 2.90 =head1 DESCRIPTION This document aims to provide a tutorial for using Chart::Clicker. =head1 EXAMPLES =head2 Simple chart from a single data source # grab the needed modules use Chart::Clicker; use Chart::Clicker::Data::Series; use Chart::Clicker::Data::DataSet; # build the chart my $chart = Chart::Clicker->new; # build the series (static here, will usually be supplied arrayrefs from elsewhere) my $series = Chart::Clicker::Data::Series->new( keys => [ 1,2,3,4,5 ], values => [ 52,74,52,82,14 ], ); # build the dataset my $dataset = Chart::Clicker::Data::DataSet->new( series => [ $series ], ); # add the dataset to the chart $chart->add_to_datasets($dataset); # write the chart to a file $chart->write_output('chart.png'); =head2 Simple chart from multiple data sources use Chart::Clicker; use Chart::Clicker::Data::Series; use Chart::Clicker::Data::DataSet; my $chart = Chart::Clicker->new; # start an array that will hold the series data my $series1 = Chart::Clicker::Data::Series->new( keys => [ 1,2,3,4,5 ], values => [ 52,74,52,82,14 ] ); my $series2 = Chart::Clicker::Data::Series->new( keys => [ 1,2,3,4,5 ], values => [ 34,67,89,45,67 ] ); # add the array of series data to the dataset my $dataset = Chart::Clicker::Data::DataSet->new( series => [ $series1, $series2 ] ); $chart->add_to_datasets($dataset); $chart->write_output('chart.png'); =head2 Simple chart with multiple data sources and custom colors use Chart::Clicker; use Chart::Clicker::Data::Series; use Chart::Clicker::Data::DataSet; # some new modules, these are only needed if you want to monkey with color changing use Graphics::Color::RGB; use Chart::Clicker::Drawing::ColorAllocator; # build the color allocator my $ca = Chart::Clicker::Drawing::ColorAllocator->new; # this hash is simply here to make things readable and cleaner, you can always call G::C::R inline my $red = Graphics::Color::RGB->new({ red => .75, green => 0, blue => 0, alpha => .8 }); my $green = Graphics::Color::RGB->new({ red => 0,green => .75, blue=> 0, alpha=> .8 }); my $blue = Graphics::Color::RGB->new({ red => 0, green => 0, blue => .75, alpha => .8 }), my $chart = Chart::Clicker->new; # Create an empty dataset that we can add to my $dataset = Chart::Clicker::Data::DataSet->new; $dataset->add_to_series(Chart::Clicker::Data::Series->new( keys => [ 1,2,3,4,5 ], values => [ 52,74,52,82,14 ] )); # add a color - note that the order of colors and the order of the # series must match, the first series will use the first color and so on # see contexts and axes for alternate ways of doing this $ca->add_to_colors($blue); $dataset->add_to_series(Chart::Clicker::Data::Series->new( keys => [ 1,2,3,4,5 ], values => [ 34,67,89,45,67 ] )); # add a second color $ca->add_to_colors($red); $dataset->add_to_series(Chart::Clicker::Data::Series->new( keys => [ 1,2,3,4,5 ], values => [ 11,22,33,44,55 ] )); # add a third color $ca->add_to_colors($green); $chart->add_to_datasets($dataset); # assign the color allocator to the chart $chart->color_allocator($ca); $chart->write_output('chart.png'); =head2 Example 4 : Simple chart with a different render type use Chart::Clicker; use Chart::Clicker::Data::Series; use Chart::Clicker::Data::DataSet; # add in the module of the renerer(s) you want to use use Chart::Clicker::Renderer::Area; my $chart = Chart::Clicker->new; my $series = Chart::Clicker::Data::Series->new( keys => [ 1,2,3,4,5 ], values => [ 52,74,52,82,14 ] ); my $dataset = Chart::Clicker::Data::DataSet->new( series => [ $series ] ); $chart->add_to_datasets($dataset); # build the renderer to use my $renderer = Chart::Clicker::Renderer::Area->new( opacity => .75, ); # assign the renderer to the default context $chart->set_renderer($renderer); $chart->write_output('chart.png'); =head2 Example 5 : Width and Height my $chart = Chart::Clicker->new(width => 1024, height => 768); =head2 Example 6 : PDF (or SVG or PS) my $chart = Chart::Clicker->new(format => 'pdf'); # Create the rest of your chart normally $chart->write_output('chart.pdf'); =head2 Example 7 : Hide the Legend and X-Axis my $chart = Chart::Clicker->new; # hide the legend $chart->legend->visible(0); # hide the X-Axis $chart->get_context('default')->domain_axis->hidden(1); =head2 Example 8 : Change the display format of the Y-Axis my $chart = Chart::Clicker->new; # a sprintf format to have 3 decimal places showing on the Y-Axis $chart->get_context('default')->range_axis->format('%.3f'); =begin :postlude =head1 CONTRIBUTORS Steve Bradford Michael Peters =end :postlude =head1 DISCLAIMER This is a work in progress. If you find errors or would like to make contributions, drop me a line! =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Component.pm100644000765000024 167113024411235 21212 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clickerpackage Chart::Clicker::Component; $Chart::Clicker::Component::VERSION = '2.90'; use Moose; extends 'Graphics::Primitive::Component'; with 'Graphics::Primitive::Oriented'; # ABSTRACT: Base class that extends Graphics::Primitive::Component has 'clicker' => ( is => 'rw', isa => 'Chart::Clicker' ); __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Component - Base class that extends Graphics::Primitive::Component =head1 VERSION version 2.90 =head1 DESCRIPTION Chart::Clicker::Component is a subclass of L. =head1 ATTRIBUTES =head2 clicker Set/Get this component's clicker object. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Container.pm100644000765000024 167113024411235 21172 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clickerpackage Chart::Clicker::Container; $Chart::Clicker::Container::VERSION = '2.90'; use Moose; extends 'Graphics::Primitive::Container'; with 'Graphics::Primitive::Oriented'; # ABSTRACT: Base class that extends Graphics::Primitive::Container has 'clicker' => ( is => 'rw', isa => 'Chart::Clicker' ); __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Container - Base class that extends Graphics::Primitive::Container =head1 VERSION version 2.90 =head1 DESCRIPTION Chart::Clicker::Container is a subclass of L. =head1 ATTRIBUTES =head2 clicker Set/Get this component's clicker object. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut decoration-color_allocator.t100644000765000024 175013024411235 21460 0ustar00gphatstaff000000000000Chart-Clicker-2.90/tuse strict; use warnings; use Test::More; use Test::Exception; BEGIN { use_ok('Chart::Clicker::Drawing::ColorAllocator'); } my $allocator; lives_ok { $allocator = Chart::Clicker::Drawing::ColorAllocator->new({ seed_hue => 0 }); } 'instantiates'; is_deeply($allocator->hues, [ 0, 45, 75, 15, 60, 30 ], 'default seed hues'); is_deeply($allocator->shade_order, [ 1, 3, 0, 2 ], 'default shade order'); my @colors; for my $shade ( 1, 3, 0, 2){ for my $seed_hue (0, 45, 75, 15, 60, 30 ){ for my $color_idx ( 0..3 ){ $allocator->color_scheme->from_hue($seed_hue); my $color = $allocator->color_scheme->colorset->[$color_idx]->[$shade]; push(@colors, $color); } } } #96 for my $color ( @colors ){ my $allocated = lc $allocator->next->as_hex_string; $allocated =~ s/#//; is($allocated, lc $color, 'color order'); } #1 $allocator->next; is( $allocator->colors->[0]->as_hex_string, $allocator->colors->[96]->as_hex_string, 'goes full circle' ); done_testing;Decoration.pm100644000765000024 136413024411235 21336 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clickerpackage Chart::Clicker::Decoration; $Chart::Clicker::Decoration::VERSION = '2.90'; use Moose; # ABSTRACT: Shiny baubles! extends 'Graphics::Primitive::Canvas'; has 'clicker' => ( is => 'rw', isa => 'Chart::Clicker' ); __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Decoration - Shiny baubles! =head1 VERSION version 2.90 =head1 DESCRIPTION Chart::Clicker::Decoration is a straight subclass of L. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Positioned.pm100644000765000024 350613024411235 21364 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clickerpackage Chart::Clicker::Positioned; $Chart::Clicker::Positioned::VERSION = '2.90'; use Moose::Role; # ABSTRACT: Role for components that care about position. use Moose::Util::TypeConstraints; enum 'Chart::Clicker::Position' => [qw(left right top bottom)]; has 'position' => ( is => 'rw', isa => 'Chart::Clicker::Position' ); sub is_left { my ($self) = @_; return $self->position eq 'left'; } sub is_right { my ($self) = @_; return $self->position eq 'right'; } sub is_top { my ($self) = @_; return $self->position eq 'top'; } sub is_bottom { my ($self) = @_; return $self->position eq 'bottom'; } no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Positioned - Role for components that care about position. =head1 VERSION version 2.90 =head1 SYNOPSIS package My::Component; use Moose; extends 'Chart::Clicker::Drawing::Component'; with 'Chart::Clicker::Positioned'; 1; =head1 DESCRIPTION Some components draw differently depending on which 'side' they are positioned. If an Axis is on the left, it will put the numbers left and the bar on the right. If positioned on the other side then those two piece are reversed. =head1 ATTRIBUTES =head2 position The 'side' on which this component is positioned. =head1 METHODS =head2 is_left Returns true if the component is positioned left. =head2 is_right Returns true if the component is positioned right. =head2 is_top Returns true if the component is positioned top. =head2 is_bottom Returns true if the component is positioned bottom. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Data000755000765000024 013024411235 17416 5ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/ClickerRange.pm100644000765000024 1136713024411235 21200 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Datapackage Chart::Clicker::Data::Range; $Chart::Clicker::Data::Range::VERSION = '2.90'; use Moose; use Moose::Util::TypeConstraints; use constant EPSILON => 0.0001; # ABSTRACT: A range of Data subtype 'Lower' => as 'Num|Undef' => where { defined($_) }; coerce 'Lower' => from 'Undef' => via { - EPSILON }; has 'lower' => ( is => 'rw', isa => 'Lower', coerce => 1); has 'max' => ( is => 'rw', isa => 'Num' ); has 'min' => ( is => 'rw', isa => 'Num' ); subtype 'Upper' => as 'Num|Undef' => where { defined($_) }; coerce 'Upper' => from 'Num|Undef' => via { EPSILON }; has 'upper' => ( is => 'rw', isa => 'Upper', coerce => 1); has 'ticks' => ( is => 'rw', isa => 'Int', default => 5 ); after 'lower' => sub { my $self = shift; if(defined($self->{'min'})) { $self->{'lower'} = $self->{'min'}; } $self->{'lower'} = $self->{'min'} unless (defined($self->{'lower'})); $self->{'upper'} = $self->{'max'} unless (defined($self->{'upper'})); if(defined($self->{'lower'}) && defined($self->{'upper'}) && $self->{'lower'} == $self->{'upper'}) { $self->{'lower'} = $self->{'lower'} - EPSILON; $self->{'lower'} = $self->{'lower'} + EPSILON; } }; after 'upper' => sub { my $self = shift; if(defined($self->{'max'})) { $self->{'upper'} = $self->{'max'}; } $self->{'lower'} = $self->{'min'} unless (defined($self->{'lower'})); $self->{'upper'} = $self->{'max'} unless (defined($self->{'upper'})); if(defined($self->{'lower'}) && defined($self->{'upper'}) && $self->{'lower'} == $self->{'upper'}) { $self->{'upper'} = $self->{'upper'} - EPSILON; $self->{'upper'} = $self->{'upper'} + EPSILON; } }; after 'min' => sub { my $self = shift; if(defined($self->{'min'})) { $self->{'lower'} = $self->{'min'}; } }; after 'max' => sub { my $self = shift; if(defined($self->{'max'})) { $self->{'upper'} = $self->{'max'}; } }; sub add { my ($self, $range) = @_; if(defined($self->upper)) { $self->upper($self->upper + $range->upper); } else { $self->upper($range->upper); } if(!defined($self->lower) || ($range->lower < $self->lower)) { $self->lower($range->lower); } } sub combine { my ($self, $range) = @_; unless(defined($self->min)) { if(!defined($self->lower) || ($range->lower < $self->lower)) { $self->lower($range->lower); } } unless(defined($self->max)) { if(!defined($self->upper) || ($range->upper > $self->upper)) { $self->upper($range->upper); } } return 1; } sub contains { my ($self, $value) = @_; return 1 if $value >= $self->lower && $value <= $self->upper; return 0; } sub span { my ($self) = @_; my $span = $self->upper - $self->lower; #we still want to be able to see flat lines! if ($span <= EPSILON) { $self->upper($self->upper() + EPSILON); $self->lower($self->lower() - EPSILON); $span = $self->upper - $self->lower; } return $span; } __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Data::Range - A range of Data =head1 VERSION version 2.90 =head1 SYNOPSIS use Chart::Clicker::Data::Range; my $range = Chart::Clicker::Data::Range->new({ lower => 1, upper => 10 }); =head1 DESCRIPTION Chart::Clicker::Data::Range implements a range of values. =head1 ATTRIBUTES =head2 lower Set/Get the lower bound for this Range =head2 max Set/Get the maximum value allowed for this Range. This value should only be set if you want to EXPLICITLY set the upper value. =head2 min Set/Get the minimum value allowed for this Range. This value should only be set if you want to EXPLICITLY set the lower value. =head2 upper Set/Get the upper bound for this Range =head2 ticks The number of ticks to be displayed for this range. =head1 METHODS =head2 add Adds the specified range to this one. The lower is reduced to that of the provided one if it is lower, and the upper is ADDED to this range's upper. =head2 combine Combine this range with the specified so that this range encompasses the values specified. For example, adding a range with an upper-lower of 1-10 with one of 5-20 will result in a combined range of 1-20. =head2 contains ($value) Returns true if supplied value falls within this range (inclusive). Otherwise returns false. =head2 span Returns the span of this range, or UPPER - LOWER. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Marker.pm100644000765000024 521513024411235 21340 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Datapackage Chart::Clicker::Data::Marker; $Chart::Clicker::Data::Marker::VERSION = '2.90'; use Moose; # ABSTRACT: Highlight arbitrary value(s) use Graphics::Color::RGB; use Graphics::Primitive::Brush; has 'brush' => ( is => 'rw', isa => 'Graphics::Primitive::Brush', default => sub { Graphics::Primitive::Brush->new(width => 1); } ); has 'color' => ( is => 'rw', isa => 'Graphics::Color', default => sub { Graphics::Color::RGB->new( red => 0, green => 0, blue => 0, alpha => 1 ); } ); has 'inside_color' => ( is => 'rw', isa => 'Graphics::Color', default => sub { Graphics::Color::RGB->new( red => 0, green => 0, blue => 0, alpha => 1 ); } ); has 'key' => ( is => 'rw', isa => 'Num' ); has 'key2' => ( is => 'rw', isa => 'Num' ); has 'value' => ( is => 'rw', isa => 'Num' ); has 'value2' => ( is => 'rw', isa => 'Num' ); __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Data::Marker - Highlight arbitrary value(s) =head1 VERSION version 2.90 =head1 SYNOPSIS use Chart::Clicker::Data::Marker; use Graphics::Color::RGB; use Graphics::Primitive::Brush; my $cc = Chart::Clicker->new; my $mark = Chart::Clicker::Data::Marker->new( color => Graphics::Color::RGB->new, brush => Graphics::Primitive::Brush->new, key => 12, value => 123, # Optionally key2 => 13, value => 146 ); my $ctx = $cc->get_context('default'); $ctx->add_marker($mark); $cc->write_output('foo.png'); =head1 DESCRIPTION Used to highlight a particular key, value or range of either. =head1 ATTRIBUTES =head2 brush Set/Get the L for this Marker. =head2 color Set/Get the L for this marker. =head2 inside_color Set/Get the inside L, which will be used if this range has two keys and two values. =head2 key Set/Get the key for this marker. This represents a point on the domain. =head2 key2 Set/Get the key2 for this marker. This represents a second point on the domain and is used to specify a range. =head2 value Set/Get the value for this marker. This represents a point on the range. =head2 value2 Set/Get the value2 for this marker. This represents a second point on the range and is used to specify a range. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Series.pm100644000765000024 1033313024411235 21366 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Datapackage Chart::Clicker::Data::Series; $Chart::Clicker::Data::Series::VERSION = '2.90'; use Moose; # ABSTRACT: A series of key, value pairs representing chart data use List::Util qw(max min); use Chart::Clicker::Data::Range; has 'keys' => ( traits => [ 'Array' ], is => 'rw', isa => 'ArrayRef[Num]', default => sub { [] }, handles => { 'add_to_keys' => 'push', 'key_count' => 'count' } ); has 'name' => ( is => 'rw', isa => 'Str', predicate => 'has_name' ); has 'range' => ( is => 'rw', isa => 'Chart::Clicker::Data::Range', lazy_build => 1 ); has 'values' => ( traits => [ 'Array' ], is => 'rw', isa => 'ArrayRef[Num|Undef]', default => sub { [] }, handles => { 'add_to_values' => 'push', 'value_count' => 'count' } ); sub _build_range { my ($self) = @_; my $values = $self->values; confess('A series must have values before it can be charted') unless scalar(@{ $values }); return Chart::Clicker::Data::Range->new( lower => min(grep { defined } @{ $values }), upper => max(grep { defined } @{ $values }) ); } sub BUILDARGS { my ($class, @args) = @_; if(@args == 1 && (ref($args[0]) eq 'HASH') && !exists($args[0]->{keys})) { my @keys = sort { $a <=> $b } keys %{ $args[0] }; my @values = (); foreach my $k (@keys) { push(@values, $args[0]->{$k}) } return { keys => \@keys, values => \@values } } elsif(@args % 2 == 0) { return { @args }; } return $args[0]; } sub add_pair { my ($self, $key, $value) = @_; $self->add_to_keys($key); $self->add_to_values($value); } sub get_value_for_key { my ($self, $key) = @_; for(0..$self->key_count) { my $ikey = $self->keys->[$_]; return $self->values->[$_] if defined($ikey) && $ikey == $key; } # We found nothing, return undef return undef; } sub prepare { my ($self) = @_; if($self->key_count != $self->value_count) { die('Series key/value counts dont match: '.$self->key_count.' != '.$self->value_count.'.'); } return 1; } __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Data::Series - A series of key, value pairs representing chart data =head1 VERSION version 2.90 =head1 SYNOPSIS use Chart::Clicker::Data::Series; my @keys = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10); my @values = (42, 25, 86, 23, 2, 19, 103, 12, 54, 9); my $series = Chart::Clicker::Data::Series->new({ keys => \@keys, value => \@values }); # Alternately, if you prefer my $series2 = Chart::Clicker::Data::Series->new({ 1 => 42, 2 => 25, 3 => 85, 4 => 23, 5 => 2, 6 => 19, 7 => 102, 8 => 12, 9 => 54, 10 => 9 }); =head1 DESCRIPTION Chart::Clicker::Data::Series represents a series of values to be charted. Despite the name (keys and values) it is expected that all keys and values will be numeric. Values is pretty obvious, but it is important that keys also be numeric, as otherwise we'd have no idea how to order the data. If you want to use text labels for your domain's see L's L method. =head1 ATTRIBUTES =head2 keys Set/Get the keys for this series. =head2 add_to_keys Adds a key to this series. =head2 name Set/Get the name for this Series =head2 range Returns the L for this series. =head2 values Set/Get the values for this series. =head1 METHODS =head2 key_count Get the count of keys in this series. =head2 add_to_values Add a value to this series. =head2 value_count Get the count of values in this series. =head2 add_pair ($key, $value) Convenience method to add a single key and a single value to the series. =head2 get_value_for_key ($key) Returns the value associated with the specified key. This is necessary because not all series will have values for every key. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut DataSet.pm100644000765000024 1114713024411235 21465 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Datapackage Chart::Clicker::Data::DataSet; $Chart::Clicker::Data::DataSet::VERSION = '2.90'; use Moose; # ABSTRACT: A collection of series use Chart::Clicker::Data::Range; has 'context' => ( is => 'rw', isa => 'Str', default => 'default' ); has 'domain' => ( is => 'rw', isa => 'Chart::Clicker::Data::Range', default => sub { Chart::Clicker::Data::Range->new } ); has 'max_key_count' => ( is => 'rw', isa => 'Int', default => 0 ); has 'range' => ( is => 'rw', isa => 'Chart::Clicker::Data::Range', default => sub { Chart::Clicker::Data::Range->new } ); has 'series' => ( traits => [ 'Array' ], is => 'rw', isa => 'ArrayRef', default => sub { [] }, handles => { 'count' => 'count', 'add_to_series' => 'push', 'get_series' => 'get' } ); sub get_all_series_keys { my ($self) = @_; my %keys; for my $series (@{$self->series}) { foreach (@{$series->keys}) { $keys{$_} = 1}; } return keys %keys; } sub get_series_keys { my ($self, $position) = @_; return map({ $_->keys->[$position] } @{ $self->series }); } sub get_series_values { my ($self, $position) = @_; return [ map({ $_->values->[$position] } @{ $self->series }) ]; } sub get_series_values_for_key { my ($self, $key) = @_; return [ map({ $_->get_value_for_key($key) } @{ $self->series }) ]; } sub largest_value_slice { my ($self) = @_; # Prime out big variable with the value of the first slice my $big; foreach (@{ $self->get_series_values(0) }) { $big += $_; } # Check that value against all the remaining slices for my $i (0 .. $self->max_key_count - 1) { my $t; foreach (@{ $self->get_series_values($i) }) { $t += $_ if defined($_); } $big = $t if(($t > $big) || !defined($big)); } return $big; } sub prepare { my ($self) = @_; unless($self->count && $self->count > 0) { die('Dataset has no series.'); } foreach my $series (@{ $self->series }) { $series->prepare; $self->range->combine($series->range); my @keys = @{ $series->keys }; $self->domain->combine( Chart::Clicker::Data::Range->new({ lower => $keys[0], upper => $keys[ $#keys ] }) ); if($series->key_count > $self->max_key_count) { $self->max_key_count($series->key_count); } } return 1; } __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Data::DataSet - A collection of series =head1 VERSION version 2.90 =head1 SYNOPSIS use Chart::Clicker::Data::DataSet; use Chart::Clicker::Data::Series; my @vals = (12, 19, 90, 4, 44, 3, 78, 87, 19, 5); my @keys = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10); my $series = Chart::Clicker::Data::Series->new({ keys => \@keys, values => \@vals }); my $ds = Chart::Clicker::Data::DataSet->new({ series => [ $series ] }); =head1 DESCRIPTION Chart::Clicker::Data::DataSet is a set of Series that are grouped for some logical reason or another. DatasSets can be associated with Renderers in the Chart. Unless you are doing something fancy like that you have no reason to use more than one in your chart. =head2 max_key_count Get the number of keys in the longest series. This will be set automatically. =head1 ATTRIBUTES =head2 context Set/Get the context this DataSet will be charted under. =head2 domain Get the L for the domain values =head2 range Get the L for the... range values... =head2 series Set/Get the series for this DataSet =head1 METHODS =head2 add_to_series Add a series to this dataset. =head2 count Get the number of series in this dataset. =head2 get_series ($index) Get the series at the specified index. =head2 get_all_series_keys Returns an array of keys representing the union of all keys from all DataSets. =head2 get_series_keys Returns the key at the specified position for every series in this DataSet. =head2 get_series_values Returns the value at the specified position for every series in this DataSet as an ArrayRef. =head2 get_series_values_for_key Returns the value for the specified key for every series in this DataSet as an ArrayRef. =head2 largest_value_slice Finds the largest cumulative 'slice' in this dataset. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Renderer000755000765000024 013024411235 20313 5ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/ClickerBar.pm100644000765000024 1536713024411235 21551 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Rendererpackage Chart::Clicker::Renderer::Bar; $Chart::Clicker::Renderer::Bar::VERSION = '2.90'; use Moose; extends 'Chart::Clicker::Renderer'; # ABSTRACT: Bar renderer use Graphics::Primitive::Brush; use Graphics::Primitive::Operation::Fill; use Graphics::Primitive::Operation::Stroke; use Graphics::Primitive::Paint::Solid; has 'bar_padding' => ( is => 'rw', isa => 'Int', default => 0 ); has 'bar_width' => ( is => 'rw', isa => 'Num', predicate => 'has_bar_width' ); has 'brush' => ( is => 'rw', isa => 'Graphics::Primitive::Brush', default => sub { Graphics::Primitive::Brush->new } ); has 'opacity' => ( is => 'rw', isa => 'Num', default => 1 ); override('prepare', sub { my $self = shift; super; my $datasets = $self->clicker->get_datasets_for_context($self->context); $self->{KEYCOUNT} = 0; foreach my $ds (@{ $datasets }) { $self->{SCOUNT} += $ds->count; if($ds->max_key_count > $self->{KEYCOUNT}) { $self->{KEYCOUNT} = $ds->max_key_count; } } return 1; }); override('finalize', sub { my ($self) = @_; my $clicker = $self->clicker; my $height = $self->height; my $width = $self->width; my $dses = $clicker->get_datasets_for_context($self->context); my $brwidth = $self->brush->width; my $padding = $self->bar_padding + $brwidth * 2; my $offset = 1; foreach my $ds (@{ $dses }) { foreach my $series (@{ $ds->series }) { # TODO if undef... my $ctx = $clicker->get_context($ds->context); my $domain = $ctx->domain_axis; my $range = $ctx->range_axis; my $owidth = $width - ($width * $domain->fudge_amount); my $bwidth; if($self->has_bar_width) { $bwidth = $self->bar_width; } else { $bwidth = int(($owidth / $self->{KEYCOUNT})) - $padding; } my $hbwidth = int($bwidth / 2); # Fudge amounts mess up the calculation of bar widths, so # we compensate for them here. my $cbwidth = $bwidth / $self->{SCOUNT}; my $chbwidth = int($cbwidth / 2); my $color = $clicker->color_allocator->next; my $base = $range->baseline; my $basey; if(defined($base)) { $basey = $height - $range->mark($height, $base); } else { $basey = $height; $base = $range->range->lower; } my @vals = @{ $series->values }; my @keys = @{ $series->keys }; my $sksent = $series->key_count; for(0..($sksent - 1)) { # Skip drawing anything if the value is equal to the baseline next if $vals[$_] == $range->baseline; my $x = $domain->mark($width, $keys[$_]); my $y = $range->mark($height, $vals[$_]); if($vals[$_] >= $base) { if($self->{SCOUNT} == 1) { $self->move_to($x + $chbwidth, $basey); $self->rectangle( -int($cbwidth), -int($y - ($height - $basey)) ); } else { $self->move_to( $x - $hbwidth + ($offset * $cbwidth), $basey ); $self->rectangle( -int($cbwidth) + $brwidth, -int($y - ($height - $basey)) ); } } else { if($self->{SCOUNT} == 1) { $self->move_to($x + $chbwidth, $basey); $self->rectangle( -int($cbwidth), -int($y - ($height - $basey)) ); } else { $self->move_to( $x - $hbwidth + ($offset * $cbwidth), $basey ); $self->rectangle( -int($cbwidth) + $brwidth, int($height - $basey - $y) ); } } } my $fillop = Graphics::Primitive::Operation::Fill->new( paint => Graphics::Primitive::Paint::Solid->new ); if($self->opacity < 1) { my $fillcolor = $color->clone; $fillcolor->alpha($self->opacity); $fillop->paint->color($fillcolor); # Since we're going to stroke this, we want to preserve it. $fillop->preserve(1) if $brwidth; } else { $fillop->paint->color($color); } $self->do($fillop); if(($self->opacity < 1) && ($brwidth > 0)) { my $strokeop = Graphics::Primitive::Operation::Stroke->new; $strokeop->brush($self->brush->clone); unless(defined($self->brush->color)) { $strokeop->brush->color($color); } $self->do($strokeop); } $offset++; } } return 1; }); __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Renderer::Bar - Bar renderer =head1 VERSION version 2.90 =head1 SYNOPSIS my $br = Chart::Clicker::Renderer::Bar->new; =head1 DESCRIPTION Chart::Clicker::Renderer::Bar renders a dataset as bars. =head1 NEGATIVE BARS If you'd like to render both "negative and positive" bars, look at L's C attribute. Setting it will result in something like this: =for HTML

Base (Baseline) Chart

=for HTML

Bar Chart

=head2 bar_padding How much padding to put around a bar. A padding of 4 will result in 2 pixels on each side. =head1 ATTRIBUTES =head2 bar_width Allows you to override the calculation that determines the optimal width for bars. Be careful using this as it can making things look terrible. Note that this number is divided evenly between all the values in a series when charting multiple series. =head2 brush Set/Get the L to use around each bar. =head2 opacity Set/Get the alpha value to make each bar more or less opaque. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Pie.pm100644000765000024 1457413024411235 21561 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Rendererpackage Chart::Clicker::Renderer::Pie; $Chart::Clicker::Renderer::Pie::VERSION = '2.90'; use Moose; extends 'Chart::Clicker::Renderer'; # ABSTRACT: Pie renderer use Graphics::Color::RGB; use Geometry::Primitive::Arc; use Geometry::Primitive::Circle; use Graphics::Primitive::Brush; use Graphics::Primitive::Paint::Gradient::Radial; use Scalar::Util qw(refaddr); has 'border_color' => ( is => 'rw', isa => 'Graphics::Color::RGB', default => sub { Graphics::Color::RGB->new }, ); has 'brush' => ( is => 'rw', isa => 'Graphics::Primitive::Brush', default => sub { Graphics::Primitive::Brush->new } ); has 'gradient_color' => ( is => 'rw', isa => 'Graphics::Color::RGB', predicate => 'has_gradient_color' ); has 'gradient_reverse' => ( is => 'rw', isa => 'Bool', default => 0, ); has 'starting_angle' => ( is => 'rw', isa => 'Int', default => -90, ); my $TO_RAD = (4 * atan2(1, 1)) / 180; override('prepare', sub { my $self = shift; super; my $clicker = $self->clicker; my $dses = $clicker->get_datasets_for_context($self->context); foreach my $ds (@{ $dses }) { foreach my $series (@{ $ds->series }) { foreach my $val (@{ $series->values }) { $self->{ACCUM}->{refaddr($series)} += $val; $self->{TOTAL} += $val; } } } }); override('finalize', sub { my $self = shift; my $clicker = $self->clicker; my $radius = $self->height; if($self->width < $self->height) { $radius = $self->width; } $radius = $radius / 2; # Take into acount the line around the edge when working out the radius $radius -= $self->brush->width; my $height = $self->height; my $linewidth = 1; my $midx = $self->width / 2; my $midy = $height / 2; my $pos = $self->starting_angle; my $dses = $clicker->get_datasets_for_context($self->context); foreach my $ds (@{ $dses }) { foreach my $series (@{ $ds->series }) { # TODO if undef... my $ctx = $clicker->get_context($ds->context); my $domain = $ctx->domain_axis; my $range = $ctx->range_axis; my $avg = $self->{ACCUM}->{refaddr($series)} / $self->{TOTAL}; my $degs = ($avg * 360) + $pos; $self->move_to($midx, $midy); $self->arc($radius, $degs * $TO_RAD, $pos * $TO_RAD); $self->close_path; my $color = $clicker->color_allocator->next; my $paint; if($self->has_gradient_color) { my $gc = $self->gradient_color; my $start_radius = 0; my $end_radius = $radius; if($self->gradient_reverse) { $start_radius = $radius; $end_radius = 0; } $paint = Graphics::Primitive::Paint::Gradient::Radial->new( start => Geometry::Primitive::Circle->new( origin => [ $midx, $midy ], radius => $start_radius ), end => Geometry::Primitive::Circle->new( origin => [ $midx, $midy ], radius => $end_radius ) ); $paint->add_stop(0, $color); $paint->add_stop(1, $color->clone( red => $color->red + ($gc->red - $color->red) * $gc->alpha, green => $color->green + ($gc->green - $color->green) * $gc->alpha, blue => $color->blue + ($gc->blue - $color->blue) * $gc->alpha, )); } else { $paint = Graphics::Primitive::Paint::Solid->new( color => $color, ); } my $fop = Graphics::Primitive::Operation::Fill->new( preserve => 1, paint => $paint ); $self->do($fop); my $op = Graphics::Primitive::Operation::Stroke->new; $op->brush($self->brush->clone); $op->brush->color($self->border_color); $self->do($op); $pos = $degs; } } return 1; }); __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Renderer::Pie - Pie renderer =head1 VERSION version 2.90 =head1 SYNOPSIS my $pier = Chart::Clicker::Renderer::Pie->new; # Optionally set the stroke width $pier->brush->width(2); =head1 DESCRIPTION Chart::Clicker::Renderer::Pie renders a dataset as slices of a pie. The keys of like-named Series are totaled and keys are ignored. So for a dataset like: my $series = Chart::Clicker::Data::Series->new( keys => [ 1, 2, 3 ], values => [ 1, 2, 3], ); my $series2 = Chart::Clicker::Data::Series->new( keys => [ 1, 2, 3], values => [ 1, 1, 1 ], ); The keys are discarded and a pie chart will be drawn with $series' slice at 66% (1 + 2 + 3 = 6) and $series2's at 33% (1 + 1 + 1 = 3). =for HTML

Pie Chart

=for HTML

Pie Chart

=head1 ATTRIBUTES =head2 border_color Set/Get the L to use for the border. =head2 brush Set/Get a L to be used for the pie's border. =head2 gradient_color If supplied, specifies a L to mix with each slice's color for use as a radial gradient. The best results are usually gotten from mixing with a white or black and manipulating the alpha, like so: $ren->gradient_color( Graphics::Color::RGB->new(red => 1, green => 1, blue => 1, alpha => .3) ); The above will cause each generated color to fade toward a lighter version of itself. Adjust the alpha to increase or decrease the effect. =head2 brush Set/Get whether or not the gradient is to be reversed. =head2 starting_angle Set/Get a starting angle for the gradient. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Axis000755000765000024 013024411235 17451 5ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/ClickerDateTime.pm100644000765000024 777413024411235 21662 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Axispackage Chart::Clicker::Axis::DateTime; $Chart::Clicker::Axis::DateTime::VERSION = '2.90'; use Moose; # ABSTRACT: An X or Y Axis using DateTime use Chart::Clicker::Data::Marker; use DateTime; use DateTime::Set; use Graphics::Color::RGB; extends 'Chart::Clicker::Axis'; has 'format' => ( is => 'rw', isa => 'Str' ); has 'time_zone' => ( is => 'rw', isa => 'Str' ); override 'prepare' => sub { my ($self, $driver) = @_; my ($dstart, $dend); eval { $dstart = DateTime->from_epoch(epoch => $self->range->lower); $dend = DateTime->from_epoch(epoch => $self->range->upper); }; if(!defined($dstart) || !defined($dend)) { $dstart = DateTime->now; $dend = DateTime->now; } my $dur = $dend - $dstart; unless(defined($self->format) && length($self->format)) { if($dur->years) { $self->format('%b %Y'); } elsif($dur->months) { $self->format('%d'); } elsif($dur->weeks) { $self->format('%d'); } elsif($dur->days) { $self->format('%m/%d %H:%M'); } else { $self->format('%H:%M'); } } super; my $clicker = shift; if(!defined($clicker)) { die('No clicker?') } # my @markers = @{ $clicker->markers }; my $set = DateTime::Span->from_datetimes( start => $dstart, end => $dend ); my $linecolor = Graphics::Color::RGB->new({ red => 0, green => 0, blue => 0, alpha => .35 }); my $fillcolor = Graphics::Color::RGB->new({ red => 0, green => 0, blue => 0, alpha => .10 }); # my @dmarkers; # my $day = $set->start->truncate(to => 'day'); # # my $dayval; # while($day < $set->end) { # if($set->contains($day)) { # if(defined($dayval)) { # push(@dmarkers, # Chart::Clicker::Data::Marker->new({ # key => $dayval, # key2 => $day->epoch, # color => $linecolor, # inside_color=> $fillcolor, # }) # ); # $dayval = undef; # } else { # $dayval = $day->epoch; # } # } # $day = $day->add(days => 1); # } # if($dayval) { # push(@dmarkers, # Chart::Clicker::Data::Marker->new({ # key => $dayval, # key2 => $day->epoch, # color => $linecolor, # inside_color=> $fillcolor, # }) # ); # } # # push(@dmarkers, @markers); # $clicker->markers(\@dmarkers); return 1; }; sub format_value { my $self = shift; my $value = shift; my %dtargs = ( 'epoch' => $value ); if($self->time_zone) { $dtargs{'time_zone'} = $self->time_zone; } my $dt = DateTime->from_epoch(%dtargs); return $dt->strftime($self->format); } __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Axis::DateTime - An X or Y Axis using DateTime =head1 VERSION version 2.90 =head1 SYNOPSIS my $axis = Chart::Clicker::Axis::DateTime->new; =head1 DESCRIPTION A temporal Axis. Requires L and L. Inherits from Axis, so check the methods there as well. Expects that times will be in unix format. =head1 ATTRIBUTES =head2 format Set/Get the formatting string used to format the DateTime. See DateTime's strftime. =head2 time_zone Set/Get the time zone to use when creating DateTime objects! Accepts an object or a string ('America/Chicago'). =head1 METHODS =head2 format_value Formats the value using L's strftime. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Area.pm100644000765000024 1142613024411235 21705 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Rendererpackage Chart::Clicker::Renderer::Area; $Chart::Clicker::Renderer::Area::VERSION = '2.90'; use Moose; extends 'Chart::Clicker::Renderer'; # ABSTRACT: Area renderer use Graphics::Primitive::Brush; use Graphics::Primitive::Path; use Graphics::Primitive::Operation::Fill; use Graphics::Primitive::Operation::Stroke; use Graphics::Primitive::Paint::Gradient::Linear; use Graphics::Primitive::Paint::Solid; has 'brush' => ( is => 'rw', isa => 'Graphics::Primitive::Brush', default => sub { Graphics::Primitive::Brush->new } ); has 'fade' => ( is => 'rw', isa => 'Bool', default => 0 ); has 'opacity' => ( is => 'rw', isa => 'Num', default => 0 ); override('finalize', sub { my ($self) = @_; my $height = $self->height; my $width = $self->width; my $clicker = $self->clicker; my $dses = $clicker->get_datasets_for_context($self->context); foreach my $ds (@{ $dses }) { foreach my $series (@{ $ds->series }) { # TODO if undef... my $ctx = $clicker->get_context($ds->context); my $domain = $ctx->domain_axis; my $range = $ctx->range_axis; my $lastx; # used for completing the path my @vals = @{ $series->values }; my @keys = @{ $series->keys }; my $startx; my $biggest; for(0..($series->key_count - 1)) { my $x = $domain->mark($width, $keys[$_]); next unless defined($x); my $ymark = $range->mark($height, $vals[$_]); next unless defined($ymark); my $y = $height - $ymark; if(defined($biggest)) { $biggest = $y if $y > $biggest; } else { $biggest = $y; } if($_ == 0) { $startx = $x; $self->move_to($x, $y); } else { $self->line_to($x, $y); } $lastx = $x; } my $color = $self->clicker->color_allocator->next; my $op = Graphics::Primitive::Operation::Stroke->new; $op->preserve(1); $op->brush($self->brush->clone); $op->brush->color($color); $self->do($op); $self->line_to($lastx, $height); $self->line_to($startx, $height); $self->close_path; my $paint; if($self->opacity) { my $clone = $color->clone; $clone->alpha($self->opacity); $paint = Graphics::Primitive::Paint::Solid->new( color => $clone ); } elsif($self->fade) { my $clone = $color->clone; $clone->alpha($self->opacity); $paint = Graphics::Primitive::Paint::Gradient::Linear->new( line => Geometry::Primitive::Line->new( start => Geometry::Primitive::Point->new(x => 0, y => 0), end => Geometry::Primitive::Point->new(x => 1, y => $biggest), ), style => 'linear' ); $paint->add_stop(1.0, $color); $paint->add_stop(0, $clone); } else { $paint = Graphics::Primitive::Paint::Solid->new( color => $color->clone ); } my $fillop = Graphics::Primitive::Operation::Fill->new( paint => $paint ); $self->do($fillop); } } return 1; }); __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Renderer::Area - Area renderer =head1 VERSION version 2.90 =head1 SYNOPSIS my $ar = Chart::Clicker::Renderer::Area->new({ fade => 1, brush => Graphics::Primitive::Brush->new({ width => 2 }) }); =head1 DESCRIPTION Chart::Clicker::Renderer::Area renders a dataset as line-like polygons with their interior areas filled. =for HTML

Area Chart

=head1 ATTRIBUTES =head2 brush Set/Get the L that informs the line surrounding the area renders individual segments. =head2 fade Set/Get the fade flag, which turns on or off a gradient in the area renderer. =head2 opacity Set the alpha value for the renderer, which makes things more or less opaque. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Line.pm100644000765000024 1752413024411235 21731 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Rendererpackage Chart::Clicker::Renderer::Line; $Chart::Clicker::Renderer::Line::VERSION = '2.90'; use Moose; # ABSTRACT: Line renderer extends 'Chart::Clicker::Renderer'; use Geometry::Primitive::Point; use Graphics::Primitive::Brush; use Graphics::Primitive::Operation::Stroke; use Geometry::Primitive::Circle; #number of defined points we must have around another point #to render a line instead of a scatter # use constant MIN_DEFINED_SURROUNDING_POINTS => 5; has 'brush' => ( is => 'rw', isa => 'Graphics::Primitive::Brush', default => sub { Graphics::Primitive::Brush->new(width => 2) } ); has 'shape' => ( is => 'rw', isa => 'Geometry::Primitive::Shape', ); has 'shape_brush' => ( is => 'rw', isa => 'Graphics::Primitive::Brush', ); # TODO Readd shapes sub finalize { my ($self) = @_; my $width = $self->width; my $height = $self->height; my $clicker = $self->clicker; my $dses = $clicker->get_datasets_for_context($self->context); my %accum; foreach my $ds (@{ $dses }) { foreach my $series (@{ $ds->series }) { # TODO if undef... my $ctx = $clicker->get_context($ds->context); my $domain = $ctx->domain_axis; my $range = $ctx->range_axis; my $color = $clicker->color_allocator->next; my @vals = @{ $series->values }; my @keys = @{ $series->keys }; my $kcount = $series->key_count - 1; my $skip = 0; my $previous_x = -1; my $previous_y = -1; my $min_y_delta_on_same_x = $height / 100; for(0..$kcount) { my $key = $keys[$_]; my $x = $domain->mark($width, $key); next unless defined($x); $skip = 1 unless defined $vals[$_]; my $ymark = $range->mark($height, $vals[$_]); next unless defined($ymark); if($self->additive) { if(exists($accum{$key})) { $accum{$key} += $ymark; $ymark = $accum{$key}; } else { $accum{$key} = $ymark; } } my $y = $height - $ymark; if( $_ == 0 || $skip ) { my $lineop = Graphics::Primitive::Operation::Stroke->new( brush => $self->brush->clone ); $lineop->brush->color($color); $self->do($lineop); $self->move_to($x, $y); my $start_new_line = 1; foreach my $i ($_..($_ + MIN_DEFINED_SURROUNDING_POINTS)) { if ($i > 0 && $i < @vals && !defined($vals[$i])) { $start_new_line = 0; } } if ($start_new_line){ $skip = 0; } else { my $shape = Geometry::Primitive::Circle->new(radius => 3); $shape->origin(Geometry::Primitive::Point->new(x => $x, y => $y)); $self->path->add_primitive($shape); my $fill = Graphics::Primitive::Operation::Fill->new( paint => Graphics::Primitive::Paint::Solid->new( color => $color ) ); $self->do($fill); } } else { # when in fast mode, we plot only if we moved by more than # 1 of a pixel on the X axis or we moved by more than 1% # of the size of the Y axis. if( $clicker->plot_mode ne 'fast' || $x - $previous_x > 1 || abs($y - $previous_y) > $min_y_delta_on_same_x ) { $self->line_to($x, $y); $previous_x = $x; $previous_y = $y; } } } my $op = Graphics::Primitive::Operation::Stroke->new; $op->brush($self->brush->clone); $op->brush->color($color); $self->do($op); if(defined($self->shape)) { for(0..$kcount) { my $key = $keys[$_]; my $x = $domain->mark($width, $key); next unless defined($x); my $ymark = $range->mark($height, $vals[$_]); next unless defined($ymark); if($self->additive) { if(exists($accum{$key})) { $ymark = $accum{$key}; } else { $accum{$key} = $ymark; } } my $y = $height - $ymark; $self->move_to($x, $y); $self->draw_point($x, $y, $series, $vals[$_]); } # Fill the shape my $op2 = Graphics::Primitive::Operation::Fill->new( paint => Graphics::Primitive::Paint::Solid->new( color => $color ) ); if(defined($self->shape_brush)) { $op2->preserve(1); } $self->do($op2); # Optionally stroke the shape if(defined($self->shape_brush)) { my $op3 = Graphics::Primitive::Operation::Stroke->new; $op3->brush($self->shape_brush->clone); $self->do($op3); } } } } return 1; } sub draw_point { my ($self, $x, $y, $series, $count) = @_; my $shape = $self->shape->clone; $shape->origin(Geometry::Primitive::Point->new(x => $x, y => $y)); $self->path->add_primitive($shape); } __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Renderer::Line - Line renderer =head1 VERSION version 2.90 =head1 SYNOPSIS my $lr = Chart::Clicker::Renderer::Line->new( brush => Graphics::Primitive::Brush->new({ #... }) ); =head1 DESCRIPTION Chart::Clicker::Renderer::Line renders a dataset as lines. =for HTML

Line Chart

=for HTML

Line + Shape Chart

=for HTML

Line + Shape (Brushed) Chart

=head1 ATTRIBUTES =head2 additive If true, the lines are drawn "stacked", each key accumulates based on those drawn below it. =head2 brush Set/Get a L to be used for the lines. =head2 shape Set a L object to draw at each of the data points. Adding a shape results in: =head2 shape_brush Set/Get the L to be used on the shapes at each point. If no shape_brush is provided, then the shapes will be filled. The brush allows you to draw a "halo" around each shape. This sometimes help to separate the points from the lines and make them more distinct. =head1 METHODS =head2 draw_point Called for each point encountered on the line. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Point.pm100644000765000024 715113024411235 22106 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Rendererpackage Chart::Clicker::Renderer::Point; $Chart::Clicker::Renderer::Point::VERSION = '2.90'; use Moose; # ABSTRACT: Point renderer extends 'Chart::Clicker::Renderer'; use Geometry::Primitive::Circle; use Geometry::Primitive::Point; use Graphics::Primitive::Operation::Fill; use Graphics::Primitive::Paint::Solid; has 'shape' => ( is => 'rw', does => 'Geometry::Primitive::Shape', default => sub { Geometry::Primitive::Circle->new({ radius => 3, }); } ); has 'shape_brush' => ( is => 'rw', isa => 'Graphics::Primitive::Brush', ); override('finalize', sub { my ($self) = @_; my $clicker = $self->clicker; my $width = $self->width; my $height = $self->height; my $dses = $clicker->get_datasets_for_context($self->context); foreach my $ds (@{ $dses }) { foreach my $series (@{ $ds->series }) { # TODO if undef... my $ctx = $clicker->get_context($ds->context); my $domain = $ctx->domain_axis; my $range = $ctx->range_axis; my $min = $range->range->lower; my @vals = @{ $series->values }; my @keys = @{ $series->keys }; for(0..($series->key_count - 1)) { my $x = $domain->mark($width, $keys[$_]); next unless defined($x); my $ymark = $range->mark($height, $vals[$_]); next unless defined($ymark); my $y = $height - $ymark; $self->move_to($x, $y); $self->draw_point($x, $y, $series, $_); } my $op = Graphics::Primitive::Operation::Fill->new( paint => Graphics::Primitive::Paint::Solid->new( color => $clicker->color_allocator->next ) ); if(defined($self->shape_brush)) { $op->preserve(1); } $self->do($op); if(defined($self->shape_brush)) { my $op3 = Graphics::Primitive::Operation::Stroke->new; $op3->brush($self->shape_brush->clone); $self->do($op3); } } } return 1; }); sub draw_point { my ($self, $x, $y, $series, $count) = @_; my $shape = $self->shape->clone; $shape->origin(Geometry::Primitive::Point->new(x => $x, y => $y)); $self->path->add_primitive($shape); } __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Renderer::Point - Point renderer =head1 VERSION version 2.90 =head1 SYNOPSIS my $pr = Chart::Clicker::Renderer::Point->new({ shape => Geometry::Primitive::Arc->new({ angle1 => 0, angle2 => 180, radius => 5 }) }); =head1 DESCRIPTION Chart::Clicker::Renderer::Point renders a dataset as points. =for HTML

Point Chart

=head1 ATTRIBUTES =head2 shape Specify the L to be used at each point. Defaults to 360 degree arc with a radius of 3. =head2 shape_brush Optionally provide a L with with to stroke each point. =head1 METHODS =head2 draw_point Called for each point. Implemented as a separate method so that subclasses such as Bubble may override the drawing. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Decoration000755000765000024 013024411235 20634 5ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/ClickerGrid.pm100644000765000024 772213024411235 22227 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Decorationpackage Chart::Clicker::Decoration::Grid; $Chart::Clicker::Decoration::Grid::VERSION = '2.90'; use Moose; extends 'Graphics::Primitive::Canvas'; with 'Graphics::Primitive::Oriented'; # ABSTRACT: Under-data grid use Graphics::Color::RGB; has '+background_color' => ( default => sub { Graphics::Color::RGB->new( red => 0.9, green => 0.9, blue => 0.9, alpha => 1 ) } ); has 'clicker' => ( is => 'rw', isa => 'Chart::Clicker' ); has 'domain_brush' => ( is => 'rw', isa => 'Graphics::Primitive::Brush', default => sub { Graphics::Primitive::Brush->new( color => Graphics::Color::RGB->new( red => .75, green => .75, blue => .75, alpha => 1 ), width => 1 ) } ); has 'range_brush' => ( is => 'rw', isa => 'Graphics::Primitive::Brush', default => sub { Graphics::Primitive::Brush->new( color => Graphics::Color::RGB->new( red => .75, green => .75, blue => .75, alpha => 1 ), width => 1 ) } ); has 'show_domain' => ( is => 'rw', isa => 'Bool', default => 1 ); has 'show_range' => ( is => 'rw', isa => 'Bool', default => 1 ); override('finalize', sub { my $self = shift; return unless ($self->show_domain || $self->show_range); my $clicker = $self->clicker; my $dflt = $clicker->get_context('default'); my $daxis = $dflt->domain_axis; my $raxis = $dflt->range_axis; if($self->show_domain) { $self->draw_lines($daxis); my $dop = Graphics::Primitive::Operation::Stroke->new; $dop->brush($self->domain_brush); $self->do($dop); } if($self->show_range) { $self->draw_lines($raxis); my $rop = Graphics::Primitive::Operation::Stroke->new; $rop->brush($self->range_brush); $self->do($rop); } }); sub draw_lines { my ($self, $axis) = @_; my $height = $self->height; my $width = $self->width; if($axis->is_horizontal) { foreach my $val (@{ $axis->tick_values }) { my $mark = $axis->mark($width, $val); # Don't try and draw a mark if the Axis wouldn't give us a value, # it might be skipping... next unless defined($mark); $self->move_to($mark, 0); $self->rel_line_to(0, $height); } } else { foreach my $val (@{ $axis->tick_values }) { my $mark = $axis->mark($height, $val); # Don't try and draw a mark if the Axis wouldn't give us a value, # it might be skipping... next unless defined($mark); $self->move_to(0, $height - $mark); $self->rel_line_to($width, 0); } } } __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Decoration::Grid - Under-data grid =head1 VERSION version 2.90 =head1 DESCRIPTION Generates a collection of Markers for use as a background. =head1 ATTRIBUTES =head2 background_color Set/Get the background L for this Grid. =head2 border Set/Get the L for this Grid. =head2 color Set/Get the L for this Grid. =head2 domain_brush Set/Get the L for inking the domain markers. =head2 range_brush Set/Get the L for inking the range markers. =head2 show_domain Flag to show or not show the domain lines. =head2 show_range Flag to show or not show the range lines. =head2 stroke Set/Get the Stroke for this Grid. =head1 METHODS =head2 draw_lines Called by pack, draws the lines for a given axis. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Plot.pm100644000765000024 416013024411235 22251 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Decorationpackage Chart::Clicker::Decoration::Plot; $Chart::Clicker::Decoration::Plot::VERSION = '2.90'; use Moose; # ABSTRACT: Area on which renderers draw use Layout::Manager::Axis; use Layout::Manager::Single; use Chart::Clicker::Decoration::Grid; extends 'Chart::Clicker::Container'; has 'clicker' => ( is => 'rw', isa => 'Chart::Clicker', ); has 'grid' => ( is => 'rw', isa => 'Chart::Clicker::Decoration::Grid', default => sub { Chart::Clicker::Decoration::Grid->new( name => 'grid' ) } ); has '+layout_manager' => ( default => sub { Layout::Manager::Axis->new } ); has 'render_area' => ( is => 'rw', isa => 'Chart::Clicker::Container', default => sub { Chart::Clicker::Container->new( name => 'render_area', layout_manager => Layout::Manager::Single->new ) } ); override('prepare', sub { my ($self) = @_; # TODO This is also happening in Clicker.pm foreach my $c (@{ $self->components }) { $c->clicker($self->clicker); } # TODO This is kinda messy... foreach my $c (@{ $self->render_area->components }) { $c->clicker($self->clicker); } super; }); __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Decoration::Plot - Area on which renderers draw =head1 VERSION version 2.90 =head1 DESCRIPTION A Component that handles the rendering of data via Renderers. Also handles rendering the markers that come from the Clicker object. =head1 ATTRIBUTES =head2 background_color Set/Get this Plot's background color. =head2 border Set/Get this Plot's border. =head2 grid Set/Get the Grid component used on this plot. =head2 layout_manager Set/Get the layout manager for this plot. Defaults to L. =head2 render_area Set/Get the container used to render within. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Bubble.pm100644000765000024 304113024411235 22202 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Rendererpackage Chart::Clicker::Renderer::Bubble; $Chart::Clicker::Renderer::Bubble::VERSION = '2.90'; use Moose; # ABSTRACT: Bubble render extends 'Chart::Clicker::Renderer::Point'; override('draw_point', sub { my ($self, $x, $y, $series, $count) = @_; my $shape = $self->shape->scale($series->get_size($count)); $shape->origin(Geometry::Primitive::Point->new(x => $x, y => $y)); $self->path->add_primitive($shape); }); __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Renderer::Bubble - Bubble render =head1 VERSION version 2.90 =head1 SYNOPSIS my $pr = Chart::Clicker::Renderer::Bubble->new({ shape => Geometry::Primitive::Circle->new({ radius => 3 }) }); =head1 DESCRIPTION Chart::Clicker::Renderer::Bubble is a subclass of the Point renderer where the points' radiuses are determined by the size value of a Series::Size. Note: B. =for HTML

Bubble Chart

=head1 METHODS =head2 draw_point Called for each point. Implemented as a separate method so that subclasses such as Bubble may override the drawing. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Series000755000765000024 013024411235 20650 5ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/DataSize.pm100644000765000024 406613024411235 22266 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Data/Seriespackage Chart::Clicker::Data::Series::Size; $Chart::Clicker::Data::Series::Size::VERSION = '2.90'; use Moose; extends 'Chart::Clicker::Data::Series'; # ABSTRACT: Chart data with additional attributes for Size charts use List::Util qw(min max); has 'sizes' => ( traits => [ 'Array' ], is => 'rw', isa => 'ArrayRef', default => sub { [] }, handles => { 'add_to_sizes' => 'push', 'size_count' => 'count', 'get_size' => 'get' } ); has max_size => ( is => 'ro', isa => 'Num', lazy => 1, default => sub { my ($self) = @_; return max(@{ $self->sizes }); } ); has min_size => ( is => 'ro', isa => 'Num', lazy => 1, default => sub { my ($self) = @_; return min(@{ $self->sizes }); } ); __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Data::Series::Size - Chart data with additional attributes for Size charts =head1 VERSION version 2.90 =head1 SYNOPSIS use Chart::Clicker::Data::Series::Size; my @keys = (); my @values = (); my @sizes = (); my $series = Chart::Clicker::Data::Series::Size->new({ keys => \@keys, values => \@values, sizes => \@sizes }); =head1 DESCRIPTION Chart::Clicker::Data::Series::Size is an extension of the Series class that provides storage for a third variable called the size. This is useful for the Bubble renderer. =head1 ATTRIBUTES =head2 sizes Set/Get the sizes for this series. =head2 max_size Gets the largest value from this Series' C. =head2 min_size Gets the smallest value from this Series' C. =head1 METHODS =head2 add_to_sizes Adds a size to this series. =head2 get_size Get a size by it's index. =head2 size_count Gets the count of sizes in this series. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Glass.pm100644000765000024 367513024411235 22416 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Decorationpackage Chart::Clicker::Decoration::Glass; $Chart::Clicker::Decoration::Glass::VERSION = '2.90'; use Moose; extends 'Chart::Clicker::Decoration'; # ABSTRACT: Under-chart gradient decoration use Graphics::Color::RGB; use Graphics::Primitive::Operation::Fill; use Graphics::Primitive::Paint::Solid; has 'background_color' => ( is => 'rw', isa => 'Graphics::Color::RGB', default => sub { Graphics::Color::RGB->new( red => 1, green => 0, blue => 0, alpha => 1 ) } ); has 'glare_color' => ( is => 'rw', isa => 'Graphics::Color::RGB', default => sub { Graphics::Color::RGB->new( red => 1, green => 1, blue => 1, alpha => 1 ) }, ); override('finalize', sub { my ($self) = @_; my $twentypofheight = $self->height * .20; $self->move_to(1, $twentypofheight); $self->rel_curve_to( 0, 0, $self->width / 2, $self->height * .30, $self->width, 0 ); $self->line_to($self->width, 0); $self->line_to(0, 0); $self->line_to(0, $twentypofheight); my $fillop = Graphics::Primitive::Operation::Fill->new( paint => Graphics::Primitive::Paint::Solid->new( color => $self->glare_color ) ); $self->do($fillop); }); __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Decoration::Glass - Under-chart gradient decoration =head1 VERSION version 2.90 =head1 DESCRIPTION A glass-like decoration. =head1 ATTRIBUTES =head2 background_color Set/Get the background L for this glass. =head2 glare_color Set/Get the glare L for this glass. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut DivisionType.pm100644000765000024 143313024411235 22576 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Axispackage Chart::Clicker::Axis::DivisionType; $Chart::Clicker::Axis::DivisionType::VERSION = '2.90'; use Moose::Role; requires qw{range ticks}; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Axis::DivisionType =head1 VERSION version 2.90 =head1 DESCRIPTION =head1 NAME Chart::Clicker::Axis::DivisionType - Division style for ticks =head1 AUTHOR Rod Taylor =head1 SEE ALSO perl(1) =head1 LICENSE You can redistribute and/or modify this code under the same terms as Perl itself. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Legend.pm100644000765000024 600513024411235 22531 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Decorationpackage Chart::Clicker::Decoration::Legend; $Chart::Clicker::Decoration::Legend::VERSION = '2.90'; use Moose; extends 'Chart::Clicker::Container'; with 'Graphics::Primitive::Oriented'; # ABSTRACT: Series name, color key use Graphics::Primitive::Font; use Graphics::Primitive::Insets; use Graphics::Primitive::TextBox; use Layout::Manager::Flow; has '+border' => ( default => sub { my $b = Graphics::Primitive::Border->new; $b->color(Graphics::Color::RGB->new( red => 0, green => 0, blue => 0)); $b->width(1); return $b; } ); has 'font' => ( is => 'rw', isa => 'Graphics::Primitive::Font', default => sub { Graphics::Primitive::Font->new } ); has 'item_padding' => ( is => 'rw', isa => 'Graphics::Primitive::Insets', default => sub { Graphics::Primitive::Insets->new({ top => 3, left => 3, bottom => 3, right => 5 }) } ); has '+layout_manager' => ( default => sub { Layout::Manager::Flow->new(anchor => 'west', wrap => 1) }, lazy => 1 ); override('prepare', sub { my ($self, $driver) = @_; return if $self->component_count > 0; my $ca = $self->clicker->color_allocator; my $font = $self->font; my $ii = $self->item_padding; #this makes sure that wrapping works $self->width($self->clicker->width); if($self->is_vertical) { # This assumes you aren't changing the layout manager... $self->layout_manager->anchor('north'); } my $count = 0; foreach my $ds (@{ $self->clicker->datasets }) { foreach my $s (@{ $ds->series }) { unless($s->has_name) { $s->name("Series $count"); } my $tb = Graphics::Primitive::TextBox->new( color => $ca->next, font => $font, padding => $ii, text => $s->name ); $self->add_component($tb); $count++; } } super; $ca->reset; }); __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Decoration::Legend - Series name, color key =head1 VERSION version 2.90 =head1 DESCRIPTION Chart::Clicker::Decoration::Legend draws a legend on a Chart. =head1 ATTRIBUTES =head2 border Set/Get this Legend's L. =head2 font Set/Get the L used for this legend's items. =head2 insets Set/Get this Legend's L. =head2 item_padding Set/Get the L for this legend's items. =head2 layout_manager Set/Get the layout manager for this lagend. Defaults to L with an anchor of C and a C of 1. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut PolarArea.pm100644000765000024 1324213024411235 22701 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Rendererpackage Chart::Clicker::Renderer::PolarArea; $Chart::Clicker::Renderer::PolarArea::VERSION = '2.90'; use Moose; extends 'Chart::Clicker::Renderer'; # ABSTRACT: Polar Area renderer use Graphics::Color::RGB; use Geometry::Primitive::Arc; use Graphics::Primitive::Brush; use Scalar::Util qw(refaddr); has 'border_color' => ( is => 'rw', isa => 'Graphics::Color::RGB', default => sub { Graphics::Color::RGB->new }, ); has 'brush' => ( is => 'rw', isa => 'Graphics::Primitive::Brush', default => sub { Graphics::Primitive::Brush->new } ); has '_accum' => ( is => 'rw', isa => 'ArrayRef', default => sub { [] } ); has '_colors' => ( is => 'rw', isa => 'ArrayRef', default => sub { [] } ); has '_largest' => ( is => 'rw', isa => 'Num', default => 0 ); my $TO_RAD = (4 * atan2(1, 1)) / 180; override('prepare', sub { my $self = shift; super; my $clicker = $self->clicker; # TODO # This implementation is dumb... the better way would be: # draw the first slice # remember once of the corner points # when drawing the next slice, start at the remembered point and arc-neg with no radius # then arc pos again # or something like that # This is really hinky, basically since figuring out the arcs and whatnot # is a pain in the ass, we employ the painter's algorithm and draw # the last series first, then paint the next one over it. As such, we have # to know the total "accumulated" value for each series' position so that # we can decrement it on each run through the series... this finds the # totals my $dses = $clicker->get_datasets_for_context($self->context); foreach my $ds (@{ $dses }) { my $lvs = $ds->largest_value_slice; if($lvs > $self->_largest) { $self->_largest($lvs) } my $count = $ds->max_key_count; for my $pos (0..$count - 1) { my $vals = $ds->get_series_values($pos); my $total = 0; foreach my $v (@{ $vals }) { $total += $v; } $self->_accum->[$pos] += $total; } } }); override('finalize', sub { my $self = shift; my $clicker = $self->clicker; my $radius = $self->height; if($self->width < $self->height) { $radius = $self->width; } $radius = $radius / 2; # Take into account the line around the edge when working out the radius $radius -= $self->brush->width; my $height = $self->height; my $linewidth = 1; my $midx = $self->width / 2; my $midy = $height / 2; my $per = $radius / $self->_largest; my $dses = $clicker->get_datasets_for_context($self->context); foreach my $ds (@{ $dses }) { foreach my $series (@{ $ds->series }) { push(@{ $self->_colors }, $clicker->color_allocator->next); } } # my $dses = $clicker->get_datasets_for_context($self->context); foreach my $ds (reverse @{ $dses }) { my $ctx = $clicker->get_context($ds->context); my $domain = $ctx->domain_axis; my $range = $ctx->range_axis; foreach my $series (reverse @{ $ds->series }) { my $pos = 0; my $degs = 360 / scalar(@{ $series->values }); my $color = pop(@{ $self->_colors }); my $v = 0; foreach my $val (@{ $series->values }) { my $foo = $self->_accum->[$v]; # Remove this value worth of accumulate from the accumulator # so that our size is properly pushed out, see above comment # in prepare... $self->_accum->[$v] -= $val; $self->move_to($midx, $midy); $self->arc(($self->_accum->[$v] + $val) * $per, ($pos - $degs) * $TO_RAD, $pos * $TO_RAD); $self->close_path; my $fop = Graphics::Primitive::Operation::Fill->new( preserve => 1, paint => Graphics::Primitive::Paint::Solid->new( color => $color, ) ); $self->do($fop); my $op = Graphics::Primitive::Operation::Stroke->new; $op->brush($self->brush->clone); $op->brush->color($self->border_color); $self->do($op); $pos += $degs; $v++; } } } return 1; }); __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Renderer::PolarArea - Polar Area renderer =head1 VERSION version 2.90 =head1 SYNOPSIS my $par = Chart::Clicker::Renderer::PolarArea->new; # Optionally set the stroke $par->brush->width(2); # and color $par->border_color(Graphics::Color::RGB->new(red => 1, green => 1, blue => 1)); =head1 DESCRIPTION Chart::Clicker::Renderer::PolarArea renders each series as a slice of a pie. The values of the series determine the radius of each slice, with larger values making the slices longer. The 360 degrees of pie is divided equally. =for HTML

Polar Area Chart

=head1 ATTRIBUTES =head2 border_color Set/Get the L to use for the border. =head2 brush Set/Get a L to be used for the polar area's borders, which are around each slice. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut HighLow.pm100644000765000024 557613024411235 22724 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Data/Seriespackage Chart::Clicker::Data::Series::HighLow; $Chart::Clicker::Data::Series::HighLow::VERSION = '2.90'; use Moose; extends 'Chart::Clicker::Data::Series'; # ABSTRACT: Series data with additional attributes for High-Low charts use List::Util qw(max min); sub _build_range { my ($self) = @_; return Chart::Clicker::Data::Range->new( lower => min(@{ $self->lows }), upper => max(@{ $self->highs }) ); } has 'highs' => ( traits => [ 'Array' ], is => 'rw', isa => 'ArrayRef', default => sub { [] }, handles => { 'add_to_highs' => 'push', 'high_count' => 'count', 'get_high' => 'get' } ); has 'lows' => ( traits => [ 'Array' ], is => 'rw', isa => 'ArrayRef', default => sub { [] }, handles => { 'add_to_lows' => 'push', 'low_count' => 'count', 'get_low' => 'get' } ); has 'opens' => ( traits => [ 'Array' ], is => 'rw', isa => 'ArrayRef', default => sub { [] }, handles => { 'add_to_opens' => 'push', 'open_count' => 'count', 'get_open' => 'get' } ); __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Data::Series::HighLow - Series data with additional attributes for High-Low charts =head1 VERSION version 2.90 =head1 SYNOPSIS use Chart::Clicker::Data::Series::HighLow; my @keys = (); my @values = (); my @highs = (); my @lows = (); my @opens = (); my $series = Chart::Clicker::Data::Series::HighLow->new({ keys => \@keys, values => \@values, highs => \@highs, lows => \@lows, opens => \@opens }); =head1 DESCRIPTION Chart::Clicker::Data::Series::HighLow is an extension of the Series class that provides storage for a three new variables called for use with the CandleStick renderer. The general idea is: --- <-- High | | - <-- max of Open, Value | | | | - <-- min of Open, Value | | --- <-- Low =head1 ATTRIBUTES =head2 highs Set/Get the highs for this series. =head2 lows Set/Get the lows for this series. =head2 opens Set/Get the opens for this series. =head1 METHODS =head2 add_to_highs Adds a high to this series. =head2 get_high ($index) Get a high by it's index. =head2 high_count Gets the count of sizes in this series. =head2 add_to_lows Adds a high to this series. =head2 get_low ($index) Get a low by it's index. =head2 low_count Gets the count of lows in this series. =head2 add_to_opens Adds an open to this series. =head2 get_open Get an open by it's index. =head2 open_count Gets the count of opens in this series. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut OverAxis.pm100644000765000024 1025413024411235 23114 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Decorationpackage Chart::Clicker::Decoration::OverAxis; $Chart::Clicker::Decoration::OverAxis::VERSION = '2.90'; use Moose; extends 'Chart::Clicker::Container'; # ABSTRACT: An axis drawn over data use Graphics::Color::RGB; use Graphics::Primitive::Operation::Fill; use Graphics::Primitive::Paint::Solid; use Layout::Manager::Flow; has 'axis_height' => ( is => 'rw', isa => 'Num', default => 20 ); has '+background_color' => ( # is => 'rw', # isa => 'Graphics::Color::RGB', default => sub { Graphics::Color::RGB->new( red => .18, green => .17, blue => .17, alpha => 1 ) } ); has 'border_color' => ( is => 'rw', isa => 'Graphics::Color::RGB', default => sub { Graphics::Color::RGB->new( red => 1, green => 1, blue => 1, alpha => 1 ) } ); has 'border_width' => ( is => 'rw', isa => 'Num', default => 2 ); has 'context' => ( is => 'rw', isa => 'Str', required => 1 ); has 'font' => ( is => 'rw', isa => 'Graphics::Primitive::Font', default => sub { Graphics::Primitive::Font->new } ); has '+layout_manager' => ( default => sub { Layout::Manager::Compass->new } ); has 'text_color' => ( is => 'rw', isa => 'Graphics::Color::RGB', default => sub { Graphics::Color::RGB->new( red => 1, green => 1, blue => 1, alpha => 1 ) } ); override('prepare', sub { my ($self) = @_; $self->height($self->axis_height); my $ctx = $self->clicker->get_context($self->context); my $ticks = $ctx->domain_axis->tick_values; foreach my $tick (@{ $ticks }) { my $tb = Graphics::Primitive::TextBox->new( text => $tick, color => $self->text_color, horizontal_alignment => 'center', vertical_alignment => 'center', font => $self->font ); $self->add_component($tb, 'w'); } super; }); override('finalize', sub { my ($self) = @_; my $ctx = $self->clicker->get_context($self->context); my $domain = $ctx->domain_axis; my $range = $ctx->range_axis; my $y = $range->mark($self->height, $range->baseline); my $axis_y = $y - ($self->axis_height / 2); $self->origin->x(0); $self->origin->y($axis_y); $self->border->top->width($self->border_width); $self->border->bottom->width($self->border_width); $self->border->color($self->border_color); $self->minimum_height($self->axis_height); $self->height($self->axis_height); my $ticks = $domain->tick_values; for my $i (0 .. $#{ $ticks }) { my $tick = $ticks->[$i]; my $comp = $self->get_component($i); $comp->width($self->width / scalar(@{ $ticks })); $comp->origin->x( $domain->mark($self->width, $tick) - $comp->width / 2 ); $comp->height($self->axis_height); } }); __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Decoration::OverAxis - An axis drawn over data =head1 VERSION version 2.90 =head1 DESCRIPTION An axis that is meant to be drawn "over" a chart. You can find an example of an OverAxis at L. =head1 ATTRIBUTES =head2 axis_height Set/Get the height of the OverAxis that will be drawn. =head2 background_color Set/Get the background L for this OverAxis. =head2 border_color Set/Get the border L for this OverAxis. =head2 border_width Set/Get the width of the border for this OverAxis =head2 context Set/Get the context that this OverAxis should use. =head2 font The L to use for the OverAxis. =head2 layout_manager The layout manager to use for this overaxis. Defaults to a L. =head2 text_color Set/Get the L of the text labels dawn for the ticks. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut StackedBar.pm100644000765000024 1243713024411235 23043 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Rendererpackage Chart::Clicker::Renderer::StackedBar; $Chart::Clicker::Renderer::StackedBar::VERSION = '2.90'; use Moose; extends 'Chart::Clicker::Renderer'; # ABSTRACT: Stacked Bar renderer use Graphics::Primitive::Brush; use Graphics::Primitive::Paint::Solid; use Graphics::Primitive::Operation::Fill; use Graphics::Primitive::Operation::Stroke; has '+additive' => ( default => 1 ); has 'bar_padding' => ( is => 'rw', isa => 'Int', default => 0 ); has 'bar_width' => ( is => 'rw', isa => 'Num', predicate => 'has_bar_width' ); has 'brush' => ( is => 'rw', isa => 'Graphics::Primitive::Brush', default => sub { Graphics::Primitive::Brush->new } ); has 'opacity' => ( is => 'rw', isa => 'Num', default => 0 ); override('prepare', sub { my ($self) = @_; super; my $dses = $self->clicker->get_datasets_for_context($self->context); foreach my $ds (@{ $dses }) { if(!defined($self->{KEYCOUNT})) { $self->{KEYCOUNT} = $ds->max_key_count; } $self->{SCOUNT} += $ds->count; } return 1; }); override('finalize', sub { my ($self) = @_; my $clicker = $self->clicker; my $height = $self->height; my $width = $self->width; my $dses = $clicker->get_datasets_for_context($self->context); my $ctx = $clicker->get_context($dses->[0]->context); my $domain = $ctx->domain_axis; my $range = $ctx->range_axis; my $padding = $self->bar_padding; my $strokewidth = $self->brush->width; $padding += $strokewidth; my $bwidth; if($self->has_bar_width) { $bwidth = $self->bar_width; } else { $bwidth = int(($width - ($width * $domain->fudge_amount) - ($padding / 2 * $self->{KEYCOUNT})) / ($self->{KEYCOUNT})); } my $hbwidth = $bwidth / 2; # Fetch all the colors we'll need. Since we build each vertical bar from # top to bottom, we'll need to change colors vertically. for (my $i = 0; $i < $self->{SCOUNT}; $i++) { push(@{ $self->{COLORS} }, $clicker->color_allocator->next); } my @keys = $dses->[0]->get_all_series_keys; # Iterate over each key... for (my $i = 0; $i < scalar(@keys); $i++) { # Mark the x, since it's the same for each Y value my $x = $domain->mark($width, $keys[$i]); my $accum = 0; # Get all the values from every dataset's series for each key my @values; foreach my $ds (@{ $dses }) { push(@values, @{ $ds->get_series_values_for_key($keys[$i]) }); } my $val = 0; for my $j (0 .. $#values) { my $sval = $values[$j]; # Skip this if there is no value for the specified key position next if !defined($sval); # Skip it if it's equal to our baseline, as there's no reason to # draw anything if so next if $sval == $range->baseline; $val += $sval; my $y = $range->mark($height, $val); next unless defined($y); $self->move_to($x - $hbwidth, $height - $y + $self->brush->width * 2); $self->rectangle($bwidth, $y - $accum - 1); # Accumulate the Y value, as it dictates how much we bump up the # next bar. $accum += $y - $accum; my $color = $self->{COLORS}->[$j]; my $fillop = Graphics::Primitive::Operation::Fill->new( paint => Graphics::Primitive::Paint::Solid->new ); if($self->opacity) { my $fillcolor = $color->clone; $fillcolor->alpha($self->opacity); $fillop->paint->color($fillcolor); # Since we're going to stroke this, we want to preserve it. $fillop->preserve(1); } else { $fillop->paint->color($color); } $self->do($fillop); if($self->opacity) { my $strokeop = Graphics::Primitive::Operation::Stroke->new; $strokeop->brush->color($color); $self->do($strokeop); } } } return 1; }); __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Renderer::StackedBar - Stacked Bar renderer =head1 VERSION version 2.90 =head1 SYNOPSIS my $br = Chart::Clicker::Renderer::Bar->new; =head1 DESCRIPTION Chart::Clicker::Renderer::StackedBar renders a dataset as stacked bars. =for HTML

Stacked Bar Chart

=head1 ATTRIBUTES =head2 bar_padding How much padding to put around a bar. A padding of 4 will result in 2 pixels on each side. =head2 bar_width Allows you to override the calculation that determines the optimal width for bars. Be careful using this as it can making things look terrible. =head2 brush A L to stroke on each bar. =head2 opacity If true this value will be used when setting the opacity of the bar's fill. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut CandleStick.pm100644000765000024 1207413024411235 23221 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Rendererpackage Chart::Clicker::Renderer::CandleStick; $Chart::Clicker::Renderer::CandleStick::VERSION = '2.90'; use Moose; extends 'Chart::Clicker::Renderer'; # ABSTRACT: CandleStick renderer use Graphics::Primitive::Brush; use Graphics::Primitive::Operation::Fill; use Graphics::Primitive::Operation::Stroke; use Graphics::Primitive::Paint::Solid; use List::Util qw(max min); has 'bar_padding' => ( is => 'rw', isa => 'Int', default => 0 ); has 'brush' => ( is => 'rw', isa => 'Graphics::Primitive::Brush', default => sub { Graphics::Primitive::Brush->new(width => 2) } ); override('prepare', sub { my $self = shift; super; my $datasets = $self->clicker->get_datasets_for_context($self->context); $self->{SCOUNT} = 1; $self->{KEYCOUNT} = 0; foreach my $ds (@{ $datasets }) { $self->{SCOUNT} += $ds->count; if($ds->max_key_count > $self->{KEYCOUNT}) { $self->{KEYCOUNT} = $ds->max_key_count; } } return 1; }); override('finalize', sub { my ($self) = @_; my $clicker = $self->clicker; my $width = $self->width; my $height = $self->height; my $dses = $clicker->get_datasets_for_context($self->context); my $padding = $self->bar_padding + $self->brush->width; my $bwidth = int(($width / $dses->[0]->max_key_count)) - $self->bar_padding; my $hbwidth = int($bwidth / 2); my $scounter = $self->{SCOUNT}; foreach my $ds (@{ $dses }) { foreach my $series (@{ $ds->series }) { my $color = $clicker->color_allocator->next; # TODO if undef... my $ctx = $clicker->get_context($ds->context); my $domain = $ctx->domain_axis; my $range = $ctx->range_axis; my $ocbwidth = $bwidth - ($bwidth * $domain->fudge_amount); my $cbwidth = $ocbwidth / $self->{SCOUNT}; my $hcbwidth = $cbwidth / 2; my $offset = $bwidth - ($bwidth / $self->{SCOUNT}); my $min = $range->range->lower; my @highs = @{ $series->highs }; my @lows = @{ $series->lows }; my @opens = @{ $series->opens }; my @vals = @{ $series->values }; my @keys = @{ $series->keys }; for(0..($series->key_count - 1)) { my $x = $domain->mark($width, $keys[$_]); $x -= $cbwidth * $scounter; $x += $offset; my $openy = $height - $range->mark($height, $opens[$_]); my $closey = $height - $range->mark($height, $vals[$_]); my $highy = $height - $range->mark($height, $highs[$_]); my $lowy = $height - $range->mark($height, $lows[$_]); my $_height = $closey - $openy; $self->move_to($x - $hcbwidth, $openy); $self->rectangle( $cbwidth, $_height ); my $op; if($_height < 0) { # We fill the bar if it closed higher $op = Graphics::Primitive::Operation::Fill->new( paint => Graphics::Primitive::Paint::Solid->new( color => $color ) ); } else { # We stroke the bar if it closed lower $op = Graphics::Primitive::Operation::Stroke->new( brush => $self->brush->clone ); $op->brush->color($color); $op->brush->width(2); } $self->do($op); $self->move_to($x, min($openy, $closey)); $self->line_to($x, $highy); $self->move_to($x, max($openy, $closey)); $self->line_to($x, $lowy); my $lineop = Graphics::Primitive::Operation::Stroke->new( brush => $self->brush->clone ); $lineop->brush->color($color); $self->do($lineop); } $scounter--; } } return 1; }); __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Renderer::CandleStick - CandleStick renderer =head1 VERSION version 2.90 =head1 SYNOPSIS my $br = Chart::Clicker::Renderer::CandleStick->new; =head1 DESCRIPTION Chart::Clicker::Renderer::CandleStick renders a dataset as a candlestick style bar chart. =for HTML

Candlestick Chart

=head1 ATTRIBUTES =head2 bar_padding How much padding to put around a bar. A padding of 4 will result in 2 pixels on each side. =head2 brush Set/Get the L to use around each bar and on each line. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut StackedArea.pm100644000765000024 1263613024411235 23210 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Rendererpackage Chart::Clicker::Renderer::StackedArea; $Chart::Clicker::Renderer::StackedArea::VERSION = '2.90'; use Moose; # ABSTRACT: Stacked Area renderer extends 'Chart::Clicker::Renderer::Area'; use Graphics::Primitive::Brush; use Graphics::Primitive::Path; use Graphics::Primitive::Operation::Fill; use Graphics::Primitive::Operation::Stroke; use Graphics::Primitive::Paint::Gradient::Linear; use Graphics::Primitive::Paint::Solid; has '+additive' => ( default => 1 ); override('finalize', sub { my ($self) = @_; my $height = $self->height; my $width = $self->width; my $clicker = $self->clicker; my %accum; my $dses = $clicker->get_datasets_for_context($self->context); foreach my $ds (@{ $dses }) { foreach my $series (@{ $ds->series }) { # TODO if undef... my $ctx = $clicker->get_context($ds->context); my $domain = $ctx->domain_axis; my $range = $ctx->range_axis; my $lastx; # used for completing the path my @vals = @{ $series->values }; my @keys = @{ $series->keys }; my $startx; my $biggest; my @replays; for(0..($series->key_count - 1)) { my $key = $keys[$_]; my $x = $domain->mark($width, $key); next unless defined($x); my $val = $vals[$_]; if(exists($accum{$key})) { # Store the previous value push(@replays, [ $x, $accum{$key}]); # Add this value to the accumulator, then replace # it's value with the total $val = $accum{$key} += $val; } else { push(@replays, [ $x, 0 ]); $accum{$key} = $val; } my $ymark = $range->mark($height, $val); next unless defined($ymark); my $y = $height - $ymark; if(defined($biggest)) { $biggest = $y if $y > $biggest; } else { $biggest = $y; } if($_ == 0) { $startx = $x; $self->move_to($x, $y); } else { $self->line_to($x, $y); } $lastx = $x; } my $color = $self->clicker->color_allocator->next; my $op = Graphics::Primitive::Operation::Stroke->new; $op->preserve(1); $op->brush($self->brush->clone); $op->brush->color($color); $self->do($op); while(my $pt = pop(@replays)) { $self->line_to($pt->[0], $height - $range->mark($height, $pt->[1])); } $self->close_path; my $paint; if($self->opacity) { my $clone = $color->clone; $clone->alpha($self->opacity); $paint = Graphics::Primitive::Paint::Solid->new( color => $clone ); } elsif($self->fade) { my $clone = $color->clone; $clone->alpha($self->opacity); $paint = Graphics::Primitive::Paint::Gradient::Linear->new( line => Geometry::Primitive::Line->new( start => Geometry::Primitive::Point->new(x => 0, y => 0), end => Geometry::Primitive::Point->new(x => 1, y => $biggest), ), style => 'linear' ); $paint->add_stop(1.0, $color); $paint->add_stop(0, $clone); } else { $paint = Graphics::Primitive::Paint::Solid->new( color => $color->clone ); } my $fillop = Graphics::Primitive::Operation::Fill->new( paint => $paint ); $self->do($fillop); } } return 1; }); __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Renderer::StackedArea - Stacked Area renderer =head1 VERSION version 2.90 =head1 SYNOPSIS my $ar = Chart::Clicker::Renderer::StackedArea->new({ fade => 1, brush => Graphics::Primitive::Brush->new({ width => 2 }) }); =head1 DESCRIPTION Chart::Clicker::Renderer::StackedArea renders a dataset as line-like polygons stacked atop one another. =head1 NOTES Note that series with varying keys (e.g. Series 1 has keys 1, 2, 3 but Series 2 only has 1 and 3) will cause you some problems. Since the keys don't match up, neither will the accumulation of area. This may be addressed in the future. =for HTML

Stacked Area Chart

=head1 ATTRIBUTES =head2 brush Set/Get the brush that informs the line surrounding the area renders individual segments. =head2 fade Set/Get the fade flag, which turns on or off a gradient in the area renderer. =head2 opacity Set the alpha value for the renderer, which makes things more or less opaque. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Annotation.pm100644000765000024 1170413024411235 23467 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Decorationpackage Chart::Clicker::Decoration::Annotation; $Chart::Clicker::Decoration::Annotation::VERSION = '2.88'; use strict; use warnings; use Moose; use Graphics::Color::RGB; use Geometry::Primitive::Point; use Layout::Manager::Absolute; extends 'Chart::Clicker::Container'; has '+background_color' => ( default => sub { Graphics::Color::RGB->new( red => 1, green => 1, blue => 1, alpha => 1 ); }, ); has 'color' => ( is => 'rw', isa => 'Graphics::Color::RGB', default => sub { Graphics::Color::RGB->new( red => 0, green => 0, blue => 0, alpha => 1 ); }, ); has 'key' => ( is => 'rw', isa => 'Num', required => 1, ); has 'value' => ( is => 'rw', isa => 'Num', required => 1, ); has 'offset' => ( is => 'rw', isa => 'Geometry::Primitive::Point', default => sub { Geometry::Primitive::Point->new( x => 0, y => 0 ) } ); has 'text' => ( is => 'rw', isa => 'Str', required => 1 ); has 'context' => ( is => 'rw', isa => 'Str', required => 1 ); has 'font' => ( is => 'rw', isa => 'Graphics::Primitive::Font', default => sub { Graphics::Primitive::Font->new } ); has '+layout_manager' => ( ( default => sub { Layout::Manager::Absolute->new } ), ); override( 'prepare', sub { my ( $self, $driver ) = @_; my $tb = Graphics::Primitive::TextBox->new( text => $self->text, color => $self->color, font => $self->font, ); my $lay = $driver->get_textbox_layout($tb); $tb->width( $lay->width ); $tb->height( $lay->height ); $tb->origin->x( $self->border->left->width + $self->padding->left ); $tb->origin->y( $self->border->top->width + $self->padding->top ); $self->add_component( $tb, 'c' ); super; } ); override( 'finalize', sub { my ($self) = @_; my $ctx = $self->clicker->get_context( $self->context ); my $domain = $ctx->domain_axis; my $range = $ctx->range_axis; my $tb = $self->get_component(0); my $width = $tb->width + $self->border->left->width + $self->border->right->width + $self->padding->left + $self->padding->right; my $height = $tb->height + $self->border->top->width + $self->border->bottom->width + $self->padding->top + $self->padding->bottom; $self->minimum_width($width); $self->width($width); $self->minimum_height($height); $self->height($height); my $plot = $self->clicker->plot; my $render_area = $plot->render_area; $self->origin->x( ( $self->key - $domain->range->lower ) / ( $domain->range->upper - $domain->range->lower ) * $render_area->width + $self->offset->x ); $self->origin->y( ( $range->range->upper - $self->value ) / ( $range->range->upper - $range->range->lower ) * $render_area->height + $self->offset->y ); } ); __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Decoration::Annotation =head1 VERSION version 2.90 =head1 DESCRIPTION A text annotation that can be put over a chart. You can find an example of an Annotation at L. =head1 NAME Chart::Clicker::Decoration::Annotation - Text annotation over data =head1 VERSION version 2.88 =head1 ATTRIBUTES =head2 axis_height Set/Get the height of the OverAxis that will be drawn. =head2 background_color Set/Get the background L for this Annotation. =head2 color Set/Get the font L for this Annotation. =head2 context Set/Get the context that this Annotation should use. =head2 key Set/Get the x-axis value for the position of the Annotation. =head2 layout_manager The layout manager to use for this overaxis. Defaults to a L. =head2 offset Set/Get the L from (key,value) for the position of the Annotation. =head2 text Set/Get the Annotation text. =head2 value Set/Get the y-axis value for the position of the Annotation. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2014 by Cold Hard Code, LLC. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Drawing000755000765000024 013024411235 20140 5ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/ClickerColorAllocator.pm100644000765000024 1320713024411235 23600 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Drawingpackage Chart::Clicker::Drawing::ColorAllocator; $Chart::Clicker::Drawing::ColorAllocator::VERSION = '2.90'; use Moose; # ABSTRACT: Color picker use Graphics::Color::RGB; use Color::Scheme; has 'colors' => ( traits => [ 'Array' ], is => 'rw', isa => 'ArrayRef', default => sub { [] }, handles => { 'add_to_colors' => 'push', 'clear_colors' => 'clear', 'color_count' => 'count', 'get_color' => 'get' } ); has 'position' => ( is => 'rw', isa => 'Int', default => -1 ); has 'color_scheme' => ( is => 'rw', isa => 'Color::Scheme', lazy_build => 1, ); has 'seed_hue' => ( is => 'rw', isa => 'Int', required => 1, default => 270, ); has hues => ( is => 'rw', isa => 'ArrayRef', required => 1, lazy => 1, default => sub { my $seed = shift->seed_hue; [ map { ($seed + $_) % 360 } (0, 45, 75, 15, 60, 30) ] }, ); has shade_order => ( is => 'rw', isa => 'ArrayRef', required => 1, default => sub { [1, 3, 0, 2] }, ); sub _build_color_scheme { my $self = shift; my $scheme = Color::Scheme->new; $scheme->scheme('tetrade'); $scheme->web_safe(1); $scheme->distance(1); return $scheme; } sub next { my $self = shift; $self->position($self->position + 1); return $self->colors->[$self->position]; } # Before we attempt to get the next color, we'll instantiate it if we need it # that way we don't waste a bunch of memory with useless colors. before 'next' => sub { my $self = shift; my $pos = $self->position; if(!defined($self->colors->[$pos + 1])) { $self->add_to_colors($self->allocate_color); } }; sub allocate_color { my $self = shift; my $pos = $self->position + 1; my $scheme = $self->color_scheme; my $hue_cnt = @{ $self->hues }; my $hue_pos = int($pos / 4) % $hue_cnt; $scheme->from_hue($self->hues->[$hue_pos]); my $shade_pos = int($pos / ( $hue_cnt * 4)) % 4; my $shade_idx = $self->shade_order->[$shade_pos]; my $color_idx = $pos % 4; my $color_hex = $scheme->colorset->[$color_idx]->[$shade_idx]; my ($r,$g,$b) = ( map{ hex } ($color_hex =~ /(..)(..)(..)/)); my $color = Graphics::Color::RGB->new( red => $r / 255, green => $g / 255, blue => $b / 255, alpha => 1, ) } sub reset { my $self = shift; $self->position(-1); return 1; } __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Drawing::ColorAllocator - Color picker =head1 VERSION version 2.90 =head1 SYNOPSIS use Graphics::Color::RGB; use Chart::Clicker::Drawing::ColorAllocator; my $ca = Chart::Clicker::Drawing::ColorAllocator->new({ colors => [ Graphics::Color::RGB->new( red => 1.0, green => 0, blue => 0, alpha => 1.0 ), #... ] }); my $red = $ca->get(0); #or let Chart::Clicker autmatically pick complementing colors for you my $ca2 = Chart::Clicker::Drawing::ColorAllocator->new({ seed_hue => 0, #red }); =head1 DESCRIPTION Allocates colors for use in the chart. The position in the color allocator corresponds to the series that will be colored. =head1 AUTOMATIC COLOR ALLOCATION This module has the capacity to automatically allocate 96 individual colors using L. It does so by picking 4 hues equally spaced in the color wheel from the C (0 (red) would be complimented by 270 (blue), 180 (green) and 90 (yellow)). After those colors are allocated it moves on to picking from the colors between those ( 45, 135, 215, 305 ) etc. Once all values of C have been utilized, it repeats them using a different shade. This has the effect of generating evenly spaced complementing colors to ensure colors are well ditinguishable from one another and have appropriate contrast. =head2 position Gets the current position. =head1 ATTRIBUTES =head2 colors An arrayref of colors that will be used for series that Clicker draws. =head2 color_scheme A lazy-building L object used to generate the color scheme of the chart; =head2 seed_hue The interger value of the first hue used when computing the tetrade color scheme. Setting this will affect the hue of the first color allocated. Subsequent colors will be allocated based on their distance from this color to maintain sifficient contrast between colors. If not specified the seed_hue will default to 270, blue. =head2 hues An array reference of evenly spaced seed hues for color allocation. By default it will use the seed hue plus 0, 45, 75, 15, 60 and 30 which is enough to cover all web-safe colors when using a tetrade color scheme. =head2 shade_order An array reference of the order in which the different shades of each color will be used for every color scheme generated. It defaults to 1, 3, 0, 2 for optimum color spacing. =head1 METHODS =head2 add_to_colors Add a color to this allocator. =head2 clear_colors Clear this allocator's colors =head2 color_count Get the number of colors in this allocator. =head2 get_color ($index) Gets the color at the specified index. Returns undef if that position has no color. =head2 next Returns the next color. Each call to next increments the position, so subsequent calls will return different colors. =head2 allocate_color Determines what the next color should be. =head2 reset Resets this allocator back to the beginning. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut DivisionType000755000765000024 013024411235 22077 5ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/AxisExact.pm100644000765000024 307413024411235 23645 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Axis/DivisionTypepackage Chart::Clicker::Axis::DivisionType::Exact; $Chart::Clicker::Axis::DivisionType::Exact::VERSION = '2.90'; use Moose::Role; with qw{Chart::Clicker::Axis::DivisionType}; sub best_tick_size { my ($self) = @_; return $self->range->span / ( $self->ticks - 1 ); } sub _real_divvy { my ($self) = @_; my $per = $self->best_tick_size; my @vals; for ( 0 .. ( $self->ticks - 1 ) ) { push( @vals, $self->range->lower + ( $_ * $per ) ); } return \@vals; } no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Axis::DivisionType::Exact =head1 VERSION version 2.90 =head1 SYNOPSIS use Chart::Clicker::Axis; my $axis = Chart::Clicker::Axis->new({ tick_division_type => 'Exact' }); =head1 DESCRIPTION Role describing how to divide data for Chart::Clicker::Axis. =head1 NAME Chart::Clicker::Axis::DivisionType::Exact - Divide axis in exact increments, linear scale. =head1 METHODS =head2 best_tick_size The tick division calculated by taking the range and dividing by the requested number of ticks. =head2 divvy Divides the range up into exact division for L. =head1 AUTHOR Rod Taylor =head1 SEE ALSO perl(1) =head1 LICENSE You can redistribute and/or modify this code under the same terms as Perl itself. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut MarkerOverlay.pm100644000765000024 703413024411235 24121 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Decorationpackage Chart::Clicker::Decoration::MarkerOverlay; $Chart::Clicker::Decoration::MarkerOverlay::VERSION = '2.90'; use Moose; extends 'Chart::Clicker::Decoration'; # ABSTRACT: Component for drawing markers use Graphics::Primitive::Operation::Stroke; use Graphics::Primitive::Operation::Fill; use Graphics::Primitive::Paint::Solid; override('finalize', sub { my ($self) = @_; my $width = $self->width; my $height = $self->height; my $clicker = $self->clicker; foreach my $cname ($clicker->context_names) { my $ctx = $clicker->get_context($cname); foreach my $marker (@{ $ctx->markers }) { my $key = $marker->key; my $value = $marker->value; if(not defined($value)) { my $key2 = $marker->key2; my $domain = $ctx->domain_axis; my $x = $domain->mark($self->width, $key); my $x2; if($key2) { $x2 = $domain->mark($self->width, $key2); $self->move_to($x, 0); $self->rectangle(($x2 - $x), $height); my $fillop = Graphics::Primitive::Operation::Fill->new( paint => Graphics::Primitive::Paint::Solid->new( color => $marker->inside_color ), ); $self->do($fillop); } $self->move_to($x, 0); $self->rel_line_to(0, $height); if($x2) { $self->move_to($x2, 0); $self->rel_line_to(0, $height); } my $op = Graphics::Primitive::Operation::Stroke->new; $op->brush($marker->brush); $op->brush->color($marker->color); $self->do($op); } elsif(not defined($key)) { my $value2 = $marker->value2; my $range = $ctx->range_axis; # my $y = $height - $range->mark($height, $value); my $y2; if($value2) { $y2 = $height - $range->mark($self->height, $value2); $self->move_to(0, $y); $self->rectangle($width, ($y2 - $y)); my $fillop = Graphics::Primitive::Operation::Fill->new( paint => Graphics::Primitive::Paint::Solid->new( color => $marker->inside_color ), ); $self->do($fillop); } $self->move_to(0, $y); $self->rel_line_to($width, 0); if($y2) { $self->move_to(0, $y2); $self->rel_line_to($width, 0); } my $op = Graphics::Primitive::Operation::Stroke->new; $op->brush($marker->brush); $op->brush->color($marker->color); $self->do($op); } } } }); __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Decoration::MarkerOverlay - Component for drawing markers =head1 VERSION version 2.90 =head1 DESCRIPTION A Component that handles the rendering of Markers. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut Legend000755000765000024 013024411235 22032 5ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/DecorationTabular.pm100644000765000024 1405313024411235 24145 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Decoration/Legendpackage Chart::Clicker::Decoration::Legend::Tabular; $Chart::Clicker::Decoration::Legend::Tabular::VERSION = '2.90'; use Moose; extends 'Chart::Clicker::Decoration::Legend'; # ABSTRACT: Tabular version of Legend use Graphics::Primitive::Font; use Graphics::Primitive::Insets; use Graphics::Primitive::TextBox; use Graphics::Color::RGB; use Layout::Manager::Grid; has '+border' => ( default => sub { my $b = Graphics::Primitive::Border->new; $b->color(Graphics::Color::RGB->new( red => 0, green => 0, blue => 0)); $b->width(1); return $b; } ); has '+color' => ( default => sub { Graphics::Color::RGB->new( red => 0, green => 0, blue => 0) } ); has 'data' => ( is => 'rw', isa => 'ArrayRef[ArrayRef[Str]]', required => 1 ); has 'font' => ( is => 'rw', isa => 'Graphics::Primitive::Font', default => sub { Graphics::Primitive::Font->new } ); has 'header' => ( is => 'rw', isa => 'ArrayRef[Str]', predicate => 'has_header' ); has 'item_padding' => ( is => 'rw', isa => 'Graphics::Primitive::Insets', default => sub { Graphics::Primitive::Insets->new({ top => 3, left => 3, bottom => 3, right => 5 }) } ); has '+layout_manager' => ( default => sub { my $self = shift; my $header_rows = $self->has_header ? 1 : 0; return Layout::Manager::Grid->new( rows => scalar(@{ $self->data }) + $header_rows, columns => scalar(@{ $self->data->[0] }) + 1 ); }, lazy => 1 ); override('prepare', sub { my ($self, $driver) = @_; return if $self->component_count > 0; my $ca = $self->clicker->color_allocator; my $font = $self->font; my $ii = $self->item_padding; if($self->is_vertical) { # This assumes you aren't changing the layout manager... $self->layout_manager->anchor('north'); } my $row_offset = 0; if($self->has_header) { $row_offset = 1; my $count = 0; # foreach my $d (@{ $self->header }) { for(0..scalar(@{ $self->header }) - 1) { $self->add_component( Graphics::Primitive::TextBox->new( color => $self->color, font => $font, padding => $ii, text => $self->header->[$_] ), { row => 0, column => $_ } ); $count++; } } my @data = @{ $self->data }; my $count = 0; foreach my $ds (@{ $self->clicker->datasets }) { foreach my $s (@{ $ds->series }) { my $color = $ca->next; unless($s->has_name) { $s->name("Series $count"); } my $tb = Graphics::Primitive::TextBox->new( color => $color, font => $font, padding => $ii, text => $s->name ); $self->add_component($tb, { row => $count + $row_offset, column => 0 }); for(0..scalar(@{ $data[$count] }) - 1) { $self->add_component( Graphics::Primitive::TextBox->new( color => $color, font => $font, padding => $ii, text => $data[$count]->[$_] ), { row => $count + $row_offset, column => $_ + 1 } ); } $count++; } } super; $ca->reset; }); __PACKAGE__->meta->make_immutable; no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Decoration::Legend::Tabular - Tabular version of Legend =head1 VERSION version 2.90 =head1 SYNOPSIS my $cc = Chart::Clicker->new; my $series1 = Chart::Clicker::Data::Series->new; my $series2 = Chart::Clicker::Data::Series->new; $cc->legend(Chart::Clicker::Decoration::Legend::Tabular->new( header => [ qw(Name Min Max) ], data => [ [ min(@{ $series1->values }), max(@{ $series1->values }) ], [ min(@{ $series2->values }), max(@{ $series2->values }) ] ] )); =head1 DESCRIPTION Chart::Clicker::Decoration::Legend::Tabular draws a legend on a Chart with tabular data display. The Tabular legend is a legend with a few extra attributes that allow you to pass it data to display. The attributes are c
and c. The C
(optional) allows you to specify the strings to display at the top of the table and the C attribute allows you to pass in arrayrefs of strings for display aside each of the series. B: The first string in the C
arrayref should be the header for the column above the name of the series. This code does not do anything to verify that you've given the appropriate counts of data. It is expected that you will provide C with one arrayref for every series, each containing n elements. Having that, C
will expect n + 1 elements with one for the series name and the remaining (n) matching the number of elements in each of C's arrayrefs. =head1 ATTRIBUTES =head2 border Set/Get this Legend's L. =head2 color Set/Get the L to use as the foreground for the legend. =head2 data Set/Get the data for this legend. Expects an arrayref of arrayrefs, with one inner arrayref for every series charted. =head2 font Set/Get the L used for this legend's items. =head2 header Set/Get the header data used for this legend. Expects an arrayref of Strings. =head2 insets Set/Get this Legend's insets. =head2 item_padding Set/Get the L for this legend's items. =head1 METHODS =head2 has_header Predicate returning true of this legend has a header, else 1. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut LinearRounded.pm100644000765000024 1133113024411235 25347 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Axis/DivisionTypepackage Chart::Clicker::Axis::DivisionType::LinearRounded; $Chart::Clicker::Axis::DivisionType::LinearRounded::VERSION = '2.90'; use Moose::Role; with qw{Chart::Clicker::Axis::DivisionType}; # Positive only has 'tick_slop' => ( is => 'rw', isa => 'Num', default => 0.1, documentation => q{Percent of a tick unit above or below graphed which we allow inserting an additional tick. Whitespace allowance above or below.} ); # Take the rough tick size which is the smallest possible 'round' scale # and use other sub-divisors to aim for the number of ticks specified. sub best_tick_size { my ($self) = @_; my $minimum_target_ticks = $self->ticks; $minimum_target_ticks = 1 if ( $minimum_target_ticks < 1 ); my $equal_tick_size = $self->range->span / ($minimum_target_ticks); # Provide a nice round divisor which is within an order of # magnitude of the actual wanted tick size. We adjust # this value using hand specified sub-divider values # # Small ranges (below 1) require an additional digit my $digits = int( log( abs($equal_tick_size) ) / log(10) ); $digits-- if ( abs( $self->range->span ) < 1 ); my $scale_size = 10**$digits; # Take the largest divider (smallest number of ticks) which will provide # a nice looking result. The below dividers were selected arbitrarily to # create visually pleasing numbers for an axis. # # The number of ticks will be equal to or larger than the requested number # of ticks. Never smaller. The worst case is the 1 to 2 range which may # provide nearly double (2N - 1) the number of requested ticks. ADJUSTSCALE: for my $scale_divider ( 25, 20, 10, 5, 4, 2.5, 2, 1 ) { my $test_scale = $scale_divider * $scale_size; if ( $self->range->span / $test_scale >= $minimum_target_ticks ) { $scale_size = $test_scale; last ADJUSTSCALE; } } return $scale_size; } sub _real_divvy { my ($self) = @_; my $tickSize = $self->best_tick_size; my $range = $self->range; # If the lowest value is nearby to the first tick below it (gap # at front of graph would be low) then use that as the starting # value; otherwise choose the first tick value above the lowest. my $lowestTick = int( $range->lower() / $tickSize ) * $tickSize; my $lowestValue = $range->lower(); my $lowTickDifference = $lowestValue - $lowestTick; if ( $lowTickDifference > $self->tick_slop * $tickSize ) { $lowestTick = $lowestTick + $tickSize; } if ( $lowestTick < $lowestValue ) { $lowestValue = $lowestTick; } $range->lower($lowestValue); my @vals; push( @vals, $lowestTick ); # Loop until upper from the starting point my $lastTick = $lowestTick; while ( $range->upper - $tickSize > $lastTick ) { $lastTick = $lastTick + $tickSize; push( @vals, $lastTick ); } # If the upper value is nearby to the last tick above it # (gap at end of graph would be low) then use that as the # ending value; otherwise use the tick value immediately before # the upper value. my $potentialUpperTick = $lastTick + $tickSize; if ( $potentialUpperTick - $range->upper < $self->tick_slop * $tickSize ) { $range->upper($potentialUpperTick); push( @vals, $potentialUpperTick ); } return \@vals; } no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Axis::DivisionType::LinearRounded =head1 VERSION version 2.90 =head1 SYNOPSIS use Chart::Clicker::Axis; my $axis = Chart::Clicker::Axis->new({ tick_division_type => 'LinearRounded' }); =head1 DESCRIPTION Role describing how to divide data for Chart::Clicker::Axis. =head1 NAME Chart::Clicker::Axis::DivisionType::LinearRounded - Nicely rounded segments on a linear scale. =head1 ATTRIBUTES =head2 tick_slop This setting determines whether to add a tick outside of the data. If the tick would be within the percentage of a ticks size specified here as a decimal (10% would be 0.1), then the tick will be added expanding the graph. =head1 METHODS =head2 best_tick_size The tick division considered best for the approximate number of ticks requested and data within the range. =head2 divvy Divides the range up into nicely rounded chunks for L. =head1 AUTHOR Rod Taylor =head1 SEE ALSO perl(1) =head1 LICENSE You can redistribute and/or modify this code under the same terms as Perl itself. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut LinearExpandGraph.pm100644000765000024 613213024411235 26133 0ustar00gphatstaff000000000000Chart-Clicker-2.90/lib/Chart/Clicker/Axis/DivisionTypepackage Chart::Clicker::Axis::DivisionType::LinearExpandGraph; $Chart::Clicker::Axis::DivisionType::LinearExpandGraph::VERSION = '2.90'; use Moose::Role; with qw{Chart::Clicker::Axis::DivisionType}; use POSIX qw(ceil floor); # Positive only has 'tick_slop' => ( is => 'rw', isa => 'Num', default => 0.1, documentation => q{Percent of a tick unit above or below graphed which we allow inserting an additional tick. Whitespace allowance above or below.} ); sub _real_divvy { my ($self) = @_; my $n = $self->ticks; my $min = $self->range->lower; my $max = $self->range->upper; my $range = _nicenum($self->range->span, 0); my $d = _nicenum($range / ($n - 1), 1); my $graphmin = $min; my $graphmax = $max; # Expand the graph as needed $graphmin = floor($min / $d) * $d; $self->range->min($graphmin); $graphmax = ceil($max / $d) * $d; $self->range->max($graphmax); my $x = $graphmin; my @ticks; do { push(@ticks, $x); $x += .5 * $d; } while($x < $graphmax); return \@ticks; } sub _nicenum { my ($num, $round) = @_; my $exp = floor(_log10($num)); my $f = $num / (10 ** $exp); my $nice; if($round) { if($f < 1.5) { $nice = 1.5; } elsif($f < 3) { $nice = 2; } elsif($f < 7) { $nice = 5; } else { $nice = 10; } } else { if($f <= 1) { $nice = 1; } elsif($f <= 2) { $nice = 2; } elsif($f <= 5) { $nice = 5; } else { $nice = 10; } } return $nice * (10 ** $exp); } sub _log10 { my $n = shift; return log($n) / log(10); } no Moose; 1; __END__ =pod =head1 NAME Chart::Clicker::Axis::DivisionType::LinearExpandGraph =head1 VERSION version 2.90 =head1 SYNOPSIS use Chart::Clicker::Axis; my $axis = Chart::Clicker::Axis->new({ tick_division_type => 'LinearRounded' }); =head1 DESCRIPTION Role describing how to divide data for Chart::Clicker::Axis. =head1 NAME Chart::Clicker::Axis::DivisionType::LinearRounded - Nicely rounded segments on a linear scale. =head1 ATTRIBUTES =head2 tick_slop This setting determines whether to add a tick outside of the data. If the tick would be within the percentage of a ticks size specified here as a decimal (10% would be 0.1), then the tick will be added expanding the graph. =head1 METHODS =head2 best_tick_size The tick division considered best for the approximate number of ticks requested and data within the range. =head2 divvy Divides the range up into nicely rounded chunks for L. =head1 AUTHOR Rod Taylor =head1 SEE ALSO perl(1) =head1 LICENSE You can redistribute and/or modify this code under the same terms as Perl itself. =head1 AUTHOR Cory G Watson =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2016 by Cory G Watson. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut