Search code examples
phpamchartsamcharts5

Creating dynamic charts for different date ranges using amchart 5


I am trying to create daily, weekly, monthly, quarterly, 6-monthly, yearly and 5-year Candlestick & OHLC charts for Dollar, Euro and Gold using amchart 5.

All data is saved in my own database.

In AmChart 5 samples, I wanted to create my chart by going through the codes in the example of the chart that will be created to receive data from outside.

You can find the relevant example at this link: https://www.amcharts.com/demos/on-demand-data-loading/

First of all, I wrote my php function that will pull the desired data from the entered date range and table. File name is data.php. You can see it below.

ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

chartit();

function chartit()
{
    /**
     * Veri Tabanı Bağlantısı
    */
    $host     = "localhost";
    $dbname  = "dbname";
    $dbuser  = "root";
    $dbpass  = "";

    try {
        $db = new PDO('mysql:host='.$host.';dbname='.$dbname.';charset=utf8',$dbuser,$dbpass);
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
    } catch ( PDOException $e ){
        print $e->getMessage();
    }

    $table = $_GET['unit'];
    $startdate = $_GET['start'];
    $enddate = $_GET['end'];
  
    //$enddate = date('Y-m-d');
    $sqlString = "SELECT * FROM ".$table." WHERE timestamp BETWEEN :startdate AND :enddate";
    $query = $db->prepare($sqlString);
    $query->execute(['startdate' => $startdate, 'enddate' => $enddate]);
    $news_sql = $query->fetchAll(PDO::FETCH_ASSOC);
    foreach($news_sql as $list) {
        $item[] = [
          'date' => intval($list["timestamp"]),
          'open' => intval($list["open"]),
          'high' => intval($list["high"]),
          'low' => intval($list["low"]),
          'close' => intval($list["close"]),
        ];
    }
  
    echo json_encode($item);
}

Then I wrote the relevant javascript codes for the area where the graph will be displayed. You can also see it below.

<script src="https://cdn.amcharts.com/lib/5/index.js"></script>
<script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
<script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>

<style> #chartdiv { width: 100%; height: 500px; max-width: 100%; } #tools { padding: 0.3em 1em; text-align: left; max-width: 100%; } #tools input.active { font-weight: bold; } </style>

    <script>
        
        am5.ready(function () {
            var currentDate = new Date();
            var currentUnit = "altinveri";            

            var root = am5.Root.new("chartdiv");

            root.setThemes([
                am5themes_Animated.new(root)
            ]);
            var chart = root.container.children.push(am5xy.XYChart.new(root, {
                focusable: true,
                panX: true,
                panY: true,
                wheelX: "panX",
                wheelY: "zoomX",
                layout: root.verticalLayout,
                pinchZoomX: true
            }));

            chart.get("colors").set("step", 2);

            var valueAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, {
                renderer: am5xy.AxisRendererY.new(root, {})
            }));

            var dateAxis = chart.xAxes.push(am5xy.GaplessDateAxis.new(root, {
                maxDeviation: 0,
                baseInterval: {
                    timeUnit: "day",
                    count: 15
                },
                gridIntervals: [{
                    timeUnit: "week",
                    count: 1
                }],
                renderer: am5xy.AxisRendererX.new(root, {
                    minGridDistance: 20
                }),
            }));

            var color = root.interfaceColors.get("background");

            var valueSeries = chart.series.push(
                am5xy.CandlestickSeries.new(root, {
                    name: "Series",
                    xAxis: dateAxis,
                    yAxis: valueAxis,
                    openValueYField: "open",
                    highValueYField: "high",
                    lowValueYField: "low",
                    valueYField: "close",
                    valueXField: "date",
                    tooltip: am5.Tooltip.new(root, {})
                })
            );

            var valueTooltip = valueSeries.get("tooltip").label.set("text",
                "[bold]{valueX.formatDate()}[/]\nAçılış: {openValueY}\nEn Yüksek: {highValueY}\nEn Düşük: {lowValueY}\nKapanış: {valueY}"
            );

            chart.set("cursor", am5xy.XYCursor.new(root, {}))

            var scrollbar = chart.set("scrollbarX", am5xy.XYChartScrollbar.new(root, {
                orientation: "horizontal",
                height: 50
            }));

            var sbDateAxis = scrollbar.chart.xAxes.push(am5xy.GaplessDateAxis.new(root, {
                baseInterval: {
                    timeUnit: "day",
                    count: 1
                },
                renderer: am5xy.AxisRendererX.new(root, {})
            }));

            var sbValueAxis = scrollbar.chart.yAxes.push(
                am5xy.ValueAxis.new(root, {
                    renderer: am5xy.AxisRendererY.new(root, {})
                })
            );

            function loadData(unit, min, max, side) {

                var url = "http://localhost/chart/data.php?unit=" + unit + "&start=" + min + "&end=" + max;

                am5.net.load(url).then(function (result) {
                    var data = result.response;
                    //console.log(result.response);

                    var processor = am5.DataProcessor.new(root, {
                        numericFields: ["date", "open", "high", "low", "close"]
                    });
                    processor.processMany(data);

                    var start = dateAxis.get("start");
                    var end = dateAxis.get("end");

                    // will hold first/last dates of each series
                    var seriesFirst = {};
                    var seriesLast = {};

                    // Set data
                    // change base interval if it's different
                    // if (dateAxis.get("baseInterval").timeUnit != unit) {
                    //     dateAxis.set("baseInterval", {
                    //         timeUnit: hour,
                    //         count: 15
                    //     });
                    //     sbDateAxis.set("baseInterval", {
                    //         timeUnit: hour,
                    //         count: 15
                    //     });
                    // }
                    
                    dateAxis.set("min", min);
                    dateAxis.set("max", max);
                    dateAxis.setPrivate("min", min); // needed in order not to animate
                    dateAxis.setPrivate("max", max); // needed in order not to animate     

                    valueSeries.data.setAll(data);
                    //sbSeries.data.setAll(data);

                    dateAxis.zoom(0, 1, 0);
                });
            }

            function loadSomeData() {
                loadData('altinveri', currentDate.getTime() - am5.time.getDuration("day", 90), currentDate.getTime(), "none");
            }

            // Button handlers
            var activeButton = document.getElementById("btn_d");
            document.getElementById("btn_h").addEventListener("click", function () {
                if (currentUnit != "hour") {
                    setActiveButton(this);
                    currentUnit = "hour";
                    loadData("altinveri", dateAxis.getPrivate("selectionMin"), dateAxis.getPrivate("selectionMax"), "none");
                }
            })

            document.getElementById("btn_d").addEventListener("click", function () {
                if (currentUnit != "altinveri") {
                    setActiveButton(this);
                    currentUnit = "altinveri";
                    loadData('altinveri', currentDate.getTime() - am5.time.getDuration("day", 90), currentDate.getTime(), "none");
                }
            })

            document.getElementById("btn_m").addEventListener("click", function () {
                if (currentUnit != "month") {
                    setActiveButton(this);
                    currentUnit = "month";
                    loadData("altinveri", dateAxis.getPrivate("selectionMin"), dateAxis.getPrivate("selectionMax"), "none");
                }
            })

            function setActiveButton(button) {
                if (activeButton) {
                    activeButton.className = "";
                }
                activeButton = button;
                button.className = "active";
            }

            // load data when panning ends
            chart.events.on("panended", function () {
                loadSomeData();
            });

            var wheelTimeout;
            chart.events.on("wheelended", function () {
                if (wheelTimeout) {
                    wheelTimeout.dispose();
                }

                wheelTimeout = chart.setTimeout(function () {
                    loadSomeData();
                }, 50);
            });

            // load some initial data
            loadData("altinveri", currentDate.getTime() - am5.time.getDuration("day", 90), currentDate.getTime(),"none");

            // Make stuff animate on load
            // https://www.amcharts.com/docs/v5/concepts/animations/
            chart.appear(1000, 500);

        }); // end am5.ready()        
    </script>
<div id="tools">
    <input type="button" value="1 hour" id="btn_h">
    <input type="button" value="90 day" id="btn_d" class="active">
    <input type="button" value="1 month" id="btn_m">
</div>
<div id="chartdiv"></div>

According to the entered url, my data content is coming. I can see this. I also see the content when I do console.log. But for some reason it doesn't generate graphics with data content.

enter image description here

If I manually type the data content in the loadData function right after the line am5.net.load(url).then(function (result) { the graph is created..

var data = [{"date":1669755600000,"open":1048,"high":1060,"low":1045,"close":1060},{"date":1669842000000,"open":1060,"high":1080,"low":1057,"close":1080},{"date":1669928400000,"open":1080,"high":1082,"low":1065,"close":1077},{"date":1670187600000,"open":1076,"high":1084,"low":1058,"close":1058},{"date":1670274000000,"open":1058,"high":1067,"low":1058,"close":1061},{"date":1670360400000,"open":1061,"high":1073,"low":1059,"close":1070},{"date":1670446800000,"open":1070,"high":1075,"low":1067,"close":1071},{"date":1670533200000,"open":1072,"high":1082,"low":1071,"close":1075},{"date":1670792400000,"open":1074,"high":1078,"low":1063,"close":1066},{"date":1670878800000,"open":1066,"high":1093,"low":1063,"close":1085},{"date":1670965200000,"open":1085,"high":1086,"low":1075,"close":1081},{"date":1671051600000,"open":1081,"high":1084,"low":1061,"close":1065},{"date":1671138000000,"open":1065,"high":1076,"low":1063,"close":1074},{"date":1671397200000,"open":1074,"high":1078,"low":1069,"close":1071},{"date":1671483600000,"open":1071,"high":1092,"low":1069,"close":1090},{"date":1671570000000,"open":1090,"high":1094,"low":1086,"close":1088},{"date":1671656400000,"open":1088,"high":1092,"low":1071,"close":1075},{"date":1671742800000,"open":1075,"high":1083,"low":1072,"close":1079},{"date":1672002000000,"open":1078,"high":1087,"low":1076,"close":1079},{"date":1672088400000,"open":1079,"high":1108,"low":1076,"close":1088},{"date":1672174800000,"open":1088,"high":1095,"low":1081,"close":1085},{"date":1672261200000,"open":1085,"high":1094,"low":1083,"close":1091},{"date":1672347600000,"open":1091,"high":1098,"low":1088,"close":1096},{"date":1672606800000,"open":1096,"high":1103,"low":1093,"close":1097},{"date":1672693200000,"open":1097,"high":1114,"low":1093,"close":1106},{"date":1672779600000,"open":1106,"high":1124,"low":1105,"close":1118},{"date":1672866000000,"open":1118,"high":1120,"low":1101,"close":1105},{"date":1672952400000,"open":1105,"high":1127,"low":1104,"close":1122},{"date":1673211600000,"open":1124,"high":1139,"low":1124,"close":1129},{"date":1673298000000,"open":1129,"high":1135,"low":1120,"close":1133},{"date":1673384400000,"open":1133,"high":1140,"low":1127,"close":1132},{"date":1673470800000,"open":1132,"high":1148,"low":1129,"close":1146},{"date":1673557200000,"open":1146,"high":1161,"low":1142,"close":1159},{"date":1673816400000,"open":1159,"high":1165,"low":1154,"close":1158},{"date":1673902800000,"open":1158,"high":1160,"low":1147,"close":1152},{"date":1673989200000,"open":1152,"high":1163,"low":1145,"close":1150},{"date":1674075600000,"open":1151,"high":1169,"low":1147,"close":1168},{"date":1674162000000,"open":1168,"high":1171,"low":1161,"close":1165},{"date":1674421200000,"open":1164,"high":1171,"low":1155,"close":1167},{"date":1674507600000,"open":1168,"high":1174,"low":1159,"close":1171},{"date":1674594000000,"open":1171,"high":1177,"low":1161,"close":1176},{"date":1674680400000,"open":1176,"high":1178,"low":1159,"close":1166},{"date":1674766800000,"open":1166,"high":1170,"low":1159,"close":1164},{"date":1675026000000,"open":1164,"high":1171,"low":1160,"close":1161},{"date":1675112400000,"open":1161,"high":1172,"low":1149,"close":1166},{"date":1675198800000,"open":1166,"high":1181,"low":1161,"close":1181},{"date":1675285200000,"open":1181,"high":1185,"low":1154,"close":1156},{"date":1675371600000,"open":1156,"high":1160,"low":1125,"close":1128},{"date":1675630800000,"open":1127,"high":1139,"low":1126,"close":1131},{"date":1675717200000,"open":1131,"high":1140,"low":1129,"close":1132},{"date":1675803600000,"open":1132,"high":1142,"low":1130,"close":1135},{"date":1675890000000,"open":1135,"high":1144,"low":1125,"close":1126},{"date":1675976400000,"open":1126,"high":1133,"low":1121,"close":1128},{"date":1676235600000,"open":1128,"high":1130,"low":1121,"close":1123},{"date":1676322000000,"open":1123,"high":1133,"low":1116,"close":1124},{"date":1676408400000,"open":1124,"high":1135,"low":1109,"close":1113},{"date":1676494800000,"open":1113,"high":1118,"low":1107,"close":1112},{"date":1676581200000,"open":1113,"high":1118,"low":1103,"close":1117}];

Screenshot of the resulting graph

enter image description here

Why does the graph not occur? Why can't I process the incoming data?


Solution

  • I changed my javascript codes like this. First of all added.

    <script src="https://cdn.amcharts.com/lib/5/stock.js"></script>
    

    And it works.

    <script>
        am5.ready(function() {
            var root = am5.Root.new("chartdiv");
            root.setThemes([am5themes_Animated.new(root)]);
            var stockChart = root.container.children.push(am5stock.StockChart.new(root, {}));
            //root.numberFormatter.set("numberFormat", "#,###.0000");
            
            var mainPanel = stockChart.panels.push(am5stock.StockPanel.new(root, {
                wheelY: "zoomX",
                height: am5.percent(70),
                layout: root.verticalLayout,
                panX: true,
                panY: true
            }));
    
            var valueAxis = mainPanel.yAxes.push(am5xy.ValueAxis.new(root, {
                renderer: am5xy.AxisRendererY.new(root, {
                    pan: "zoom"
                }),
                tooltip: am5.Tooltip.new(root, {}),
                //numberFormat: "#,###.00",
                extraTooltipPrecision: 2,
                visible: true
            }));
    
            var dateAxis = mainPanel.xAxes.push(am5xy.GaplessDateAxis.new(root, {
                groupData: true,
                groupCount:150,
                baseInterval: {
                    timeUnit: "day",
                    count: 1
                },
                renderer: am5xy.AxisRendererX.new(root, {}),
                tooltip: am5.Tooltip.new(root, {})
            }));
    
            var color = root.interfaceColors.get("background");
    
            var valueSeries = mainPanel.series.push(am5xy.CandlestickSeries.new(root, {
                clustered: false,
                fill: color,
                calculateAggregates: true,
                stroke: color,
                xAxis: dateAxis,
                yAxis: valueAxis,
                valueXField: "date",
                valueYField: "close",
                highValueYField: "high",
                lowValueYField: "low",
                openValueYField: "open",
                tooltip: am5.Tooltip.new(root, {
                    labelText: "[bold]{valueX.formatDate()}\nAçılış: {openValueY}\nEn Düşük: {lowValueY}\nEn Yüksek: {highValueY}\nKapanış: {valueY}"
                })            
    
            }));
    
            stockChart.set("stockSeries", valueSeries);
    
            mainPanel.set("cursor", am5xy.XYCursor.new(root, {
                yAxis: valueAxis,
                xAxis: dateAxis,
                snapToSeries: [valueSeries],
                snapToSeriesBy: "y!"
            }));
    
            function loadChartData(json_file_url) {
                am5.net.load(json_file_url).then(function(result) {
                    var data = am5.JSONParser.parse(result.response);
                    am5.array.each(data, function(item) {
                        var processor = am5.DataProcessor.new(root, {
                            numericFields: ["date", "open", "high", "low", "close"]
                        });
                        processor.processMany(data);
                        valueSeries.data.setAll(data);                    
                    });
    
                    console.log(data);
                }).catch(function(result) {
                    console.log("Error loadChartData");
                });
            }
    
            loadChartData("data.json");
            
            var toolbar = am5stock.StockToolbar.new(root, {
                container: document.getElementById("chartcontrols"),
                stockChart: stockChart,
                controls: [
                    am5stock.PeriodSelector.new(root, {
                        stockChart: stockChart
                    }),
                    am5stock.ResetControl.new(root, {
                        stockChart: stockChart
                    })
                ]
            })
    
        });
    </script>