function renderChart(ticker, exchange, divId, useLogScale, title, ylevel) { fetch(`https://api.friedrich.report/tv?ticker=${ticker}&exchange=${exchange}`) .then(response => response.json()) .then(data => { const timestamps = Object.keys(data.close); const closePrices = Object.values(data.close); const xAxisCategories = timestamps.map(ts => new Date(parseInt(ts)).toISOString()); // Calculate 31-day SMA const sma31 = []; for (let i = 0; i < closePrices.length; i++) { if (i < 30) { sma31.push(null); // Not enough data to calculate SMA } else { const sum = closePrices.slice(i - 30, i + 1).reduce((a, b) => a + b, 0); sma31.push(sum / 31); } } var options = { chart: { fontFamily: 'Outfit', background: '#ffffff', // Set the background color to white zoom: { enabled: true, type: 'x', autoScaleYaxis: true, events: { zoomed: function(chartContext, { xaxis, yaxis }) { const zoomMessage = document.createElement('div'); zoomMessage.innerText = 'Press ESC to leave zoom'; zoomMessage.style.position = 'absolute'; zoomMessage.style.top = '10px'; zoomMessage.style.left = '10px'; zoomMessage.style.backgroundColor = 'rgba(0, 0, 0, 0.7)'; zoomMessage.style.color = 'white'; zoomMessage.style.padding = '5px'; zoomMessage.style.borderRadius = '5px'; zoomMessage.style.zIndex = 1000; document.querySelector(`#${divId}`).appendChild(zoomMessage); setTimeout(() => { document.querySelector(`#${divId}`).removeChild(zoomMessage); }, 2000); } } }, toolbar: { show: true, tools: { download: true, selection: true, zoom: { icon: '', title: 'Zoom In', click: function(chart, options, e) { if (chart.zoomed) { // Simulate ESC key press var escEvent = new KeyboardEvent('keydown', { key: 'Escape' }); document.dispatchEvent(escEvent); chart.zoomed = false; } else { chart.zoomed = true; } } }, zoomin: true, zoomout: true, pan: true, // Enable pan tool reset: true, customIcons: [{ icon: '', index: -1, title: 'Fullscreen', class: 'custom-icon', click: function(chart, options, e) { const chartElement = chart.el; if (chartElement.requestFullscreen) { chartElement.requestFullscreen({ navigationUI: "hide" }); } else if (chartElement.mozRequestFullScreen) { // Firefox chartElement.mozRequestFullScreen({ navigationUI: "hide" }); } else if (chartElement.webkitRequestFullscreen) { // Chrome, Safari and Opera chartElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); } else if (chartElement.msRequestFullscreen) { // IE/Edge chartElement.msRequestFullscreen(); } // Add exit fullscreen button const exitFullscreenButton = document.createElement('button'); exitFullscreenButton.innerText = 'Exit Fullscreen'; exitFullscreenButton.style.position = 'absolute'; exitFullscreenButton.style.top = '10px'; exitFullscreenButton.style.right = '10px'; exitFullscreenButton.style.zIndex = 1001; exitFullscreenButton.onclick = function() { if (document.exitFullscreen) { document.exitFullscreen(); } else if (document.mozCancelFullScreen) { // Firefox document.mozCancelFullScreen(); } else if (document.webkitExitFullscreen) { // Chrome, Safari and Opera document.webkitExitFullscreen(); } else if (document.msExitFullscreen) { // IE/Edge document.msExitFullscreen(); } }; document.querySelector(`#${divId}`).appendChild(exitFullscreenButton); } }] }, autoSelected: 'pan' // Auto-select pan tool }, width: "100%", type: "line", stacked: false, pan: { enabled: true, // Enable panning mode: 'x', // Allow panning only on the x-axis } }, title: { text: `${title}`, align: 'center', margin: 20, style: { fontSize: '16px', fontWeight: 'bold', color: '#0000af' } }, dataLabels: { enabled: false }, colors: ["#0000af", "#FFA500", "#FF4560"], series: [{ name: "Close Prices", data: closePrices.map((price, index) => ({ x: new Date(parseInt(timestamps[index])), y: price })) }, { name: "31-day SMA", data: sma31.map((price, index) => ({ x: new Date(parseInt(timestamps[index])), y: price })) }], stroke: { curve: 'smooth', width: [2, 2] }, markers: { size: 0 // Disable markers for better performance }, fill: { type: 'gradient', gradient: { type: "vertical" } }, xaxis: { type: 'datetime' }, yaxis: [{ opposite: true, axisTicks: { show: true }, axisBorder: { show: false, color: "#0000af" }, labels: { style: { colors: "#0000af" }, formatter: function (value) { return value.toFixed(2); } }, title: { text: "Kurs", rotate: -90, offsetX: 0, offsetY: 0, style: { color: "#0000af" } } }], tooltip: { shared: true, intersect: false, x: { show: true, format: 'dd MMM yyyy' } }, annotations: { yaxis: [{ y: ylevel, borderColor: '#FF4560', label: { borderColor: '#FF4560', position: 'left', offsetX: 50, // Adjust this value to position the label in the left 25% quarter style: { color: '#fff', background: '#FF4560' }, text: 'Kaufzone' } }], xaxis: [{ x: new Date(parseInt(timestamps[Math.floor(timestamps.length / 2)])), borderColor: '#775DD0', label: { borderColor: '#775DD0', style: { color: '#fff', background: '#775DD0' }, text: 'Event' } }] }, legend: { show: true, horizontalAlign: "left", offsetX: 40 } }; var chart = new ApexCharts(document.querySelector(`#${divId}`), options); chart.zoomed = false; chart.render(); }) .catch(error => console.error('Error fetching data:', error)); }