Oracle APEX Chart Customizations: Moving Legends, Download HD Charts Image & Styling Chart Fonts

 



File URLs

<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.3.2/html2canvas.min.js"></script>


Function and Global Variable Declaration

function downloadSVGAsImage() {
    // Select the SVG element.
    const svgElement = document.querySelector('#eb_bubble_chart_jet svg');
    if (!svgElement) {
        console.error('SVG element not found');
        return;
    }

    // Clone the SVG element and modify its background for the download.
    const clonedSvgElement = svgElement.cloneNode(true);

    // Hide the scroller elements in the cloned SVG by setting their visibility to 'hidden'.
    const scrollers = clonedSvgElement.querySelectorAll('g:nth-child(4) > rect, g:nth-child(5) > rect');
    scrollers.forEach(rect => {
        rect.style.visibility = 'hidden';
    });

    // Add a white background rectangle to the cloned SVG.
    const whiteBackground = document.createElementNS("http://www.w3.org/2000/svg", "rect");
    whiteBackground.setAttribute('width', '100%');
    whiteBackground.setAttribute('height', '100%');
    whiteBackground.setAttribute('fill', 'white');
    clonedSvgElement.insertBefore(whiteBackground, clonedSvgElement.firstChild);

    // Serialize the cloned SVG to a string.
    const serializer = new XMLSerializer();
    let svgString = serializer.serializeToString(clonedSvgElement);

    // Fix potential namespace issues.
    svgString = svgString.replace(/(\w+)?:?xlink=/g, 'xmlns:xlink=').replace(/NS\d+:href/g, 'xlink:href');

    // Convert the SVG string to a data URL.
    const svgBlob = new Blob([svgString], { type: "image/svg+xml;charset=utf-8" });
    const url = URL.createObjectURL(svgBlob);

    // Create an Image element from the SVG.
    const img = new Image();
    img.onload = function() {
        // Define the size of the canvas for a higher resolution.
        const scale = 8; // Adjust scale to get the desired image quality.
        const canvas = document.createElement('canvas');
        canvas.width = svgElement.clientWidth * scale;
        canvas.height = svgElement.clientHeight * scale;
        const ctx = canvas.getContext('2d');
        ctx.scale(scale, scale); // Scale the context to match the canvas scale.
        ctx.drawImage(img, 0, 0); // Draw the image onto the canvas.

        // Convert the canvas to a data URL and trigger the download.
        const dataUrl = canvas.toDataURL('image/png');
        const a = document.createElement('a');
        a.href = dataUrl;
        a.download = 'bubble_chart_high_res.png'; // Set the desired file name.
        document.body.appendChild(a);
        a.click(); // Trigger the download.
        document.body.removeChild(a); // Clean up the DOM.

        // Revoke the created object URL to free up resources.
        URL.revokeObjectURL(url);
    };
    img.src = url; // Set the source of the image to the object URL.
}

document.addEventListener('DOMContentLoaded', function () {
    const downloadButton = document.getElementById('downloadChartButton');
    downloadButton.addEventListener('click', downloadSVGAsImage);
});


Inline

svg {
  width: 105% !important;
}


/* Hide scroller by default */
#eb_bubble_chart_jet svg g g g:nth-child(4) rect,
#eb_bubble_chart_jet svg g g g:nth-child(5) rect {
    visibility: hidden;
}

/* Show scroller only on hover of the chart */
#eb_bubble_chart_jet:hover svg g g g:nth-child(4) rect,
#eb_bubble_chart_jet:hover svg g g g:nth-child(5) rect {
    visibility: visible;
}


eb_bubble_chart is a static id of your chart region

Create Page Item as select list

SELECT 'auto' AS display_value, 'auto' AS return_value FROM DUAL
UNION ALL
SELECT 'Left' AS display_value, 'start' AS return_value FROM DUAL
UNION ALL
SELECT 'Right' AS display_value, 'end' AS return_value FROM DUAL
UNION ALL
SELECT 'Bottom' AS display_value, 'bottom' AS return_value FROM DUAL
UNION ALL
SELECT 'Top' AS display_value, 'top' AS return_value FROM DUAL;


  • P3_LEGEND_POSITION  
Then Dynamic Action and select JS code 

// Function to set legend position for a single chart
function setLegendPosition(chartRegionId, position) {
    var chart = apex.region(chartRegionId).widget(); // Get the chart widget
    
    console.log("Setting legend position to:", position, "for chart:", chartRegionId); // Debug: Log the desired position and chart ID
    
    // Check if the chart widget has the 'ojChart' function available
    if (typeof chart.ojChart === "function") {
        // Set the legend position using the 'ojChart' function
        chart.ojChart("option", "legend.position", position);
        
        // Refresh the chart
        chart.ojChart("refresh");
        
        console.log("Legend position set successfully for chart:", chartRegionId);
    } else {
        console.error("ojChart function not available on the widget for region: " + chartRegionId);
    }
}

// Function to update legend position for multiple charts
function updateLegendPosition(chartRegionIds, selectedPosition) {
    var chartIds = chartRegionIds.split(','); // Split the comma-separated IDs into an array
    
    console.log("Selected legend position:", selectedPosition); // Debug: Log the selected position

    // Check if the selectedPosition is valid ("start," "end," "bottom," "top," or "auto")
    if (selectedPosition === "start" || selectedPosition === "end" || selectedPosition === "bottom" || selectedPosition === "top" || selectedPosition === "auto") {
        // Update the legend position for each chart
        for (var i = 0; i < chartIds.length; i++) {
            var chartRegionId = chartIds[i].trim(); // Trim any extra spaces
            setLegendPosition(chartRegionId, selectedPosition);
            console.log("Updating legend position to:", selectedPosition, "for chart:", chartRegionId);
        }
    } else {
        console.error("Invalid legend position selected:", selectedPosition);
        // Handle invalid selections as needed
    }
}

// Bind the updateLegendPosition function to the change event of the select list
apex.jQuery("#P3_LEGEND_POSITION").change(function() {
    var selectedPosition = apex.item("P3_LEGEND_POSITION").getValue();  
   // var chartRegionIds = "eb_bubble_chart,eb_scatter_chart,eb_scatter_chart_jet,eb_bubble_chart_mask_jet"; // Add more IDs if needed

   var chartRegionIds = "eb_bubble_chart"; // Add more IDs if needed

    updateLegendPosition(chartRegionIds, selectedPosition);
});

// Call updateLegendPosition on page load to set the initial position
apex.jQuery(document).ready(function() {
    var selectedPosition = apex.item("P3_LEGEND_POSITION").getValue();
    var chartRegionIds = "eb_bubble_chart"; // Add more IDs if needed
    updateLegendPosition(chartRegionIds, selectedPosition);
    console.log("Page loaded. Initial legend position set.");
});


/*****************Font Styling selection *******************************/

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Oracle APEX Chart Customization</title>
    <style>
        /* Add your common styles here */
        body {
            font-family: 'Arial', sans-serif;
        }

        .control-panel {
            display: flex;
            flex-direction: column;
            padding: 10px;
            
        }

        .control-group {
            margin-bottom: 15px;
        }

        .control-label {
            font-size: 14px;
            color: #333;
            margin-bottom: 5px;
        }

        .radio-group {
            display: flex;
            flex-direction: column;
        }

        .radio-input {
            margin: 5px 0;
        }

        .radio-label {
            font-size: 12px;
            color: #333;
        }

        .control-input {
            padding: 5px;
            border-radius: 4px;
            border: 1px solid #ccc;
            font-size: 14px;
        }

        .apply-button {
            padding: 10px 15px;
            font-size: 14px;
            color: white;
            background-color: #4CAF50;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            text-align: center;
        }

        .apply-button:hover {
            background-color: #45a049;
        }

        .color-button {
    padding: 10px 20px;
    font-size: 14px;
    color: #007BFF; /* This is a blue color; change it to the color you need */
    background-color: white;
    border: 1px solid #007BFF; /* This is a blue border; change it to the color you need */
    border-radius: 4px;
    cursor: pointer;
    transition: background-color 0.3s, color 0.3s; /* Smooth transition for hover effect */
      }

       .color-button:hover {
    background-color: #007BFF; /* Button color on hover */
    color: white; /* Text color on hover */
    border-color: #0056b3; /* Border color on hover; darker blue */
    }


    </style>
</head>
<body>
   <div class="control-panel">
    <!-- Font Family Selection -->
    <div class="control-group">
        <div class="control-label">Font Family:</div>
        <div class="radio-group-horizontal">
            <label class="radio-label">
                <input type="radio" name="fontFamily" value="Arial" checked> Arial
            </label>
            <label class="radio-label">
                <input type="radio" name="fontFamily" value="OpenSans"> Open Sans
            </label>
            <!-- Additional font families can be added here -->
        </div>
    </div>

    <!-- Font Style Selection -->
    <div class="control-group">
        <div class="control-label">Font Style:</div>
        <div class="radio-group-horizontal">
            <label class="radio-label">
                <input type="radio" name="fontStyle" value="normal" checked> Normal
            </label>
            <label class="radio-label">
                <input type="radio" name="fontStyle" value="bold"> Bold
            </label>
            <label class="radio-label">
                <input type="radio" name="fontStyle" value="semi-bold"> Semi-bold
            </label>
            <!-- Additional font styles can be added here -->
        </div>
    </div>

    <!-- Font Size Selection -->
    <div class="control-group">
        <div class="control-label">Font Size:</div>
        <div class="radio-group-horizontal">
            <label class="radio-label">
                <input type="radio" name="fontSize" value="14px" checked> 14px
            </label>
            <label class="radio-label">
                <input type="radio" name="fontSize" value="16px"> 16px
            </label>
            <label class="radio-label">
                <input type="radio" name="fontSize" value="18px"> 18px
            </label>
            <!-- Additional font sizes can be added here -->
        </div>
    </div>

    <!-- Axis Line Width Selection -->
    <div class="control-group">
        <div class="control-label">Axis Line Width:</div>
        <div class="radio-group-horizontal">
            <label class="radio-label">
                <input type="radio" name="axisStrokeWidth" value="1" checked> 1px
            </label>
            <label class="radio-label">
                <input type="radio" name="axisStrokeWidth" value="2"> 2px
            </label>
            <!-- Additional line width options can be added here -->
        </div>
    </div>

    <!-- Chart Size Selection -->
    <div class="control-group">
        <div class="control-label">Chart Size:</div>
        <select id="chartSizeSelect" class="control-input">
            <option value="640x370">640 x 370</option>
            <option value="900x400">900 x 400</option>
            <option value="1390x440">1390 x 440</option>
            <!-- Additional chart sizes can be added here -->
        </select>
    </div>
</div>



<button type="button" id="applyStylesButton" class="color-button">Apply Styles</button>

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>

<script>
$(document).ready(function() {
    // Function to apply chart styles
    function applyChartStyles() {
        var fontFamily = $('input[name="fontFamily"]:checked').val();
        var fontStyle = $('input[name="fontStyle"]:checked').val();
        var fontSize = $('input[name="fontSize"]:checked').val();
        var axisStrokeWidth = $('input[name="axisStrokeWidth"]:checked').val();
        var chartSize = $('#chartSizeSelect').val();

        // Apply font styles and size to SVG text elements
        $('svg text').css({
            'font-family': fontFamily,
            'font-weight': fontStyle,
            'font-size': fontSize
        });

        // Update axis lines based on selection
        $('svg .oj-chart-axis-tick line, svg path[stroke="#9E9E9E"]').css({
            'stroke': 'black',
            'stroke-width': axisStrokeWidth + 'px'
        });

        // Update chart size and center it based on selection
        if (chartSize) {
            var dimensions = chartSize.split('x');
            var chartWidth = parseInt(dimensions[0]);
            var chartHeight = parseInt(dimensions[1]);
            
            var $chartContainer = $('#eb_bubble_chart_jet, #eb_scatter_chart_jet, #eb_bubble_chart_mask, #eb_scatter_chart_mask,#eb_bubble_chart_mask_jet,#eb_scatter_chart_mask_jet');
            var $parentContainer = $chartContainer.parent();

            // Set chart container size
            $chartContainer.css({
                'width': chartWidth + 'px',
                'height': chartHeight + 'px'
            });

            // Center chart container within the parent
            $chartContainer.css({
                'position': 'absolute',
                'left': '50%',
                'top': '50%',
                'transform': 'translate(-50%, -50%)'
            });

            // Optionally, if the parent container's size is not set, adjust it as well
            $parentContainer.css({
                'position': 'relative',
                'width': '100%',  // Set to the maximum width you want
                'height': chartHeight + 'px' // Adjust the height accordingly
            });
        }
    }

    function simulateDoubleClick() {
        applyChartStyles(); // First application
        setTimeout(applyChartStyles, 100); // Second application after 100ms delay
    }

    $('#applyStylesButton').on('click', function(event) {
        event.preventDefault();
        simulateDoubleClick();
    });
});
</script>

</body>
</html>

/*********************************Result will Look like this ************************************/




Stay Informed:  Stay up-to-date with the latest Oracle APEX tips and updates by following my social media profiles.

 Follow on YouTube:  Dive deeper into Oracle APEX by exploring my YouTube channel for tutorials and insights: 

 YouTube Channel: YouTube


Connect on LinkedIn:  Let's connect on LinkedIn for networking opportunities, discussions, and more: 

 LinkedIn Profile: Linkedin




Comments