从Web应用程序

时间:2016-05-30 14:17:47

标签: javascript java angularjs pdf

我想从Web应用程序生成PDF报告。 PDF应包含图表(饼图,条形图),表格,不同的字体和颜色。

应用程序的服务器端是Java,客户端是AngularJS(当然还有CSS3和HTML)。

两个主要选项:

  • 客户端将一些参数传递给服务器,服务器将使用Java包生成PDF报告。然后,报告将作为下载文件发送回客户端。
  • 客户端将使用将HTML和CSS转换为PDF的JS包生成报告。

在Java世界中,我发现了例如iText和JFreeChart,例如here。这里的问题是图表的设计在示例中看起来很糟糕,我不知道它是否可以通过我所拥有的样式指南(可以通过CSS轻松完成的设计)进行设计。

在JS世界中,我发现了html2canvas和pdfMake,例如here。这里的问题是我不确定从HTML转换到画布再转换为PDF在Angular应用程序中的效果是否正常。而且我不确定它是否转换了复杂的DOM元素,比如svg或canvas元素中的图表。

您对这些套餐有什么经验吗?您是否知道此任务,客户端或服务器的其他推荐软件包?

1 个答案:

答案 0 :(得分:0)

想要分享我的解决方案......我选择了一个客户端解决方案。

我从jsPDF开始,但遇到了一些问题。例如,很难用我想要的样式转换表。

我选择pdfMake进行PDF生成,html2canvas进行复杂设计组件的截图,canvg进行d3js图表(svg图表)转换为画布(pdfMake可以添加画布作为文件的图像)。

我写了一个函数来获取我要转换为PDF的部分的HTML根的CSS类(记住它是单页应用程序),并且还获取了哪些HTML节点的元数据(再次,由他们的应该将CSS类添加到PDF(以及节点的类型 - table / text / image / svg)。

然后,通过DOM遍历,我浏览了要添加到PDF的元素,并按类型处理每个元素。部分代码(按类型遍历和切换案例):

$(htmlRootSelector).contents().each(function processNodes(index, element) {
    var classMeta = getMetaByClass(element.className);

    if (!classMeta) {
      $(element).contents().each(processNodes);
      return;
    }

    var pdfObj = {};
    pdfObj.width = classMeta.width || angular.undefined;
    pdfObj.height = classMeta.height || angular.undefined;
    pdfObj.style = classMeta.style || angular.undefined;
    pdfObj.pageBreak = classMeta.pageBreak || angular.undefined;

    switch (classMeta.type) {
    case 'text':
      pdfObj.text = element.innerText;
      pdfDefinition.content.push(pdfObj);
      break;
    case 'table':
      var tableArray = [];
      var headerArray = [];
      var headers = $(element).find('th');
      var rows = $(element).find('tr');
      $.each(headers, function (i, header) {
        headerArray.push({text: header.innerHTML, style: classMeta.style + '-header'});
      });
      tableArray.push(headerArray);

      $.each(rows, function (i, row) {
        var rowArray = [];
        var cells = $(row).find('td');

        if (cells.length) {
          $.each(cells, function (j, cell) {
            rowArray.push(i % 2 === 1 ? {text: cell.innerText, style: classMeta.style + '-odd-row'} : cell.innerText);
          });

          tableArray.push(rowArray);
        }
      });

      pdfObj.table = {
        widths: $.map(headers, function (d, i) {
          return i === 0 ? 80 : '*';
        }),
        body: tableArray
      };
      pdfDefinition.content.push(pdfObj);
      break;
    case 'image':
      html2CanvasCount++;
      htmlToCanvas(element, pdfObj);
      pdfDefinition.content.push(pdfObj);
      break;
    case 'svg':
      svgToCanvas(element, pdfObj);
      pdfDefinition.content.push(pdfObj);
      break;
    default:
      break;
    }

    $(element).contents().each(processNodes);
  });

这是一般的解决方案。 希望它会帮助别人。