123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520 |
- <?php
- namespace Dcat\Admin\Widgets\Chart;
- use Dcat\Admin\Admin;
- use Dcat\Admin\Widgets\Color;
- use Dcat\Admin\Traits\FromApi;
- use Dcat\Admin\Widgets\Widget;
- use Illuminate\Support\Str;
- /**
- * @see https://www.chartjs.org/docs/latest/
- *
- * @method $this blue()
- * @method $this green()
- * @method $this orange()
- * @method $this purple()
- */
- abstract class Chart extends Widget
- {
- use FromApi;
- public static $js = '@chartjs';
- public static $css = '@chartjs';
- public static $globalSettings = [
- 'defaultFontColor' => '#555',
- 'defaultFontFamily' => 'Nunito,system-ui,sans-serif',
- 'scaleShowGridLines' => false,
- 'scaleShowHorizontalLines' => false,
- ];
- public $colors = [];
- protected $id = '';
- protected $type = 'line';
- protected $data = [
- 'labels' => [],
- 'datasets' => [],
- ];
- protected $options = [];
- protected $width;
- protected $height;
- protected $containerStyle = '';
- public function __construct(...$params)
- {
- if (count($params) == 2) {
- [$title, $labels] = $params;
- $title && $this->title($title);
- $labels && $this->labels($labels);
- } elseif (! empty($params[0])) {
- if (is_string($params[0])) {
- $this->title($params[0]);
- } elseif (is_array($params[0])) {
- $this->labels($params[0]);
- }
- }
- $this->setDefaultColors();
- }
- /**
- * @param Chart $chart
- *
- * @return $this
- */
- public function combine(self $chart)
- {
- $this->data['datasets']
- = array_merge($this->data['datasets'], $chart->datasets());
- return $this;
- }
- /**
- * Set labels.
- *
- * @param $labels
- *
- * @return $this
- */
- public function labels(array $labels)
- {
- $this->data['labels'] = $labels;
- return $this;
- }
- /**
- * Add datasets.
- *
- * @example
- * $this->add('LiXin', [1, 23, 6, 10, 6]);
- * $this->add([
- * ['LiXin', [1, 23, 6, 10, 6]], ['阿翡', [4, 11, 8, 25, 19]]
- * ]);
- *
- * @param string|array $label
- * @param array $data
- * @param string|array $fillColor
- *
- * @return $this
- */
- public function add($label, $data = [], $fillColor = null)
- {
- if (is_array($label)) {
- foreach ($label as $item) {
- call_user_func_array([$this, 'add'], $item);
- }
- return $this;
- }
- $item = [
- 'label' => $label,
- 'data' => $data,
- 'backgroundColor' => $fillColor,
- ];
- if ($fillColor) {
- if (is_string($fillColor)) {
- $item['backgroundColor'] = $fillColor;
- } elseif (is_array($fillColor)) {
- $item = array_merge($fillColor, $item);
- }
- }
- $this->data['datasets'][] = &$item;
- return $this;
- }
- /**
- * @return array
- */
- public function data()
- {
- return $this->data;
- }
- /**
- * @param bool $val
- *
- * @return $this
- */
- public function responsive(bool $val = true)
- {
- return $this->options(['responsive' => $val]);
- }
- /**
- * @see https://www.chartjs.org/docs/latest/configuration/legend.html
- *
- * @param array $opts
- *
- * @return $this
- */
- public function legend(array $opts)
- {
- if (! isset($this->options['legend'])) {
- $this->options['legend'] = [];
- }
- $this->options['legend'] = array_merge($this->options['legend'], $opts);
- return $this;
- }
- /**
- * @return $this
- */
- public function disableLegend()
- {
- return $this->legend(['display' => false]);
- }
- /**
- * @return $this
- */
- public function legendPosition(string $val)
- {
- return $this->legend(['position' => $val]);
- }
- /**
- * @see https://www.chartjs.org/docs/latest/configuration/tooltip.html
- *
- * @param array $opts
- *
- * @return $this
- */
- public function tooltips(array $opts)
- {
- if (! isset($this->options['tooltips'])) {
- $this->options['tooltips'] = [];
- }
- $this->options['tooltips'] = array_merge($this->options['tooltips'], $opts);
- return $this;
- }
- /**
- * Disable tooltip.
- *
- * @return $this
- */
- public function disableTooltip()
- {
- return $this->tooltips(['enabled' => false]);
- }
- /**
- * @see https://www.chartjs.org/docs/latest/configuration/title.html
- *
- * @param array $options
- *
- * @return $this
- */
- public function title($options)
- {
- if (is_array($options)) {
- $this->options['title'] = $options;
- } else {
- $this->options['title'] = ['text' => $options, 'display' => true, 'fontSize' => '14'];
- }
- return $this;
- }
- /**
- * @see https://www.chartjs.org/docs/latest/configuration/elements.html
- *
- * @param array $options
- *
- * @return $this
- */
- public function elements(array $options)
- {
- if (! isset($this->options['elements'])) {
- $this->options['elements'] = [];
- }
- $this->options['elements'] = array_merge($this->options['elements'], $options);
- return $this;
- }
- /**
- * @see https://www.chartjs.org/docs/latest/configuration/layout.html
- *
- * @param array $opts
- *
- * @return $this
- */
- public function layout(array $opts)
- {
- if (! isset($this->options['layout'])) {
- $this->options['layout'] = [];
- }
- $this->options['layout'] = array_merge($this->options['layout'], $opts);
- return $this;
- }
- /**
- * The padding to add inside the chart.
- *
- * @param array|int $opts
- *
- * @return Chart
- */
- public function padding($opts)
- {
- return $this->layout(['padding' => $opts]);
- }
- /**
- * @param array $opts
- *
- * @return $this
- */
- public function animation(array $opts)
- {
- if (! isset($this->options['animation'])) {
- $this->options['animation'] = [];
- }
- $this->options['animation'] = array_merge($this->options['animation'], $opts);
- return $this;
- }
- /**
- * Set width of container.
- *
- * @param string $width
- *
- * @return Chart
- */
- public function width($width)
- {
- return $this->setContainerStyle('width:'.$width);
- }
- /**
- * Set height of container.
- *
- * @param string $height
- *
- * @return Chart
- */
- public function height($height)
- {
- return $this->setContainerStyle('height:'.$height);
- }
- /**
- * @param string $style
- * @param bool $append
- *
- * @return $this
- */
- public function setContainerStyle(string $style, bool $append = true)
- {
- if ($append) {
- $this->containerStyle .= ';'.$style;
- } else {
- $this->containerStyle = $style;
- }
- return $this;
- }
- /**
- * Fill default color.
- *
- * @param array $colors
- *
- * @return void
- */
- protected function fillColor(array $colors = [])
- {
- $colors = $colors ?: $this->colors;
- foreach ($this->data['datasets'] as &$item) {
- if (empty($item['backgroundColor'])) {
- $item['backgroundColor'] = array_shift($colors);
- }
- }
- }
- /**
- * Setup script.
- *
- * @return string
- */
- protected function script()
- {
- $this->setupGlobalSettingScripts();
- $config = [
- 'type' => $this->type,
- 'data' => &$this->data,
- 'options' => &$this->options,
- ];
- $options = json_encode($config);
- if (! $this->allowBuildRequest()) {
- return <<<JS
- setTimeout(function () {
- new Chart($("#{$this->getId()}").get(0).getContext("2d"), $options)
- }, 60)
- JS;
- }
- $this->fetched(
- <<<JS
- if (! response.status) {
- return Dcat.error(response.message || 'Server internal error.');
- }
- var id = '{$this->getId()}', opt = $options, prev = window['chart'+id];
- opt.options = $.extend(opt.options, response.options || {});
- opt.data.datasets = response.datasets || opt.data.datasets;
- if (prev) {
- prev.destroy();
- }
- window['chart'+id] = new Chart($("#"+id).get(0).getContext("2d"), opt);
- JS
- );
- return $this->buildRequestScript();
- }
- protected function setupGlobalSettingScripts()
- {
- // Global configure.
- $globalSettings = '';
- foreach (self::$globalSettings as $k => $v) {
- $globalSettings .= sprintf('Chart.defaults.global.%s="%s";', $k, $v);
- }
- Admin::script($globalSettings);
- }
- /**
- * Get datasets.
- *
- * @return array
- */
- public function datasets()
- {
- $this->fillColor();
- return array_map(function ($v) {
- $v['type'] = $v['type'] ?? $this->type;
- return $v;
- }, $this->data['datasets']);
- }
- /**
- * @return string
- */
- public function render()
- {
- $this->fillColor();
- $this->script = $this->script();
- $this->setHtmlAttribute([
- 'id' => $this->getId(),
- ]);
- $this->collectAssets();
- return <<<HTML
- <div class="chart" style="{$this->containerStyle}">
- <canvas {$this->formatHtmlAttributes()}>
- Your browser does not support the canvas element.
- </canvas>
- </div>
- HTML;
- }
- /**
- * @param string $method
- * @param array $parameters
- *
- * @return $this
- */
- public function __call($method, $parameters)
- {
- if (isset(Color::$chartTheme[$method])) {
- $this->colors = Color::$chartTheme[$method];
- return $this;
- }
- return parent::__call($method, $parameters); // TODO: Change the autogenerated stub
- }
- /**
- * @param bool $returnOptions
- * @param array $data
- *
- * @return \Illuminate\Http\JsonResponse
- */
- public function toJsonResponse()
- {
- return response()->json([
- 'status' => 1,
- 'datasets' => $this->datasets(),
- 'options' => $this->getOptions(),
- ]);
- }
- /**
- * @return \Illuminate\Http\JsonResponse
- */
- public function result()
- {
- return $this->toJsonResponse();
- }
- /**
- * @return void
- */
- protected function setDefaultColors()
- {
- if (! $this->colors) {
- $this->colors = Color::$chartTheme['blue'];
- }
- }
- protected function generateId()
- {
- return 'chart-'.$this->type.Str::random(8);
- }
- public function getId()
- {
- return $this->id ?: ($this->id = $this->generateId());
- }
- }
|