
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
-->

<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="stylesheet" href="lib/reset.css"/>
        <script src="lib/esl.js"></script>
        <script src="lib/config.js"></script>
    </head>
    <body>
        <style>
            html, body, #main {
                width: 100%;
                height: 100%;
                margin: 0;
            }
            #chart1, #chart2 {
                width: 100%;
                height: 50%;
            }
        </style>
        <div id="main">
            <div id="chart1"></div>
            <div id="chart2"></div>
        </div>
    <script>

    require([
        'echarts'
        // 'echarts/chart/line',
        // 'echarts/chart/scatter',
        // 'echarts/component/title',
        // 'echarts/component/legend',
        // 'echarts/component/dataZoom',
        // 'echarts/component/grid',
        // 'echarts/component/tooltip'
    ], function (echarts, rawData, prepareBoxplotData, env) {


        var chart1 = echarts.init(document.getElementById('chart1'));
        var chart2 = echarts.init(document.getElementById('chart2'));

        var data1 = [];
        var data2 = [];

        var timeBase = +new Date();
        var hour = 1000 * 60 * 60;

        for (var i = 0; i < 100; i++) {
            data1.push([timeBase, Math.random() * 4]);

            if (i < 40) {
                data2.push([timeBase, Math.random() * 14]);
            }

            timeBase += hour;
        }

        chart1.setOption({
            legend: {
                top: 50,
                data: ['line']
            },
            tooltip: {
                trigger: 'axis',
                formatter: '{c}'
            },
            grid: {
                top: '26%',
                bottom: '26%'
            },
            xAxis: {
                type: 'time',
                max: timeBase
            },
            yAxis: {
                type: 'value'
            },
            dataZoom: {
                type: 'inside'
            },
            series: [
                {
                    type: 'line',
                    data: data1
                }
            ]
        });

        chart2.setOption({
            legend: {
                top: 50,
                data: ['line']
            },
            tooltip: {
                trigger: 'axis',
                formatter: '{c}'
            },
            grid: {
                top: '26%',
                bottom: '26%'
            },
            xAxis: {
                type: 'time',
                max: timeBase
            },
            yAxis: {
                type: 'value'
            },
            dataZoom: {
                type: 'inside'
            },
            series: [
                {
                    type: 'line',
                    data: data2
                }
            ]
        });

        // echarts.connect([chart1, chart2]);

        bindAction([chart1, chart2]);

        function bindAction(chartList) {
            echarts.util.each(chartList, function (fromChart) {
                echarts.util.each(chartList, function (toChart) {
                    if (fromChart === toChart) {
                        return;
                    }

                    fromChart.on('updateAxisPointer', function (params) {
                        toChart.dispatchAction(
                            toChart.makeActionFromEvent(params),
                            true
                        );
                    });

                    fromChart.on('dataZoom', function (params) {
                        toChart.dispatchAction({
                            type: 'dataZoom',
                            dataZoomIndex: params.batch[0].dataZoomIndex,
                            start: params.batch[0].start,
                            end: params.batch[0].end
                        }, true);
                    });
                });
            });
        }

    });
    </script>
    </body>
</html>