MergeRows.vb
'' 
'' このコードは、DioDocs for PDF のサンプルの一部として提供されています。
'' © MESCIUS 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()

            '' HTML のレンダリングに使用する GcHtmlBrowser のインスタンスを生成します。
            Using browser = Util.NewHtmlBrowser()
                '' PdfOptions では、HTML から PDF への変換のオプションを提供できます。
                Dim pdfOptions = New PdfOptions() With {
                    .Margins = New PdfMargins(0.2F, 1, 0.2F, 1),
                    .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 ページを一時ファイルにレンダリングします。
                Using htmlPage = browser.NewPage(html)
                    htmlPage.SaveAsPdf(tmp, pdfOptions)
                End Using
            End Using
            '' 作成した PDF を一時ファイルからターゲットストリームにコピーします。
            Using ts = File.OpenRead(tmp)
                ts.CopyTo(stream)
            End Using
            '' 一時ファイルを削除します。
            File.Delete(tmp)
        End Using
        '' PDF ドキュメントを保存します。
    End Sub
End Class