* @copyright Copyright © Clevertech 2012-
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
* @package YiiBooster bootstrap.widgets
*/
Yii::import('bootstrap.widgets.TbGridView');
/**
* TbExtendedGridView is an extended version of TbGridView.
*
* Features are:
* - Display an extended summary of the records shown. The extended summary can be configured to any of the
* {@link TbOperation} type of widgets.
* - Automatic chart display (using TbHighCharts widget), where user can 'switch' between views.
*/
class TbExtendedGridView extends TbGridView
{
/**
* @var bool $fixedHeader if set to true will keep the header fixed position
*/
public $fixedHeader = false;
/**
* @var integer $headerOffset, when $fixedHeader is set to true, headerOffset will position table header top position
* at $headerOffset. If you are using bootstrap and has navigation top fixed, its height is 40px, so it is recommended
* to use $headerOffset=40;
*/
public $headerOffset = 0;
/**
* @var string the template to be used to control the layout of various sections in the view.
* These tokens are recognized: {extendedSummary}, {summary}, {items} and {pager}. They will be replaced with the
* extended summary, summary text, the items, and the pager.
*/
public $template = "{summary}\n{items}\n{pager}\n{extendedSummary}";
/**
* @var array $extendedSummary displays an extended summary version. There are different types of summary types,
* please, see {@link TbSumOperation}, {@link TbSumOfTypeOperation},{@link TbPercentOfTypeGooglePieOperation}
* {@link TbPercentOfTypeOperation} and {@link TbPercentOfTypeEasyPieOperation}.
*
* The following is an example, please review the different types of TbOperation classes to find out more about
* its configuration parameters.
*
*
* 'extendedSummary' => array(
* 'title' => '', // the extended summary title
* 'columns' => array( // the 'columns' that will be displayed at the extended summary
* 'id' => array( // colum name "id"
* 'class' => 'TbSumOperation', // what is the type of TbOperation we are going to display
* 'label' => 'Sum of Ids' // label is name of label of the resulted value (ie Sum of Ids:)
* ),
* 'results' => array( // column name "results"
* 'class' => 'TbPercentOfTypeGooglePieOperation', // the type of TbOperation
* 'label' => 'How Many Of Each? ', // the label of the operation
* 'types' => array( // TbPercentOfTypeGooglePieOperation "types" attributes
* '0' => array('label' => 'zeros'), // a value of "0" will be labelled "zeros"
* '1' => array('label' => 'ones'), // a value of "1" will be labelled "ones"
* '2' => array('label' => 'twos')) // a value of "2" will be labelled "twos"
* )
* )
* ),
*
*/
public $extendedSummary = array();
/**
* @var string $extendedSummaryCssClass is the class name of the layer containing the extended summary
*/
public $extendedSummaryCssClass = 'extended-summary';
/**
* @var array $extendedSummaryOptions the HTML attributes of the layer containing the extended summary
*/
public $extendedSummaryOptions = array();
/**
* @var array $componentsAfterAjaxUpdate has scripts that will be executed after components have updated.
* It is used internally to render scripts required for components to work correctly. You may use it for your own
* scripts, just make sure it is of type array.
*/
public $componentsAfterAjaxUpdate = array();
/**
* @var array $componentsReadyScripts hold scripts that will be executed on document ready.
* It is used internally to render scripts required for components to work correctly. You may use it for your own
* scripts, just make sure it is of type array.
*/
public $componentsReadyScripts = array();
/**
* @var array $chartOptions if configured, the extended view will display a highcharts chart.
*/
public $chartOptions = array();
/**
* @var bool $sortableRows. If true the rows at the table will be sortable.
*/
public $sortableRows = false;
/**
* @var string a javascript function that will be invoked after a successful sorting is done.
* The function signature is function(id, position)
where 'id' refers to the ID of the model id key,
* 'position' the new position in the list.
*/
public $afterSortableUpdate;
/**
* @var bool whether to allow selecting of cells
*/
public $selectableCells = false;
/**
* @var string the filter to use to allow selection. For example, if you set the "htmlOptions" property of a column to have a
* "class" of "tobeselected", you could set this property as: "td.tobeselected" in order to allow selection to
* those columns with that class only.
*/
public $selectableCellsFilter = 'td';
/**
* @var string a javascript function that will be invoked after a selection is done.
* The function signature is function(selected)
where 'selected' refers to the selected columns.
*/
public $afterSelectableCells;
/**
* @var array the configuration options to display a TbBulkActions widget
* @see TbBulkActions widget for its configuration
*/
public $bulkActions = array();
/**
* @var string the aligment of the bulk actions. It can be 'left' or 'right'.
*/
public $bulkActionAlign = 'right';
/**
* @var TbBulkActions component that will display the bulk actions to the grid
*/
protected $bulk;
/**
* @var boolean $displayExtendedSummary a helper property that is set to true if we have to render the
* extended summary
*/
protected $displayExtendedSummary;
/**
* @var boolean $displayChart a helper property that is set to true if we have to render a chart.
*/
protected $displayChart;
/**
* @var array $extendedSummaryTypes hold the current configured TbOperation that will process column values.
*/
protected $extendedSummaryTypes = array();
/**
* @var array $extendedSummaryOperations hold the supported operation types
*/
protected $extendedSummaryOperations = array(
'TbSumOperation',
'TbCountOfTypeOperation',
'TbPercentOfTypeOperation',
'TbPercentOfTypeEasyPieOperation',
'TbPercentOfTypeGooglePieOperation'
);
/**
* Widget initialization
*/
public function init()
{
if (preg_match('/extendedsummary/i', $this->template) && !empty($this->extendedSummary) && isset($this->extendedSummary['columns']))
{
$this->template .= "\n{extendedSummaryContent}";
$this->displayExtendedSummary = true;
}
if (!empty($this->chartOptions) && @$this->chartOptions['data'] && $this->dataProvider->getItemCount())
{
$this->displayChart = true;
}
if ($this->bulkActions !== array() && isset($this->bulkActions['actionButtons']))
{
if(!isset($this->bulkActions['class']))
$this->bulkActions['class'] = 'bootstrap.widgets.TbBulkActions';
$this->bulk = Yii::createComponent($this->bulkActions, $this);
$this->bulk->init();
}
parent::init();
}
/**
* Renders grid content
*/
public function renderContent()
{
parent::renderContent();
$this->registerCustomClientScript();
}
/**
* Renders grid header
*/
public function renderTableHeader()
{
$this->renderChart();
parent::renderTableHeader();
}
/**
* Renders the table footer.
*/
public function renderTableFooter()
{
$hasFilter = $this->filter !== null && $this->filterPosition === self::FILTER_POS_FOOTER;
$hasFooter = $this->getHasFooter();
if ($this->bulk !== null || $hasFilter || $hasFooter)
{
echo "\n";
if ($hasFooter)
{
echo "\n";
foreach ($this->columns as $column)
$column->renderFooterCell();
echo "
\n";
}
if ($hasFilter)
$this->renderFilter();
if ($this->bulk !== null)
$this->renderBulkActions();
echo "\n";
}
}
public function renderBulkActions()
{
echo '';
$this->bulk->renderButtons();
echo ' |
';
}
/**
* Renders chart
* @throws CException
*/
public function renderChart()
{
if (!$this->displayChart || $this->dataProvider->getItemCount() <= 0)
return;
if (!isset($this->chartOptions['data']['series']))
throw new CException(Yii::t('zii', 'You need to set the "series" attribute in order to render a chart'));
$configSeries = $this->chartOptions['data']['series'];
if (!is_array($configSeries))
throw new CException(Yii::t('zii', '"chartOptions.series" is expected to be an array.'));
$chartId = 'exgvwChart' . $this->getId();
if (!isset($this->chartOptions['config']))
$this->chartOptions['config'] = array();
// ****************************************
// render switch buttons
$buttons = Yii::createComponent(array('class' => 'bootstrap.widgets.TbButtonGroup',
'toggle' => 'radio',
'buttons' => array(
array('label' => Yii::t('zii', 'Grid'), 'url' => '#', 'htmlOptions' => array('class' => 'active ' . $this->getId() . '-grid-control grid')),
array('label' => Yii::t('zii', 'Chart'), 'url' => '#', 'htmlOptions' => array('class' => $this->getId() . '-grid-control chart')),
),
'htmlOptions' => array('style' => 'margin-bottom:5px')
));
echo '';
$buttons->init();
$buttons->run();
echo '
';
$this->componentsReadyScripts[] = '$(document).on("click",".' . $this->getId() . '-grid-control", function(){
if($(this).hasClass("grid") && $("#' . $this->getId() . ' #' . $chartId . '").is(":visible"))
{
$("#' . $this->getId() . ' #' . $chartId . '").hide();
$("#' . $this->getId() . ' table.items").show();
}
if($(this).hasClass("chart") && $("#' . $this->getId() . ' table.items").is(":visible"))
{
$("#' . $this->getId() . ' table.items").hide();
$("#' . $this->getId() . ' #' . $chartId . '").show();
}
return false;
});';
// end switch buttons
// ****************************************
// render Chart
// chart options
$data = $this->dataProvider->getData();
$count = count($data);
$seriesData = array();
$cnt = 0;
foreach ($configSeries as $set)
{
$seriesData[$cnt] = array('name' => isset($set['name']) ? $set['name'] : null, 'data' => array());
for ($row = 0; $row < $count; ++$row)
{
$column = $this->getColumnByName($set['attribute']);
if (!is_null($column) && $column->value !== null)
{
$seriesData[$cnt]['data'][] = $this->evaluateExpression($column->value, array('data' => $data[$row], 'row' => $row));
} else
{
$value = CHtml::value($data[$row], $set['attribute']);
$seriesData[$cnt]['data'][] = is_numeric($value) ? (float)$value : $value;
}
}
++$cnt;
}
// ****************************************
// render chart
$options = CMap::mergeArray(
$this->chartOptions['config'],
array('series' => $seriesData)
);
$this->chartOptions['htmlOptions'] = isset($this->chartOptions['htmlOptions']) ? $this->chartOptions['htmlOptions'] : array();
$this->chartOptions['htmlOptions']['style'] = 'display:none'; // sorry but use a class to provide styles, we need this
// build unique ID
// important!
echo '';
if ($this->ajaxUpdate !== false)
{
if (isset($options['chart']) && is_array($options['chart']))
{
$options['chart']['renderTo'] = $chartId;
} else
{
$options['chart'] = array('renderTo' => $chartId);
}
$jsOptions = CJSON::encode($options);
if (isset($this->chartOptions['htmlOptions']['data-config']))
unset($this->chartOptions['htmlOptions']['data-config']);
echo "
chartOptions['htmlOptions']) . " data-config='{$jsOptions}'>
";
$this->componentsAfterAjaxUpdate[] = "highchart{$chartId} = new Highcharts.Chart($('#{$chartId}').data('config'));";
}
$configChart = array(
'class' => 'bootstrap.widgets.TbHighCharts',
'id' => $chartId,
'options' => $options,
'htmlOptions' => $this->chartOptions['htmlOptions']
);
$chart = Yii::createComponent($configChart);
$chart->init();
$chart->run();
echo '
';
// end chart display
// ****************************************
}
/**
* Renders a table body row.
* @param integer $row the row number (zero-based).
*/
public function renderTableRow($row)
{
if ($this->rowCssClassExpression !== null)
{
$data = $this->dataProvider->data[$row];
echo '';
} else if (is_array($this->rowCssClass) && ($n = count($this->rowCssClass)) > 0)
echo '
';
else
echo '
';
foreach ($this->columns as $column)
{
echo $this->displayExtendedSummary && !empty($this->extendedSummary['columns']) ? $this->parseColumnValue($column, $row) : $column->renderDataCell($row);
}
echo "
\n";
}
/**
* Renders summary
*/
public function renderExtendedSummary()
{
if (!isset($this->extendedSummaryOptions['class']))
$this->extendedSummaryOptions['class'] = $this->extendedSummaryCssClass;
else
$this->extendedSummaryOptions['class'] .= ' ' . $this->extendedSummaryCssClass;
echo 'extendedSummaryOptions) . '>
';
}
/**
* Renders summary content. Will be appended to
*/
public function renderExtendedSummaryContent()
{
if (($count = $this->dataProvider->getItemCount()) <= 0)
return;
if (!empty($this->extendedSummaryTypes))
{
echo '';
if (isset($this->extendedSummary['title']))
{
echo '
' . $this->extendedSummary['title'] . '
';
}
foreach ($this->extendedSummaryTypes as $summaryType)
{
$summaryType->run();
echo '
';
}
echo '';
}
}
/**
* This script must be run at the end of content rendering not at the beginning as it is common with normal CGridViews
*/
public function registerCustomClientScript()
{
$cs = Yii::app()->getClientScript();
$fixedHeaderJs = '';
if ($this->fixedHeader)
{
Yii::app()->bootstrap->registerAssetJs('jquery.stickytableheaders.js');
$fixedHeaderJs = "$('#{$this->id} table.items').stickyTableHeaders({fixedOffset:{$this->headerOffset}});";
$this->componentsAfterAjaxUpdate[] = $fixedHeaderJs;
}
if ($this->sortableRows)
{
if ($this->afterSortableUpdate !== null)
{
if (!($this->afterSortableUpdate instanceof CJavaScriptExpression) && strpos($this->afterSortableUpdate, 'js:') !== 0)
{
$afterSortableUpdate = new CJavaScriptExpression($this->afterSortableUpdate);
} else
{
$afterSortableUpdate = $this->afterSortableUpdate;
}
}
$this->selectableRows = 1;
$cs->registerCoreScript('jquery.ui');
Yii::app()->bootstrap->registerAssetJs('jquery.sortable.gridview.js');
$afterSortableUpdate = CJavaScript::encode($afterSortableUpdate);
$this->componentsReadyScripts[] = "$.fn.yiiGridView.sortable('{$this->id}', {$afterSortableUpdate});";
$this->componentsAfterAjaxUpdate[] = "$.fn.yiiGridView.sortable('{$this->id}', {$afterSortableUpdate});";
}
if($this->selectableCells)
{
if($this->afterSelectableCells !== null)
{
echo strpos($this->afterSelectableCells, 'js:');
if (!($this->afterSelectableCells instanceof CJavaScriptExpression) && strpos($this->afterSelectableCells, 'js:') !== 0)
{
$afterSelectableCells = new CJavaScriptExpression($this->afterSelectableCells);
} else
{
$afterSelectableCells = $this->afterSelectableCells;
}
}
$cs->registerCoreScript('jquery.ui');
Yii::app()->bootstrap->registerAssetJs('jquery.selectable.gridview.js');
$afterSelectableCells = CJavaScript::encode($afterSelectableCells);
$this->componentsReadyScripts[] = "$.fn.yiiGridView.selectable('{$this->id}','{$this->selectableCellsFilter}',{$afterSelectableCells});";
$this->componentsAfterAjaxUpdate[] = "$.fn.yiiGridView.selectable('{$this->id}','{$this->selectableCellsFilter}', {$afterSelectableCells});";
}
$cs->registerScript(__CLASS__ . '#' . $this->id . 'Ex', '
$grid = $("#' . $this->id . '");
' . $fixedHeaderJs . '
if($(".' . $this->extendedSummaryCssClass . '", $grid).length)
{
$(".' . $this->extendedSummaryCssClass . '", $grid).html($("#' . $this->id . '-extended-summary", $grid).html());
}
' . (count($this->componentsReadyScripts) ? implode(PHP_EOL, $this->componentsReadyScripts) : '') . '
$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
var qs = $.deparam.querystring(options.url);
if(qs.hasOwnProperty("ajax") && qs.ajax == "' . $this->id . '")
{
options.realsuccess = options.success;
options.success = function(data)
{
if(options.realsuccess) {
options.realsuccess(data);
var $data = $("" + data + "
");
// we need to get the grid again... as it has been updated
if($(".' . $this->extendedSummaryCssClass . '", $("#' . $this->id . '")))
{
$(".' . $this->extendedSummaryCssClass . '", $("#' . $this->id . '")).html($("#' . $this->id . '-extended-summary", $data).html());
}
' . (count($this->componentsAfterAjaxUpdate) ? implode(PHP_EOL, $this->componentsAfterAjaxUpdate) : '') . '
}
}
}
});');
}
/**
* @param CDataColumn $column
* @param $row the current row numbeer
*/
protected function parseColumnValue($column, $row)
{
ob_start();
$column->renderDataCell($row);
$value = ob_get_clean();
if ($column instanceof CDataColumn && array_key_exists($column->name, $this->extendedSummary['columns']))
{
// lets get the configuration
$config = $this->extendedSummary['columns'][$column->name];
// add the required column object in
$config['column'] = $column;
// build the summary operation object
$op = $this->getSummaryOperationInstance($config);
// process the value
$op->processValue($value);
}
return $value;
}
/**
* Each type of 'extended' summary
* @param $config
* @return mixed
* @throws CException
*/
protected function getSummaryOperationInstance($config)
{
if (!isset($config['class']))
throw new CException(Yii::t('zii', 'Column summary configuration must be an array containing a "type" element.'));
if (!in_array($config['class'], $this->extendedSummaryOperations))
throw new CException(Yii::t('zii', '"{operation}" is an unsupported class operation.', array('{operation}' => $config['class'])));
if (!isset($this->extendedSummaryTypes[$config['class']]))
{
$this->extendedSummaryTypes[$config['class']] = Yii::createComponent($config);
$this->extendedSummaryTypes[$config['class']]->init();
}
return $this->extendedSummaryTypes[$config['class']];
}
/**
* Helper function to get a column by its name
* @param $name
* @return null
*/
protected function getColumnByName($name)
{
foreach ($this->columns as $column)
{
if (strcmp($column->name, $name) === 0)
return $column;
}
return null;
}
}
/**
* TbOperation class
*
* Abstract class where all types of operations extend from
*/
abstract class TbOperation extends CWidget
{
/**
* @var string $template the template to display label and value of the operation at the summary
*/
public $template = '{label}: {value}';
/**
* @var int $value the resulted value of operation
*/
public $value = 0;
/**
* @var string $label the label of the calculated value
*/
public $label;
/**
* @var TbDataColumn $column
*/
public $column;
/**
* Widget initialization
* @throws CException
*/
public function init()
{
if (null == $this->column)
throw new CException(Yii::t('zii', '"{attribute}" attribute must be defined', array('{attribute}' => 'column')));
}
/**
* Widget's run method
*/
public function run()
{
$this->displaySummary();
}
/**
* Process the row data value
* @param $value
* @return mixed
*/
abstract public function processValue($value);
/**
* Displays the resulting summary
* @return mixed
*/
abstract public function displaySummary();
}
/**
* TbSumOperation class
*
* Displays a total of specified column name.
*
*/
class TbSumOperation extends TbOperation
{
/**
* @var float $total the total sum
*/
protected $total;
/**
* @var array $supportedTypes the supported type of values
*/
protected $supportedTypes = array('raw', 'text', 'ntext', 'number');
/**
* Widget's initialization method
* @throws CException
*/
public function init()
{
parent::init();
if (!in_array($this->column->type, $this->supportedTypes))
{
throw new CException(Yii::t('zii', 'Unsupported column type. Supported column types are: "{types}"', array(
'{types}' => implode(', ', $this->supportedTypes))));
}
}
/**
* Extracts the digital part of the calculated value.
* @param $value
* @return bool
*/
protected function extractNumber($value)
{
preg_match_all('/([0-9]+[,\.]?)+/', $value, $matches);
return !empty($matches[0]) && @$matches[0][0] ? $matches[0][0] : 0;
}
/**
* Process the value to calculate
* @param $value
* @return mixed|void
*/
public function processValue($value)
{
// remove html tags as we cannot access renderDataCellContent from the column
$clean = strip_tags($value);
$this->total += ((float)$this->extractNumber($clean));
}
/**
* Displays the summary
* @return mixed|void
*/
public function displaySummary()
{
echo strtr($this->template, array('{label}' => $this->label, '{value}' => $this->total === null ? '' : Yii::app()->format->format($this->total, $this->column->type)));
}
}
/**
* TbCountOfTypeOperation class
*
* Renders a summary based on the count of specified types. For example, if a value has a type 'blue', this class will
* count the number of times the value 'blue' has on that column.
*/
class TbCountOfTypeOperation extends TbOperation
{
/**
* @var string $template
* @see parent class
*/
public $template = '{label}: {types}';
/**
* @var string $typeTemplate holds the template of each calculated type
*/
public $typeTemplate = '{label}({value})';
/**
* @var array $types hold the configuration of types to calculate. The configuration is set by an array which keys
* are the value types to count. You can set their 'label' independently.
*
*
* 'types' => array(
* '0' => array('label' => 'zeros'),
* '1' => array('label' => 'ones'),
* '2' => array('label' => 'twos')
*
*/
public $types = array();
/**
* Widget's initialization
* @throws CException
*/
public function init()
{
if (empty($this->types))
throw new CException(Yii::t('zii', '"{attribute}" attribute must be defined', array('{attribute}' => 'types')));
foreach ($this->types as $type)
{
if (!isset($type['label']))
throw new CException(Yii::t('zii', 'The "label" of a type must be defined.'));
}
parent::init();
}
/**
* (no phpDoc)
* @see TbOperation
* @param $value
* @return mixed|void
*/
public function processValue($value)
{
$clean = strip_tags($value);
if (array_key_exists($clean, $this->types))
{
if (!isset($this->types[$clean]['value']))
$this->types[$clean]['value'] = 0;
$this->types[$clean]['value'] += 1;
}
}
/**
* (no phpDoc)
* @see TbOperation
* @return mixed|void
*/
public function displaySummary()
{
$typesResults = array();
foreach ($this->types as $type)
{
if (!isset($type['value']))
{
$type['value'] = 0;
}
$typesResults[] = strtr($this->typeTemplate, array('{label}' => $type['label'], '{value}' => $type['value']));
}
echo strtr($this->template, array('{label}' => $this->label, '{types}' => implode(' ', $typesResults)));
}
}
/**
* TbPercentOfTypeOperation class
* Renders a summary based on the percent count of specified types. For example, if a value has a type 'blue', this class will
* count the percentage number of times the value 'blue' has on that column.
*/
class TbPercentOfTypeOperation extends TbCountOfTypeOperation
{
/**
* @var string $typeTemplate
* @see TbCountOfTypeOperation
*/
public $typeTemplate = '{label}({value}%)';
/**
* @var $_total holds the total sum of the values. Required to get the percentage.
*/
protected $_total;
/**
* @return mixed|void
* @see TbOperation
*/
public function displaySummary()
{
$typesResults = array();
foreach ($this->types as $type)
{
if (!isset($type['value']))
{
$type['value'] = 0;
}
$type['value'] = $this->getTotal() ? number_format((float)($type['value'] / $this->getTotal()) * 100, 1) : 0;
$typesResults[] = strtr($this->typeTemplate, array('{label}' => $type['label'], '{value}' => $type['value']));
}
echo strtr($this->template, array('{label}' => $this->label, '{types}' => implode(' ', $typesResults)));
}
/**
* Returns the total of types
* @return holds|int
*/
protected function getTotal()
{
if (null == $this->_total)
{
$this->_total = 0;
foreach ($this->types as $type)
{
if (isset($type['value']))
{
$this->_total += $type['value'];
}
}
}
return $this->_total;
}
}
/**
* TbPercentOfTypeGooglePieOperation class
*
* Displays a Google visualization pie chart based on the percentage count of type.
*/
class TbPercentOfTypeGooglePieOperation extends TbPercentOfTypeOperation
{
/**
* @var string $chartCssClass the class name of the layer holding the chart
*/
public $chartCssClass = 'bootstrap-operation-google-pie-chart';
/**
* The options
* @var array $chartOptions
* @see https://google-developers.appspot.com/chart/interactive/docs/gallery/piechart
*/
public $chartOptions = array(
'title' => 'Google Pie Chart'
);
/**
* @var array $data the configuration data of the chart
*/
protected $data = array();
/**
* @see TbOperation
* @return mixed|void
*/
public function displaySummary()
{
$this->data[] = array('Label', 'Percent');
foreach ($this->types as $type)
{
if (!isset($type['value']))
{
$type['value'] = 0;
}
$this->data[] = $this->getTotal() ? array($type['label'], (float)number_format(($type['value'] / $this->getTotal()) * 100, 1)) : 0;
}
$data = CJavaScript::jsonEncode($this->data);
$options = CJavaScript::jsonEncode($this->chartOptions);
echo "";
$this->registerClientScript();
}
/**
* Registers required scripts
*/
public function registerClientScript()
{
$chart = Yii::createComponent(array('class' => 'bootstrap.widgets.TbGoogleVisualizationChart',
'visualization' => 'PieChart',
'containerId' => $this->getId(),
'data' => $this->data,
'options' => $this->chartOptions
));
$chart->init();
$chart->run();
/**
* create custom chart update by using the global chart variable
* @see TbGoogleVisualizationChart
*/
$this->column->grid->componentsAfterAjaxUpdate[__CLASS__] =
'var $el = $("#' . $this->getId() . '");var data = $el.data("data");var opts = $el.data("options");
data = google.visualization.arrayToDataTable(data);
' . $chart->getId() . '=new google.visualization.PieChart(document.getElementById("' . $this->getId() . '"));
' . $chart->getId() . '.draw(data,opts);';
}
}
/**
* TbPercentOfTypeEasyPieOperation class
*
* Displays an chart based on jquery.easy.pie plugin
*/
class TbPercentOfTypeEasyPieOperation extends TbPercentOfTypeOperation
{
/**
* @var string $chartCssClass the class of the layer containing the class
*/
public $chartCssClass = 'bootstrap-operation-easy-pie-chart';
/**
* @var string $template
* @see TbOperation
*/
public $template = '{label}:
{types}';
/**
* @var string $typeTemplate
* @see parent class
*/
public $typeTemplate = '';
// easy-pie-chart plugin options
// @see https://github.com/rendro/easy-pie-chart#configuration-parameter
public $chartOptions = array(
'barColor' => '#ef1e25', // The color of the curcular bar. You can pass either a css valid color string like rgb,
// rgba hex or string colors. But you can also pass a function that accepts the current
// percentage as a value to return a dynamically generated color.
'trackColor' => '#f2f2f2', // The color of the track for the bar, false to disable rendering.
'scaleColor' => '#dfe0e0', // The color of the scale lines, false to disable rendering.
'lineCap' => 'round', // Defines how the ending of the bar line looks like. Possible values are: butt, round and square.
'lineWidth' => 5, // Width of the bar line in px.
'size' => 80, // Size of the pie chart in px. It will always be a square.
'animate' => false, // Time in milliseconds for a eased animation of the bar growing, or false to deactivate.
'onStart' => 'js:$.noop', // Callback function that is called at the start of any animation (only if animate is not false).
'onStop' => 'js:$.noop' // Callback function that is called at the end of any animation (only if animate is not false).
);
/**
* @see TbOperation
* @return mixed|void
*/
public function displaySummary()
{
$this->typeTemplate = strtr($this->typeTemplate, array('{class}' => $this->chartCssClass));
parent::displaySummary();
$this->registerClientScripts();
}
/**
* Register required scripts
*/
protected function registerClientScripts()
{
Yii::app()->bootstrap->registerAssetCss('easy-pie-chart.css');
Yii::app()->bootstrap->registerAssetJs('jquery.easy.pie.chart.js');
$options = CJavaScript::encode($this->chartOptions);
Yii::app()->getClientScript()->registerScript(__CLASS__ . '#percent-of-type-operation-simple-pie', '
$("#' . $this->column->grid->id . ' .' . $this->column->grid->extendedSummaryCssClass . ' .' . $this->chartCssClass . '")
.easyPieChart(' . $options . ');
');
$this->column->grid->componentsReadyScripts[__CLASS__] =
$this->column->grid->componentsAfterAjaxUpdate[__CLASS__] =
'$("#' . $this->column->grid->id . ' .' . $this->column->grid->extendedSummaryCssClass . ' .' . $this->chartCssClass . '")
.easyPieChart(' . $options . ');';
}
}