From e11f69d5a29fd85d89bdf54d4ee68079acb960eb Mon Sep 17 00:00:00 2001 From: Daniel Cothran <daniel@andile.co> Date: Thu, 7 Dec 2017 18:02:20 -0500 Subject: [PATCH] Issue: 2928419 by mwebaze: Charts Plugins --- charts.api.php | 37 +- charts.module | 18 +- charts.services.yml | 3 + includes/charts.pages.inc | 30 +- .../src/Plugin/chart/CThreeCharts.php | 116 ++++++ .../src/Plugin/chart/GoogleCharts.php | 369 ++++++++++++++++++ .../src/Charts/HighchartsChartsRender.php | 10 +- .../src/Plugin/chart/Highchart.php | 154 ++++++++ src/Annotation/Chart.php | 24 ++ src/Plugin/chart/AbstractChart.php | 34 ++ src/Plugin/chart/ChartInterface.php | 21 + src/Plugin/chart/ChartManager.php | 30 ++ 12 files changed, 812 insertions(+), 34 deletions(-) create mode 100755 modules/charts_c3/src/Plugin/chart/CThreeCharts.php create mode 100755 modules/charts_google/src/Plugin/chart/GoogleCharts.php create mode 100755 modules/charts_highcharts/src/Plugin/chart/Highchart.php create mode 100755 src/Annotation/Chart.php create mode 100755 src/Plugin/chart/AbstractChart.php create mode 100755 src/Plugin/chart/ChartInterface.php create mode 100755 src/Plugin/chart/ChartManager.php diff --git a/charts.api.php b/charts.api.php index 8247270..cdd8c6a 100644 --- a/charts.api.php +++ b/charts.api.php @@ -50,15 +50,15 @@ use Drupal\charts\Theme\ChartsInterface; * chart_data, chart_xaxis, and chart_yaxis). For a full list, see the * charts_element_info() function. * + * * @see charts_element_info() - */ - -/** + * + * * Alter an individual chart before it is printed. * - * @param array $chart + * @param $chart * The chart renderable. Passed in by reference. - * @param string $chart_id + * @param $chart_id * The chart identifier, pulled from the $chart['#chart_id'] property (if * any). Not all charts have a chart identifier. */ @@ -76,12 +76,9 @@ function hook_chart_alter(&$chart, $chart_id) { * name instead of being passed in as an argument. * * @see hook_chart_alter() - * - * @param array $chart - * Chart. + * @param $chart */ function hook_chart_CHART_ID_alter(&$chart) { - } /** @@ -96,14 +93,13 @@ function hook_chart_CHART_ID_alter(&$chart) { * Even though this hook may be fragile, it may provide developers with access * to library-specific functionality. * - * @param array $definition + * @param $definition * The chart definition to be modified. The raw values are passed directly to * the charting library. - * @param array $chart + * @param $chart * The chart renderable. This may be used for reference (or read to add * support for new properties), but any changes to this variable will not * have an effect on output. - * * @internal param $chart_id The chart ID, derived from the $chart['#chart_id'] property. Note that not* The chart ID, derived from the $chart['#chart_id'] property. Note that not * all charts may have a $chart_id. */ @@ -115,10 +111,8 @@ function hook_chart_definition_alter(&$definition, $chart) { * * Same as hook_chart_definition_alter(), only including the $chart_id in the * function name instead of being passed in as an argument. - * @see hook_chart_definition_alter(). - * - * @param array $chart - * Chart. + * @see hook_chart_definition_alter() + * @param $chart */ function hook_chart_definition_CHART_ID_alter(&$chart) { } @@ -149,9 +143,7 @@ function hook_charts_info() { * * If your module needs to modify the capabilities of a charting library, such * as to add support for a new chart type, it may do so with this hook. - * - * @param array $info - * Info. + * @param $info */ function hook_charts_info_alter(&$info) { // Say the Google charts library supports geo charts. @@ -175,8 +167,7 @@ function hook_charts_type_info() { // Many charting libraries always refer to the main axis as the "y-axis", // even if the chart's main axis is horizontal. An example of this is a // bar chart, where the values are along the horizontal axis. - // Meaning x/y axis are flipped. - 'axis_inverted' => TRUE, + 'axis_inverted' => TRUE, // Meaning x/y axis are flipped. // For bar/area/other charts that support stacking of series, set this value // to TRUE. 'stacking' => TRUE, @@ -189,9 +180,7 @@ function hook_charts_type_info() { * * If your module needs to modify the capabilities or labels of a paricular * chart type, it may alter the definitions provided by other modules. - * - * @param array $chart_types - * Chart Types. + * @param $chart_types */ function hook_charts_type_info_alter(&$chart_types) { $chart_types['bar']['stacking'] = FALSE; diff --git a/charts.module b/charts.module index cce6439..86374a3 100644 --- a/charts.module +++ b/charts.module @@ -91,9 +91,19 @@ function template_preprocess_views_view_charts(&$variables) { $attachmentDisplayOptions[$i]['inherit_yaxis'] = $view->displayHandlers->get($attachmentId)->options['inherit_yaxis']; } $seriesData = array_merge($seriesData, $seriesDataAttachment); - $moduleSelector = new ModuleSelector($library, $categories, $seriesData, $options, $attachmentDisplayOptions, $chartId); - if ($moduleSelector->moduleExists()) { - $moduleSelector->buildVariables($variables); - } + $plugin_manager = \Drupal::service('plugin.manager.charts'); + $plugin_definitions = $plugin_manager->getDefinitions(); + + if (!isset($plugin_definitions)) { + //to be removed in drupal 9 + $moduleSelector = new ModuleSelector($library, $categories, $seriesData, $options, $attachmentDisplayOptions, $chartId); + if ($moduleSelector->moduleExists()) { + $moduleSelector->buildVariables($variables); + } + } + else{ + $plugin = $plugin_manager->createInstance($library); + $plugin->buildVariables($options, $categories, $seriesData, $attachmentDisplayOptions, $variables, $chartId); + } } diff --git a/charts.services.yml b/charts.services.yml index 5320eb5..f769994 100644 --- a/charts.services.yml +++ b/charts.services.yml @@ -8,3 +8,6 @@ services: charts.settings: class: Drupal\charts\Services\ChartsSettingsService arguments: ['@config.factory'] + plugin.manager.charts: + class: Drupal\charts\Plugin\chart\ChartManager + parent: default_plugin_manager diff --git a/includes/charts.pages.inc b/includes/charts.pages.inc index dfc80f3..1405b5e 100644 --- a/includes/charts.pages.inc +++ b/includes/charts.pages.inc @@ -198,8 +198,34 @@ function charts_settings_form($form, $defaults = [], $field_options = [], $paren // Ensure all defaults are set. $options = array_merge(charts_default_settings(), $defaults); + //using plugins to get the available installed libraries + $plugin_manager = \Drupal::service('plugin.manager.charts'); + $plugin_definitions = $plugin_manager->getDefinitions(); + $library_options = []; + + foreach ($plugin_definitions as $plugin_definition){ + $library_options[$plugin_definition['id']] = $plugin_definition['name']; + } + + // Get a list of available chart libraries if plugins have not been implemented. + // This will be removed as ModuleSelector is now @deprecated + + if (empty($library_options)){ + $charts_info = charts_info(); + $library_options = []; + foreach ($charts_info as $library_name => $library_info) { + + if (Drupal::moduleHandler()->moduleExists($charts_info[$library_name]['module'])) { + $library_options[$library_name] = $library_info['label']; + } + } + if (empty($library_options)) { + drupal_set_message(t('There are no enabled charting libraries. Please enable a Charts sub-module.')); + } + } + // Get a list of available chart libraries. - $charts_info = charts_info(); + /*$charts_info = charts_info(); $library_options = []; foreach ($charts_info as $library_name => $library_info) { if (Drupal::moduleHandler()->moduleExists($charts_info[$library_name]['module'])) { @@ -208,7 +234,7 @@ function charts_settings_form($form, $defaults = [], $field_options = [], $paren } if (count($library_options) == 0) { drupal_set_message(t('There are no enabled charting libraries. Please enable a Charts sub-module.')); - } + }*/ $form['library'] = [ '#title' => t('Charting library'), '#type' => 'select', diff --git a/modules/charts_c3/src/Plugin/chart/CThreeCharts.php b/modules/charts_c3/src/Plugin/chart/CThreeCharts.php new file mode 100755 index 0000000..09e3ee0 --- /dev/null +++ b/modules/charts_c3/src/Plugin/chart/CThreeCharts.php @@ -0,0 +1,116 @@ +<?php + +namespace Drupal\charts_c3\Plugin\chart; + +use Drupal\charts\Plugin\chart\AbstractChart; +use Drupal\charts_c3\Settings\CThree\ChartType; +use Drupal\charts_c3\Settings\CThree\CThree; +use Drupal\charts_c3\Settings\CThree\ChartTitle; +use Drupal\charts_c3\Settings\CThree\ChartData; +use Drupal\charts_c3\Settings\CThree\ChartColor; +use Drupal\charts_c3\Settings\CThree\ChartAxis; + +/** + * Define a concrete class for a Chart. + * + * @Chart( + * id = "c3_charts", + * name = @Translation("C3 Charts") + * ) + */ +class CThreeCharts extends AbstractChart{ + public function buildVariables($options, $categories = [], $seriesData = [], $attachmentDisplayOptions = [], &$variables, + $chartId) { + $noAttachmentDisplays = count($attachmentDisplayOptions) === 0; + $types = []; + + // @todo - make this work for more that one attachment. + for ($i = 1; $i <= count($attachmentDisplayOptions); $i++) { + if ($attachmentDisplayOptions[$i - 1]['style']['options']['type'] == 'column') { + $types[$seriesData[$i]['name']] = 'bar'; + } + else { + $types[$seriesData[$i]['name']] = $attachmentDisplayOptions[$i - 1]['style']['options']['type']; + } + } + $c3Data = []; + for ($i = 0; $i < count($seriesData); $i++) { + $c3DataTemp = $seriesData[$i]['data']; + array_unshift($c3DataTemp, $seriesData[$i]['name']); + array_push($c3Data, $c3DataTemp); + } + + $c3Chart = new ChartType(); + $c3Chart->setType($options['type']); + $c3ChartTitle = new ChartTitle(); + $c3ChartTitle->setText($options['title']); + $chartAxis = new ChartAxis(); + $c3 = new CThree(); + $bindTo = '#' . $chartId; + $c3->setBindTo($bindTo); + $c3->setTitle($c3ChartTitle); + $chartData = new ChartData(); + if ($noAttachmentDisplays > 0) { + $chartData->setLabels(FALSE); + } + + // Sets the primary y axis. + $yAxis = []; + $yAxis[$seriesData[0]['name']] = 'y'; + $showAxis['show'] = TRUE; + $showAxis['label'] = $options['yaxis_title']; + $chartAxis->y = $showAxis; + + // Sets secondary axis from the first attachment only. + if (!$noAttachmentDisplays && $attachmentDisplayOptions[0]['inherit_yaxis'] == 0) { + $yAxis[$seriesData[1]['name']] = 'y2'; + $showSecAxis['show'] = TRUE; + $showSecAxis['label'] = $attachmentDisplayOptions[0]['style']['options']['yaxis_title']; + $chartAxis->y2 = $showSecAxis; + } + + // Sets the chart type. + $chartData->setType($options['type']); + $c3->setData($chartData); + if ($options['type'] == 'bar') { + $chartAxis->setRotated(TRUE); + array_unshift($categories, 'x'); + array_push($c3Data, $categories); + $chartData->setColumns($c3Data); + } + else if ($options['type'] == 'column') { + $chartData->setType('bar'); + $chartAxis->setRotated(FALSE); + array_unshift($categories, 'x'); + array_push($c3Data, $categories); + $chartData->setColumns($c3Data); + } + else if ($options['type'] == 'pie' || $options['type'] == 'donut') { + $chartData->setColumns($c3Data); + } + else { + array_unshift($categories, 'x'); + array_push($c3Data, $categories); + $chartData->setColumns($c3Data); + } + $chartData->types = $types; + + if ($options['type'] != 'pie' && $options['type'] != 'donut') { + $c3->setAxis($chartAxis); + } + + $chartColor = new ChartColor(); + $seriesColors = []; + for ($i = 0; $i < count($seriesData); $i++) { + $seriesColor = $seriesData[$i]['color']; + array_push($seriesColors, $seriesColor); + } + $chartColor->setPattern($seriesColors); + $c3->setColor($chartColor); + + $variables['chart_type'] = 'c3'; + $variables['content_attributes']['data-chart'][] = json_encode($c3); + $variables['attributes']['id'][0] = $chartId; + $variables['attributes']['class'][] = 'charts-c3'; + } +} \ No newline at end of file diff --git a/modules/charts_google/src/Plugin/chart/GoogleCharts.php b/modules/charts_google/src/Plugin/chart/GoogleCharts.php new file mode 100755 index 0000000..a55d547 --- /dev/null +++ b/modules/charts_google/src/Plugin/chart/GoogleCharts.php @@ -0,0 +1,369 @@ +<?php +namespace Drupal\charts_google\Plugin\chart; + +use Drupal\charts\Plugin\chart\AbstractChart; +use Drupal\charts_google\Settings\Google\GoogleOptions; +use Drupal\charts_google\Settings\Google\ChartType; +use Drupal\charts_google\Settings\Google\ChartArea; +use Drupal\charts_google\Settings\Google\HorizontalAxis; +use Drupal\charts_google\Settings\Google\VerticalAxis; + +/** + * Define a concrete class for a Chart. + * + * @Chart( + * id = "google", + * name = @Translation("Google charts") + * ) + */ +class GoogleCharts extends AbstractChart { + /** + * Creates a JSON Object formatted for Google charts to use + * @param array $categories + * @param array $seriesData + * + * @return json|string + */ + public function buildVariables($options, $categories = [], $seriesData = [], $attachmentDisplayOptions = [], &$variables, $chartId) { + $categoriesCount = count($categories); + $seriesCount = count($seriesData); + + // Creates an array of the length of the series data. + $dataCount = []; + for ($x = 0; $x < $seriesCount; $x++) { + $dataCountTemp = count($seriesData[$x]['data']); + array_push($dataCount, $dataCountTemp); + } + + $dataTable = []; + for ($j = 0; $j < $categoriesCount; $j++) { + $rowDataTable = []; + for ($i = 0; $i < $seriesCount; $i++) { + $rowDataTabletemp = $seriesData[$i]['data'][$j]; + array_push($rowDataTable, $rowDataTabletemp); + } + array_unshift($rowDataTable, $categories[$j]); + array_push($dataTable, $rowDataTable); + } + + $dataTableHeader = []; + for ($r = 0; $r < $seriesCount; $r++) { + array_push($dataTableHeader, $seriesData[$r]['name']); + } + array_unshift($dataTableHeader, 'label'); + array_unshift($dataTable, $dataTableHeader); + + $googleOptions = $this->createChartsOptions($options, $seriesData, $attachmentDisplayOptions); + $googleChartType = $this->createChartType($options); + $variables['chart_type'] = 'google'; + $variables['attributes']['class'][0] = 'charts-google'; + $variables['attributes']['id'][0] = $chartId; + $variables['content_attributes']['data-chart'][] = json_encode($dataTable); + $variables['attributes']['google-options'][1] = json_encode($googleOptions); + $variables['attributes']['google-chart-type'][2] = json_encode($googleChartType); + } + + /** + * Create charts options. + * + * @param array $options + * Options. + * @param array $seriesData + * Series data. + * @param array $attachmentDisplayOptions + * Attachment Display Options. + * + * @return \Drupal\charts_google\Settings\Google\GoogleOptions + * GoogleOptions object with chart options or settings to be used by google visualization framework. + */ + private function createChartsOptions(array $options = [], array $seriesData = [], array $attachmentDisplayOptions = []) { + $noAttachmentDisplays = count($attachmentDisplayOptions) === 0; + + $chartSelected = []; + $seriesTypes = []; + + $firstVaxis = new VerticalAxis(); + + if (isset($options['yaxis_min'])) { + $firstVaxis->setMinValue($options['yaxis_min']); + } + + if (isset($options['yaxis_view_min'])) { + $firstVaxis->setViewWindowValue('min', $options['yaxis_view_min']); + } + + if (isset($options['yaxis_view_max'])) { + $firstVaxis->setViewWindowValue('max', $options['yaxis_view_max']); + } + + if (isset($options['yaxis_max'])) { + $firstVaxis->setMaxValue($options['yaxis_max']); + } + + // A format string for numeric or date axis labels. + if (isset($options['yaxis_title'])) { + $firstVaxis->setTitle($options['yaxis_title']); + } + + if (isset($options['yaxis_title_color'])) { + $firstVaxis->setTitleTextStyleValue('color', $options['yaxis_title_color']); + } + + if (isset($options['yaxis_title_font'])) { + $firstVaxis->setTitleTextStyleValue('fontName', $options['yaxis_title_font']); + } + + if (isset($options['yaxis_title_size'])) { + $firstVaxis->setTitleTextStyleValue('fontSize', $options['yaxis_title_size']); + } + + if (isset($options['yaxis_title_bold'])) { + $firstVaxis->setTitleTextStyleValue('bold', $options['yaxis_title_bold']); + } + + if (isset($options['yaxis_title_italic'])) { + $firstVaxis->setTitleTextStyleValue('italic', $options['yaxis_title_italic']); + } + + // Axis title position. + if (isset($options['yaxis_title_position'])) { + $firstVaxis->setTextPosition($options['yaxis_title_position']); + } + + if (isset($options['yaxis_baseline'])) { + $firstVaxis->setBaseline($options['yaxis_baseline']); + } + + if (isset($options['yaxis_baseline_color'])) { + $firstVaxis->setBaselineColor($options['yaxis_baseline_color']); + } + + if (isset($options['yaxis_direction'])) { + $firstVaxis->setDirection($options['yaxis_direction']); + } + + // A format string for numeric or date axis labels. + if (isset($options['yaxis_format'])) { + $firstVaxis->setFormat($options['yaxis_format']); + } + + if (isset($options['yaxis_view_window_mode'])) { + $firstVaxis->setViewWindowMode($options['yaxis_view_window_mode']); + } + + $firstHaxis = new HorizontalAxis(); + + if (isset($options['xaxis_min'])) { + $firstHaxis->setMinValue($options['xaxis_min']); + } + + if (isset($options['xaxis_view_min'])) { + $firstHaxis->setViewWindowValue('min', $options['xaxis_view_min']); + } + + if (isset($options['xaxis_view_max'])) { + $firstHaxis->setViewWindowValue('max', $options['xaxis_view_max']); + } + + if (isset($options['xaxis_max'])) { + $firstHaxis->setMaxValue($options['xaxis_max']); + } + + // A format string for numeric or date axis labels. + if (isset($options['xaxis_title'])) { + $firstHaxis->setTitle($options['xaxis_title']); + } + + if (isset($options['xaxis_title_color'])) { + $firstHaxis->setTitleTextStyleValue('color', $options['xaxis_title_color']); + } + + if (isset($options['xaxis_title_font'])) { + $firstHaxis->setTitleTextStyleValue('fontName', $options['xaxis_title_font']); + } + + if (isset($options['xaxis_title_size'])) { + $firstHaxis->setTitleTextStyleValue('fontSize', $options['xaxis_title_size']); + } + + if (isset($options['xaxis_title_bold'])) { + $firstHaxis->setTitleTextStyleValue('bold', $options['xaxis_title_bold']); + } + + if (isset($options['xaxis_title_italic'])) { + $firstHaxis->setTitleTextStyleValue('italic', $options['xaxis_title_italic']); + } + + // Axis title position. + if (isset($options['xaxis_title_position'])) { + $firstHaxis->setTextPosition($options['xaxis_title_position']); + } + + if (isset($options['xaxis_baseline'])) { + $firstHaxis->setBaseline($options['xaxis_baseline']); + } + + if (isset($options['xaxis_baseline_color'])) { + $firstHaxis->setBaselineColor($options['xaxis_baseline_color']); + } + + if (isset($options['xaxis_direction'])) { + $firstHaxis->setDirection($options['xaxis_direction']); + } + + // A format string for numeric or date axis labels. + if (isset($options['xaxis_format'])) { + $firstHaxis->setFormat($options['xaxis_format']); + } + + if (isset($options['xaxis_view_window_mode'])) { + $firstHaxis->setViewWindowMode($options['xaxis_view_window_mode']); + } + + $vAxes = []; + $hAxes = []; + + array_push($vAxes, $firstVaxis); + array_push($hAxes, $firstHaxis); + + // Sets secondary axis from the first attachment only. + if (!$noAttachmentDisplays && $attachmentDisplayOptions[0]['inherit_yaxis'] == 0) { + $secondVaxis = new VerticalAxis(); + $secondVaxis->setTitle($attachmentDisplayOptions[0]['style']['options']['yaxis_title']); + array_push($vAxes, $secondVaxis); + } + + array_push($chartSelected, $options['type']); + + // @todo: make sure this works for more than one attachment. + for ($i = 0; $i < count($attachmentDisplayOptions); $i++) { + $attachmentChartType = $attachmentDisplayOptions[$i]['style']['options']['type']; + + if ($attachmentChartType == 'column') { + $attachmentChartType = 'bars'; + } + + if ($attachmentDisplayOptions[$i]['inherit_yaxis'] == 0 && $i == 0) { + $seriesTypes[$i + 1] = [ + 'type' => $attachmentChartType, + 'targetAxisIndex' => 1 + ]; + } + else { + $seriesTypes[$i + 1] = ['type' => $attachmentChartType]; + } + + array_push($chartSelected, $attachmentChartType); + } + + $chartSelected = array_unique($chartSelected); + $googleOptions = new GoogleOptions(); + + if (count($chartSelected) > 1) { + $parentChartType = $options['type']; + + if ($parentChartType == 'column') { + $parentChartType = 'bars'; + } + + $googleOptions->seriesType = $parentChartType; + $googleOptions->series = $seriesTypes; + } + + $googleOptions->setTitle($options['title']); + + if (isset($options['subtitle'])) { + $googleOptions->setSubTitle($options['subtitle']); + } + + $googleOptions->setVerticalAxes($vAxes); + $googleOptions->setHorizontalAxes($hAxes); + + if (in_array('donut', $chartSelected)) { + $googleOptions->pieHole = '0.5'; + } + + $chartArea = new ChartArea(); + + // Chart Area width. + if (isset($options['chart_area']['width'])) { + $chartArea->setWidth($options['chart_area']['width']); + } + + // Chart Area height. + if (isset($options['chart_area']['height'])) { + $chartArea->setHeight($options['chart_area']['height']); + } + + // Chart Area padding top. + if (isset($options['chart_area']['top'])) { + $chartArea->setPaddingTop($options['chart_area']['top']); + } + + // Chart Area padding left. + if (isset($options['chart_area']['left'])) { + $chartArea->setPaddingLeft($options['chart_area']['left']); + } + + $seriesColors = []; + for ($i = 0; $i < count($seriesData); $i++) { + $seriesColor = $seriesData[$i]['color']; + array_push($seriesColors, $seriesColor); + } + $googleOptions->setColors($seriesColors); + + // Width of the chart, in pixels. + if (isset($options['width'])) { + $googleOptions->setWidth($options['width']); + } + + // Height of the chart, in pixels. + if (isset($options['height'])) { + $googleOptions->setHeight($options['height']); + } + + // 'legend' can be a string (for position) or an array with legend + // properties: [position: 'top', textStyle: [color: 'blue', fontSize: 16]] + if (isset($options['legend'])) { + $googleOptions->setLegend($options['legend']); + } + + // Set legend position. + if (isset($options['legend_position'])) { + if(empty($options['legend_position'])) { + $options['legend_position'] = 'none'; + $googleOptions->setLegend($options['legend_position']); + } else { + $googleOptions->setLegend($options['legend_position']); + } + } + + // Where to place the chart title, compared to the chart area. + if (isset($options['title_position'])) { + $googleOptions->setTitlePosition($options['title_position']); + } + + // Where to place the axis titles, compared to the chart area + if (isset($options['axis_titles_position'])) { + $googleOptions->setAxisTitlesPosition($options['axis_titles_position']); + } + + return $googleOptions; + } + + /** + * Create Chart Type. + * + * @param array $options + * Options. + * + * @return \Drupal\charts_google\Settings\Google\ChartType + * ChartType. + */ + private function createChartType(array $options = []) { + $googleChartType = new ChartType(); + $googleChartType->setChartType($options['type']); + + return $googleChartType; + } +} \ No newline at end of file diff --git a/modules/charts_highcharts/src/Charts/HighchartsChartsRender.php b/modules/charts_highcharts/src/Charts/HighchartsChartsRender.php index c70f023..7b522aa 100644 --- a/modules/charts_highcharts/src/Charts/HighchartsChartsRender.php +++ b/modules/charts_highcharts/src/Charts/HighchartsChartsRender.php @@ -49,10 +49,12 @@ class HighchartsChartsRender implements ChartsRenderInterface { } // Add innerSize to differentiate between donut and pie. foreach ($seriesData as $key => &$value) { - $innerSize['showInLegend'] = 'true'; - $innerSize['innerSize'] = '40%'; - $chartPlacement = array_search($value, $seriesData); - $seriesData[$chartPlacement] = array_merge($innerSize, $seriesData[$chartPlacement]); + if ($typeOptions == 'pie') { + $innerSize['showInLegend'] = 'true'; + $innerSize['innerSize'] = '40%'; + $chartPlacement = array_search($value, $seriesData); + $seriesData[$chartPlacement] = array_merge($innerSize, $seriesData[$chartPlacement]); + } } } $chart->setType($typeOptions); diff --git a/modules/charts_highcharts/src/Plugin/chart/Highchart.php b/modules/charts_highcharts/src/Plugin/chart/Highchart.php new file mode 100755 index 0000000..0cc1340 --- /dev/null +++ b/modules/charts_highcharts/src/Plugin/chart/Highchart.php @@ -0,0 +1,154 @@ +<?php +namespace Drupal\charts_highcharts\Plugin\chart; + +use Drupal\charts\Plugin\chart\AbstractChart; +//use Drupal\Charts\Annotation\Chart; +use Drupal\charts_highcharts\Settings\Highcharts\Chart; +//use Drupal\charts_highcharts\Settings\Highcharts\ChartType; +use Drupal\charts_highcharts\Settings\Highcharts\ChartTitle; +use Drupal\charts_highcharts\Settings\Highcharts\Xaxis; +use Drupal\charts_highcharts\Settings\Highcharts\XaxisTitle; +use Drupal\charts_highcharts\Settings\Highcharts\ChartLabel; +use Drupal\charts_highcharts\Settings\Highcharts\YaxisLabel; +use Drupal\charts_highcharts\Settings\Highcharts\Yaxis; +use Drupal\charts_highcharts\Settings\Highcharts\YaxisTitle; +use Drupal\charts_highcharts\Settings\Highcharts\DataLabelStatus; +use Drupal\charts_highcharts\Settings\Highcharts\DataLabels; +use Drupal\charts_highcharts\Settings\Highcharts\PlotOptions; +use Drupal\charts_highcharts\Settings\Highcharts\Tooltip; +use Drupal\charts_highcharts\Settings\Highcharts\ChartCredits; +use Drupal\charts_highcharts\Settings\Highcharts\ChartLegend; +use Drupal\charts_highcharts\Settings\Highcharts\Highcharts; +/** + * Defines a concrete class for a Highcharts. + * + * @Chart( + * id = "highcharts", + * name = @Translation("Highcharts") + * ) + */ +class Highchart extends AbstractChart{ + /** + * Creates a JSON Object formatted for Highcharts to use + * + * @param $options + * @param array $categories + * @param array $seriesData + * + * @param array $attachmentDisplayOptions + * + * @return Highcharts object to be used by highcharts javascripts visualization framework + */ + public function buildVariables($options, $categories = [], $seriesData = [], $attachmentDisplayOptions = [], &$variables, $chartId) { + $noAttachmentDisplays = count($attachmentDisplayOptions) === 0; + + $chart = new Chart(); + $typeOptions = $options['type']; + // @todo: make this so that it happens if any display uses donut. + if ($typeOptions == 'donut'){ + $typeOptions = 'pie'; + // Remove donut from seriesData. + foreach ($seriesData as $key => &$value) { + $value = str_replace('donut','pie',$value); + } + // Add innerSize to differentiate between donut and pie. + foreach ($seriesData as $key => &$value) { + $innerSize['showInLegend'] = 'true'; + $innerSize['innerSize'] = '40%'; + $chartPlacement = array_search($value, $seriesData); + $seriesData[$chartPlacement] = array_merge($innerSize, $seriesData[$chartPlacement]); + } + } + $chart->setType($typeOptions); + + // Set chart width. + if (isset($options['width'])) { + $chart->setWidth($options['width']); + } + + // Set chart height. + if (isset($options['height'])) { + $chart->setHeight($options['height']); + } + + // Set chart title. + $chartTitle = new ChartTitle(); + if (isset($options['title'])) { + $chartTitle->setText($options['title']); + } + + $chartXaxis = new Xaxis(); + $chartLabels = new ChartLabel(); + + // Set x-axis label rotation. + if (isset($options['xaxis_labels_rotation'])) { + $chartLabels->setRotation($options['xaxis_labels_rotation']); + } + + $chartXaxis->setCategories($categories); + + // Set x-axis title. + $xAxisTitle = new XaxisTitle(); + if (isset($options['xaxis_title'])) { + $xAxisTitle->setText($options['xaxis_title']); + } + $chartXaxis->setTitle($xAxisTitle); + $chartXaxis->setLabels($chartLabels); + $yaxisLabels = new YaxisLabel(); + $chartYaxis = new Yaxis(); + $yAxes = []; + $yAxisTitle = new YaxisTitle(); + $yAxisTitle->setText($options['yaxis_title']); + if (!empty($options['yaxis_min'])) { + $chartYaxis->min = $options['yaxis_min']; + } + if (!empty($options['yaxis_max'])) { + $chartYaxis->max = $options['yaxis_max']; + } + + $chartYaxis->setLabels($yaxisLabels); + $chartYaxis->setTitle($yAxisTitle); + array_push($yAxes, $chartYaxis); + + // Chart libraries tend to support only one secondary axis. + if (!$noAttachmentDisplays && $attachmentDisplayOptions[0]['inherit_yaxis'] == 0) { + $chartYaxisSecondary = new Yaxis(); + $yAxisTitleSecondary = new YaxisTitle(); + $yAxisTitleSecondary->setText($attachmentDisplayOptions[0]['style']['options']['yaxis_title']); + $chartYaxisSecondary->setTitle($yAxisTitleSecondary); + $chartYaxisSecondary->setLabels($yaxisLabels); + $chartYaxisSecondary->opposite = 'true'; + if (!empty($attachmentDisplayOptions[0]['style']['options']['yaxis_min'])) { + $chartYaxisSecondary->min = $attachmentDisplayOptions[0]['style']['options']['yaxis_min']; + } + if (!empty($attachmentDisplayOptions[0]['style']['options']['yaxis_max'])) { + $chartYaxisSecondary->max = $attachmentDisplayOptions[0]['style']['options']['yaxis_max']; + } + array_push($yAxes, $chartYaxisSecondary); + } + $dataLabelStatus = new DataLabelStatus(); + $dataLabels = new DataLabels(); + $dataLabels->setDataLabels($dataLabelStatus); + $plotOptions = new PlotOptions(); + $plotOptions->setPlotType($dataLabels); + $chartTooltip = new Tooltip(); + $chartCredits = new ChartCredits(); + $chartLegend = new ChartLegend(); + + $highchart = new Highcharts(); + $highchart->setChart($chart); + $highchart->setTitle($chartTitle); + $highchart->setXAxis($chartXaxis); +// $highchart->yAxis = $yAxes; + $highchart->setTooltip($chartTooltip); + $highchart->setPlotOptions($plotOptions); + $highchart->setCredits($chartCredits); + $highchart->setLegend($chartLegend); + $highchart->setSeries($seriesData); + + $variables['chart_type'] = 'highcharts'; + $variables['content_attributes']['data-chart'][] = json_encode($highchart); + $variables['attributes']['id'][0] = $chartId; + $variables['attributes']['class'][] = 'charts-highchart'; + } +} \ No newline at end of file diff --git a/src/Annotation/Chart.php b/src/Annotation/Chart.php new file mode 100755 index 0000000..2b95c0e --- /dev/null +++ b/src/Annotation/Chart.php @@ -0,0 +1,24 @@ +<?php +namespace Drupal\charts\Annotation; +use Drupal\Component\Annotation\Plugin; + +/** + * Defines an Chart annotation object. + * + * @Annotation + */ +class Chart extends Plugin{ + /** + * The plugin ID. + * + * @var string + */ + public $id; + /** + * The plugin name. + * + * @var string + */ + public $name; + +} \ No newline at end of file diff --git a/src/Plugin/chart/AbstractChart.php b/src/Plugin/chart/AbstractChart.php new file mode 100755 index 0000000..cc51fa0 --- /dev/null +++ b/src/Plugin/chart/AbstractChart.php @@ -0,0 +1,34 @@ +<?php + +namespace Drupal\charts\Plugin\chart; +use Drupal\Component\Plugin\PluginBase; +use Drupal\Core\Plugin\ContainerFactoryPluginInterface; +use Drupal\Core\StringTranslation\StringTranslationTrait; +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Base class Chart plugins. + */ +abstract class AbstractChart extends PluginBase implements ChartInterface, ContainerFactoryPluginInterface{ + use StringTranslationTrait; + /** + * {@inheritdoc} + */ + public function __construct(array $configuration, $plugin_id, $plugin_definition) + { + parent::__construct($configuration, $plugin_id, $plugin_definition); + } + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition){ + return new static( + $configuration, + $plugin_id, + $plugin_definition + ); + } + public function getChartName() { + return $this->pluginDefinition['name']; + } +} \ No newline at end of file diff --git a/src/Plugin/chart/ChartInterface.php b/src/Plugin/chart/ChartInterface.php new file mode 100755 index 0000000..22d64be --- /dev/null +++ b/src/Plugin/chart/ChartInterface.php @@ -0,0 +1,21 @@ +<?php +namespace Drupal\charts\Plugin\chart; +use Drupal\Component\Plugin\PluginInspectionInterface; +/** + * Defines an interface for Chart plugins. + */ +interface ChartInterface extends PluginInspectionInterface{ + /** + * Build Variables. + * + * @return an array + */ + public function buildVariables($options, $categories, $seriesData, $attachmentDisplayOptions, &$variables, $chartId); + /** + * Return the name of the chart. + * + * @return string + * returns the name as a string. + */ + public function getChartName(); +} \ No newline at end of file diff --git a/src/Plugin/chart/ChartManager.php b/src/Plugin/chart/ChartManager.php new file mode 100755 index 0000000..f3e4c4f --- /dev/null +++ b/src/Plugin/chart/ChartManager.php @@ -0,0 +1,30 @@ +<?php +namespace Drupal\charts\Plugin\chart; + +use Drupal\Core\Plugin\DefaultPluginManager; +use Drupal\Core\Cache\CacheBackendInterface; +use Drupal\Core\Extension\ModuleHandlerInterface; + +/** + * @file + * + * Provides the Chart plugin plugin manager and manages discovery and instantiation of chart plugins. + * + */ +class ChartManager extends DefaultPluginManager{ + /** + * Constructor for ChartManager objects. + * + * @param \Traversable $namespaces + * An object that implements \Traversable which contains the root paths + * keyed by the corresponding namespace to look for plugin implementations. + * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend + * Cache backend instance to use. + * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler + * The module handler to invoke the alter hook with. + */ + public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler){ + parent::__construct('Plugin/chart',$namespaces,$module_handler,'Drupal\charts\Plugin\chart\ChartInterface', + 'Drupal\charts\Annotation\Chart'); + } +} \ No newline at end of file -- GitLab