d3_sankey_examples.module 11.1 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php

/**
 * @file
 * Hooks and helper functions for the d3_sankey_examples module.
 */

/* Hooks. */

/**
 * Implements hook_menu().
 */
function d3_sankey_examples_menu() {
  $items = array();

  // Uses d3_sankey module to create a sample Sankey chart.
  $items['d3/examples/sankey'] = array(
    'title' => 'Sankey chart',
    'description' => 'Uses d3_sankey module to create a sample Sankey chart.',
20
21
22
23
    // For consistency with d3_examples, this has no access restriction (i.e.:
    // an open page callback). Note that in this module's implementation of
    // hook_requirements() (in d3_sankey_examples.install), we remind users to
    // disable this module on the live site.
24
25
26
27
28
    'access callback' => TRUE,
    'page callback' => '_d3_sankey_examples_sankey',
    'type' => MENU_LOCAL_TASK,
  );

29
30
31
32
33
34
35
36
37
38
  // We want the Sankey tab to have sub-tabs so we can add examples for
  // preprocessed data, but the default sub-tab needs to have the same settings
  // as the parent tab, except for the type, title, and description.
  $items['d3/examples/sankey/default'] = array(
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'title' => 'Raw data',
    'description' => 'Creates a Sankey chart by specifying raw data.',
    'weight' => -1,
  ) + $items['d3/examples/sankey'];

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  // Uses d3_sankey_table_group_pp to create a Sankey chart.
  if (module_exists('d3_sankey_table_group_pp')) {
    $items['d3/examples/sankey/table_group_preprocess'] = array(
      'title' => 'Table grouping preprocessor',
      'description' => 'Creates a Sankey chart using a preprocessor that links values in the same row, grouping duplicates.',
      // For consistency with d3_examples, this has no access restriction (i.e.:
      // an open page callback). Note that in this module's implementation of
      // hook_requirements() (in d3_sankey_examples.install), we remind users to
      // disable this module on the live site.
      'access callback' => TRUE,
      'page callback' => '_d3_sankey_examples_table_group_pp',
      'type' => MENU_LOCAL_TASK,
    );
  }

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
  return $items;
}

/* Menu callbacks. */

/**
 * Menu callback: Uses d3_sankey module to create a sample Sankey chart.
 */
function _d3_sankey_examples_sankey() {
  $chart = array(
    'type' => 'sankey',

    // This will be the HTML id attribute of the div that will contain the
    // chart.
    'id' => 'visualization',

    // You can (optionally) specify the type of Sankey chart:
    // - D3_SANKEY_SANKEYTYPE_DEFAULT will not "select" the nodes or link when a
    //   user hovers over them.
    // - D3_SANKEY_SANKEYTYPE_SELECTION will "select" a node or link when a user
    //   hovers over it, but that selection will be limited only to only one
    //   node/link - the one being hovered.
    // - D3_SANKEY_SANKEYTYPE_PATH will "select" a node or link, as well as any
    //   nodes or links connected to it when a user hovers over it.
    'sankeyType' => D3_SANKEY_SANKEYTYPE_PATH,

    // You can (optionally) specify the width and/or height of the chart in
    // pixels. These numbers must be positive integers. If you do not specify a
    // width, sankey.js will choose 700px. If you do not specify a height,
    // sankey.js will choose 400px.
    'width' => '700',
    'height' => '400',

    // You can (optionally) specify the width and padding of nodes. These
    // numbers must be positive integers. If you do not specify a nodeWidth,
    // sankey.js will choose 24px. If you do not specify a padding, sankey.js
    // will choose 8px.
    'nodeWidth' => 24,
    'nodePadding' => 8,

    // You can (optionally) choose whether or not to spread the nodes across the
    // full height of the chart. You must specify a boolean. If you do not set
    // this setting, sankey.js will assume that you want to do so, as that looks
    // better.
    //
    // See https://github.com/q-m/d3.chart.sankey for more information.
    'spread' => TRUE,

    // You can (optionally) specify how many additional times the Sankey library
    // should pass over the diagram to try to make things look better. You must
    // specify zero, or positive integer. Note that higher numbers will make the
    // chart take longer to render. If you do not set this setting, sankey.js
    // will assume 1.
    'iterations' => 1,

    // You can (optionally) specify how labels will be attached to nodes:
    // - D3_SANKEY_ALIGNLABEL_AUTO will align node labels automatically. You
    //   probably want this alignment unless you are prepared to write custom
    //   CSS to handle labels overflowing one side of the diagram and being
    //   clipped.
    // - D3_SANKEY_ALIGNLABEL_START will align node labels to the start of paths
    //   connecting from them. In LTR languages, this setting will result in the
    //   labels for the right-most column of nodes overflowing on the right-hand
    //   side of the chart; default CSS causes these labels to be clipped (i.e.:
    //   not visible).
    // - D3_SANKEY_ALIGNLABEL_END will align node labels to the end of paths
    //   connecting to them. In LTR languages, this setting will result in the
    //   labels for the left-most column of nodes overflowing on the left-hand
    //   side of the chart; default CSS causes these labels to be clipped (i.e.:
    //   not visible).
    'alignLabel' => D3_SANKEY_ALIGNLABEL_AUTO,

    // The nodes are the boxes that appear in the diagram. You can define each
    // node as an associative PHP array (which will get turned into a JS
    // object). The D3, d3-plugins-sankey, d3.chart, and d3.chart.sankey source
    // code does not explicitly specify what keys are valid in node objects, but
    // the following keys are known to work:
    // - 'name' (optional): A label for the node.
    // - 'id' (optional): An SVG ID attribute (similar to an HTML ID attribute)
    //   to add to the node.
    //
    // It is important to note that the Sankey charting library *only identifies
    // nodes using their array index*: you cannot use the 'id' attribute to
    // define links between nodes! I have explicitly set the array indicies in
    // the example below, but you don't need to.
    //
    // Note also that the Sankey charting library arranges nodes on the page
    // based on how they link together (see the 'links' key below); you do not
    // get control over this!
    //
    // The order that you specify the nodes doesn't really affect the final
    // layout, but does matter, because their index is what you use to define
    // the links between them (see below). You will probably want to add nodes
    // to the bottom of the array so that you don't have to re-calculate all the
    // link sources/targets.
    'nodes' => array(
      0 => array('name' => 'Revenue', 'id' => 'revenue'),
      1 => array('name' => 'New work', 'id' => 'lob_new_work'),
      2 => array('name' => 'Service level agreements', 'id' => 'lob_sla'),
      3 => array('name' => 'Tech support', 'id' => 'lob_techsupport'),
      4 => array('name' => 'Client 1', 'id' => 'client_1'),
      5 => array('name' => 'Client 2', 'id' => 'client_2'),
    ),

158
159
160
161
162
163
164
165
166
167
168
    // You can define the colors of nodes as either a single string containing
    // a valid SVG color string, or as an array of strings containing valid SVG
    // color strings.
    //
    // See https://www.w3.org/TR/SVGColor12/#color for the SVG color string
    // syntax.
    //
    // This is an example of a single SVG color string; see 'link_colors' below
    // for an example of an array of SVG color strings.
    'node_colors' => '#ff0000',

169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
    // The links are the paths between the nodes. You can define each link as an
    // associative PHP array (which will get turned into a JS object). The D3,
    // d3-plugins-sankey, d3.chart, and d3.chart.sankey source code does not
    // explicitly specify what keys are valid in link objects, but the following
    // keys are known to work:
    // - source (required): The array index of the node to connect from.
    // - target (required): The array index of the node to connect to.
    // - value (optional): A number representing how big the link is. If you do
    //   not specify a value, the actual size of the link will depend on how
    //   many other links are connected to the source and target nodes. You can
    //   specify any number (integer, float; positive or negative): the Sankey
    //   charting library will assume that the value of all links are all in the
    //   same unit (e.g.: dollars, percentage points, etc.).
    //
    // The order of the links do not matter. I have visually grouped the links
    // with blank lines to illustrate each path from one side of the Sankey
    // diagram to the other.
    'links' => array(
      array('value' => 10000, 'source' => 0, 'target' => 1),
      array('value' => 7000, 'source' => 1, 'target' => 4),
      array('value' => 3000, 'source' => 1, 'target' => 5),

      array('value' => 15000, 'source' => 0, 'target' => 2),
      array('value' => 7500, 'source' => 2, 'target' => 4),
      array('value' => 7500, 'source' => 2, 'target' => 5),

      array('value' => 8000, 'source' => 0, 'target' => 3),
      array('value' => 4000, 'source' => 3, 'target' => 4),
      array('value' => 4000, 'source' => 3, 'target' => 5),
    ),
199
200
201
202
203
204
205
206
207
208
209

    // You can define the colors of links as either a single string containing
    // a valid SVG color string, or as an array of strings containing valid SVG
    // color strings.
    //
    // See https://www.w3.org/TR/SVGColor12/#color for the SVG color string
    // syntax.
    //
    // This is an example of an array of SVG color strings; see 'node_colors'
    // above for an example of a single SVG color string.
    'link_colors' => array('red', '#7F7F26'),
210
211
212
213
  );

  return d3_draw($chart);
}
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231

/**
 * Menu callback: Uses d3_sankey_table_group_pp to create a Sankey chart.
 */
function _d3_sankey_examples_table_group_pp() {
  $chart = array(
    'type' => 'sankey',

    // See _d3_sankey_examples_sankey() for an explanation of these properties.
    'id' => 'visualization',
    'sankeyType' => D3_SANKEY_SANKEYTYPE_PATH,
    'width' => '700',
    'height' => '400',
    'nodeWidth' => 24,
    'nodePadding' => 8,
    'spread' => TRUE,
    'iterations' => 1,
    'alignLabel' => D3_SANKEY_ALIGNLABEL_AUTO,
232
233
    'node_colors' => '#ff0000',
    'link_colors' => array('red', '#7F7F26'),
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
  );

  // Create some sample data.
  $unprocessed_data = array(
    array('1970s', 'Drama', 'The Godfather'),
    array('1970s', 'Sci-fi/Fantasy', 'Star Wars'),
    array('1980s', 'Sci-fi/Fantasy', 'The Empire Strikes Back'),
    array('1990s', 'Drama', 'The Shawshank Redemption'),
    array('1990s', 'Biography', "Schindler's List"),
    array('2000s', 'Action', 'The Dark Knight'),
    array('2000s', 'Sci-fi/Fantasy', 'LotR: Return of the King'),
  );

  // Initialize a GroupingPreprocessor.
  $preprocessor = new \Drupal\d3_sankey_table_group_pp\TableGroupingPreprocessor();

  // Feed the preprocessor the sample data.
  foreach ($unprocessed_data as $row) {
    $preprocessor->ingestRow($row);
  }

  // Get an object containing the raw chart data out of the preprocessor.
  $raw_data = $preprocessor->getRawData();

  // Add the nodes and links to the chart.
  $chart['nodes'] = $raw_data->getAssocArrayNodes();
  $chart['links'] = $raw_data->getAssocArrayLinks();

  return d3_draw($chart);
}