Implement bare-bones support for debugging SVG meshes
This commit is contained in:
parent
e7a6861846
commit
0e9a59088c
|
@ -9,6 +9,7 @@
|
||||||
<body class="pf-unscrollable">
|
<body class="pf-unscrollable">
|
||||||
{{>partials/navbar.html isTool=true}}
|
{{>partials/navbar.html isTool=true}}
|
||||||
<canvas id="pf-canvas" width="400" height="300"></canvas>
|
<canvas id="pf-canvas" width="400" height="300"></canvas>
|
||||||
|
<svg id="pf-svg" xmlns="http://www.w3.org/2000/svg" width="400" height="300"></svg>
|
||||||
<div class="fixed-bottom mb-3 d-flex justify-content-end align-items-end pf-pointer-events-none">
|
<div class="fixed-bottom mb-3 d-flex justify-content-end align-items-end pf-pointer-events-none">
|
||||||
<div id="pf-toolbar">
|
<div id="pf-toolbar">
|
||||||
<button id="pf-open-button" type="button"
|
<button id="pf-open-button" type="button"
|
||||||
|
|
|
@ -101,7 +101,7 @@ class ThreeDController extends DemoAppController<ThreeDView> {
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(textData => this.parseTextData(textData));
|
.then(textData => this.parseTextData(textData));
|
||||||
|
|
||||||
this.loadInitialFile();
|
this.loadInitialFile(this.builtinFileURI);
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseTextData(textData: any): MonumentSide[] {
|
private parseTextData(textData: any): MonumentSide[] {
|
||||||
|
|
|
@ -18,19 +18,19 @@ export abstract class AppController {
|
||||||
const canvas = document.getElementById('pf-canvas') as HTMLCanvasElement;
|
const canvas = document.getElementById('pf-canvas') as HTMLCanvasElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected loadInitialFile() {
|
protected loadInitialFile(builtinFileURI: string) {
|
||||||
const selectFileElement = document.getElementById('pf-select-file') as
|
const selectFileElement = document.getElementById('pf-select-file') as
|
||||||
(HTMLSelectElement | null);
|
(HTMLSelectElement | null);
|
||||||
if (selectFileElement != null) {
|
if (selectFileElement != null) {
|
||||||
const selectedOption = selectFileElement.selectedOptions[0] as HTMLOptionElement;
|
const selectedOption = selectFileElement.selectedOptions[0] as HTMLOptionElement;
|
||||||
this.fetchFile(selectedOption.value);
|
this.fetchFile(selectedOption.value, builtinFileURI);
|
||||||
} else {
|
} else {
|
||||||
this.fetchFile(this.defaultFile);
|
this.fetchFile(this.defaultFile, builtinFileURI);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fetchFile(file: string) {
|
protected fetchFile(file: string, builtinFileURI: string) {
|
||||||
window.fetch(`${this.builtinFileURI}/${file}`)
|
window.fetch(`${builtinFileURI}/${file}`)
|
||||||
.then(response => response.arrayBuffer())
|
.then(response => response.arrayBuffer())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
this.fileData = data;
|
this.fileData = data;
|
||||||
|
@ -47,7 +47,6 @@ export abstract class AppController {
|
||||||
protected abstract fileLoaded(): void;
|
protected abstract fileLoaded(): void;
|
||||||
|
|
||||||
protected abstract get defaultFile(): string;
|
protected abstract get defaultFile(): string;
|
||||||
protected abstract get builtinFileURI(): string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class DemoAppController<View extends PathfinderDemoView> extends AppController {
|
export abstract class DemoAppController<View extends PathfinderDemoView> extends AppController {
|
||||||
|
@ -221,11 +220,13 @@ export abstract class DemoAppController<View extends PathfinderDemoView> extends
|
||||||
selectFileElement.removeChild(placeholder);
|
selectFileElement.removeChild(placeholder);
|
||||||
|
|
||||||
// Fetch the file.
|
// Fetch the file.
|
||||||
this.fetchFile(selectedOption.value);
|
this.fetchFile(selectedOption.value, this.builtinFileURI);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract createView(): View;
|
protected abstract createView(): View;
|
||||||
|
|
||||||
|
protected abstract readonly builtinFileURI: string;
|
||||||
|
|
||||||
view: Promise<View>;
|
view: Promise<View>;
|
||||||
|
|
||||||
protected filePickerElement: HTMLInputElement | null;
|
protected filePickerElement: HTMLInputElement | null;
|
||||||
|
|
|
@ -56,7 +56,7 @@ class BenchmarkAppController extends DemoAppController<BenchmarkTestView> {
|
||||||
const runBenchmarkButton = unwrapNull(document.getElementById('pf-run-benchmark-button'));
|
const runBenchmarkButton = unwrapNull(document.getElementById('pf-run-benchmark-button'));
|
||||||
runBenchmarkButton.addEventListener('click', () => this.runBenchmark(), false);
|
runBenchmarkButton.addEventListener('click', () => this.runBenchmark(), false);
|
||||||
|
|
||||||
this.loadInitialFile();
|
this.loadInitialFile(this.builtinFileURI);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fileLoaded(): void {
|
protected fileLoaded(): void {
|
||||||
|
|
|
@ -17,6 +17,8 @@ import {B_QUAD_UPPER_RIGHT_VERTEX_OFFSET} from "./meshes";
|
||||||
import {B_QUAD_UPPER_CONTROL_POINT_VERTEX_OFFSET, B_QUAD_LOWER_LEFT_VERTEX_OFFSET} from "./meshes";
|
import {B_QUAD_UPPER_CONTROL_POINT_VERTEX_OFFSET, B_QUAD_LOWER_LEFT_VERTEX_OFFSET} from "./meshes";
|
||||||
import {B_QUAD_LOWER_RIGHT_VERTEX_OFFSET} from "./meshes";
|
import {B_QUAD_LOWER_RIGHT_VERTEX_OFFSET} from "./meshes";
|
||||||
import {B_QUAD_LOWER_CONTROL_POINT_VERTEX_OFFSET, PathfinderMeshData} from "./meshes";
|
import {B_QUAD_LOWER_CONTROL_POINT_VERTEX_OFFSET, PathfinderMeshData} from "./meshes";
|
||||||
|
import {Partitionable} from "./meshes";
|
||||||
|
import { SVGLoader, BUILTIN_SVG_URI } from './svg-loader';
|
||||||
import {BUILTIN_FONT_URI, TextFrameGlyphStorage, PathfinderGlyph, TextRun} from "./text";
|
import {BUILTIN_FONT_URI, TextFrameGlyphStorage, PathfinderGlyph, TextRun} from "./text";
|
||||||
import {GlyphStorage, TextFrame} from "./text";
|
import {GlyphStorage, TextFrame} from "./text";
|
||||||
import {unwrapNull, UINT32_SIZE, UINT32_MAX, assert} from "./utils";
|
import {unwrapNull, UINT32_SIZE, UINT32_MAX, assert} from "./utils";
|
||||||
|
@ -32,10 +34,19 @@ const POINT_LABEL_FONT: string = "12px sans-serif";
|
||||||
const POINT_LABEL_OFFSET: glmatrix.vec2 = glmatrix.vec2.fromValues(12.0, 12.0);
|
const POINT_LABEL_OFFSET: glmatrix.vec2 = glmatrix.vec2.fromValues(12.0, 12.0);
|
||||||
const POINT_RADIUS: number = 2.0;
|
const POINT_RADIUS: number = 2.0;
|
||||||
|
|
||||||
|
const BUILTIN_URIS = {
|
||||||
|
font: BUILTIN_FONT_URI,
|
||||||
|
svg: BUILTIN_SVG_URI,
|
||||||
|
};
|
||||||
|
|
||||||
|
type FileType = 'font' | 'svg';
|
||||||
|
|
||||||
class MeshDebuggerAppController extends AppController {
|
class MeshDebuggerAppController extends AppController {
|
||||||
start() {
|
start() {
|
||||||
super.start();
|
super.start();
|
||||||
|
|
||||||
|
this.fileType = 'font';
|
||||||
|
|
||||||
this.view = new MeshDebuggerView(this);
|
this.view = new MeshDebuggerView(this);
|
||||||
|
|
||||||
this.openModal = unwrapNull(document.getElementById('pf-open-modal'));
|
this.openModal = unwrapNull(document.getElementById('pf-open-modal'));
|
||||||
|
@ -54,7 +65,7 @@ class MeshDebuggerAppController extends AppController {
|
||||||
const openOKButton = unwrapNull(document.getElementById('pf-open-ok-button'));
|
const openOKButton = unwrapNull(document.getElementById('pf-open-ok-button'));
|
||||||
openOKButton.addEventListener('click', () => this.loadPath(), false);
|
openOKButton.addEventListener('click', () => this.loadPath(), false);
|
||||||
|
|
||||||
this.loadInitialFile();
|
this.loadInitialFile(BUILTIN_FONT_URI);
|
||||||
}
|
}
|
||||||
|
|
||||||
private showOpenDialog(): void {
|
private showOpenDialog(): void {
|
||||||
|
@ -67,57 +78,83 @@ class MeshDebuggerAppController extends AppController {
|
||||||
|
|
||||||
this.fontPathSelectGroup.classList.add('pf-display-none');
|
this.fontPathSelectGroup.classList.add('pf-display-none');
|
||||||
|
|
||||||
if (optionValue.startsWith('font-')) {
|
const results = unwrapNull(/^([a-z]+)-(.*)$/.exec(optionValue));
|
||||||
this.fetchFile(optionValue.substr('font-'.length));
|
this.fileType = results[1] as FileType;
|
||||||
} else if (optionValue.startsWith('svg-')) {
|
this.fetchFile(results[2], BUILTIN_URIS[this.fileType]);
|
||||||
// TODO(pcwalton)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fileLoaded(): void {
|
protected fileLoaded(): void {
|
||||||
this.font = opentype.parse(this.fileData);
|
|
||||||
assert(this.font.isSupported(), "The font type is unsupported!");
|
|
||||||
|
|
||||||
while (this.fontPathSelect.lastChild != null)
|
while (this.fontPathSelect.lastChild != null)
|
||||||
this.fontPathSelect.removeChild(this.fontPathSelect.lastChild);
|
this.fontPathSelect.removeChild(this.fontPathSelect.lastChild);
|
||||||
|
|
||||||
this.fontPathSelectGroup.classList.remove('pf-display-none');
|
this.fontPathSelectGroup.classList.remove('pf-display-none');
|
||||||
|
|
||||||
const glyphCount = this.font.numGlyphs;
|
if (this.fileType === 'font')
|
||||||
|
this.fontLoaded();
|
||||||
|
else if (this.fileType === 'svg')
|
||||||
|
this.svgLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private fontLoaded(): void {
|
||||||
|
this.file = opentype.parse(this.fileData);
|
||||||
|
assert(this.file.isSupported(), "The font type is unsupported!");
|
||||||
|
|
||||||
|
const glyphCount = this.file.numGlyphs;
|
||||||
for (let glyphIndex = 1; glyphIndex < glyphCount; glyphIndex++) {
|
for (let glyphIndex = 1; glyphIndex < glyphCount; glyphIndex++) {
|
||||||
const newOption = document.createElement('option');
|
const newOption = document.createElement('option');
|
||||||
newOption.value = "" + glyphIndex;
|
newOption.value = "" + glyphIndex;
|
||||||
const glyphName = this.font.glyphIndexToName(glyphIndex);
|
const glyphName = this.file.glyphIndexToName(glyphIndex);
|
||||||
newOption.appendChild(document.createTextNode(glyphName));
|
newOption.appendChild(document.createTextNode(glyphName));
|
||||||
this.fontPathSelect.appendChild(newOption);
|
this.fontPathSelect.appendChild(newOption);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Automatically load a path if this is the initial pageload.
|
// Automatically load a path if this is the initial pageload.
|
||||||
if (this.meshes == null)
|
if (this.meshes == null)
|
||||||
this.loadPath(this.font.charToGlyph(CHARACTER));
|
this.loadPath(this.file.charToGlyph(CHARACTER));
|
||||||
|
}
|
||||||
|
|
||||||
|
private svgLoaded(): void {
|
||||||
|
this.file = new SVGLoader;
|
||||||
|
this.file.loadFile(this.fileData);
|
||||||
|
|
||||||
|
const pathCount = this.file.pathInstances.length;
|
||||||
|
for (let pathIndex = 0; pathIndex < pathCount; pathIndex++) {
|
||||||
|
const newOption = document.createElement('option');
|
||||||
|
newOption.value = "" + pathIndex;
|
||||||
|
newOption.appendChild(document.createTextNode(`Path ${pathIndex}`));
|
||||||
|
this.fontPathSelect.appendChild(newOption);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected loadPath(opentypeGlyph?: opentype.Glyph | null) {
|
protected loadPath(opentypeGlyph?: opentype.Glyph | null) {
|
||||||
window.jQuery(this.openModal).modal('hide');
|
window.jQuery(this.openModal).modal('hide');
|
||||||
|
|
||||||
|
let partitionable: Partitionable | null = null;
|
||||||
|
|
||||||
|
if (this.file instanceof opentype.Font) {
|
||||||
if (opentypeGlyph == null) {
|
if (opentypeGlyph == null) {
|
||||||
const glyphIndex = parseInt(this.fontPathSelect.selectedOptions[0].value);
|
const glyphIndex = parseInt(this.fontPathSelect.selectedOptions[0].value);
|
||||||
opentypeGlyph = this.font.glyphs.get(glyphIndex);
|
opentypeGlyph = this.file.glyphs.get(glyphIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
const glyph = new MeshDebuggerGlyph(opentypeGlyph);
|
const glyph = new MeshDebuggerGlyph(opentypeGlyph);
|
||||||
const glyphStorage = new GlyphStorage(this.fileData, [glyph], this.font);
|
partitionable = new GlyphStorage(this.fileData, [glyph], this.file);
|
||||||
|
} else if (this.file instanceof SVGLoader) {
|
||||||
|
partitionable = this.file;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
glyphStorage.partition().then(meshes => {
|
partitionable.partition().then(meshes => {
|
||||||
this.meshes = meshes;
|
this.meshes = meshes;
|
||||||
this.view.attachMeshes();
|
this.view.attachMeshes();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
protected readonly defaultFile: string = FONT;
|
protected readonly defaultFile: string = FONT;
|
||||||
protected readonly builtinFileURI: string = BUILTIN_FONT_URI;
|
|
||||||
|
|
||||||
private font: Font;
|
private file: Font | SVGLoader | null;
|
||||||
|
private fileType: FileType;
|
||||||
|
|
||||||
meshes: PathfinderMeshData | null;
|
meshes: PathfinderMeshData | null;
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,10 @@ export const B_QUAD_LOWER_INDICES_OFFSET: number = B_QUAD_LOWER_LEFT_VERTEX_OFFS
|
||||||
|
|
||||||
type BufferType = 'ARRAY_BUFFER' | 'ELEMENT_ARRAY_BUFFER';
|
type BufferType = 'ARRAY_BUFFER' | 'ELEMENT_ARRAY_BUFFER';
|
||||||
|
|
||||||
|
export interface Partitionable {
|
||||||
|
partition(): Promise<PathfinderMeshData>;
|
||||||
|
}
|
||||||
|
|
||||||
export interface Meshes<T> {
|
export interface Meshes<T> {
|
||||||
readonly bQuads: T;
|
readonly bQuads: T;
|
||||||
readonly bVertexPositions: T;
|
readonly bVertexPositions: T;
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
|
|
||||||
import * as glmatrix from 'gl-matrix';
|
import * as glmatrix from 'gl-matrix';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import 'path-data-polyfill.js';
|
|
||||||
|
|
||||||
import {DemoAppController} from './app-controller';
|
import {DemoAppController} from './app-controller';
|
||||||
import {AntialiasingStrategy, AntialiasingStrategyName, NoAAStrategy} from "./aa-strategy";
|
import {AntialiasingStrategy, AntialiasingStrategyName, NoAAStrategy} from "./aa-strategy";
|
||||||
|
@ -18,7 +17,7 @@ import {OrthographicCamera} from "./camera";
|
||||||
import {ECAAStrategy, ECAAMulticolorStrategy} from "./ecaa-strategy";
|
import {ECAAStrategy, ECAAMulticolorStrategy} from "./ecaa-strategy";
|
||||||
import {PathfinderMeshData} from "./meshes";
|
import {PathfinderMeshData} from "./meshes";
|
||||||
import {ShaderMap, ShaderProgramSource} from './shader-loader';
|
import {ShaderMap, ShaderProgramSource} from './shader-loader';
|
||||||
import {SVGLoader} from './svg-loader';
|
import { SVGLoader, BUILTIN_SVG_URI } from './svg-loader';
|
||||||
import {panic, unwrapNull} from './utils';
|
import {panic, unwrapNull} from './utils';
|
||||||
import {PathfinderDemoView, Timings} from './view';
|
import {PathfinderDemoView, Timings} from './view';
|
||||||
import SSAAStrategy from "./ssaa-strategy";
|
import SSAAStrategy from "./ssaa-strategy";
|
||||||
|
@ -28,8 +27,6 @@ const parseColor = require('parse-color');
|
||||||
|
|
||||||
const SVG_NS: string = "http://www.w3.org/2000/svg";
|
const SVG_NS: string = "http://www.w3.org/2000/svg";
|
||||||
|
|
||||||
const BUILTIN_SVG_URI: string = "/svg/demo";
|
|
||||||
|
|
||||||
const DEFAULT_FILE: string = 'tiger';
|
const DEFAULT_FILE: string = 'tiger';
|
||||||
|
|
||||||
const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = {
|
const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = {
|
||||||
|
@ -38,17 +35,6 @@ const ANTIALIASING_STRATEGIES: AntialiasingStrategyTable = {
|
||||||
ecaa: ECAAMulticolorStrategy,
|
ecaa: ECAAMulticolorStrategy,
|
||||||
};
|
};
|
||||||
|
|
||||||
declare class SVGPathSegment {
|
|
||||||
type: string;
|
|
||||||
values: number[];
|
|
||||||
}
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface SVGPathElement {
|
|
||||||
getPathData(settings: any): SVGPathSegment[];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AntialiasingStrategyTable {
|
interface AntialiasingStrategyTable {
|
||||||
none: typeof NoAAStrategy;
|
none: typeof NoAAStrategy;
|
||||||
ssaa: typeof SSAAStrategy;
|
ssaa: typeof SSAAStrategy;
|
||||||
|
@ -61,11 +47,12 @@ class SVGDemoController extends DemoAppController<SVGDemoView> {
|
||||||
|
|
||||||
this.loader = new SVGLoader;
|
this.loader = new SVGLoader;
|
||||||
|
|
||||||
this.loadInitialFile();
|
this.loadInitialFile(this.builtinFileURI);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fileLoaded() {
|
protected fileLoaded() {
|
||||||
this.loader.loadFile(this.fileData).then(meshes => {
|
this.loader.loadFile(this.fileData);
|
||||||
|
this.loader.partition().then(meshes => {
|
||||||
this.meshes = meshes;
|
this.meshes = meshes;
|
||||||
this.meshesReceived();
|
this.meshesReceived();
|
||||||
})
|
})
|
||||||
|
@ -77,9 +64,7 @@ class SVGDemoController extends DemoAppController<SVGDemoView> {
|
||||||
unwrapNull(this.shaderSources));
|
unwrapNull(this.shaderSources));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected get builtinFileURI(): string {
|
protected readonly builtinFileURI: string = BUILTIN_SVG_URI;
|
||||||
return BUILTIN_SVG_URI;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected get defaultFile(): string {
|
protected get defaultFile(): string {
|
||||||
return DEFAULT_FILE;
|
return DEFAULT_FILE;
|
||||||
|
|
|
@ -11,37 +11,52 @@
|
||||||
import * as glmatrix from 'gl-matrix';
|
import * as glmatrix from 'gl-matrix';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
import 'path-data-polyfill.js';
|
||||||
import {panic, unwrapNull} from "./utils";
|
import {panic, unwrapNull} from "./utils";
|
||||||
import {PathfinderMeshData} from "./meshes";
|
import {PathfinderMeshData, Partitionable} from "./meshes";
|
||||||
|
|
||||||
|
export const BUILTIN_SVG_URI: string = "/svg/demo";
|
||||||
|
|
||||||
const PARTITION_SVG_PATHS_ENDPOINT_URL: string = "/partition-svg-paths";
|
const PARTITION_SVG_PATHS_ENDPOINT_URL: string = "/partition-svg-paths";
|
||||||
|
|
||||||
/// The minimum size of a stroke.
|
/// The minimum size of a stroke.
|
||||||
const HAIRLINE_STROKE_WIDTH: number = 0.25;
|
const HAIRLINE_STROKE_WIDTH: number = 0.25;
|
||||||
|
|
||||||
|
declare class SVGPathSegment {
|
||||||
|
type: string;
|
||||||
|
values: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface SVGPathElement {
|
||||||
|
getPathData(settings: any): SVGPathSegment[];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface PathInstance {
|
export interface PathInstance {
|
||||||
element: SVGPathElement;
|
element: SVGPathElement;
|
||||||
stroke: number | 'fill';
|
stroke: number | 'fill';
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SVGLoader {
|
export class SVGLoader implements Partitionable {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.svg = unwrapNull(document.getElementById('pf-svg')) as Element as SVGSVGElement;
|
this.svg = unwrapNull(document.getElementById('pf-svg')) as Element as SVGSVGElement;
|
||||||
this.pathInstances = [];
|
this.pathInstances = [];
|
||||||
|
this.paths = [];
|
||||||
this.bounds = glmatrix.vec4.create();
|
this.bounds = glmatrix.vec4.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
loadFile(fileData: ArrayBuffer): Promise<PathfinderMeshData> {
|
loadFile(fileData: ArrayBuffer) {
|
||||||
this.fileData = fileData;
|
this.fileData = fileData;
|
||||||
|
|
||||||
const decoder = new (window as any).TextDecoder('utf-8');
|
const decoder = new (window as any).TextDecoder('utf-8');
|
||||||
const fileStringData = decoder.decode(new DataView(this.fileData));
|
const fileStringData = decoder.decode(new DataView(this.fileData));
|
||||||
const svgDocument = (new DOMParser).parseFromString(fileStringData, 'image/svg+xml');
|
const svgDocument = (new DOMParser).parseFromString(fileStringData, 'image/svg+xml');
|
||||||
const svgElement = svgDocument.documentElement as Element as SVGSVGElement;
|
const svgElement = svgDocument.documentElement as Element as SVGSVGElement;
|
||||||
return this.attachSVG(svgElement);
|
this.attachSVG(svgElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
private attachSVG(svgElement: SVGSVGElement): Promise<PathfinderMeshData> {
|
private attachSVG(svgElement: SVGSVGElement) {
|
||||||
// Clear out the current document.
|
// Clear out the current document.
|
||||||
let kid;
|
let kid;
|
||||||
while ((kid = this.svg.firstChild) != null)
|
while ((kid = this.svg.firstChild) != null)
|
||||||
|
@ -76,8 +91,8 @@ export class SVGLoader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const request: any = { paths: [] };
|
|
||||||
let minX = 0, minY = 0, maxX = 0, maxY = 0;
|
let minX = 0, minY = 0, maxX = 0, maxY = 0;
|
||||||
|
this.paths = [];
|
||||||
|
|
||||||
// Extract, normalize, and transform the path data.
|
// Extract, normalize, and transform the path data.
|
||||||
for (const instance of this.pathInstances) {
|
for (const instance of this.pathInstances) {
|
||||||
|
@ -112,16 +127,18 @@ export class SVGLoader {
|
||||||
else
|
else
|
||||||
kind = { Stroke: Math.max(HAIRLINE_STROKE_WIDTH, instance.stroke) };
|
kind = { Stroke: Math.max(HAIRLINE_STROKE_WIDTH, instance.stroke) };
|
||||||
|
|
||||||
request.paths.push({ segments: segments, kind: kind });
|
this.paths.push({ segments: segments, kind: kind });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.bounds = glmatrix.vec4.clone([minX, minY, maxX, maxY]);
|
this.bounds = glmatrix.vec4.clone([minX, minY, maxX, maxY]);
|
||||||
|
}
|
||||||
|
|
||||||
|
partition(): Promise<PathfinderMeshData> {
|
||||||
// Make the request.
|
// Make the request.
|
||||||
return window.fetch(PARTITION_SVG_PATHS_ENDPOINT_URL, {
|
return window.fetch(PARTITION_SVG_PATHS_ENDPOINT_URL, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
body: JSON.stringify(request),
|
body: JSON.stringify({ paths: this.paths }),
|
||||||
}).then(response => response.text()).then(responseText => {
|
}).then(response => response.text()).then(responseText => {
|
||||||
const response = JSON.parse(responseText);
|
const response = JSON.parse(responseText);
|
||||||
if (!('Ok' in response))
|
if (!('Ok' in response))
|
||||||
|
@ -135,5 +152,6 @@ export class SVGLoader {
|
||||||
private fileData: ArrayBuffer;
|
private fileData: ArrayBuffer;
|
||||||
|
|
||||||
pathInstances: PathInstance[];
|
pathInstances: PathInstance[];
|
||||||
|
private paths: any[];
|
||||||
bounds: glmatrix.vec4;
|
bounds: glmatrix.vec4;
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,7 +142,7 @@ class TextDemoController extends DemoAppController<TextDemoView> {
|
||||||
const editTextOkButton = unwrapNull(document.getElementById('pf-edit-text-ok-button'));
|
const editTextOkButton = unwrapNull(document.getElementById('pf-edit-text-ok-button'));
|
||||||
editTextOkButton.addEventListener('click', () => this.updateText(), false);
|
editTextOkButton.addEventListener('click', () => this.updateText(), false);
|
||||||
|
|
||||||
this.loadInitialFile();
|
this.loadInitialFile(this.builtinFileURI);
|
||||||
}
|
}
|
||||||
|
|
||||||
showTextEditor() {
|
showTextEditor() {
|
||||||
|
|
Loading…
Reference in New Issue