PDF Schematics

This section provides a simple demonstration of how to export schematics components to PDF.

# Vertical Schematics Widget

This code creates vertical schematic widget and table widget.

import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { Group } from "@int/geotoolkit/scene/Group.ts";
import { HorizontalBoxLayout } from "@int/geotoolkit/layout/HorizontalBoxLayout.ts";
import { CompositeSchematicsWidget } from "@int/geotoolkit/schematics/widgets/CompositeSchematicsWidget.ts";
import { Events as SchematicsNodeEvents } from "@int/geotoolkit/schematics/scene/WellBoreNode.ts";
import { TableView } from "@int/geotoolkit/widgets/TableView.ts";
import { Dimension } from "@int/geotoolkit/util/Dimension.ts";
import { DataTable } from "@int/geotoolkit/data/DataTable.ts";
import { DataTableAdapter } from "@int/geotoolkit/widgets/data/DataTableAdapter.ts";
import { FixedTrackWidthStrategy } from "@int/geotoolkit/schematics/FixedTrackWidthStrategy.ts";
import { AlignmentStyle, BaseLineStyle, TextStyle } from "@int/geotoolkit/attributes/TextStyle.ts";
import { AnnotationLocation } from "@int/geotoolkit/layout/AnnotationLocation.ts";
import { TableView as TableShapeView } from "@int/geotoolkit/controls/shapes/tableview/TableView.ts";
const CellStyle = TableShapeView.CellStyle;
import { obfuscate } from "@int/geotoolkit/lib.js";
import { Application, loadSchematicsData } from "/src/code/Schematics/PDFSchematics/wellBore2pdf.ts";
const createSchematicTable = (rows) => {
  const dataTable = new DataTable({
    cols: [
      { name: "Type", type: "string" },
      { name: "From", type: "number" },
      { name: "To", type: "number" },
      { name: "Radius (out)", type: "number" },
      { name: "Radius (in)", type: "number" },
      { name: "Description", type: "string" }
    ],
    rowsdata: rows
  });
  const generalTextStyle = TextStyle.fromObject({
    "color": "#6b6b6b",
    "alignment": AlignmentStyle.Right,
    "baseline": BaseLineStyle.Middle,
    "font": "12px Courier"
  });
  const descriptionTextStyle = TextStyle.fromObject({
    "color": "#6b6b6b",
    "alignment": AlignmentStyle.Left,
    "baseline": BaseLineStyle.Middle,
    "font": "12px Courier"
  });
  const dataProvider = new (obfuscate(class extends DataTableAdapter {
    constructor(props) {
      super(props);
    }
    getContentFormat(column, row, cellStyle) {
      cellStyle["text"]["bounds"].inflate(-5, 0);
      cellStyle["text"]["textstyle"] = column === 5 ? descriptionTextStyle : generalTextStyle;
      return cellStyle;
    }
  }))({
    "datatable": dataTable
  });
  const table = new TableView({
    "horizontalscroll": "floating",
    "verticalscroll": "floating",
    "defaultcellsize": new Dimension(80, 30),
    "fitborder": true,
    "border": {
      "pixelsnapmode": true,
      "color": "#C0C0C0"
    }
  }).setData(dataProvider).setColumnsSize(0, 90).setColumnsSize(1, 60).setColumnsSize(2, 60).setColumnsSize(5, 250);
  return table;
};
const loadSchematicsWidget = async () => {
  const schematicsData = await loadSchematicsData();
  const registry = schematicsData.registry;
  const componentRows = schematicsData.componentRows;
  const wellBoreData = schematicsData.wellBoreData;
  const schematicsWidget = new CompositeSchematicsWidget({
    "gap": {
      "left": {
        "size": "0"
      },
      "right": {
        "size": "0"
      },
      "top": {
        "size": "0"
      },
      "bottom": {
        "size": "0"
      }
    },
    "annotationssizes": {
      "south": 0
    },
    "trackwidthstrategy": new FixedTrackWidthStrategy(150),
    "north": { "title": { "text": "Schematics Widget" } },
    "wellborenode": {
      "registry": registry
    },
    "data": {
      "elements": wellBoreData
    }
  });
  return {
    schematicsWidget,
    wellBoreData,
    componentRows
  };
};
const createScene = async (plotElement) => {
  const schematicsScene = await loadSchematicsWidget();
  const schematicsWidget = schematicsScene.schematicsWidget;
  const wellBoreData = schematicsScene.wellBoreData;
  const schematicTable = createSchematicTable(schematicsScene.componentRows);
  const plot = new Plot({
    "divelement": plotElement,
    "autosize": true,
    "root": new Group().setAutoModelLimitsMode(true).setLayout(new HorizontalBoxLayout()).addChild([
      schematicsWidget.setLayoutStyle({
        "width": 390
      }).setMarginsStyle({ right: "2px" }),
      schematicTable.setMarginsStyle({ left: "2px" })
    ])
  });
  schematicsWidget.getAnnotation(AnnotationLocation.Center).setVisible(false);
  schematicsWidget.on(SchematicsNodeEvents.ComponentsLoaded, () => {
    schematicsWidget.getAnnotation(AnnotationLocation.Center).setVisible(true);
    schematicsWidget.fitToBounds();
  });
  return new Application({
    plot,
    widget: schematicsWidget,
    wellBoreData
  });
};
export { createScene };

createScene(document.querySelector('[ref="plot"]'));

Close

# Deviated Schematics Widget

This code creates deviated schematic widget.

import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { ScalesRatioMode } from "@int/geotoolkit/schematics/scene/MultiLateralWellBoreNode.ts";
import { Trajectory2d } from "@int/geotoolkit/deviation/Trajectory2d.ts";
import { Mode } from "@int/geotoolkit/schematics/labeling/Mode.ts";
import { LocationType } from "@int/geotoolkit/schematics/labeling/LocationType.ts";
import { CompositeSchematicsWidget, DisplayMode } from "@int/geotoolkit/schematics/widgets/CompositeSchematicsWidget.ts";
import { Application, loadSchematicsData } from "/src/code/Schematics/PDFSchematics/wellBore2pdf.ts";
const loadSchematicsWidget = async () => loadSchematicsData().then((schematicsData) => {
  const wellBoreData = schematicsData.wellBoreData;
  const geometryBounds = wellBoreData.getGeometryBounds();
  const minDepth = geometryBounds.getTop();
  const maxDepth = geometryBounds.getBottom();
  const trajectory = new Trajectory2d({
    "data": {
      "x": [0, 0, 200],
      "y": [0, 250, 500],
      "d": [minDepth, (minDepth + maxDepth) / 2, maxDepth]
    }
  });
  const options = {
    "north": {
      "title": {
        "text": "Deviated Schematics Widget"
      }
    },
    "scalesratiomode": ScalesRatioMode.Free,
    "labeling": {
      "mode": Mode.Trajectory,
      "defaultLocation": LocationType.Auto
    },
    "annotationssizes": {
      "north": 50,
      "west": 70,
      "south": 75
    },
    "gap": {
      "left": {
        "size": "230px"
      },
      "right": {
        "size": "180px"
      },
      "top": {
        "size": "10px"
      },
      "bottom": {
        "size": "20px"
      }
    },
    "data": {
      "elements": wellBoreData,
      "trajectory": trajectory
    }
  };
  const schematicsWidget = new CompositeSchematicsWidget(options);
  schematicsWidget.setDisplayMode(DisplayMode.Deviated);
  return {
    schematicsWidget,
    wellBoreData,
    trajectory
  };
});
const createScene = async (canvas) => {
  const schematicsScene = await loadSchematicsWidget();
  const schematicsWidget = schematicsScene.schematicsWidget;
  const wellBoreData = schematicsScene.wellBoreData;
  const plot = new Plot({
    "canvaselement": canvas,
    "autosize": false,
    "root": schematicsWidget
  });
  schematicsWidget.fitToBounds();
  return new Application({
    plot,
    widget: schematicsWidget,
    wellBoreData,
    trajectory: schematicsScene.trajectory
  });
};
export { createScene };

createScene(document.querySelector('[ref="plot"]'));

Close

# Composite Schematics Document

This code does not create any schematic widget, it's just export WellBoreData to PDF.

import { Application, loadSchematicsData } from "/src/code/Schematics/PDFSchematics/wellBore2pdf.ts";
import { createTrajectory2d } from "/src/code/Schematics/PDFSchematics/data/trajectory2d.ts";
const createScene = async (canvas) => {
  const schematicsData = await loadSchematicsData();
  const wellBoreData = schematicsData.wellBoreData;
  const geometryBounds = wellBoreData.getGeometryBounds();
  const minDepth = geometryBounds.getTop();
  const maxDepth = geometryBounds.getBottom();
  const trajectory2d = createTrajectory2d(minDepth, maxDepth);
  return new Application({
    wellBoreData,
    trajectory: trajectory2d
  });
};
export { createScene };

createScene(document.querySelector('[ref="plot"]'));

Close

# Export Schematics and Table to PDF

This code shows how to export the Schematics Widget and Table Widget to PDF using Reports.JS. XML template defines layout of widgets. This code shows preprocessing of document to fill necessary fields.

# Export Schematics to PDF via NodeJS

This section provides a simple demonstration of how to export schematics components to PDF via NodeJS.
To do this:

  • Go to the the PDFSchematics folder and run npm install. Check to ensure node.js is installed. Supported version of node.js can be found in package.json.
  • Run npm start

To run server-side code, install the following prerequisites:

The file nodeJS-pdf-schematics.js contains a standard initialization for ReportJS, loading custom fonts if necessary and export to PDF.

import fsPromises from 'fs/promises';
import path from 'path';
import Canvas from 'canvas';

import '@int/geotoolkit/environment';
import {log} from '@int/geotoolkit/base';

import {FontSubType} from '@int/geotoolkit/pdf/FontSubType';
import {PaperOrientation} from '@int/geotoolkit/scene/exports/PaperOrientation';
import {ScalingOptions} from '@int/geotoolkit/scene/exports/ScalingOptions';
import {PaperFormatFactory} from '@int/geotoolkit/scene/exports/PaperFormatFactory';
import {UnitFactory} from '@int/geotoolkit/util/UnitFactory';

import {createWellBoreData} from './../data/wellboredata';
import {createTrajectory2d} from './../data/trajectory2d';

import {NodeStream} from './utils/stream';
import {SchematicsSession} from './session';
import {SchematicsApplication} from './application';

// we need to register real fonts on Canvas to measure it properly, as well as on PDF context
const __dirname = './';
Canvas.registerFont(path.join(__dirname, './fonts', 'roboto.ttf'), {family: 'Roboto'});
Canvas.registerFont(path.join(__dirname, './fonts', 'roboto-bold.ttf'), {family: 'Roboto', weight: 'bold'});

exportToPdf('./templates/composite-template.xml', 'nodejs-pdf-schematics.pdf');

type EmbededFontOptions = {
    'fontName': string;
    'fontUrl'?: string;
    'subType'?: FontSubType;
    'fontWeight'?: string;
    'fontStyle'?: string;
    'fontBase64EncodedFile'?: string | ArrayBuffer;
    'encoding'?: string;
};

function loadFonts (embeddedFonts: EmbededFontOptions[], exportFonts: EmbededFontOptions[]) {
    const embeddedFontsFontFiles: Promise<void>[] = [];
    embeddedFonts
        .forEach((font: EmbededFontOptions) => {
            const fontFilePath = font['fontUrl'];
            const fontFilePromise: Promise<void> = fsPromises.readFile(fontFilePath)
                .then((result) => {
                    exportFonts
                        .push({
                            'subType': FontSubType.TrueType,
                            'fontName': font['fontName'],
                            'fontWeight': font['fontWeight'] || 'normal',
                            'fontStyle': font['fontStyle'] || 'normal',
                            'fontBase64EncodedFile': result.toString('base64'),
                            'encoding': 'Identity-H'
                        });
                }, (error) => log(error));
            embeddedFontsFontFiles.push(fontFilePromise);
        });
    return Promise.all(embeddedFontsFontFiles);
}

function exportToPdf (reportFileName: string, resultFileName: string) {
    const onFail = function (reason: Error) {
        log('Error : ' + reason);
    };
    fsPromises.readFile(reportFileName)
        .then((reportTemplateBuffer) => {
            const reportTemplateSrc = reportTemplateBuffer.toString();

            const unitFactory = UnitFactory.getInstance();
            const px = unitFactory.getUnit('px');

            const printSettings = {
                'paperFormat': PaperFormatFactory.getInstance().getPaper('Letter', px, PaperOrientation.Portrait),
                's1caling': ScalingOptions.FitWidth,
                'keepaspectratio': false,
                'continuous': false,
                'drawwesttoeast': false,
                'top': 0.5,
                'bottom': 0.5,
                'left': 0.5,
                'right': 0.5,
                'units': 'cm'
            };

            const stream = new NodeStream(resultFileName);
            const pdfOptions = {
                'output': 'Widget',
                'printsettings': printSettings, // uppercase
                'pdfstream': stream,
                'embededfonts': [] as EmbededFontOptions[]
            };

            const robotoFonts: EmbededFontOptions[] = [{
                'fontUrl': './assets/fonts/roboto.ttf',
                'fontName': 'Roboto'
            }, {
                'fontUrl': './assets/fonts/roboto-bold.ttf',
                'fontName': 'Roboto',
                'fontWeight': 'bold'
            }];
            loadFonts(robotoFonts, pdfOptions['embededfonts']) // lowercase
                .then(() => {
                    const wellBoreData = createWellBoreData();
                    const geometryBounds = wellBoreData.getGeometryBounds();
                    const minDepth = geometryBounds.getTop();
                    const maxDepth = geometryBounds.getBottom();
                    const trajectory2d = createTrajectory2d(minDepth, maxDepth);
                    const sessionData = new SchematicsSession(wellBoreData, trajectory2d);
                    const application = new SchematicsApplication(sessionData);

                    application.exportToPdf(reportTemplateSrc, pdfOptions)
                        .then(() => end(application), (reason) => {
                            onFail(reason);
                            end(application);
                        });
                });
        });
}

function end (application: SchematicsApplication) {
    if (application) application.dispose();
    process.exit();
}

Close