php-yaoi/php-yaoi

View on GitHub
src/View/HighCharts.php

Summary

Maintainability
D
1 day
Test Coverage
<?php

namespace Yaoi\View;

use Yaoi\BaseClass;

class HighCharts extends BaseClass implements Renderer
{

    public function isEmpty()
    {
        return empty($this->series);
    }

    public function __toString()
    {
        ob_start();
        $this->render();
        $result = ob_get_contents();
        ob_end_clean();
        return $result;
    }

    private $options;
    /**
     * @var HighCharts\Series[]
     */
    private $series = array();


    public function __construct()
    {
        $this->options = array(
            'title' => false,

            /*
            'chart' => array(
                'resetZoomButton' => array(
                    'position' => array(
                        'align' => 'left', // by default
                        'verticalAlign' => 'bottom', // by default
                        'x' => 0,
                        'y' => -130,
                    )
                )
            ),
            */

            'chart' => array(
                'zoomType' => 'x'
            ),

            'legend' => array(
                'enabled' => true,
                //'layout' => 'vertical',
                'verticalAlign' => 'top'
            ),

            'plotOptions' => array(
                'series' => array(
                    'marker' => array(
                        'enabled' => false
                    )
                )
            ),

            'tooltip' => array(
                'crosshairs' => array(true, true),
                'shared' => false,
            ),

            'credits' => array(
                'enabled' => false
            )

        );
    }


    public function setType($type = HighCharts\Series::TYPE_LINE)
    {
        $this->options['chart']['type'] = $type;
        return $this;
    }


    public function setTitle($title)
    {
        if ($title) {
            $this->options['title']['text'] = $title;
        } else {
            $this->options['title'] = false;
        }
        return $this;
    }

    public function setYTitle($title)
    {
        if ($title) {
            $this->options['yAxis']['title']['text'] = $title;
        } else {
            $this->options['yAxis']['title']['text'] = null;
        }
        return $this;
    }

    public function setXTitle($title)
    {
        if ($title) {
            $this->options['xAxis']['title']['text'] = $title;
        } else {
            $this->options['xAxis']['title']['text'] = null;
        }
        return $this;
    }


    private $literalDateAxis;

    public function withDateAxis($literal = false)
    {
        $this->options['xAxis']['type'] = 'datetime';
        $this->literalDateAxis = $literal;
        return $this;
    }


    public function addOptions($options)
    {
        $this->options = \Yaoi\Misc::arrayMergeRecursiveDistinct($this->options, $options);
        return $this;
    }


    private $unquote = false;

    public function addCallbackOption()
    {
        $this->unquote = true;
        $args = func_get_args();
        $value = 'unquoted' . array_pop($args) . 'unquoted';
        $t = &$this->options;
        foreach ($args as $arg) {
            $t = &$t[$arg];
        }
        $t = $value;
        return $this;
    }

    /**
     * @return $this
     */
    public function addOption()
    {
        $args = func_get_args();
        $value = array_pop($args);
        $t = &$this->options;
        foreach ($args as $arg) {
            $t = &$t[$arg];
        }
        $t = $value;
        return $this;
    }

    /**
     * @var HighCharts\Series
     */
    private $defaultSeries;

    /**
     * @param mixed $defaultSeries
     * @return $this
     */
    public function setDefaultSeries(HighCharts\Series $defaultSeries = null)
    {
        $this->defaultSeries = $defaultSeries;
        return $this;
    }


    public function addRow($x, $y, $id = 'default')
    {
        if ($this->literalDateAxis) {
            $x = 1000 * strtotime($x);
        }

        //echo 'row added';
        if (!$series = &$this->series[$id]) {
            if ($this->defaultSeries) {
                $series = clone $this->defaultSeries;
            } else {
                $series = new HighCharts\Series();
            }
            $series->setId($id);
        }
        if (isset($this->ranges[$id])) {
            $series->addRangeRow($x, $y, $this->ranges[$id]);
        } else {
            $series->addRow($x, $y);
        }
        return $this;
    }

    private $ranges = array();

    public function addSeries(HighCharts\Series $series, $rangeHighId = null)
    {
        $this->series[$rangeLowId = $series->getId()] = $series;
        if (null !== $rangeHighId) {
            $this->series[$rangeHighId] = $series;
            $this->ranges[$rangeLowId] = HighCharts\Series::VALUE_LOW;
            $this->ranges[$rangeHighId] = HighCharts\Series::VALUE_HIGH;
        }
        return $this;
    }


    private $containerSelector;

    public function setContainerSelector($id)
    {
        $this->containerSelector = $id;
        return $this;
    }


    public $globalOptions = array(
        'global' => array(
            'useUTC' => false
        ),
    );

    public function langRussian()
    {
        $this->globalOptions['lang'] = array(
            'shortMonths' => array('Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн', 'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек'),
            'rangeSelectorFrom' => 'C',
            'rangeSelectorTo' => 'по',
            'rangeSelectorZoom' => 'Период',
            'thousandsSep' => '',
            'resetZoom' => 'Сбросить масштаб',
            'resetZoomTitle' => 'Установить масштаб 1:1',
            'weekdays' => array('Воскресенье', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота')
        );
        $this->jsonLoadingText = 'Загрузка...';

        return $this;
    }


    private $jsonLoadingText = 'Loading data from server...';
    private $withJsonZoom;
    private $jsonUrl;

    public function withJsonZoom($jsonUrl = null)
    {
        $this->withJsonZoom = true;
        $this->jsonUrl = $jsonUrl;
        return $this;
    }


    private $minX;
    private $maxX;

    private function countExtremes()
    {
        $this->minX = 0;
        $this->maxX = 0;
        foreach ($this->series as $series) {
            $this->minX = $series->minX;
            $this->maxX = $series->maxX;
            break;
        }
        foreach ($this->series as $series) {
            $this->minX = min($this->minX, $series->minX);
            $this->maxX = max($this->maxX, $series->maxX);
        }
    }

    private static $autoContainerId = 0;
    private static $jsLoaded = false;

    public function render()
    {
        if ($this->withJsonZoom) {
            $this->addCallbackOption('xAxis', 'events', 'afterSetExtremes', 'loadPoints');
            $this->addCallbackOption('xAxis', 'events', 'setExtremes', 'setExtremesCallback');
            if (null === $this->jsonUrl) {
                $this->jsonUrl = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
                if (strpos($this->jsonUrl, '?') !== false) {
                    $this->jsonUrl .= '&';
                } else {
                    $this->jsonUrl .= '?';
                }
                $this->jsonUrl .= 'min=:min&max=:max&callback=?';
            }
            $this->countExtremes();

        }

        $this->options['series'] = array();
        //var_dump($this->series);
        $options = json_encode($this->options);
        if ($this->unquote) {
            $options = str_replace(array('"unquoted', 'unquoted"'), '', $options);
        }

        if (!$this->containerSelector) {
            $this->containerSelector = 'highcharts-' . self::$autoContainerId++;
            ?>
<div id="<?php echo $this->containerSelector ?>"></div>
<?php
            $this->containerSelector = '#' . $this->containerSelector;
        }

        if (!self::$jsLoaded) {
            ?>
<script type="text/javascript" src="//code.highcharts.com/stock/highstock.js"></script>
<script type="text/javascript" src="//code.highcharts.com/highcharts.js"></script>
<script type="text/javascript" src="//code.highcharts.com/highcharts-more.js"></script>
<?php
            self::$jsLoaded = true;
        }

        ?>
<script type="text/javascript">
(function(){
    <?php
    if ($this->withJsonZoom) {
    ?>
    var isReset = false;

    function setExtremesCallback(e) {
        if (e.max == null || e.min == null) {
            isReset = true;
        }
        else {
            isReset = false;
        }
    }

    function loadPoints(e) {

        var url = '<?php echo $this->jsonUrl?>',
            chart = $('#hc-container-1').highcharts();

        var min = <?php echo $this->minX ?>;
        var max = <?php echo $this->maxX ?>;

        if(!isReset)
        {
            min = e.min;
            max = e.max;
        }
        chart.showLoading('<?php echo $this->jsonLoadingText?>');

        url = url.replace(/:min/g, min).replace(/:max/g, max);

        $.getJSON(url, function (data) {
            var seriesOptions, series;
            for (var i in data) {
                if (data.hasOwnProperty(i)) {
                    seriesOptions = data[i];
                    if (series = chart.get(seriesOptions.id)) {
                        series.setData(seriesOptions.data, false);
                    }
                    else {
                        chart.addSeries(seriesOptions, false);
                    }
                }
            }
            chart.redraw();
            chart.hideLoading();
        });
    }
<?php
    }
    ?>Highcharts.setOptions(<?php echo json_encode($this->globalOptions)?>);

    var chart = $('<?php echo $this->containerSelector ?>').highcharts(<?php echo $options ?>).highcharts();
    <?php
    if ($this->withJsonZoom && empty($this->series)) {
        ?>isReset = true;
    loadPoints();
    <?php
        } else {
            foreach ($this->series as $id => $series) {
                if (isset($this->ranges[$id]) && HighCharts\Series::VALUE_HIGH == $this->ranges[$id]) {
                    continue;
                }
            ?>chart.addSeries(<?php echo json_encode($series->exportOptions())?>, false);
    <?php
        }
    }

?>chart.redraw();
})();
</script><?php
    }


    /**
     * @return array
     */
    public function getData()
    {
        $data = array();
        foreach ($this->series as $series) {
            $data [] = $series->exportOptions();
        }
        return $data;
    }


    /**
     * @return $this
     */
    public function renderJson()
    {
        Jsonp::create($this->getData(), $_GET['callback'])->render();
        return $this;
    }


}