├── LICENSE.txt
├── README.md
├── index.html
├── lib
├── jasmine-1.0.1
│ ├── jasmine-html.js
│ ├── jasmine.css
│ └── jasmine.js
├── lodash.underscore.min.js
└── protovis-3.2
│ ├── LICENSE
│ ├── MIT.LICENSE
│ ├── README
│ ├── examples
│ ├── antibiotics
│ │ ├── antibiotics-scatter.html
│ │ ├── antibiotics.html
│ │ └── antibiotics.js
│ ├── barley
│ │ ├── barley.html
│ │ └── barley.js
│ ├── cars
│ │ ├── cars.html
│ │ └── cars.js
│ └── crimea
│ │ ├── crimea-grouped-bar.html
│ │ ├── crimea-line.html
│ │ ├── crimea-stacked-area.html
│ │ ├── crimea-stacked-bar.html
│ │ ├── crimea.html
│ │ └── crimea.js
│ ├── jsdoc
│ ├── files.html
│ ├── index.html
│ └── symbols
│ │ ├── Array.html
│ │ ├── _global_.html
│ │ ├── pv.Anchor.html
│ │ ├── pv.Area.html
│ │ ├── pv.Bar.html
│ │ ├── pv.Behavior.drag.html
│ │ ├── pv.Behavior.html
│ │ ├── pv.Behavior.pan.html
│ │ ├── pv.Behavior.point.html
│ │ ├── pv.Behavior.resize.html
│ │ ├── pv.Behavior.select.html
│ │ ├── pv.Behavior.zoom.html
│ │ ├── pv.Color.Hsl.html
│ │ ├── pv.Color.Rgb.html
│ │ ├── pv.Color.html
│ │ ├── pv.Colors.html
│ │ ├── pv.Constraint.bound.html
│ │ ├── pv.Constraint.collision.html
│ │ ├── pv.Constraint.html
│ │ ├── pv.Constraint.position.html
│ │ ├── pv.Dom.Node.html
│ │ ├── pv.Dom.html
│ │ ├── pv.Dot.html
│ │ ├── pv.Flatten.html
│ │ ├── pv.Force.charge.html
│ │ ├── pv.Force.drag.html
│ │ ├── pv.Force.html
│ │ ├── pv.Force.spring.html
│ │ ├── pv.Format.date.html
│ │ ├── pv.Format.html
│ │ ├── pv.Format.number.html
│ │ ├── pv.Format.time.html
│ │ ├── pv.Geo.LatLng.html
│ │ ├── pv.Geo.Projection.html
│ │ ├── pv.Geo.projections.html
│ │ ├── pv.Geo.scale#ticks.html
│ │ ├── pv.Geo.scale.html
│ │ ├── pv.Image.html
│ │ ├── pv.Label.html
│ │ ├── pv.Layout.Arc.html
│ │ ├── pv.Layout.Bullet.html
│ │ ├── pv.Layout.Cluster.Fill.html
│ │ ├── pv.Layout.Cluster.html
│ │ ├── pv.Layout.Force.html
│ │ ├── pv.Layout.Grid.html
│ │ ├── pv.Layout.Hierarchy.html
│ │ ├── pv.Layout.Horizon.html
│ │ ├── pv.Layout.Indent.html
│ │ ├── pv.Layout.Matrix.html
│ │ ├── pv.Layout.Network.Link.html
│ │ ├── pv.Layout.Network.Node.html
│ │ ├── pv.Layout.Network.html
│ │ ├── pv.Layout.Pack.html
│ │ ├── pv.Layout.Partition.Fill.html
│ │ ├── pv.Layout.Partition.html
│ │ ├── pv.Layout.Rollup.html
│ │ ├── pv.Layout.Stack.html
│ │ ├── pv.Layout.Tree.html
│ │ ├── pv.Layout.Treemap.html
│ │ ├── pv.Layout.html
│ │ ├── pv.Line.html
│ │ ├── pv.Mark.html
│ │ ├── pv.Nest.html
│ │ ├── pv.Panel.html
│ │ ├── pv.Particle.html
│ │ ├── pv.Quadtree.Node.html
│ │ ├── pv.Quadtree.html
│ │ ├── pv.Rule.html
│ │ ├── pv.Scale.html
│ │ ├── pv.Scale.linear.html
│ │ ├── pv.Scale.log.html
│ │ ├── pv.Scale.ordinal.html
│ │ ├── pv.Scale.quantile.html
│ │ ├── pv.Scale.quantitative.html
│ │ ├── pv.Scale.root.html
│ │ ├── pv.Simulation.html
│ │ ├── pv.Transform.html
│ │ ├── pv.Tree.html
│ │ ├── pv.Vector.html
│ │ ├── pv.Wedge.html
│ │ ├── pv.histogram.Bin.html
│ │ ├── pv.histogram.html
│ │ ├── pv.html
│ │ ├── pv.version.html
│ │ └── src
│ │ ├── src_behavior_Behavior.js.html
│ │ ├── src_behavior_Drag.js.html
│ │ ├── src_behavior_Pan.js.html
│ │ ├── src_behavior_Point.js.html
│ │ ├── src_behavior_Resize.js.html
│ │ ├── src_behavior_Select.js.html
│ │ ├── src_behavior_Zoom.js.html
│ │ ├── src_color_Color.js.html
│ │ ├── src_color_Colors.js.html
│ │ ├── src_color_Ramp.js.html
│ │ ├── src_data_Arrays.js.html
│ │ ├── src_data_Dom.js.html
│ │ ├── src_data_Flatten.js.html
│ │ ├── src_data_Histogram.js.html
│ │ ├── src_data_LinearScale.js.html
│ │ ├── src_data_LogScale.js.html
│ │ ├── src_data_Nest.js.html
│ │ ├── src_data_Numbers.js.html
│ │ ├── src_data_Objects.js.html
│ │ ├── src_data_OrdinalScale.js.html
│ │ ├── src_data_QuantileScale.js.html
│ │ ├── src_data_QuantitativeScale.js.html
│ │ ├── src_data_RootScale.js.html
│ │ ├── src_data_Scale.js.html
│ │ ├── src_data_Transform.js.html
│ │ ├── src_data_Tree.js.html
│ │ ├── src_data_Vector.js.html
│ │ ├── src_geo_Geo.js.html
│ │ ├── src_geo_GeoScale.js.html
│ │ ├── src_geo_LatLng.js.html
│ │ ├── src_geo_Projection.js.html
│ │ ├── src_geo_Projections.js.html
│ │ ├── src_lang_Array.js.html
│ │ ├── src_lang_init.js.html
│ │ ├── src_layout_Arc.js.html
│ │ ├── src_layout_Bullet.js.html
│ │ ├── src_layout_Cluster.js.html
│ │ ├── src_layout_Force.js.html
│ │ ├── src_layout_Grid.js.html
│ │ ├── src_layout_Hierarchy.js.html
│ │ ├── src_layout_Horizon.js.html
│ │ ├── src_layout_Indent.js.html
│ │ ├── src_layout_Layout.js.html
│ │ ├── src_layout_Matrix.js.html
│ │ ├── src_layout_Network.js.html
│ │ ├── src_layout_Pack.js.html
│ │ ├── src_layout_Partition.js.html
│ │ ├── src_layout_Rollup.js.html
│ │ ├── src_layout_Stack.js.html
│ │ ├── src_layout_Tree.js.html
│ │ ├── src_layout_Treemap.js.html
│ │ ├── src_mark_Anchor.js.html
│ │ ├── src_mark_Area.js.html
│ │ ├── src_mark_Bar.js.html
│ │ ├── src_mark_Dot.js.html
│ │ ├── src_mark_Image.js.html
│ │ ├── src_mark_Label.js.html
│ │ ├── src_mark_Line.js.html
│ │ ├── src_mark_Mark.js.html
│ │ ├── src_mark_Panel.js.html
│ │ ├── src_mark_Rule.js.html
│ │ ├── src_mark_Wedge.js.html
│ │ ├── src_physics_BoundConstraint.js.html
│ │ ├── src_physics_ChargeForce.js.html
│ │ ├── src_physics_CollisionConstraint.js.html
│ │ ├── src_physics_Constraint.js.html
│ │ ├── src_physics_DragForce.js.html
│ │ ├── src_physics_Force.js.html
│ │ ├── src_physics_Particle.js.html
│ │ ├── src_physics_PositionConstraint.js.html
│ │ ├── src_physics_Quadtree.js.html
│ │ ├── src_physics_Simulation.js.html
│ │ ├── src_physics_SpringForce.js.html
│ │ ├── src_pv-internals.js.html
│ │ ├── src_pv.js.html
│ │ ├── src_scene_SvgArea.js.html
│ │ ├── src_scene_SvgBar.js.html
│ │ ├── src_scene_SvgCurve.js.html
│ │ ├── src_scene_SvgDot.js.html
│ │ ├── src_scene_SvgImage.js.html
│ │ ├── src_scene_SvgLabel.js.html
│ │ ├── src_scene_SvgLine.js.html
│ │ ├── src_scene_SvgPanel.js.html
│ │ ├── src_scene_SvgRule.js.html
│ │ ├── src_scene_SvgScene.js.html
│ │ ├── src_scene_SvgWedge.js.html
│ │ ├── src_text_DateFormat.js.html
│ │ ├── src_text_Format.js.html
│ │ ├── src_text_NumberFormat.js.html
│ │ └── src_text_TimeFormat.js.html
│ ├── protovis-d3.2.js
│ └── protovis-r3.2.js
├── radar.js
├── radar_test.html
├── radars
├── radarData.js
└── thoughtworks_tech_radar_aug_2010.js
├── techradar_example.pdf
├── techradar_example.png
├── utils.js
└── utils_test.js
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction, and
10 | distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright
13 | owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all other entities
16 | that control, are controlled by, or are under common control with that entity.
17 | For the purposes of this definition, "control" means (i) the power, direct or
18 | indirect, to cause the direction or management of such entity, whether by
19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
20 | outstanding shares, or (iii) beneficial ownership of such entity.
21 |
22 | "You" (or "Your") shall mean an individual or Legal Entity exercising
23 | permissions granted by this License.
24 |
25 | "Source" form shall mean the preferred form for making modifications, including
26 | but not limited to software source code, documentation source, and configuration
27 | files.
28 |
29 | "Object" form shall mean any form resulting from mechanical transformation or
30 | translation of a Source form, including but not limited to compiled object code,
31 | generated documentation, and conversions to other media types.
32 |
33 | "Work" shall mean the work of authorship, whether in Source or Object form, made
34 | available under the License, as indicated by a copyright notice that is included
35 | in or attached to the work (an example is provided in the Appendix below).
36 |
37 | "Derivative Works" shall mean any work, whether in Source or Object form, that
38 | is based on (or derived from) the Work and for which the editorial revisions,
39 | annotations, elaborations, or other modifications represent, as a whole, an
40 | original work of authorship. For the purposes of this License, Derivative Works
41 | shall not include works that remain separable from, or merely link (or bind by
42 | name) to the interfaces of, the Work and Derivative Works thereof.
43 |
44 | "Contribution" shall mean any work of authorship, including the original version
45 | of the Work and any modifications or additions to that Work or Derivative Works
46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work
47 | by the copyright owner or by an individual or Legal Entity authorized to submit
48 | on behalf of the copyright owner. For the purposes of this definition,
49 | "submitted" means any form of electronic, verbal, or written communication sent
50 | to the Licensor or its representatives, including but not limited to
51 | communication on electronic mailing lists, source code control systems, and
52 | issue tracking systems that are managed by, or on behalf of, the Licensor for
53 | the purpose of discussing and improving the Work, but excluding communication
54 | that is conspicuously marked or otherwise designated in writing by the copyright
55 | owner as "Not a Contribution."
56 |
57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf
58 | of whom a Contribution has been received by Licensor and subsequently
59 | incorporated within the Work.
60 |
61 | 2. Grant of Copyright License.
62 |
63 | Subject to the terms and conditions of this License, each Contributor hereby
64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
65 | irrevocable copyright license to reproduce, prepare Derivative Works of,
66 | publicly display, publicly perform, sublicense, and distribute the Work and such
67 | Derivative Works in Source or Object form.
68 |
69 | 3. Grant of Patent License.
70 |
71 | Subject to the terms and conditions of this License, each Contributor hereby
72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
73 | irrevocable (except as stated in this section) patent license to make, have
74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where
75 | such license applies only to those patent claims licensable by such Contributor
76 | that are necessarily infringed by their Contribution(s) alone or by combination
77 | of their Contribution(s) with the Work to which such Contribution(s) was
78 | submitted. If You institute patent litigation against any entity (including a
79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a
80 | Contribution incorporated within the Work constitutes direct or contributory
81 | patent infringement, then any patent licenses granted to You under this License
82 | for that Work shall terminate as of the date such litigation is filed.
83 |
84 | 4. Redistribution.
85 |
86 | You may reproduce and distribute copies of the Work or Derivative Works thereof
87 | in any medium, with or without modifications, and in Source or Object form,
88 | provided that You meet the following conditions:
89 |
90 | You must give any other recipients of the Work or Derivative Works a copy of
91 | this License; and
92 | You must cause any modified files to carry prominent notices stating that You
93 | changed the files; and
94 | You must retain, in the Source form of any Derivative Works that You distribute,
95 | all copyright, patent, trademark, and attribution notices from the Source form
96 | of the Work, excluding those notices that do not pertain to any part of the
97 | Derivative Works; and
98 | If the Work includes a "NOTICE" text file as part of its distribution, then any
99 | Derivative Works that You distribute must include a readable copy of the
100 | attribution notices contained within such NOTICE file, excluding those notices
101 | that do not pertain to any part of the Derivative Works, in at least one of the
102 | following places: within a NOTICE text file distributed as part of the
103 | Derivative Works; within the Source form or documentation, if provided along
104 | with the Derivative Works; or, within a display generated by the Derivative
105 | Works, if and wherever such third-party notices normally appear. The contents of
106 | the NOTICE file are for informational purposes only and do not modify the
107 | License. You may add Your own attribution notices within Derivative Works that
108 | You distribute, alongside or as an addendum to the NOTICE text from the Work,
109 | provided that such additional attribution notices cannot be construed as
110 | modifying the License.
111 | You may add Your own copyright statement to Your modifications and may provide
112 | additional or different license terms and conditions for use, reproduction, or
113 | distribution of Your modifications, or for any such Derivative Works as a whole,
114 | provided Your use, reproduction, and distribution of the Work otherwise complies
115 | with the conditions stated in this License.
116 |
117 | 5. Submission of Contributions.
118 |
119 | Unless You explicitly state otherwise, any Contribution intentionally submitted
120 | for inclusion in the Work by You to the Licensor shall be under the terms and
121 | conditions of this License, without any additional terms or conditions.
122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of
123 | any separate license agreement you may have executed with Licensor regarding
124 | such Contributions.
125 |
126 | 6. Trademarks.
127 |
128 | This License does not grant permission to use the trade names, trademarks,
129 | service marks, or product names of the Licensor, except as required for
130 | reasonable and customary use in describing the origin of the Work and
131 | reproducing the content of the NOTICE file.
132 |
133 | 7. Disclaimer of Warranty.
134 |
135 | Unless required by applicable law or agreed to in writing, Licensor provides the
136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
138 | including, without limitation, any warranties or conditions of TITLE,
139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
140 | solely responsible for determining the appropriateness of using or
141 | redistributing the Work and assume any risks associated with Your exercise of
142 | permissions under this License.
143 |
144 | 8. Limitation of Liability.
145 |
146 | In no event and under no legal theory, whether in tort (including negligence),
147 | contract, or otherwise, unless required by applicable law (such as deliberate
148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be
149 | liable to You for damages, including any direct, indirect, special, incidental,
150 | or consequential damages of any character arising as a result of this License or
151 | out of the use or inability to use the Work (including but not limited to
152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or
153 | any and all other commercial damages or losses), even if such Contributor has
154 | been advised of the possibility of such damages.
155 |
156 | 9. Accepting Warranty or Additional Liability.
157 |
158 | While redistributing the Work or Derivative Works thereof, You may choose to
159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or
160 | other liability obligations and/or rights consistent with this License. However,
161 | in accepting such obligations, You may act only on Your own behalf and on Your
162 | sole responsibility, not on behalf of any other Contributor, and only if You
163 | agree to indemnify, defend, and hold each Contributor harmless for any liability
164 | incurred by, or claims asserted against, such Contributor by reason of your
165 | accepting any such warranty or additional liability.
166 |
167 | END OF TERMS AND CONDITIONS
168 |
169 | APPENDIX: How to apply the Apache License to your work
170 |
171 | To apply the Apache License to your work, attach the following boilerplate
172 | notice, with the fields enclosed by brackets "[]" replaced with your own
173 | identifying information. (Don't include the brackets!) The text should be
174 | enclosed in the appropriate comment syntax for the file format. We also
175 | recommend that a file or class name and description of purpose be included on
176 | the same "printed page" as the copyright notice for easier identification within
177 | third-party archives.
178 |
179 | Copyright [yyyy] [name of copyright owner]
180 |
181 | Licensed under the Apache License, Version 2.0 (the "License");
182 | you may not use this file except in compliance with the License.
183 | You may obtain a copy of the License at
184 |
185 | http://www.apache.org/licenses/LICENSE-2.0
186 |
187 | Unless required by applicable law or agreed to in writing, software
188 | distributed under the License is distributed on an "AS IS" BASIS,
189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
190 | See the License for the specific language governing permissions and
191 | limitations under the License.
192 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Build Your Own Technology Radar.
2 |
3 | Inspired by the ThoughtWorks Tech Radar: http://www.thoughtworks.com/radar/.
4 |
5 | I love the ThoughtWorks Radar. But it is for all clients, averaged out across industries, organisational maturity and risk adverseness.
6 |
7 | 
8 |
9 | It is a powerful talking point, but I need it to be customised for particular circumstances.
10 |
11 | This Technology Radar has pretty simple functionality, uses json data source and renders SVG within html.
12 |
13 | The data currently is provided in a radial format. I chose this and SVG, for the scalable properties. In practice, a table based structure, that automatically lays out the points could be more useful.
14 |
15 | Eg. {name:'Cool Tech', r:50, t:30}
16 | Appears in the Top Right Quadrant, in the inner most "Adopt" Sector.
17 |
18 | Eg. {name:'Bright Shiny Toy 5', r:390, t:30}
19 | Appears in the Top Right Quadrant, in the outer most "Hold" Sector.
20 |
21 | Appears in the Lower Left Quadrant, in the second "Trial" Sector.
22 |
23 | Where r = radius, and t = theta; the degrees in radians. with 0/360 degrees being the typical right hand x line rotating in an anti-clockwise direction.
24 |
25 | See http://en.wikipedia.org/wiki/Polar_coordinates for more details.
26 |
27 | ## Similar Projects
28 |
29 | [andyw8/techradar](https://github.com/andyw8/techradar) (the Rails app behind [techradar.io](http://techradar.io).
30 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
36 | Diagram of the Causes of Mortality
37 | in the Army of the East
38 |
39 |
87 |
88 | The Areas of the blue, red, & black wedges are each measured from the
89 | centre as the common vertex
90 |
The blue wedges measured from the centre of the circle represent area
91 | for area the deaths from Preventible or Mitigable Zymotic Diseases, the
92 | red wedges measured from the center the deaths from wounds, & the
93 | black wedges measured from the center the deaths from all other causes
94 |
In October 1844, & April 1855, the black area coincides with the
95 | red, in January & February 1856, the blue coincides with the black
96 |
The entire areas may be compared by following the blue, the red &
97 | the black lines enclosing them.
98 |
1/**
9 | 2 * Abstract; see an implementing class for details.
10 | 3 *
11 | 4 * @class Represents a reusable interaction; applies an interactive behavior to
12 | 5 * a given mark. Behaviors are themselves functions designed to be used as event
13 | 6 * handlers. For example, to add pan and zoom support to any panel, say:
14 | 7 *
15 | 8 * <pre> .event("mousedown", pv.Behavior.pan())
16 | 9 * .event("mousewheel", pv.Behavior.zoom())</pre>
17 | 10 *
18 | 11 * The behavior should be registered on the event that triggers the start of the
19 | 12 * behavior. Typically, the behavior will take care of registering for any
20 | 13 * additional events that are necessary. For example, dragging starts on
21 | 14 * mousedown, while the drag behavior automatically listens for mousemove and
22 | 15 * mouseup events on the window. By listening to the window, the behavior can
23 | 16 * continue to receive mouse events even if the mouse briefly leaves the mark
24 | 17 * being dragged, or even the root panel.
25 | 18 *
26 | 19 * <p>Each behavior implementation has specific requirements as to which events
27 | 20 * it supports, and how it should be used. For example, the drag behavior
28 | 21 * requires that the data associated with the mark be an object with <tt>x</tt>
29 | 22 * and <tt>y</tt> attributes, such as a {@link pv.Vector}, storing the mark's
30 | 23 * position. See an implementing class for details.
31 | 24 *
32 | 25 * @see pv.Behavior.drag
33 | 26 * @see pv.Behavior.pan
34 | 27 * @see pv.Behavior.point
35 | 28 * @see pv.Behavior.select
36 | 29 * @see pv.Behavior.zoom
37 | 30 * @extends function
38 | 31 */
39 | 32pv.Behavior={};
40 | 33
1/**
9 | 2 * Returns a linear color ramp from the specified <tt>start</tt> color to the
10 | 3 * specified <tt>end</tt> color. The color arguments may be specified either as
11 | 4 * <tt>string</tt>s or as {@link pv.Color}s. This is equivalent to:
12 | 5 *
13 | 6 * <pre> pv.Scale.linear().domain(0, 1).range(...)</pre>
14 | 7 *
15 | 8 * @param {string} start the start color; may be a <tt>pv.Color</tt>.
16 | 9 * @param {string} end the end color; may be a <tt>pv.Color</tt>.
17 | 10 * @returns {Function} a color ramp from <tt>start</tt> to <tt>end</tt>.
18 | 11 * @see pv.Scale.linear
19 | 12 */
20 | 13pv.ramp=function(start,end){
21 | 14varscale=pv.Scale.linear();
22 | 15scale.range.apply(scale,arguments);
23 | 16returnscale;
24 | 17};
25 | 18
1/**
9 | 2 * Returns a linear scale for the specified domain. The arguments to this
10 | 3 * constructor are optional, and equivalent to calling {@link #domain}.
11 | 4 * The default domain and range are [0,1].
12 | 5 *
13 | 6 * @class Represents a linear scale; a function that performs a linear
14 | 7 * transformation. <style type="text/css">sub{line-height:0}</style> Most
15 | 8 * commonly, a linear scale represents a 1-dimensional linear transformation
16 | 9 * from a numeric domain of input data [<i>d<sub>0</sub></i>,
17 | 10 * <i>d<sub>1</sub></i>] to a numeric range of pixels [<i>r<sub>0</sub></i>,
18 | 11 * <i>r<sub>1</sub></i>]. The equation for such a scale is:
19 | 12 *
20 | 13 * <blockquote><i>f(x) = (x - d<sub>0</sub>) / (d<sub>1</sub> - d<sub>0</sub>) *
21 | 14 * (r<sub>1</sub> - r<sub>0</sub>) + r<sub>0</sub></i></blockquote>
22 | 15 *
23 | 16 * For example, a linear scale from the domain [0, 100] to range [0, 640]:
24 | 17 *
25 | 18 * <blockquote><i>f(x) = (x - 0) / (100 - 0) * (640 - 0) + 0</i><br>
26 | 19 * <i>f(x) = x / 100 * 640</i><br>
27 | 20 * <i>f(x) = x * 6.4</i><br>
28 | 21 * </blockquote>
29 | 22 *
30 | 23 * Thus, saying
31 | 24 *
32 | 25 * <pre> .height(function(d) d * 6.4)</pre>
33 | 26 *
34 | 27 * is identical to
35 | 28 *
36 | 29 * <pre> .height(pv.Scale.linear(0, 100).range(0, 640))</pre>
37 | 30 *
38 | 31 * Note that the scale is itself a function, and thus can be used as a property
39 | 32 * directly, assuming that the data associated with a mark is a number. While
40 | 33 * this is convenient for single-use scales, frequently it is desirable to
41 | 34 * define scales globally:
42 | 35 *
43 | 36 * <pre>var y = pv.Scale.linear(0, 100).range(0, 640);</pre>
44 | 37 *
45 | 38 * The <tt>y</tt> scale can now be equivalently referenced within a property:
46 | 39 *
47 | 40 * <pre> .height(function(d) y(d))</pre>
48 | 41 *
49 | 42 * Alternatively, if the data are not simple numbers, the appropriate value can
50 | 43 * be passed to the <tt>y</tt> scale (e.g., <tt>d.foo</tt>). The {@link #by}
51 | 44 * method similarly allows the data to be mapped to a numeric value before
52 | 45 * performing the linear transformation.
53 | 46 *
54 | 47 * @param {number...} domain... optional domain values.
55 | 48 * @extends pv.Scale.quantitative
56 | 49 */
57 | 50pv.Scale.linear=function(){
58 | 51varscale=pv.Scale.quantitative();
59 | 52scale.domain.apply(scale,arguments);
60 | 53returnscale;
61 | 54};
62 | 55
1/**
9 | 2 * Returns a root scale for the specified domain. The arguments to this
10 | 3 * constructor are optional, and equivalent to calling {@link #domain}.
11 | 4 * The default domain and range are [0,1].
12 | 5 *
13 | 6 * @class Represents a root scale; a function that performs a power
14 | 7 * transformation. <style type="text/css">sub{line-height:0}</style> Most
15 | 8 * commonly, a root scale represents a 1-dimensional root transformation from a
16 | 9 * numeric domain of input data [<i>d<sub>0</sub></i>, <i>d<sub>1</sub></i>] to
17 | 10 * a numeric range of pixels [<i>r<sub>0</sub></i>, <i>r<sub>1</sub></i>].
18 | 11 *
19 | 12 * <p>Note that the scale is itself a function, and thus can be used as a
20 | 13 * property directly, assuming that the data associated with a mark is a
21 | 14 * number. While this is convenient for single-use scales, frequently it is
22 | 15 * desirable to define scales globally:
23 | 16 *
24 | 17 * <pre>var y = pv.Scale.root(0, 100).range(0, 640);</pre>
25 | 18 *
26 | 19 * The <tt>y</tt> scale can now be equivalently referenced within a property:
27 | 20 *
28 | 21 * <pre> .height(function(d) y(d))</pre>
29 | 22 *
30 | 23 * Alternatively, if the data are not simple numbers, the appropriate value can
31 | 24 * be passed to the <tt>y</tt> scale (e.g., <tt>d.foo</tt>). The {@link #by}
32 | 25 * method similarly allows the data to be mapped to a numeric value before
33 | 26 * performing the root transformation.
34 | 27 *
35 | 28 * @param {number...} domain... optional domain values.
36 | 29 * @extends pv.Scale.quantitative
37 | 30 */
38 | 31pv.Scale.root=function(){
39 | 32varscale=pv.Scale.quantitative();
40 | 33
41 | 34/**
42 | 35 * Sets or gets the exponent; defaults to 2.
43 | 36 *
44 | 37 * @function
45 | 38 * @name pv.Scale.root.prototype.power
46 | 39 * @param {number} [v] the new exponent.
47 | 40 * @returns {pv.Scale.root} <tt>this</tt>, or the current base.
48 | 41 */
49 | 42scale.power=function(v){
50 | 43if(arguments.length){
51 | 44varb=Number(v),p=1/b;
52 | 45scale.transform(
53 | 46function(x){returnMath.pow(x,p);},
54 | 47function(y){returnMath.pow(y,b);});
55 | 48returnthis;
56 | 49}
57 | 50returnb;
58 | 51};
59 | 52
60 | 53scale.domain.apply(scale,arguments);
61 | 54returnscale.power(2);
62 | 55};
63 | 56
1/**
9 | 2 * Abstract; not implemented. There is no explicit constructor; this class
10 | 3 * merely serves to document the representation used by {@link pv.Geo.scale}.
11 | 4 *
12 | 5 * @class Represents a geographic projection. This class provides the core
13 | 6 * implementation for {@link pv.Geo.scale}s, mapping between geographic
14 | 7 * coordinates (latitude and longitude) and normalized screen space in the range
15 | 8 * [-1,1]. The remaining mapping between normalized screen space and actual
16 | 9 * pixels is performed by <tt>pv.Geo.scale</tt>.
17 | 10 *
18 | 11 * <p>Many geographic projections have a point around which the projection is
19 | 12 * centered. Rather than have each implementation add support for a
20 | 13 * user-specified center point, the <tt>pv.Geo.scale</tt> translates the
21 | 14 * geographic coordinates relative to the center point for both the forward and
22 | 15 * inverse projection.
23 | 16 *
24 | 17 * <p>In general, this class should not be used directly, unless the desire is
25 | 18 * to implement a new geographic projection. Instead, use <tt>pv.Geo.scale</tt>.
26 | 19 * Implementations are not required to implement inverse projections, but are
27 | 20 * needed for some forms of interactivity. Also note that some inverse
28 | 21 * projections are ambiguous, such as the connecting points in Dymaxian maps.
29 | 22 *
30 | 23 * @name pv.Geo.Projection
31 | 24 * @see pv.Geo.scale
32 | 25 */
33 | 26
34 | 27/**
35 | 28 * The <i>forward</i> projection.
36 | 29 *
37 | 30 * @function
38 | 31 * @name pv.Geo.Projection.prototype.project
39 | 32 * @param {pv.Geo.LatLng} latlng the latitude and longitude to project.
40 | 33 * @returns {pv.Vector} the xy-coordinates of the given point.
41 | 34 */
42 | 35
43 | 36/**
44 | 37 * The <i>inverse</i> projection; optional.
45 | 38 *
46 | 39 * @function
47 | 40 * @name pv.Geo.Projection.prototype.invert
48 | 41 * @param {pv.Vector} xy the x- and y-coordinates to invert.
49 | 42 * @returns {pv.Geo.LatLng} the latitude and longitude of the given point.
50 | 43 */
51 | 44
1/*
9 | 2 * Parses the Protovis specifications on load, allowing the use of JavaScript
10 | 3 * 1.8 function expressions on browsers that only support JavaScript 1.6.
11 | 4 *
12 | 5 * @see pv.parse
13 | 6 */
14 | 7pv.listen(window,"load",function(){
15 | 8/*
16 | 9 * Note: in Firefox any variables declared here are visible to the eval'd
17 | 10 * script below. Even worse, any global variables declared by the script
18 | 11 * could overwrite local variables here (such as the index, `i`)! To protect
19 | 12 * against this, all variables are explicitly scoped on a pv.$ object.
20 | 13 */
21 | 14pv.$={i:0,x:document.getElementsByTagName("script")};
22 | 15for(;pv.$.i<pv.$.x.length;pv.$.i++){
23 | 16pv.$.s=pv.$.x[pv.$.i];
24 | 17if(pv.$.s.type=="text/javascript+protovis"){
25 | 18try{
26 | 19window.eval(pv.parse(pv.$.s.text));
27 | 20}catch(e){
28 | 21pv.error(e);
29 | 22}
30 | 23}
31 | 24}
32 | 25deletepv.$;
33 | 26});
34 | 27
1/**
9 | 2 * Constructs a new, empty layout with default properties. Layouts are not
10 | 3 * typically constructed directly; instead, a concrete subclass is added to an
11 | 4 * existing panel via {@link pv.Mark#add}.
12 | 5 *
13 | 6 * @class Represents an abstract layout, encapsulating a visualization technique
14 | 7 * such as a streamgraph or treemap. Layouts are themselves containers,
15 | 8 * extending from {@link pv.Panel}, and defining a set of mark prototypes as
16 | 9 * children. These mark prototypes provide default properties that together
17 | 10 * implement the given visualization technique.
18 | 11 *
19 | 12 * <p>Layouts do not initially contain any marks; any exported marks (such as a
20 | 13 * network layout's <tt>link</tt> and <tt>node</tt>) are intended to be used as
21 | 14 * prototypes. By adding a concrete mark, such as a {@link pv.Bar}, to the
22 | 15 * appropriate mark prototype, the mark is added to the layout and inherits the
23 | 16 * given properties. This approach allows further customization of the layout,
24 | 17 * either by choosing a different mark type to add, or more simply by overriding
25 | 18 * some of the layout's defined properties.
26 | 19 *
27 | 20 * <p>Each concrete layout, such as treemap or circle-packing, has different
28 | 21 * behavior and may export different mark prototypes, depending on what marks
29 | 22 * are typically needed to render the desired visualization. Therefore it is
30 | 23 * important to understand how each layout is structured, such that the provided
31 | 24 * mark prototypes are used appropriately.
32 | 25 *
33 | 26 * <p>In addition to the mark prototypes, layouts may define custom properties
34 | 27 * that affect the overall behavior of the layout. For example, a treemap layout
35 | 28 * might use a property to specify which layout algorithm to use. These
36 | 29 * properties are just like other mark properties, and can be defined as
37 | 30 * constants or as functions. As with panels, the data property can be used to
38 | 31 * replicate layouts, and properties can be defined to in terms of layout data.
39 | 32 *
40 | 33 * @extends pv.Panel
41 | 34 */
42 | 35pv.Layout=function(){
43 | 36pv.Panel.call(this);
44 | 37};
45 | 38
46 | 39pv.Layout.prototype=pv.extend(pv.Panel);
47 | 40
48 | 41/**
49 | 42 * @private Defines a local property with the specified name and cast. Note that
50 | 43 * although the property method is only defined locally, the cast function is
51 | 44 * global, which is necessary since properties are inherited!
52 | 45 *
53 | 46 * @param {string} name the property name.
54 | 47 * @param {function} [cast] the cast function for this property.
55 | 48 */
56 | 49pv.Layout.prototype.property=function(name,cast){
57 | 50if(!this.hasOwnProperty("properties")){
58 | 51this.properties=pv.extend(this.properties);
59 | 52}
60 | 53this.properties[name]=true;
61 | 54this.propertyMethod(name,false,pv.Mark.cast[name]=cast);
62 | 55returnthis;
63 | 56};
64 | 57
1/**
9 | 2 * Constructs a new mark anchor with default properties.
10 | 3 *
11 | 4 * @class Represents an anchor on a given mark. An anchor is itself a mark, but
12 | 5 * without a visual representation. It serves only to provide useful default
13 | 6 * properties that can be inherited by other marks. Each type of mark can define
14 | 7 * any number of named anchors for convenience. If the concrete mark type does
15 | 8 * not define an anchor implementation specifically, one will be inherited from
16 | 9 * the mark's parent class.
17 | 10 *
18 | 11 * <p>For example, the bar mark provides anchors for its four sides: left,
19 | 12 * right, top and bottom. Adding a label to the top anchor of a bar,
20 | 13 *
21 | 14 * <pre>bar.anchor("top").add(pv.Label);</pre>
22 | 15 *
23 | 16 * will render a text label on the top edge of the bar; the top anchor defines
24 | 17 * the appropriate position properties (top and left), as well as text-rendering
25 | 18 * properties for convenience (textAlign and textBaseline).
26 | 19 *
27 | 20 * <p>Note that anchors do not <i>inherit</i> from their targets; the positional
28 | 21 * properties are copied from the scene graph, which guarantees that the anchors
29 | 22 * are positioned correctly, even if the positional properties are not defined
30 | 23 * deterministically. (In addition, it also improves performance by avoiding
31 | 24 * re-evaluating expensive properties.) If you want the anchor to inherit from
32 | 25 * the target, use {@link pv.Mark#extend} before adding. For example:
33 | 26 *
34 | 27 * <pre>bar.anchor("top").extend(bar).add(pv.Label);</pre>
35 | 28 *
36 | 29 * The anchor defines it's own positional properties, but other properties (such
37 | 30 * as the title property, say) can be inherited using the above idiom. Also note
38 | 31 * that you can override positional properties in the anchor for custom
39 | 32 * behavior.
40 | 33 *
41 | 34 * @extends pv.Mark
42 | 35 * @param {pv.Mark} target the anchor target.
43 | 36 */
44 | 37pv.Anchor=function(target){
45 | 38pv.Mark.call(this);
46 | 39this.target=target;
47 | 40this.parent=target.parent;
48 | 41};
49 | 42
50 | 43pv.Anchor.prototype=pv.extend(pv.Mark)
51 | 44.property("name",String);
52 | 45
53 | 46/**
54 | 47 * The anchor name. The set of supported anchor names is dependent on the
55 | 48 * concrete mark type; see the mark type for details. For example, bars support
56 | 49 * left, right, top and bottom anchors.
57 | 50 *
58 | 51 * <p>While anchor names are typically constants, the anchor name is a true
59 | 52 * property, which means you can specify a function to compute the anchor name
60 | 53 * dynamically. For instance, if you wanted to alternate top and bottom anchors,
61 | 54 * saying
62 | 55 *
63 | 56 * <pre>m.anchor(function() (this.index % 2) ? "top" : "bottom").add(pv.Dot);</pre>
64 | 57 *
65 | 58 * would have the desired effect.
66 | 59 *
67 | 60 * @type string
68 | 61 * @name pv.Anchor.prototype.name
69 | 62 */
70 | 63
71 | 64/**
72 | 65 * Returns the anchor target of this mark, if it is derived from an anchor;
73 | 66 * otherwise returns null. For example, if a label is derived from a bar anchor,
74 | 67 *
75 | 68 * <pre>bar.anchor("top").add(pv.Label);</pre>
76 | 69 *
77 | 70 * then property functions on the label can refer to the bar via the
78 | 71 * <tt>anchorTarget</tt> method. This method is also useful for mark types
79 | 72 * defining properties on custom anchors.
80 | 73 *
81 | 74 * @returns {pv.Mark} the anchor target of this mark; possibly null.
82 | 75 */
83 | 76pv.Anchor.prototype.anchorTarget=function(){
84 | 77returnthis.target;
85 | 78};
86 | 79
1/**
9 | 2 * Constructs a new bar mark with default properties. Bars are not typically
10 | 3 * constructed directly, but by adding to a panel or an existing mark via
11 | 4 * {@link pv.Mark#add}.
12 | 5 *
13 | 6 * @class Represents a bar: an axis-aligned rectangle that can be stroked and
14 | 7 * filled. Bars are used for many chart types, including bar charts, histograms
15 | 8 * and Gantt charts. Bars can also be used as decorations, for example to draw a
16 | 9 * frame border around a panel; in fact, a panel is a special type (a subclass)
17 | 10 * of bar.
18 | 11 *
19 | 12 * <p>Bars can be positioned in several ways. Most commonly, one of the four
20 | 13 * corners is fixed using two margins, and then the width and height properties
21 | 14 * determine the extent of the bar relative to this fixed location. For example,
22 | 15 * using the bottom and left properties fixes the bottom-left corner; the width
23 | 16 * then extends to the right, while the height extends to the top. As an
24 | 17 * alternative to the four corners, a bar can be positioned exclusively using
25 | 18 * margins; this is convenient as an inset from the containing panel, for
26 | 19 * example. See {@link pv.Mark} for details on the prioritization of redundant
27 | 20 * positioning properties.
28 | 21 *
29 | 22 * <p>See also the <a href="../../api/Bar.html">Bar guide</a>.
30 | 23 *
31 | 24 * @extends pv.Mark
32 | 25 */
33 | 26pv.Bar=function(){
34 | 27pv.Mark.call(this);
35 | 28};
36 | 29
37 | 30pv.Bar.prototype=pv.extend(pv.Mark)
38 | 31.property("width",Number)
39 | 32.property("height",Number)
40 | 33.property("lineWidth",Number)
41 | 34.property("strokeStyle",pv.color)
42 | 35.property("fillStyle",pv.color);
43 | 36
44 | 37pv.Bar.prototype.type="bar";
45 | 38
46 | 39/**
47 | 40 * The width of the bar, in pixels. If the left position is specified, the bar
48 | 41 * extends rightward from the left edge; if the right position is specified, the
49 | 42 * bar extends leftward from the right edge.
50 | 43 *
51 | 44 * @type number
52 | 45 * @name pv.Bar.prototype.width
53 | 46 */
54 | 47
55 | 48/**
56 | 49 * The height of the bar, in pixels. If the bottom position is specified, the
57 | 50 * bar extends upward from the bottom edge; if the top position is specified,
58 | 51 * the bar extends downward from the top edge.
59 | 52 *
60 | 53 * @type number
61 | 54 * @name pv.Bar.prototype.height
62 | 55 */
63 | 56
64 | 57/**
65 | 58 * The width of stroked lines, in pixels; used in conjunction with
66 | 59 * <tt>strokeStyle</tt> to stroke the bar's border.
67 | 60 *
68 | 61 * @type number
69 | 62 * @name pv.Bar.prototype.lineWidth
70 | 63 */
71 | 64
72 | 65/**
73 | 66 * The style of stroked lines; used in conjunction with <tt>lineWidth</tt> to
74 | 67 * stroke the bar's border. The default value of this property is null, meaning
75 | 68 * bars are not stroked by default.
76 | 69 *
77 | 70 * @type string
78 | 71 * @name pv.Bar.prototype.strokeStyle
79 | 72 * @see pv.color
80 | 73 */
81 | 74
82 | 75/**
83 | 76 * The bar fill style; if non-null, the interior of the bar is filled with the
84 | 77 * specified color. The default value of this property is a categorical color.
85 | 78 *
86 | 79 * @type string
87 | 80 * @name pv.Bar.prototype.fillStyle
88 | 81 * @see pv.color
89 | 82 */
90 | 83
91 | 84/**
92 | 85 * Default properties for bars. By default, there is no stroke and the fill
93 | 86 * style is a categorical color.
94 | 87 *
95 | 88 * @type pv.Bar
96 | 89 */
97 | 90pv.Bar.prototype.defaults=newpv.Bar()
98 | 91.extend(pv.Mark.prototype.defaults)
99 | 92.lineWidth(1.5)
100 | 93.fillStyle(pv.Colors.category20().by(pv.parent));
101 | 94
1/**
9 | 2 * Abstract; see an implementing class.
10 | 3 *
11 | 4 * @class Represents a constraint that acts on particles. Note that this
12 | 5 * interface does not specify how to bind a constraint to specific particles; in
13 | 6 * general, constraints are applied globally to all particles. However, some
14 | 7 * constraints may be applied to specific particles or between particles, such
15 | 8 * as position constraints, through additional specialization.
16 | 9 *
17 | 10 * @see pv.Simulation
18 | 11 * @see pv.Particle
19 | 12 * @see pv.Constraint.bound
20 | 13 * @see pv.Constraint.collision
21 | 14 * @see pv.Constraint.position
22 | 15 */
23 | 16pv.Constraint={};
24 | 17
25 | 18/**
26 | 19 * Applies this constraint to the specified particles.
27 | 20 *
28 | 21 * @function
29 | 22 * @name pv.Constraint.prototype.apply
30 | 23 * @param {pv.Particle} particles particles to which to apply this constraint.
31 | 24 * @param {pv.Quadtree} q a quadtree for spatial acceleration.
32 | 25 * @returns {pv.Constraint} this.
33 | 26 */
34 | 27
1/**
9 | 2 * Abstract; see an implementing class.
10 | 3 *
11 | 4 * @class Represents a force that acts on particles. Note that this interface
12 | 5 * does not specify how to bind a force to specific particles; in general,
13 | 6 * forces are applied globally to all particles. However, some forces may be
14 | 7 * applied to specific particles or between particles, such as spring forces,
15 | 8 * through additional specialization.
16 | 9 *
17 | 10 * @see pv.Simulation
18 | 11 * @see pv.Particle
19 | 12 * @see pv.Force.charge
20 | 13 * @see pv.Force.drag
21 | 14 * @see pv.Force.spring
22 | 15 */
23 | 16pv.Force={};
24 | 17
25 | 18/**
26 | 19 * Applies this force to the specified particles.
27 | 20 *
28 | 21 * @function
29 | 22 * @name pv.Force.prototype.apply
30 | 23 * @param {pv.Particle} particles particles to which to apply this force.
31 | 24 * @param {pv.Quadtree} q a quadtree for spatial acceleration.
32 | 25 */
33 | 26
1/**
9 | 2 * Constructs a default position constraint using the <tt>fix</tt> attribute.
10 | 3 * An optional position function can be specified to determine how the fixed
11 | 4 * position per-particle is determined.
12 | 5 *
13 | 6 * @class Constraints particles to a fixed position. The fixed position per
14 | 7 * particle is determined using a given position function, which defaults to
15 | 8 * <tt>function(d) d.fix</tt>.
16 | 9 *
17 | 10 * <p>If the position function returns null, then no position constraint is
18 | 11 * applied to the given particle. Otherwise, the particle's position is set to
19 | 12 * the returned position, as expressed by a {@link pv.Vector}. (Note: the
20 | 13 * position does not need to be an instance of <tt>pv.Vector</tt>, but simply an
21 | 14 * object with <tt>x</tt> and <tt>y</tt> attributes.)
22 | 15 *
23 | 16 * <p>This constraint also supports a configurable alpha parameter, which
24 | 17 * defaults to 1. If the alpha parameter is in the range [0,1], then rather than
25 | 18 * setting the particle's new position directly to the position returned by the
26 | 19 * supplied position function, the particle's position is interpolated towards
27 | 20 * the fixed position. This results is a smooth (exponential) drift towards the
28 | 21 * fixed position, which can increase the stability of the physics simulation.
29 | 22 * In addition, the alpha parameter can be decayed over time, relaxing the
30 | 23 * position constraint, which helps to stabilize on an optimal solution.
31 | 24 *
32 | 25 * @param {function} [f] the position function.
33 | 26 */
34 | 27pv.Constraint.position=function(f){
35 | 28vara=1,// default alpha
36 | 29constraint={};
37 | 30
38 | 31if(!arguments.length)/** @ignore */f=function(p){returnp.fix;};
39 | 32
40 | 33/**
41 | 34 * Sets or gets the alpha parameter for position interpolation. If the alpha
42 | 35 * parameter is in the range [0,1], then rather than setting the particle's
43 | 36 * new position directly to the position returned by the supplied position
44 | 37 * function, the particle's position is interpolated towards the fixed
45 | 38 * position.
46 | 39 *
47 | 40 * @function
48 | 41 * @name pv.Constraint.position.prototype.alpha
49 | 42 * @param {number} x the new alpha parameter, in the range [0,1].
50 | 43 * @returns {pv.Constraint.position} this.
51 | 44 */
52 | 45constraint.alpha=function(x){
53 | 46if(arguments.length){
54 | 47a=Number(x);
55 | 48returnconstraint;
56 | 49}
57 | 50returna;
58 | 51};
59 | 52
60 | 53/**
61 | 54 * Applies this constraint to the specified particles.
62 | 55 *
63 | 56 * @function
64 | 57 * @name pv.Constraint.position.prototype.apply
65 | 58 * @param {pv.Particle} particles particles to which to apply this constraint.
66 | 59 */
67 | 60constraint.apply=function(particles){
68 | 61for(varp=particles;p;p=p.next){
69 | 62varv=f(p);
70 | 63if(v){
71 | 64p.x+=(v.x-p.x)*a;
72 | 65p.y+=(v.y-p.y)*a;
73 | 66p.fx=p.fy=p.vx=p.vy=0;
74 | 67}
75 | 68}
76 | 69};
77 | 70
78 | 71returnconstraint;
79 | 72};
80 | 73
1/**
9 | 2 * The top-level Protovis namespace. All public methods and fields should be
10 | 3 * registered on this object. Note that core Protovis source is surrounded by an
11 | 4 * anonymous function, so any other declared globals will not be visible outside
12 | 5 * of core methods. This also allows multiple versions of Protovis to coexist,
13 | 6 * since each version will see their own <tt>pv</tt> namespace.
14 | 7 *
15 | 8 * @namespace The top-level Protovis namespace, <tt>pv</tt>.
16 | 9 */
17 | 10varpv={};
18 | 11
19 | 12/**
20 | 13 * Protovis major and minor version numbers.
21 | 14 *
22 | 15 * @namespace Protovis major and minor version numbers.
23 | 16 */
24 | 17pv.version={
25 | 18/**
26 | 19 * The major version number.
27 | 20 *
28 | 21 * @type number
29 | 22 * @constant
30 | 23 */
31 | 24major:3,
32 | 25
33 | 26/**
34 | 27 * The minor version number.
35 | 28 *
36 | 29 * @type number
37 | 30 * @constant
38 | 31 */
39 | 32minor:2
40 | 33};
41 | 34
42 | 35/**
43 | 36 * Returns the passed-in argument, <tt>x</tt>; the identity function. This method
44 | 37 * is provided for convenience since it is used as the default behavior for a
45 | 38 * number of property functions.
46 | 39 *
47 | 40 * @param x a value.
48 | 41 * @returns the value <tt>x</tt>.
49 | 42 */
50 | 43pv.identity=function(x){returnx;};
51 | 44
52 | 45/**
53 | 46 * Returns <tt>this.index</tt>. This method is provided for convenience for use
54 | 47 * with scales. For example, to color bars by their index, say:
55 | 48 *
56 | 49 * <pre>.fillStyle(pv.Colors.category10().by(pv.index))</pre>
57 | 50 *
58 | 51 * This method is equivalent to <tt>function() this.index</tt>, but more
59 | 52 * succinct. Note that the <tt>index</tt> property is also supported for
60 | 53 * accessor functions with {@link pv.max}, {@link pv.min} and other array
61 | 54 * utility methods.
62 | 55 *
63 | 56 * @see pv.Scale
64 | 57 * @see pv.Mark#index
65 | 58 */
66 | 59pv.index=function(){returnthis.index;};
67 | 60
68 | 61/**
69 | 62 * Returns <tt>this.childIndex</tt>. This method is provided for convenience for
70 | 63 * use with scales. For example, to color bars by their child index, say:
71 | 64 *
72 | 65 * <pre>.fillStyle(pv.Colors.category10().by(pv.child))</pre>
73 | 66 *
74 | 67 * This method is equivalent to <tt>function() this.childIndex</tt>, but more
75 | 68 * succinct.
76 | 69 *
77 | 70 * @see pv.Scale
78 | 71 * @see pv.Mark#childIndex
79 | 72 */
80 | 73pv.child=function(){returnthis.childIndex;};
81 | 74
82 | 75/**
83 | 76 * Returns <tt>this.parent.index</tt>. This method is provided for convenience
84 | 77 * for use with scales. This method is provided for convenience for use with
85 | 78 * scales. For example, to color bars by their parent index, say:
86 | 79 *
87 | 80 * <pre>.fillStyle(pv.Colors.category10().by(pv.parent))</pre>
88 | 81 *
89 | 82 * Tthis method is equivalent to <tt>function() this.parent.index</tt>, but more
90 | 83 * succinct.
91 | 84 *
92 | 85 * @see pv.Scale
93 | 86 * @see pv.Mark#index
94 | 87 */
95 | 88pv.parent=function(){returnthis.parent.index;};
96 | 89
97 | 90/**
98 | 91 * Stores the current event. This field is only set within event handlers.
99 | 92 *
100 | 93 * @type Event
101 | 94 * @name pv.event
102 | 95 */
103 | 96
1/**
9 | 2 * Abstract; see an implementing class.
10 | 3 *
11 | 4 * @class Represents an abstract text formatter and parser. A <i>format</i> is a
12 | 5 * function that converts an object of a given type, such as a <tt>Date</tt>, to
13 | 6 * a human-readable string representation. The format may also have a
14 | 7 * {@link #parse} method for converting a string representation back to the
15 | 8 * given object type.
16 | 9 *
17 | 10 * <p>Because formats are themselves functions, they can be used directly as
18 | 11 * mark properties. For example, if the data associated with a label are dates,
19 | 12 * a date format can be used as label text:
20 | 13 *
21 | 14 * <pre> .text(pv.Format.date("%m/%d/%y"))</pre>
22 | 15 *
23 | 16 * And as with scales, if the format is used in multiple places, it can be
24 | 17 * convenient to declare it as a global variable and then reference it from the
25 | 18 * appropriate property functions. For example, if the data has a <tt>date</tt>
26 | 19 * attribute, and <tt>format</tt> references a given date format:
27 | 20 *
28 | 21 * <pre> .text(function(d) format(d.date))</pre>
29 | 22 *
30 | 23 * Similarly, to parse a string into a date:
31 | 24 *
32 | 25 * <pre>var date = format.parse("4/30/2010");</pre>
33 | 26 *
34 | 27 * Not all format implementations support parsing. See the implementing class
35 | 28 * for details.
36 | 29 *
37 | 30 * @see pv.Format.date
38 | 31 * @see pv.Format.number
39 | 32 * @see pv.Format.time
40 | 33 */
41 | 34pv.Format={};
42 | 35
43 | 36/**
44 | 37 * Formats the specified object, returning the string representation.
45 | 38 *
46 | 39 * @function
47 | 40 * @name pv.Format.prototype.format
48 | 41 * @param {object} x the object to format.
49 | 42 * @returns {string} the formatted string.
50 | 43 */
51 | 44
52 | 45/**
53 | 46 * Parses the specified string, returning the object representation.
54 | 47 *
55 | 48 * @function
56 | 49 * @name pv.Format.prototype.parse
57 | 50 * @param {string} x the string to parse.
58 | 51 * @returns {object} the parsed object.
59 | 52 */
60 | 53
61 | 54/**
62 | 55 * @private Given a string that may be used as part of a regular expression,
63 | 56 * this methods returns an appropriately quoted version of the specified string,
64 | 57 * with any special characters escaped.
65 | 58 *
66 | 59 * @param {string} s a string to quote.
67 | 60 * @returns {string} the quoted string.
68 | 61 */
69 | 62pv.Format.re=function(s){
70 | 63returns.replace(/[\\\^\$\*\+\?\[\]\(\)\.\{\}]/g,"\\$&");
71 | 64};
72 | 65
73 | 66/**
74 | 67 * @private Optionally pads the specified string <i>s</i> so that it is at least
75 | 68 * <i>n</i> characters long, using the padding character <i>c</i>.
76 | 69 *
77 | 70 * @param {string} c the padding character.
78 | 71 * @param {number} n the minimum string length.
79 | 72 * @param {string} s the string to pad.
80 | 73 * @returns {string} the padded string.
81 | 74 */
82 | 75pv.Format.pad=function(c,n,s){
83 | 76varm=n-String(s).length;
84 | 77return(m<1)?s:newArray(m+1).join(c)+s;
85 | 78};
86 | 79
--------------------------------------------------------------------------------
/radar.js:
--------------------------------------------------------------------------------
1 | function init(h,w) {
2 | $('#title').text(document.title).width(w);
3 |
4 | var radar = new pv.Panel()
5 | .width(w)
6 | .height(h)
7 | .canvas('radar')
8 |
9 | // arcs
10 | radar.add(pv.Dot)
11 | .data(radar_arcs)
12 | .left(w/2)
13 | .bottom(h/2)
14 | .radius(function(d){return d.r;})
15 | .strokeStyle("#ccc")
16 | .anchor("top")
17 | .add(pv.Label).text(function(d) { return d.name;});
18 |
19 | //quadrant lines -- vertical
20 | radar.add(pv.Line)
21 | .data([(h/2-radar_arcs[radar_arcs.length-1].r),h-(h/2-radar_arcs[radar_arcs.length-1].r)])
22 | .lineWidth(1)
23 | .left(w/2)
24 | .bottom(function(d) {return d;})
25 | .strokeStyle("#bbb");
26 |
27 | //quadrant lines -- horizontal
28 | radar.add(pv.Line)
29 | .data([(w/2-radar_arcs[radar_arcs.length-1].r),w-(w/2-radar_arcs[radar_arcs.length-1].r)])
30 | .lineWidth(1)
31 | .bottom(h/2)
32 | .left(function(d) {return d;})
33 | .strokeStyle("#bbb");
34 |
35 |
36 | // blips
37 | // var total_index=1;
38 | // for (var i = 0; i < radar_data.length; i++) {
39 | // radar.add(pv.Dot)
40 | // .def("active", false)
41 | // .data(radar_data[i].items)
42 | // .size( function(d) { return ( d.blipSize !== undefined ? d.blipSize : 70 ); })
43 | // .left(function(d) { var x = polar_to_raster(d.pc.r, d.pc.t)[0];
44 | // //console.log("name:" + d.name + ", x:" + x);
45 | // return x;})
46 | // .bottom(function(d) { var y = polar_to_raster(d.pc.r, d.pc.t)[1];
47 | // //console.log("name:" + d.name + ", y:" + y);
48 | // return y;})
49 | // .title(function(d) { return d.name;})
50 | // .cursor( function(d) { return ( d.url !== undefined ? "pointer" : "auto" ); })
51 | // .event("click", function(d) { if ( d.url !== undefined ){self.location = d.url}})
52 | // .angle(Math.PI) // 180 degrees in radians !
53 | // .strokeStyle(radar_data[i].color)
54 | // .fillStyle(radar_data[i].color)
55 | // .shape(function(d) {return (d.movement === 't' ? "triangle" : "circle");})
56 | // .anchor("center")
57 | // .add(pv.Label)
58 | // .text(function(d) {return total_index++;})
59 | // .textBaseline("middle")
60 | // .textStyle("white");
61 | // }
62 |
63 |
64 | //Quadrant Ledgends
65 | var radar_quadrant_ctr=1;
66 | var quadrantFontSize = 18;
67 | var headingFontSize = 14;
68 | var stageHeadingCount = 0;
69 | var lastRadius = 0;
70 | var lastQuadrant='';
71 | var spacer = 6;
72 | var fontSize = 10;
73 | var total_index = 1;
74 |
75 | //TODO: Super fragile: re-order the items, by radius, in order to logically group by the rings.
76 | for (var i = 0; i < radar_data.length; i++) {
77 | //adjust top by the number of headings.
78 | if (lastQuadrant != radar_data[i].quadrant) {
79 | radar.add(pv.Label)
80 | .left( radar_data[i].left )
81 | .top( radar_data[i].top )
82 | .text( radar_data[i].quadrant )
83 | .strokeStyle( radar_data[i].color )
84 | .fillStyle( radar_data[i].color )
85 | .font(quadrantFontSize + "px sans-serif");
86 |
87 | lastQuadrant = radar_data[i].quadrant;
88 |
89 | }
90 |
91 | // group items by stage based on how far they are from each arc
92 | var itemsByStage = _.groupBy(radar_data[i].items, function(item) {
93 | for(var arc_i = 0; arc_i < radar_arcs.length; arc_i++) {
94 | if (item.pc.r < radar_arcs[arc_i].r)
95 | {
96 | return arc_i;
97 | }
98 | }
99 | return 0;
100 | });
101 |
102 | // In the case where a quadrant doesn't have an item, group_by will return undefined
103 | // To avoid this, fill in the blanks with an empty array
104 | for (var j=0;j 0) {
113 | offsetIndex = offsetIndex + itemsByStage[stageIdx-1].length + 1;
114 | console.log("offsetIndex = " + itemsByStage[stageIdx-1].length, offsetIndex );
115 | }
116 |
117 | radar.add(pv.Label)
118 | .left( radar_data[i].left + headingFontSize )
119 | .top( radar_data[i].top + quadrantFontSize + spacer + (stageIdx * headingFontSize) + (offsetIndex * fontSize) )
120 | .text( radar_arcs[stageIdx].name)
121 | .strokeStyle( '#cccccc' )
122 | .fillStyle( '#cccccc')
123 | .font(headingFontSize + "px Courier New");
124 |
125 | radar.add(pv.Label)
126 | .left( radar_data[i].left )
127 | .top( radar_data[i].top + quadrantFontSize + spacer + (stageIdx * headingFontSize) + (offsetIndex * fontSize) )
128 | .strokeStyle( radar_data[i].color )
129 | .fillStyle( radar_data[i].color )
130 | .add( pv.Dot )
131 | .def("i", radar_data[i].top + quadrantFontSize + spacer + (stageIdx * headingFontSize) + spacer + (offsetIndex * fontSize) )
132 | .data(itemsByStage[stageIdx])
133 | .top( function() { return ( this.i() + (this.index * fontSize) );} )
134 | .shape( function(d) {return (d.movement === 't' ? "triangle" : "circle");})
135 | .cursor( function(d) { return ( d.url !== undefined ? "pointer" : "auto" ); })
136 | .event("click", function(d) { if ( d.url !== undefined ){self.location = d.url}})
137 | .size(fontSize)
138 | .angle(45)
139 | .anchor("right")
140 | .add(pv.Label)
141 | .text(function(d) {return radar_quadrant_ctr++ + ". " + d.name;} );
142 |
143 | radar.add(pv.Dot)
144 | .def("active", false)
145 | .data(itemsByStage[stageIdx])
146 | .size( function(d) { return ( d.blipSize !== undefined ? d.blipSize : 70 ); })
147 | .left(function(d) { var x = polar_to_raster(d.pc.r, d.pc.t)[0];
148 | //console.log("name:" + d.name + ", x:" + x);
149 | return x;})
150 | .bottom(function(d) { var y = polar_to_raster(d.pc.r, d.pc.t)[1];
151 | //console.log("name:" + d.name + ", y:" + y);
152 | return y;})
153 | .title(function(d) { return d.name;})
154 | .cursor( function(d) { return ( d.url !== undefined ? "pointer" : "auto" ); })
155 | .event("click", function(d) { if ( d.url !== undefined ){self.location = d.url}})
156 | .angle(Math.PI) // 180 degrees in radians !
157 | .strokeStyle(radar_data[i].color)
158 | .fillStyle(radar_data[i].color)
159 | .shape(function(d) {return (d.movement === 't' ? "triangle" : "circle");})
160 | .anchor("center")
161 | .add(pv.Label)
162 | .text(function(d) {return total_index++;})
163 | .textBaseline("middle")
164 | .textStyle("white");
165 |
166 |
167 | }
168 | }
169 |
170 | radar.anchor('radar');
171 | radar.render();
172 |
173 | };
174 |
--------------------------------------------------------------------------------
/radar_test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Architecture Radar
5 |
6 |
7 |
8 |
9 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/radars/radarData.js:
--------------------------------------------------------------------------------
1 | //This is the title for your window tab, and your Radar
2 | document.title = "WotifGroup's Technology Radar (December 2014)";
3 |
4 |
5 | //This is the concentic circles that want on your radar
6 | var radar_arcs = [
7 | {'r':100,'name':'Adopt'}
8 | ,{'r':200,'name':'Trial'}
9 | ,{'r':300,'name':'Assess'}
10 | ,{'r':400,'name':'Hold'}
11 | // ,{'r':500,'name':'Possible Extra if you want it'}
12 | ];
13 |
14 | //This is your raw data
15 | //
16 | // Key
17 | //
18 | // movement:
19 | // t = moved
20 | // c = stayed put
21 | //
22 | // blipSize:
23 | // intValue; This is optional, if you omit this property, then your blip will be size 70.
24 | // This give you the ability to be able to indicate information by blip size too
25 | //
26 | // url:
27 | // StringValue : This is optional, If you add it then your blips will be clickable to some URL
28 | //
29 | // pc: polar coordinates
30 | // r = distance away from origin ("radial coordinate")
31 | // - Each level is 100 points away from origin
32 | // t = angle of the point from origin ("angular coordinate")
33 | // - 0 degrees is due east
34 | //
35 | // Coarse-grained quadrants
36 | // - Techniques: elements of a software development process, such as experience design; and ways of structuring software, such micro-services.
37 | // - Tools: components, such as databases, software development tools, such as versions control systems; or more generic categories of tools, such as the notion of polyglot persistance.
38 | // - Platforms: things that we build software on top of: mobile technologies like Android, virtual platforms like the JVM, or generic kinds of platforms like hybrid clouds
39 | // - Programming Languages and Frameworks
40 | //
41 | // Rings:
42 | // - Adopt: blips you should be using now; proven and mature for use
43 | // - Trial: blips ready for use, but not as completely proven as those in the adopt ring; use on a trial basis, to decide whether they should be part of your toolkit
44 | // - Assess: things that you should look at closely, but not necessarily trial yet - unless you think they would be a particularly good fit for you
45 | // - Hold: things that are getting attention in the industry, but not ready for use; sometimes they are not mature enough yet, sometimes they are irredeemably flawed
46 | // Note: there's no "avoid" ring, but throw things in the hold ring that people shouldn't use.
47 |
48 | var h = 1000;
49 | var w = 1200;
50 |
51 | var radar_data = [
52 | { "quadrant": "Techniques",
53 | "left" : 45,
54 | "top" : 18,
55 | "color" : "#8FA227",
56 | "items" : [
57 | { name: 'Git flow / Pull Requests ^', pc: { r: 230, t: 133 }, movement: 'c' },
58 | {"name":"Incremental data warehousing", "pc":{"r":250,"t":165},"movement":"c"},
59 | {"name":"Events for messages - CQRS", "pc":{"r":225,"t":120},"movement":"c"},
60 | {"name":"Measure Pipeline disruptions", "pc":{"r":280,"t":110},"movement":"c"},
61 | {"name":"Continuous Experimentation", "pc":{"r":230,"t":110},"movement":"c"},
62 | { name: 'Reduce iRules dependence ^', pc: { r: 280, t: 133 }, movement: 'c' },
63 | {"name":"SaaS for non-core systems", "pc":{"r":170,"t":150},"movement":"c"},
64 | {"name":"Pair Programming", "pc":{"r":130,"t":170},"movement":"c"},
65 | {"name":"iOS Accessibility", "pc":{"r":170,"t":110},"movement":"c"},
66 | {"name":"Single Page App", "pc":{"r":150,"t":95},"movement":"c", "url":"http://www.google.com"},
67 | {"name":"iOS Adaptivity", "pc":{"r":180,"t":105},"movement":"c"},
68 | {"name":"Build Pipelines", "pc":{"r":180,"t":100},"movement":"c"},
69 | {"name":"Data Informed Decion Making", "pc":{"r":130,"t":110},"movement":"c"},
70 | {"name":"Polygot Programming", "pc":{"r":180,"t":170},"movement":"c"},
71 | { name: 'internal load balancing off F5^', pc: { r: 180, t: 133 }, movement: 'c' },
72 | {"name":"Isolated dev envs", "pc":{"r":180,"t":125},"movement":"c"},
73 | {"name":"Edge Services", "pc":{"r":130,"t":160},"movement":"c"},
74 | {"name":"Clean Code", "pc":{"r":130,"t":120},"movement":"c"},
75 | {"name":"Wide and Thin Front-Ends", "pc":{"r":180,"t":160},"movement":"c"},
76 | {"name":"Zookeeper for App Config", "pc":{"r":130,"t":130},"movement":"c"},
77 | {"name":"Property based testing", "pc":{"r":130,"t":165},"movement":"c"},
78 | {"name":"Evolutionary architecture", "pc":{"r":120,"t":95},"movement":"c"},
79 | {"name":"Code Reviews", "pc":{"r":110,"t":110},"movement":"c"},
80 | {"name":"Valuable, cheap tests", "pc":{"r":130,"t":150},"movement":"c"},
81 | {"name":"Sacrificial Architecture", "pc":{"r":80,"t":100},"movement":"c"},
82 | {"name":"Sensible defaults", "pc":{"r":80,"t":150},"movement":"c"},
83 | {"name":"Dependency Injection", "pc":{"r":80,"t":130},"movement":"c"},
84 | {"name":"Coding architects", "pc":{"r":90,"t":170},"movement":"c"}
85 |
86 | ]
87 | },
88 | { "quadrant": "Tools",
89 | "left": w-200+30,
90 | "top" : 18,
91 | "color" : "#587486",
92 | "items" : [
93 |
94 | { name: 'Docker', pc: { r: 170, t: 19 }, movement: 't' },
95 | { name: 'bind', pc: { r: 150, t: 69 }, movement: 'c' },
96 | { name: 'Appium', pc: { r: 110, t: 70 }, movement: 'c', domain: 'mobile, front-end' },
97 | { name: 'Android Studio', pc: { r: 180, t: 66 }, movement: 'c', domain: 'mobile, dev' },
98 | { name: 'Responsive Android', pc: { r: 150, t: 14 }, movement: 'c' },
99 | { name: 'AutoLayout - iOS', pc: { r: 180, t: 55 }, movement: 'c', domain: '' },
100 | { name: 'Kiwi - iOS unit test', pc: { r: 120, t: 14 }, movement: 'c', domain: '' },
101 | { name: 'BEM', pc: { r: 160, t: 60 }, movement: 'c', domain: 'front-end' },
102 | { name: 'Crashlytics', pc: { r: 180, t: 5 }, movement: 'c', domain: 'mobile' },
103 | { name: 'Consul', pc: { r: 170, t: 29 }, movement: 't' },
104 | { name: 'Swagger Code-Gen', pc: { r: 180, t: 82 }, movement: 'c' },
105 | { name: 'PowerMock ^', pc: { r: 180, t: 46 }, movement: 'c' },
106 | { name: 'Mockito', pc: { r: 170, t: 84 }, movement: 'c', domain: 'back-end' },
107 | { name: 'Json Web Tokens (JWT)', pc: { r: 180, t: 77 }, movement: 'c' },
108 | { name: 'Lemming', pc: { r: 160, t: 82 }, movement: 'c' },
109 | { name: 'Hystrix', pc: { r: 150, t: 36 }, movement: 'c' },
110 | { name: 'Git', pc: { r: 130, t: 73 }, movement: 'c' },
111 |
112 | { name: 'Ansible', pc: { r: 280, t: 74 }, movement: 'c' },
113 | { name: 'Hip Chat', pc: { r: 280, t: 78 }, movement: 'c' },
114 | { name: 'Trello', pc: { r: 260, t: 75 }, movement: 'c' },
115 | { name: 'Charles HTTP Proxy', pc: { r: 260, t: 48 }, movement: 'c' },
116 | { name: 'Xamarin', pc: { r: 280, t: 51 }, movement: 'c' },
117 | { name: 'Android Annotations', pc: { r: 280, t: 25 }, movement: 'c' },
118 | { name: 'GenyMotion', pc: { r: 210, t: 31 }, movement: 'c' },
119 |
120 | { name: 'JDBI ^', pc: { r: 80, t: 56 }, movement: 'c' },
121 | { name: 'Kafka', pc: { r: 12, t: 25 }, movement: 'c', domain: 'back-end' },
122 | { name: 'ELK', pc: { r: 30, t: 72 }, movement: 'c', domain: 'back-end' },
123 | { name: 'Liquibase', pc: { r: 80, t: 76 }, movement: 'c' },
124 | { name: 'haproxy', pc: { r: 80, t: 46 }, movement: 'c' },
125 |
126 | { name: 'AppManager ^', pc: { r: 360, t: 82 }, movement: 'c' },
127 | { name: 'Hibernate ^', pc: { r: 380, t: 56 }, movement: 'c' },
128 | { name: 'mongoDB', pc: { r: 330, t: 5 }, movement: 'c' },
129 | { name: 'Subversion', pc: { r: 330, t: 18 }, movement: 'c' }
130 | ]
131 | },
132 | { "quadrant": "Platforms",
133 | "left" :45,
134 | "top" : (h/2 + 18),
135 | "color" : "#DC6F1D",
136 | "items" : [
137 |
138 | {"name":"OpenId Connect", "pc":{"r":130,"t":260},"movement":"t"},
139 | {"name":"Location based services", "pc":{"r":130,"t":230},"movement":"c"},
140 | {"name":"Openstack", "pc":{"r":190,"t":190},"movement":"c"},
141 | {"name":"RHEL 7", "pc":{"r":170,"t":215},"movement":"c"},
142 |
143 | {"name":"App containers", "pc":{"r":250,"t":260},"movement":"c"},
144 | {"name":"Google Cloud Data Flow", "pc":{"r":275,"t":260},"movement":"t"},
145 | { name: 'Postgres as NoSQL', pc: { r: 220, t: 255 }, movement: 'c' },
146 | {"name":"AWS 2014 Innovations", "pc":{"r":270,"t":195},"movement":"c"},
147 | {"name":"Azure", "pc":{"r":290,"t":265},"movement":"c"},
148 | { name: 'Mesos', pc: { r: 260, t: 265 }, movement: 't' },
149 | { name: 'Marathon', pc: { r: 240, t: 268 }, movement: 't' },
150 | { name: 'Kubernetes', pc: { r: 270, t: 236 }, movement: 't' },
151 | {"name":"Google App Engine", "pc":{"r":290,"t":255},"movement":"c"},
152 | {"name":"Google as corporate platform", "pc":{"r":290,"t":200},"movement":"c"},
153 |
154 |
155 | {"name":"Google Play - (alpha/beta builds)", "pc":{"r":30,"t":225},"movement":"c"},
156 | {"name":"JVM as platform", "pc":{"r":90,"t":265},"movement":"c"},
157 | {"name":"AWS", "pc":{"r":90,"t":250},"movement":"c"},
158 | { name: 'BigIP v11', pc: { r: 50, t: 257 }, movement: 'c' },
159 |
160 |
161 |
162 | {"name":"Ruby On Rails", "pc":{"r":390,"t":215},"movement":"c"},
163 | {"name":"Everest", "pc":{"r":390,"t":185},"movement":"c"},
164 | {"name":"Magnolia CMS", "pc":{"r":390,"t":235},"movement":"c"},
165 | {"name":"Java EE - the Bad Parts", "pc":{"r":390,"t":245},"movement":"c"},
166 | {"name":"MS SqlServer", "pc":{"r":390,"t":190},"movement":"c"},
167 | {"name":"RHEL 5", "pc":{"r":370,"t":195},"movement":"c"}
168 |
169 | ]
170 | },
171 | { "quadrant": "Languages & Frameworks",
172 | "color" : "#B70062",
173 | "left" : (w-200+30),
174 | "top" : (h/2 + 18),
175 | "items" : [
176 | { name: 'CDI', pc: { r: 60, t: 290 }, movement: 'c' },
177 | { name: 'Jersey', pc: { r: 60, t: 310 }, movement: 'c' },
178 |
179 | { name: 'Guice', pc: { r: 60, t: 278 }, movement: 'c' },
180 | { name: 'RxJava', pc: { r: 150, t: 298 }, movement: 'c', domain: 'template' },
181 |
182 | {"name":"Java 8", "pc":{"r":130,"t":355},"movement":"c"},
183 | {"name":"Groovy ^", "pc":{"r":190,"t":280},"movement":"c"},
184 |
185 | {"name":"Swift", "pc":{"r":280,"t":300},"movement":"c"},
186 | {"name":"Scala - the good parts ^", "pc":{"r":290,"t":320},"movement":"c"},
187 | {"name":"Serverside Javascript", "pc":{"r":220,"t":275},"movement":"c"},
188 | {"name":"Coffeescript", "pc":{"r":270,"t":282},"movement":"c"},
189 | {"name":"Functional Reactive Programming", "pc":{"r":285,"t":330},"movement":"c"},
190 | {"name":"Clojure", "pc":{"r":280,"t":310},"movement":"c"},
191 | { name: 'RxJs', pc: { r: 250, t: 338 }, movement: 'c', domain: 'template' },
192 | { name: 'Web Components', pc: { r: 260, t: 330 }, movement: 'c' },
193 |
194 | { name: 'Mustache/Handlebars template', pc: { r: 50, t: 298 }, movement: 'c', domain: 'template' },
195 | { name: 'Spring ^', pc: { r: 360, t: 330 }, movement: 'c' },
196 | {"name":"Web Objects", "pc":{"r":390,"t":290},"movement":"c"},
197 | {"name":"ASP Classic", "pc":{"r":375,"t":330},"movement":"c"},
198 | {"name":"Java 6 and earlier", "pc":{"r":390,"t":350},"movement":"c"}
199 | ]
200 | }
201 | ];
202 |
--------------------------------------------------------------------------------
/radars/thoughtworks_tech_radar_aug_2010.js:
--------------------------------------------------------------------------------
1 | // Key
2 | //
3 | // movement:
4 | // t = moved
5 | // c = stayed put
6 | //
7 | // pc: polar coordinates
8 | // r = distance away from origin ("radial coordinate")
9 | // - Each level is 100 points away from origin
10 | // t = angle of the point from origin ("angular coordinate")
11 | // - 0 degrees is due east
12 | //
13 | // Coarse-grained quadrants
14 | // - Techniques: elements of a software development process, such as experience design; and ways of structuring software, such micro-services.
15 | // - Tools: components, such as databases, software development tools, such as versions control systems; or more generic categories of tools, such as the notion of polyglot persistance.
16 | // - Platforms: things that we build software on top of: mobile technologies like Android, virtual platforms like the JVM, or generic kinds of platforms like hybrid clouds
17 | // - Programming Languages and Frameworks
18 | //
19 | // Rings:
20 | // - Adopt: blips you should be using now; proven and mature for use
21 | // - Trial: blips ready for use, but not as completely proven as those in the adopt ring; use on a trial basis, to decide whether they should be part of your toolkit
22 | // - Assess: things that you should look at closely, but not necessarily trial yet - unless you think they would be a particularly good fit for you
23 | // - Hold: things that are getting attention in the industry, but not ready for use; sometimes they are not mature enough yet, sometimes they are irredeemably flawed
24 | // Note: there's no "avoid" ring, but throw things in the hold ring that people shouldn't use.
25 |
26 | var radar_data = [
27 | { "quadrant": "Techniques",
28 | "color" : "#8FA227",
29 | "items" : [
30 | {"name":"Database based Integration", "pc":{"r":350,"t":135},"movement":"t"},
31 | {"name":"Scrum certification", "pc":{"r":350,"t":95},"movement":"c"},
32 | {"name":"Incremental data warehousing", "pc":{"r":250,"t":165},"movement":"c"},
33 | {"name":"DevOps", "pc":{"r":250,"t":110},"movement":"c"},
34 | {"name":"Polygot Programming", "pc":{"r":180,"t":170},"movement":"c"},
35 | {"name":"Automation of technical tests", "pc":{"r":180,"t":155},"movement":"c"},
36 | {"name":"Capability modelling", "pc":{"r":180,"t":125},"movement":"c"},
37 | {"name":"Service choreography", "pc":{"r":180,"t":105},"movement":"c"},
38 | {"name":"Continuous deployment", "pc":{"r":180,"t":100},"movement":"c"},
39 | {"name":"Evolutionary architecture", "pc":{"r":120,"t":95},"movement":"c"},
40 | {"name":"Coding architects", "pc":{"r":90,"t":170},"movement":"c"},
41 | {"name":"Visualisation and metrics", "pc":{"r":80,"t":150},"movement":"c"},
42 | {"name":"Web as platform", "pc":{"r":80,"t":110},"movement":"c"},
43 | {"name":"Emergent design", "pc":{"r":80,"t":100},"movement":"c"},
44 | {"name":"Evolutionary database", "pc":{"r":70,"t":170},"movement":"c"},
45 | {"name":"Platform roadmaps", "pc":{"r":30,"t":100},"movement":"c"},
46 | {"name":"Build pipelines", "pc":{"r":30,"t":160},"movement":"c"}
47 | ]
48 | },
49 | { "quadrant": "Tools",
50 | "color" : "#587486",
51 | "items" : [
52 | {"name":"ESB", "pc":{"r":390,"t":20},"movement":"t"},
53 | {"name":"Intentional Programming", "pc":{"r":310,"t":10},"movement":"c"},
54 | {"name":"Cross mobile platforms", "pc":{"r":280,"t":85},"movement":"c"},
55 | {"name":"Github", "pc":{"r":280,"t":70},"movement":"c"},
56 | {"name":"Restfulie", "pc":{"r":280,"t":50},"movement":"c"},
57 | {"name":"RDF triple stores", "pc":{"r":280,"t":30},"movement":"c"},
58 | {"name":"Apache camel", "pc":{"r":180,"t":85},"movement":"c"},
59 | {"name":"Next gen test tools", "pc":{"r":180,"t":75},"movement":"c"},
60 | {"name":"NoSQL", "pc":{"r":180,"t":65},"movement":"c"},
61 | {"name":"Neo4j", "pc":{"r":180,"t":50},"movement":"c"},
62 | {"name":"Message busses without smarts", "pc":{"r":160,"t":85},"movement":"c"},
63 | {"name":"Puppet", "pc":{"r":130,"t":85},"movement":"c"},
64 | {"name":"mongoDB", "pc":{"r":130,"t":55},"movement":"c"},
65 | {"name":"Mercurial", "pc":{"r":130,"t":30},"movement":"c"},
66 | {"name":"Git", "pc":{"r":130,"t":15},"movement":"c"},
67 | {"name":"Squid", "pc":{"r":80,"t":85},"movement":"c"},
68 | {"name":"ASP.NET MVC", "pc":{"r":80,"t":10},"movement":"c"},
69 | {"name":"Subversion", "pc":{"r":30,"t":30},"movement":"c"}
70 | ]
71 | },
72 | { "quadrant": "Platforms",
73 | "color" : "#DC6F1D",
74 | "items" : [
75 | {"name":"Rich internet applications", "pc":{"r":390,"t":265},"movement":"c"},
76 | {"name":"GWT", "pc":{"r":390,"t":250},"movement":"c"},
77 | {"name":"IE8", "pc":{"r":390,"t":230},"movement":"c"},
78 | {"name":"WS-* beyond basic profile", "pc":{"r":390,"t":190},"movement":"c"},
79 | {"name":"Azure", "pc":{"r":290,"t":265},"movement":"c"},
80 | {"name":"Mobile Web", "pc":{"r":275,"t":260},"movement":"t"},
81 | {"name":"Google App Engine", "pc":{"r":290,"t":255},"movement":"c"},
82 | {"name":"Application appliances", "pc":{"r":190,"t":245},"movement":"c"},
83 | {"name":"Google as corporate platform", "pc":{"r":290,"t":200},"movement":"c"},
84 | {"name":"GPGPU", "pc":{"r":190,"t":185},"movement":"t"},
85 | {"name":"App containers", "pc":{"r":250,"t":260},"movement":"c"},
86 | {"name":"OAuth", "pc":{"r":130,"t":260},"movement":"t"},
87 | {"name":"RDFa", "pc":{"r":130,"t":250},"movement":"t"},
88 | {"name":"Location based services", "pc":{"r":130,"t":230},"movement":"c"},
89 | {"name":"iPad", "pc":{"r":130,"t":220},"movement":"c"},
90 | {"name":"EC2 & S3", "pc":{"r":190,"t":250},"movement":"c"},
91 | {"name":"Facebook as a business platform", "pc":{"r":190,"t":190},"movement":"c"},
92 | {"name":"JVM as platform", "pc":{"r":90,"t":265},"movement":"c"},
93 | {"name":"iPhone", "pc":{"r":90,"t":215},"movement":"c"},
94 | {"name":"Android", "pc":{"r":90,"t":190},"movement":"c"},
95 | {"name":"KVM", "pc":{"r":70,"t":260},"movement":"t"},
96 | {"name":"Atom", "pc":{"r":70,"t":245},"movement":"t"},
97 | {"name":"ALT.NET", "pc":{"r":90,"t":190},"movement":"c"},
98 | {"name":"IE6 End of Life", "pc":{"r":30,"t":225},"movement":"c"}
99 | ]
100 | },
101 | { "quadrant": "Languages",
102 | "color" : "#B70062",
103 | "items" : [
104 | {"name":"Java language end of life", "pc":{"r":290,"t":355},"movement":"c"},
105 | {"name":"F#", "pc":{"r":270,"t":330},"movement":"c"},
106 | {"name":"Scala", "pc":{"r":290,"t":320},"movement":"c"},
107 | {"name":"Clojure", "pc":{"r":260,"t":310},"movement":"c"},
108 | {"name":"HTML 5", "pc":{"r":250,"t":275},"movement":"c"},
109 | {"name":"DSLs", "pc":{"r":190,"t":340},"movement":"c"},
110 | {"name":"Groovy", "pc":{"r":190,"t":280},"movement":"c"},
111 | {"name":"C#4", "pc":{"r":90,"t":355},"movement":"c"},
112 | {"name":"JRuby", "pc":{"r":90,"t":330},"movement":"c"},
113 | {"name":"Javascript as a 1st class language", "pc":{"r":90,"t":275},"movement":"c"},
114 | {"name":"Ruby", "pc":{"r":30,"t":282},"movement":"c"}
115 | ]
116 | }
117 | ];
118 |
119 | var radar_title = "ThoughtWorks Technology Radar (Aug 2010)";
--------------------------------------------------------------------------------
/techradar_example.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdargan/techradar/86928bdea5b8539c62ed7583d78a54eca4480cca/techradar_example.pdf
--------------------------------------------------------------------------------
/techradar_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bdargan/techradar/86928bdea5b8539c62ed7583d78a54eca4480cca/techradar_example.png
--------------------------------------------------------------------------------
/utils.js:
--------------------------------------------------------------------------------
1 |
2 | function polar_to_cartesian(r,t) {
3 | //radians to degrees, requires the t*pi/180
4 | var x = r * Math.cos((t*Math.PI/180));
5 | var y = r * Math.sin((t*Math.PI/180));
6 | return [x,y];
7 | }
8 |
9 | function cartesian_to_raster(x,y) {
10 | var rx = w/2 + x;
11 | var ry = h/2 + y;
12 | return [rx,ry];
13 | }
14 |
15 | function raster_to_cartesian(rx,ry) {
16 | var x = rx - w/2;
17 | var y = ry - h/2;
18 | return [x,y];
19 | }
20 |
21 | function polar_to_raster(r,t) {
22 | var xy= polar_to_cartesian(r,t);
23 | return cartesian_to_raster(xy[0], xy[1]);
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/utils_test.js:
--------------------------------------------------------------------------------
1 |
2 | describe("Radar", function() {
3 | describe("Cartesian to Raster Co-ordinate Transformation functions", function() {
4 | it("cartesian_to_raster_origin", function() {
5 | expect(cartesian_to_raster(0,0)).toEqual([w/2,h/2]);
6 | });
7 |
8 | it("cartesian_to_raster_bounds", function() {
9 | expect(cartesian_to_raster(-500,-500)).toEqual([0,0]);
10 | expect(cartesian_to_raster(500,500)).toEqual([w,h]);
11 | expect(cartesian_to_raster(-500,500)).toEqual([0,h]);
12 | expect(cartesian_to_raster(500,0)).toEqual([w,h/2]);
13 | });
14 | });
15 |
16 | describe("Polar to Cartesian Co-ordinate Transformation functions", function() {
17 |
18 | it("polar origin ", function() {
19 | var r = 0, t = 0;
20 | expect(Math.round(polar_to_cartesian(r,t)[0])).toEqual(0);
21 | expect(Math.round(polar_to_cartesian(r,t)[1])).toEqual(0);
22 | });
23 |
24 | it("polar to cartesian 1,90", function() {
25 | var r = 1, t = 90;
26 | expect(Math.round(polar_to_cartesian(r,t)[0])).toEqual(0);
27 | expect(Math.round(polar_to_cartesian(r,t)[1])).toEqual(1);
28 | });
29 |
30 | it("polar to cartesian 20,90", function() {
31 | var r = 20;
32 | var t = 90;
33 | expect(Math.round(polar_to_cartesian(r,t)[0])).toEqual(0);
34 | expect(Math.round(polar_to_cartesian(r,t)[1])).toEqual(r);
35 | });
36 |
37 | it("polar to cartesian 20, 180", function() {
38 | var r = 20, t = 180;
39 | expect(Math.round(polar_to_cartesian(r,t)[0])).toEqual(-20);
40 | expect(Math.round(polar_to_cartesian(r,t)[1])).toEqual(0);
41 | });
42 |
43 | it("polar to cartesian, 20, 270", function() {
44 | var r = 20, t = 270;
45 | expect(Math.round(polar_to_cartesian(r,t)[0])).toEqual(0);
46 | expect(Math.round(polar_to_cartesian(r,t)[1])).toEqual(-20);
47 | });
48 |
49 | });
50 |
51 | describe("Raster to Cartesian Co-ordinate Transformation functions", function() {
52 | it("Raster to cartesian", function() {
53 | expect(raster_to_cartesian(0,0)).toEqual([-500,-500]);
54 | expect(raster_to_cartesian(1000,1000)).toEqual([500,500]);
55 | });
56 |
57 | });
58 | });
59 | jasmine.getEnv().addReporter(new jasmine.TrivialReporter());;
60 | jasmine.getEnv().execute();
61 |
--------------------------------------------------------------------------------