MergeRows.vb
'' 
'' このコードは、DioDocs for PDF のサンプルの一部として提供されています。
'' Copyright (c) GrapeCity inc. All rights reserved.
'' 
Imports System.IO
Imports System.Drawing
Imports System.Text
Imports System.Data
Imports System.Linq
Imports System.Collections.Generic
Imports GrapeCity.Documents.Pdf
Imports GrapeCity.Documents.Text
Imports GrapeCity.Documents.Html

'' このサンプルでは、最初の列でグループ化されたテーブルベースのレポートを作成
'' およびレンダリングし、同じ列のセルを同じ値で結合する方法を示します。
'' このサンプルでは、HTML の JavaScript コードを使用して実際にセルをマージし、
'' HTML を PDF にレンダリングする際の JavaScript の使用方法を示します。
'' サンプルでは、テーブル全体が1ページに収まるように行数が制限されています。
'' 
'' GcHtml をプロジェクトに追加する方法の詳細については、HelloWorldHtml
'' サンプルコードの上部にあるコメントのメモを参照してください。
Public Class MergeRows
    Sub CreatePDF(ByVal stream As Stream)
        Const TTAG = "___TABLE___"

        '' HTML ページテンプレート:
        Const tableTpl =
            "<!DOCTYPE html>" +
            "<html>" +
            "<head>" +
            "<style>" +
            "" +
            "html * {" +
            "  font-family: 'Trebuchet MS', Arial, Helvetica, sans-serif !important;" +
            "}" +
            "" +
            "h1 {" +
            "  color: #1a5276;" +
            "  background-color: #d2b4de;" +
            "  text-align: center;" +
            "  padding: 6px;" +
            "}" +
            "" +
            "thead {display: table-header-group;}" +
            "" +
            "#products {" +
            "  font-family: 'Trebuchet MS', Arial, Helvetica, sans-serif;" +
            "  border-collapse: collapse;" +
            "  width: 100%;" +
            "}" +
            "" +
            "#products td, #products th {" +
            "  border: 1px solid #ddd;" +
            "  padding: 8px;" +
            "}" +
            "" +
            "#products tr:hover {background-color: #ddd;}" +
            "" +
            "#products th {" +
            "  padding-top: 12px;" +
            "  padding-bottom: 12px;" +
            "  text-align: left;" +
            "  background-color: #a569bd;" +
            "  color: white;" +
            "}" +
            "</style>" +
            "" +
            "</head>" +
            "<body onload='mergeRows()'>" +
            "" +
            "<script>" +
            "function mergeRows() {" +
            "  const table = document.querySelector('table');" +
            "  let headerCell = null;" +
            "  for (let row of table.rows)" +
            "  {" +
            "    const firstCell = row.cells[0];" +
            "    if (headerCell === null || firstCell.innerText !== headerCell.innerText)" +
            "    {" +
            "      headerCell = firstCell;" +
            "    }" +
            "    else" +
            "    {" +
            "      headerCell.rowSpan++;" +
            "      firstCell.remove();" +
            "    }" +
            "  }" +
            "}" +
            "</script>" +
            "" +
            TTAG +
            "" +
            "</body>" +
            "</html>"

        Const tableHead = "<h1>仕入れ先別商品</h1>"

        Const tableFmt =
            "<table id='products'>" +
            "  <thead>" +
            "    <th>仕入れ先</th>" +
            "    <th>商品名</th>" +
            "    <th>数量</th>" +
            "    <th>単価</th>" +
            "  </thead>" +
            "{0}" +
            "</table>"

        Const dataRowFmt =
            "  <tr>" +
            "    <td>{0}</td>" +
            "    <td>{1}</td>" +
            "    <td>{2}</td>" +
            "    <td align='right'>{3:C}</td>" +
            "  </tr>"

        Using ds = New DataSet()
            ds.ReadXml(Path.Combine("Resources", "data", "GcNWind.xml"))

            Dim dtProds = ds.Tables("Products")
            Dim dtSupps = ds.Tables("Suppliers")

            Dim products =
            (From prod In dtProds.Select()
             Join supp In dtSupps.Select()
            On prod("SupplierID") Equals supp("SupplierID")
             Order By supp("CompanyName")
             Select New With {
                 .ProductName = prod("ProductName"),
                 .Supplier = supp("CompanyName"),
                 .QuantityPerUnit = prod("QuantityPerUnit"),
                 .UnitPrice = prod("UnitPrice")
            }).Take(16)

            Dim sb = New StringBuilder()
            sb.AppendLine(tableHead)
            For Each prod In products
                sb.AppendFormat(dataRowFmt, prod.Supplier, prod.ProductName, prod.QuantityPerUnit, prod.UnitPrice)
            Next

            Dim html = tableTpl.Replace(TTAG, String.Format(tableFmt, sb.ToString()))

            Dim tmp = Path.GetTempFileName()
            Using re = New GcHtmlRenderer(html)
                '' PdfSettings では、HTML から PDF への変換のオプションを提供できます。
                Dim pdfSettings = New PdfSettings() With {
                    .Margins = New Margins(0.2F, 1, 0.2F, 1),
                    .IgnoreCSSPageSize = True,
                    .DisplayHeaderFooter = True,
                    .HeaderTemplate = "<div style='color:#1a5276; font-size:12px; width:1000px; margin-left:0.2in; margin-right:0.2in'>" +
                        "<span style='float:left;'>Product Price List</span>" +
                        "<span style='float:right'>Page <span class='pageNumber'></span> of <span class='totalPages'></span></span>" +
                        "</div>",
                    .FooterTemplate = "<div style='color: #1a5276; font-size:12em; width:1000px; margin-left:0.2in; margin-right:0.2in;'>" +
                        "<span>(c) GrapeCity inc. All Rights Reserved.</span>" +
                        "<span style='float:right'>Generated on <span class='date'></span></span></div>"
                }
                '' ソース Web ページを一時ファイルにレンダリングします。
                re.RenderToPdf(tmp, pdfSettings)
            End Using
            '' 作成した PDF を一時ファイルからターゲットストリームにコピーします。
            Using ts = File.OpenRead(tmp)
                ts.CopyTo(stream)
            End Using
            '' 一時ファイルを削除します。
            File.Delete(tmp)
        End Using
        '' PDF ドキュメントを保存します。
    End Sub
End Class