4

我正在使用 AMcharts 绘制图表。我需要以 pdf 格式显示图表。因此,我已将图形转换为 png 图像并以 pdf 格式显示。此过程在除 IE9 之外的现代浏览器中成功运行。

我的问题仅在 IE9 中。

我在 div 容器中有两个 svg 标签。正如我所料,第二个 svg 标签被完美解析。但是第一个 svg 标签显示为空白图像。

我将 canvg.js 用于 html 画布。

<script src="http://canvg.googlecode.com/svn/trunk/canvg.js" type="text/javascript"></script>
<script src="http://canvg.googlecode.com/svn/trunk/rgbcolor.js" type="text/javascript"></script>
<script src="http://www.amcharts.com/lib/amcharts.js" type="text/javascript"></script>
<script type="text/javascript">

        var chart;
        var chartData = [];

        AmCharts.ready(function () {
        // generate some random data first
        generateChartData();

        // SERIAL CHART    
        chart = new AmCharts.AmSerialChart();
        chart.pathToImages = "http://amcharts.com/lib/samples/stock/images/";
        chart.zoomOutButton = {
            backgroundColor: '#000000',
            backgroundAlpha: 0.15
        };
        chart.dataProvider = chartData;
        chart.categoryField = "date";

        // listen for "dataUpdated" event (fired when chart is inited) and call zoomChart method when it happens
        chart.addListener("dataUpdated", zoomChart);

        // AXES
        // category                
        var categoryAxis = chart.categoryAxis;
        categoryAxis.parseDates = true; // as our data is date-based, we set parseDates to true
        categoryAxis.minPeriod = "DD"; // our data is daily, so we set minPeriod to DD
        categoryAxis.dashLength = 2;
        categoryAxis.gridAlpha = 0.15;
        categoryAxis.axisColor = "#DADADA";

        // first value axis (on the left)
        var valueAxis1 = new AmCharts.ValueAxis();
        valueAxis1.axisColor = "#FF6600";
        valueAxis1.axisThickness = 2;
        valueAxis1.gridAlpha = 0;
        chart.addValueAxis(valueAxis1);

        // second value axis (on the right) 
        var valueAxis2 = new AmCharts.ValueAxis();
        valueAxis2.position = "right"; // this line makes the axis to appear on the right
        valueAxis2.axisColor = "#FCD202";
        valueAxis2.gridAlpha = 0;
        valueAxis2.axisThickness = 2;
        chart.addValueAxis(valueAxis2);

        // third value axis (on the left, detached)
        valueAxis3 = new AmCharts.ValueAxis();
        valueAxis3.offset = 50; // this line makes the axis to appear detached from plot area
        valueAxis3.gridAlpha = 0;
        valueAxis3.axisColor = "#B0DE09";
        valueAxis3.axisThickness = 2;
        chart.addValueAxis(valueAxis3);

        // GRAPHS
        // first graph
        var graph1 = new AmCharts.AmGraph();
        graph1.valueAxis = valueAxis1; // we have to indicate which value axis should be used
        graph1.title = "red line";
        graph1.valueField = "visits";
        graph1.bullet = "round";
        graph1.hideBulletsCount = 30;
        chart.addGraph(graph1);

        // second graph                
        var graph2 = new AmCharts.AmGraph();
        graph2.valueAxis = valueAxis2; // we have to indicate which value axis should be used
        graph2.title = "yellow line";
        graph2.valueField = "hits";
        graph2.bullet = "square";
        graph2.hideBulletsCount = 30;
        chart.addGraph(graph2);

        // third graph
        var graph3 = new AmCharts.AmGraph();
        graph3.valueAxis = valueAxis3; // we have to indicate which value axis should be used
        graph3.valueField = "views";
        graph3.title = "green line";
        graph3.bullet = "triangleUp";
        graph3.hideBulletsCount = 30;
        chart.addGraph(graph3);

        // CURSOR
        var chartCursor = new AmCharts.ChartCursor();
        chartCursor.cursorPosition = "mouse";
        chart.addChartCursor(chartCursor);

        // SCROLLBAR
        var chartScrollbar = new AmCharts.ChartScrollbar();
        chart.addChartScrollbar(chartScrollbar);

        // LEGEND
        var legend = new AmCharts.AmLegend();
        legend.marginLeft = 110;
        chart.addLegend(legend);

        // WRITE
        chart.write("chartdiv");
        });

        // generate some random data, quite different range
        function generateChartData() {
        var firstDate = new Date();
        firstDate.setDate(firstDate.getDate() - 50);

        for (var i = 0; i < 50; i++) {
            var newDate = new Date(firstDate);
            newDate.setDate(newDate.getDate() + i);

            var visits = Math.round(Math.random() * 40) + 100;
            var hits = Math.round(Math.random() * 80) + 500;
            var views = Math.round(Math.random() * 6000);

            chartData.push({
            date: newDate,
            visits: visits,
            hits: hits,
            views: views
            });
        }
        }

        // this method is called when chart is first inited as we listen for "dataUpdated" event
        function zoomChart() {
        // different zoom methods can be used - zoomToIndexes, zoomToDates, zoomToCategoryValues
        chart.zoomToIndexes(10, 20);
        }


/*
 * Export.js - AmCharts to PNG
 * Benjamin Maertz (tetra1337@gmail.com)
 *
 * Requires:    rgbcolor.js - http://www.phpied.com/rgb-color-parser-in-javascript/
 *                 canvg.js - http://code.google.com/p/canvg/
 *                amcharts.js - http://www.amcharts.com/download
 */

// Lookup for required libs
if ( typeof(AmCharts) === 'undefined' || typeof(canvg) === 'undefined' || typeof(RGBColor) === 'undefined' ) {
    throw('Woup smth is wrong you might review that http://www.amcharts.com/forum/viewtopic.php?id=11001');
}

// Define custom util
AmCharts.getExport = function(anything) {
    /*
    ** PRIVATE FUNCTIONS
    */

    // Word around until somebody found out how to cover that
    function removeImages(svg) {
    var startStr    = '<image';
    var stopStr        = '</image>';
    var start        = svg.indexOf(startStr);
    var stop        = svg.indexOf(stopStr);
    var match        = '';

    // Recursion
    if ( start != -1 && stop != -1 ) {
        svg = removeImages(svg.slice(0,start) + svg.slice(stop + stopStr.length,svg.length));
    }
    return svg;
    };

    // Senseless function to handle any input
    function gatherAnything(anything,inside) {
    switch(String(anything)) {
        case '[object String]':
        if ( document.getElementById(anything) ) {
            anything = inside?document.getElementById(anything):new Array(document.getElementById(anything));
        }
        break;
        case '[object Array]':
        for ( var i=0;i<anything.length;i++) {
            anything[i] = gatherAnything(anything[i],true);
        }
        break;

        case '[object XULElement]':
        anything = inside?anything:new Array(anything);
        break;

        case '[object HTMLDivElement]':
        anything = inside?anything:new Array(anything);
        break;

        default:
        anything = new Array();
        for ( var i=0;i<AmCharts.charts.length;i++) {
            anything.push(AmCharts.charts[i].div);
        }
        break;
    }
    return anything;
    }

    /*
    ** varibales VARIABLES!!!
    */
    var chartContainer    = gatherAnything(anything);
    var chartImages        = [];
    var canvgOptions    = {
    ignoreAnimation    :    true,
    ignoreMouse        :    true,
    ignoreClear        :    true,
    ignoreDimensions:    true,
    offsetX            :    0,
    offsetY            :    0
    };

    /*
    ** Loop, generate, offer
    */

    // Loop through given container
    for(var i1=0;i1<chartContainer.length;i1++) {
    var canvas        = document.createElement('canvas');
    var context        = canvas.getContext('2d');
    var svgs        = chartContainer[i1].getElementsByTagName('svg');
    var image        = new Image();
    var heightCounter = 0;

    // Set dimensions, background color to the canvas
    canvas.width    = chartContainer[i1].offsetWidth;
    canvas.height    = chartContainer[i1].offsetHeight;
    context.fillStyle = '#FFFFFF';
    context.fillRect(0,0,canvas.width,canvas.height);

    // Loop through all svgs within the container
    for(var i2=0;i2<svgs.length;i2++) {

        var wrapper        = svgs[i2].parentNode;
        var clone        = svgs[i2].cloneNode(true);
        var cloneDiv    = document.createElement('div');
        var offsets        = {
        x:    wrapper.style.left.slice(0,-2) || 0,
        y:    wrapper.style.top.slice(0,-2) || 0,
        height:    wrapper.offsetHeight,
        width:    wrapper.offsetWidth
        };

        // Remove the style and append the clone to the div to receive the full SVG data
        clone.setAttribute('style','');
        cloneDiv.appendChild(clone);
        innerHTML = removeImages(cloneDiv.innerHTML); // without imagery

        // Apply parent offset
        if ( offsets.y == 0 ) {
        offsets.y = heightCounter;
        heightCounter += offsets.height;
        }

        canvgOptions.offsetX = offsets.x;
        canvgOptions.offsetY = offsets.y;

        // Some magic beyond the scenes...
        canvg(canvas,innerHTML,canvgOptions);
    }
        //console.log(canvas);return false;
    // Get the final data URL and throw that image to the array

    image.src = canvas.toDataURL();
    chartImages.push(image);
    }
    // Return DAT IMAGESS!!!!
    return chartImages
}

// Function to show the export in the document
function exportThis(opt) {
    var items = AmCharts.getExport('chartdiv');
    document.getElementById('button').innerHTML = 'Update Export';
    document.getElementById('not_button').innerHTML = '';
    for ( index in items ) {
    document.getElementById('not_button').appendChild(items[index]);        
    }
}


</script>


<div id="chartdiv" style="width:100%; height:400px; margin-bottom:10px;"></div>
<button id="button" onclick="exportThis();">Export</button>
<div id="not_button"></div>

请帮我解决这个问题。这是我的第一篇文章。提前致谢。

4

1 回答 1

1

更新您的 removeimages 功能。它会起作用的。

function removeImages(svg) {
    var startStr    = '<image';
    var stopStr        = '</image>';
    if(navigator.userAgent.toLowerCase().match('msie')) {
        var stopStr        = 'gif" />';
    }
    var start        = svg.indexOf(startStr);
    var stop        = svg.indexOf(stopStr);
    var match        = '';

    // Recursion
        if ( start != -1 && stop != -1 ) {
            svg = removeImages(svg.slice(0,start) + svg.slice(stop + stopStr.length,svg.length));
    }
    console.log(svg);
        return svg;
};

Amcharts 在 IE9 中自己创建结束标记。所以就是这样。如果 svg 标记中存在图像标记,则 todataURL 将不起作用。

于 2013-02-28T12:55:57.350 回答