Make the demo UI less cluttered
This commit is contained in:
parent
d7b606987a
commit
58b558de64
|
@ -1,12 +1,33 @@
|
|||
.pf-bottom-control {
|
||||
position: fixed;
|
||||
bottom: 1em;
|
||||
}
|
||||
#pf-load-font-button-label,
|
||||
#pf-load-svg-button-label {
|
||||
left: 1em;
|
||||
margin: 0;
|
||||
}
|
||||
#pf-settings {
|
||||
user-select: none;
|
||||
-moz-user-select: none;
|
||||
opacity: 1.0;
|
||||
transition: opacity 300ms, transform 300ms;
|
||||
transform: translateY(0);
|
||||
}
|
||||
#pf-settings-button:not(:hover) {
|
||||
background: rgba(255, 255, 255, 0.75);
|
||||
}
|
||||
#pf-file-select {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
}
|
||||
#pf-settings.pf-invisible {
|
||||
opacity: 0.0;
|
||||
transform: translateY(1em);
|
||||
}
|
||||
button > svg {
|
||||
width: 1.25em;
|
||||
display: block;
|
||||
}
|
||||
button > svg path {
|
||||
fill: currentColor;
|
||||
}
|
||||
#pf-rendering-options-group {
|
||||
right: 1em;
|
||||
}
|
||||
|
@ -16,12 +37,32 @@
|
|||
touch-action: none;
|
||||
}
|
||||
#pf-fps-label {
|
||||
position: absolute;
|
||||
right: 1em;
|
||||
margin-top: 1em;
|
||||
color: white;
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
#pf-svg {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.pf-arrow-box:after, .pf-arrow-box:before {
|
||||
top: 100%;
|
||||
left: 22px;
|
||||
border: solid transparent;
|
||||
content: " ";
|
||||
height: 0;
|
||||
width: 0;
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
}
|
||||
.pf-arrow-box:after {
|
||||
border-color: rgba(0, 0, 0, 0);
|
||||
border-top-color: white;
|
||||
border-width: 14px;
|
||||
margin-left: -14px;
|
||||
}
|
||||
.pf-arrow-box:before {
|
||||
border-color: rgba(0, 0, 0, 0);
|
||||
border-top-color: rgba(0, 0, 0, 0.125);
|
||||
border-width: 15px;
|
||||
margin-left: -15px;
|
||||
}
|
|
@ -8,15 +8,36 @@
|
|||
</head>
|
||||
<body>
|
||||
${require('./include/navbar.html')}
|
||||
<div class="rounded py-1 px-3" id="pf-fps-label">0 ms</div>
|
||||
<canvas id="pf-canvas" width="400" height="300"></canvas>
|
||||
<div class="pf-bottom-control" id="pf-rendering-options-group">
|
||||
<select class="custom-select" id="pf-aa-level-select">
|
||||
<option data-pf-type="none" data-pf-level="0" selected>No AA</option>
|
||||
<option data-pf-type="ecaa" data-pf-level="0">ECAA (BROKEN)</option>
|
||||
<option data-pf-type="ssaa" data-pf-level="2">2×SSAA</option>
|
||||
<option data-pf-type="ssaa" data-pf-level="4">4×SSAA</option>
|
||||
</select>
|
||||
<div class="fixed-bottom mb-3 d-flex justify-content-between align-items-end">
|
||||
<div class="ml-3">
|
||||
<div id="pf-settings" class="card mb-4 pf-invisible">
|
||||
<div class="card-body">
|
||||
<button id="pf-settings-close-button" type="button" class="close"
|
||||
aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h4 class="card-title">Settings</h4>
|
||||
<form>
|
||||
<div class="form-group">
|
||||
<label for="pf-aa-level-select">Antialiasing</label>
|
||||
<select id="pf-aa-level-select" class="form-control custom-select">
|
||||
<option value="none" selected>None</option>
|
||||
<option value="ssaa-2">2×SSAA</option>
|
||||
<option value="ssaa-4">4×SSAA</option>
|
||||
<option value="ecaa">ECAA (BROKEN)</option>
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="pf-arrow-box"></div>
|
||||
</div>
|
||||
<button id="pf-settings-button" type="button" class="btn btn-outline-secondary"
|
||||
aria-expanded="false" aria-controls="#pf-settings">
|
||||
${require('octicons/build/svg/gear.svg')}
|
||||
</button>
|
||||
</div>
|
||||
<div class="rounded py-1 px-3 mr-3" id="pf-fps-label">0 ms</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<link rel="stylesheet" href="/css/bootstrap/bootstrap.css">
|
||||
<link rel="stylesheet" href="/css/octicons/octicons.css">
|
||||
<link rel="stylesheet" href="/css/pathfinder.css">
|
||||
<script type="text/javascript" src="/js/jquery/jquery.js"></script>
|
||||
<script type="text/javascript" src="/js/popper.js/popper.js"></script>
|
||||
|
|
|
@ -8,20 +8,45 @@
|
|||
</head>
|
||||
<body>
|
||||
${require('./include/navbar.html')}
|
||||
<div class="rounded py-1 px-3" id="pf-fps-label">0 ms</div>
|
||||
<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>
|
||||
<label class="btn btn-secondary btn-file pf-bottom-control" id="pf-load-svg-button-label">
|
||||
Load SVG…
|
||||
<input type="file" style="display: none" id="pf-load-svg-button">
|
||||
</label>
|
||||
<div class="pf-bottom-control" id="pf-rendering-options-group">
|
||||
<select class="custom-select" id="pf-aa-level-select">
|
||||
<option data-pf-type="none" data-pf-level="0" selected>No AA</option>
|
||||
<option data-pf-type="ecaa" data-pf-level="0">ECAA (BROKEN)</option>
|
||||
<option data-pf-type="ssaa" data-pf-level="2">2×SSAA</option>
|
||||
<option data-pf-type="ssaa" data-pf-level="4">4×SSAA</option>
|
||||
</select>
|
||||
<div class="fixed-bottom mb-3 d-flex justify-content-between align-items-end">
|
||||
<div class="ml-3">
|
||||
<div id="pf-settings" class="card mb-4 pf-invisible">
|
||||
<div class="card-body">
|
||||
<button id="pf-settings-close-button" type="button" class="close"
|
||||
aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h4 class="card-title">Settings</h4>
|
||||
<form>
|
||||
<div class="form-group">
|
||||
<label for="pf-select-file">SVG document</label>
|
||||
<select id="pf-select-file" class="form-control custom-select">
|
||||
<option value="tiger" selected>Ghostscript Tiger</option>
|
||||
<option value="load-custom">Load File…</option>
|
||||
</select>
|
||||
<input id="pf-file-select" type="file">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="pf-aa-level-select">Antialiasing</label>
|
||||
<select id="pf-aa-level-select" class="form-control custom-select">
|
||||
<option value="none" selected>None</option>
|
||||
<option value="ssaa-2">2×SSAA</option>
|
||||
<option value="ssaa-4">4×SSAA</option>
|
||||
<option value="ecaa">ECAA (BROKEN)</option>
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="pf-arrow-box"></div>
|
||||
</div>
|
||||
<button id="pf-settings-button" type="button" class="btn btn-outline-secondary"
|
||||
aria-expanded="false" aria-controls="#pf-settings">
|
||||
${require('octicons/build/svg/gear.svg')}
|
||||
</button>
|
||||
</div>
|
||||
<div class="rounded py-1 px-3 mr-3" id="pf-fps-label">0 ms</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -8,19 +8,46 @@
|
|||
</head>
|
||||
<body>
|
||||
${require('./include/navbar.html')}
|
||||
<div class="rounded py-1 px-3" id="pf-fps-label">0 ms</div>
|
||||
<canvas id="pf-canvas" width="400" height="300"></canvas>
|
||||
<label class="btn btn-secondary btn-file pf-bottom-control" id="pf-load-font-button-label">
|
||||
Load Font…
|
||||
<input type="file" style="display: none" id="pf-load-font-button">
|
||||
</label>
|
||||
<div class="pf-bottom-control" id="pf-rendering-options-group">
|
||||
<select class="custom-select" id="pf-aa-level-select">
|
||||
<option data-pf-type="none" data-pf-level="0" selected>No AA</option>
|
||||
<option data-pf-type="ecaa" data-pf-level="0">ECAA</option>
|
||||
<option data-pf-type="ssaa" data-pf-level="2">2×SSAA</option>
|
||||
<option data-pf-type="ssaa" data-pf-level="4">4×SSAA</option>
|
||||
</select>
|
||||
<div class="fixed-bottom mb-3 d-flex justify-content-between align-items-end">
|
||||
<div class="ml-3">
|
||||
<div id="pf-settings" class="card mb-4 pf-invisible">
|
||||
<div class="card-body">
|
||||
<button id="pf-settings-close-button" type="button" class="close"
|
||||
aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h4 class="card-title">Settings</h4>
|
||||
<form>
|
||||
<div class="form-group">
|
||||
<label for="pf-select-file">Font</label>
|
||||
<select id="pf-select-file" class="form-control custom-select">
|
||||
<option value="open-sans" selected>Open Sans</option>
|
||||
<option value="nimbus-sans">Nimbus Sans</option>
|
||||
<option value="eb-garamond">EB Garamond</option>
|
||||
<option value="load-custom">Load File…</option>
|
||||
</select>
|
||||
<input id="pf-file-select" type="file">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="pf-aa-level-select">Antialiasing</label>
|
||||
<select id="pf-aa-level-select" class="form-control custom-select">
|
||||
<option value="none" selected>None</option>
|
||||
<option value="ssaa-2">2×SSAA</option>
|
||||
<option value="ssaa-4">4×SSAA</option>
|
||||
<option value="ecaa">ECAA</option>
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="pf-arrow-box"></div>
|
||||
</div>
|
||||
<button id="pf-settings-button" type="button" class="btn btn-outline-secondary"
|
||||
aria-expanded="false" aria-controls="#pf-settings">
|
||||
${require('octicons/build/svg/gear.svg')}
|
||||
</button>
|
||||
</div>
|
||||
<div class="rounded py-1 px-3 mr-3" id="pf-fps-label">0 ms</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -22,10 +22,12 @@
|
|||
"html-loader": "^0.5.1",
|
||||
"jquery": "^3.2.1",
|
||||
"lodash": "^4.17.4",
|
||||
"octicons": "^6.0.1",
|
||||
"opentype.js": "^0.7.3",
|
||||
"parse-color": "^1.0.0",
|
||||
"path-data-polyfill.js": "^1.0.2",
|
||||
"popper.js": "^1.12.5",
|
||||
"svg-inline-loader": "^0.8.0",
|
||||
"ts-loader": "^2.3.2",
|
||||
"typescript": "^2.4.2",
|
||||
"webpack": "^3.4.1"
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
import {AntialiasingStrategyName} from "./aa-strategy";
|
||||
import {ShaderLoader, ShaderMap, ShaderProgramSource} from './shader-loader';
|
||||
import {expectNotNull, unwrapUndef} from './utils';
|
||||
import { expectNotNull, unwrapUndef, unwrapNull } from './utils';
|
||||
import {PathfinderView} from "./view";
|
||||
|
||||
export default abstract class AppController<View extends PathfinderView> {
|
||||
|
@ -19,6 +19,25 @@ export default abstract class AppController<View extends PathfinderView> {
|
|||
start() {
|
||||
const canvas = document.getElementById('pf-canvas') as HTMLCanvasElement;
|
||||
|
||||
this.settingsCard = document.getElementById('pf-settings') as HTMLElement;
|
||||
this.settingsButton = document.getElementById('pf-settings-button') as HTMLButtonElement;
|
||||
this.settingsCloseButton = document.getElementById('pf-settings-close-button') as
|
||||
HTMLButtonElement;
|
||||
this.settingsButton.addEventListener('click', () => {
|
||||
this.settingsCard.classList.toggle('pf-invisible');
|
||||
}, false);
|
||||
this.settingsCloseButton.addEventListener('click', () => {
|
||||
this.settingsCard.classList.add('pf-invisible');
|
||||
}, false);
|
||||
|
||||
this.filePickerElement = document.getElementById('pf-file-select') as HTMLInputElement;
|
||||
this.filePickerElement.addEventListener('change', () => this.loadFile(), false);
|
||||
|
||||
this.selectFileElement = document.getElementById('pf-select-file') as HTMLSelectElement;
|
||||
this.selectFileElement.addEventListener('click', () => {
|
||||
this.fileSelectionChanged();
|
||||
}, false);
|
||||
|
||||
const shaderLoader = new ShaderLoader;
|
||||
shaderLoader.load();
|
||||
|
||||
|
@ -33,14 +52,14 @@ export default abstract class AppController<View extends PathfinderView> {
|
|||
|
||||
private updateAALevel() {
|
||||
const selectedOption = this.aaLevelSelect.selectedOptions[0];
|
||||
const aaType = unwrapUndef(selectedOption.dataset.pfType) as
|
||||
AntialiasingStrategyName;
|
||||
const aaLevel = parseInt(unwrapUndef(selectedOption.dataset.pfLevel));
|
||||
const aaValues = unwrapNull(/^([a-z-]+)(?:-([0-9]+))?$/.exec(selectedOption.value));
|
||||
const aaType = aaValues[1] as AntialiasingStrategyName;
|
||||
const aaLevel = aaValues[2] === "" ? 1 : parseInt(aaValues[2]);
|
||||
this.view.then(view => view.setAntialiasingOptions(aaType, aaLevel));
|
||||
}
|
||||
|
||||
protected loadFile() {
|
||||
const file = expectNotNull(this.loadFileButton.files, "No file selected!")[0];
|
||||
const file = expectNotNull(this.filePickerElement.files, "No file selected!")[0];
|
||||
const reader = new FileReader;
|
||||
reader.addEventListener('loadend', () => {
|
||||
this.fileData = reader.result;
|
||||
|
@ -49,18 +68,41 @@ export default abstract class AppController<View extends PathfinderView> {
|
|||
reader.readAsArrayBuffer(file);
|
||||
}
|
||||
|
||||
protected fileSelectionChanged() {
|
||||
const selectedOption = this.selectFileElement.selectedOptions[0] as HTMLOptionElement;
|
||||
|
||||
if (selectedOption.value === 'load-custom') {
|
||||
this.filePickerElement.click();
|
||||
|
||||
const oldSelectedIndex = this.selectFileElement.selectedIndex;
|
||||
const newOption = document.createElement('option');
|
||||
newOption.id = 'pf-custom-option-placeholder';
|
||||
newOption.appendChild(document.createTextNode("Custom"));
|
||||
this.selectFileElement.insertBefore(newOption, selectedOption);
|
||||
this.selectFileElement.selectedIndex = oldSelectedIndex;
|
||||
return;
|
||||
}
|
||||
|
||||
const placeholder = document.getElementById('pf-custom-option-placeholder');
|
||||
if (placeholder != null)
|
||||
this.selectFileElement.removeChild(placeholder);
|
||||
}
|
||||
|
||||
protected abstract fileLoaded(): void;
|
||||
|
||||
protected abstract createView(canvas: HTMLCanvasElement,
|
||||
commonShaderSource: string,
|
||||
shaderSources: ShaderMap<ShaderProgramSource>):
|
||||
View;
|
||||
shaderSources: ShaderMap<ShaderProgramSource>): View;
|
||||
|
||||
view: Promise<View>;
|
||||
|
||||
protected fileData: ArrayBuffer;
|
||||
|
||||
protected canvas: HTMLCanvasElement;
|
||||
protected loadFileButton: HTMLInputElement;
|
||||
protected selectFileElement: HTMLSelectElement;
|
||||
protected filePickerElement: HTMLInputElement;
|
||||
private aaLevelSelect: HTMLSelectElement;
|
||||
private settingsCard: HTMLElement;
|
||||
private settingsButton: HTMLButtonElement;
|
||||
private settingsCloseButton: HTMLButtonElement;
|
||||
}
|
||||
|
|
|
@ -59,9 +59,6 @@ class SVGDemoController extends AppController<SVGDemoView> {
|
|||
this.svg = document.getElementById('pf-svg') as Element as SVGSVGElement;
|
||||
|
||||
this.pathElements = [];
|
||||
|
||||
this.loadFileButton = document.getElementById('pf-load-svg-button') as HTMLInputElement;
|
||||
this.loadFileButton.addEventListener('change', () => this.loadFile(), false);
|
||||
}
|
||||
|
||||
protected fileLoaded() {
|
||||
|
|
|
@ -119,9 +119,6 @@ class TextDemoController extends AppController<TextDemoView> {
|
|||
this.fontSize = INITIAL_FONT_SIZE;
|
||||
|
||||
this.fpsLabel = unwrapNull(document.getElementById('pf-fps-label'));
|
||||
|
||||
this.loadFileButton = document.getElementById('pf-load-font-button') as HTMLInputElement;
|
||||
this.loadFileButton.addEventListener('change', () => this.loadFile(), false);
|
||||
}
|
||||
|
||||
protected createView(canvas: HTMLCanvasElement,
|
||||
|
|
|
@ -12,6 +12,10 @@ module.exports = {
|
|||
use: 'ts-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
{
|
||||
test: /\.svg?$/,
|
||||
use: 'svg-inline-loader',
|
||||
},
|
||||
{
|
||||
test: /html\/[a-zA-Z0-9_-]+\.html$/,
|
||||
use: [
|
||||
|
|
|
@ -42,11 +42,13 @@ static STATIC_TEXT_DEMO_PATH: &'static str = "../client/text-demo.html";
|
|||
static STATIC_SVG_DEMO_PATH: &'static str = "../client/svg-demo.html";
|
||||
static STATIC_3D_DEMO_PATH: &'static str = "../client/3d-demo.html";
|
||||
static STATIC_CSS_BOOTSTRAP_PATH: &'static str = "../client/node_modules/bootstrap/dist/css";
|
||||
static STATIC_CSS_OCTICONS_PATH: &'static str = "../client/node_modules/octicons/build";
|
||||
static STATIC_CSS_PATHFINDER_PATH: &'static str = "../client/css/pathfinder.css";
|
||||
static STATIC_JS_BOOTSTRAP_PATH: &'static str = "../client/node_modules/bootstrap/dist/js";
|
||||
static STATIC_JS_JQUERY_PATH: &'static str = "../client/node_modules/jquery/dist";
|
||||
static STATIC_JS_POPPER_JS_PATH: &'static str = "../client/node_modules/popper.js/dist/umd";
|
||||
static STATIC_JS_PATHFINDER_PATH: &'static str = "../client";
|
||||
static STATIC_SVG_OCTICONS_PATH: &'static str = "../client/node_modules/octicons/build/svg";
|
||||
static STATIC_GLSL_PATH: &'static str = "../../shaders";
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
|
@ -489,6 +491,10 @@ fn static_3d_demo() -> io::Result<NamedFile> {
|
|||
fn static_css_bootstrap(file: PathBuf) -> Option<NamedFile> {
|
||||
NamedFile::open(Path::new(STATIC_CSS_BOOTSTRAP_PATH).join(file)).ok()
|
||||
}
|
||||
#[get("/css/octicons/<file..>")]
|
||||
fn static_css_octicons(file: PathBuf) -> Option<NamedFile> {
|
||||
NamedFile::open(Path::new(STATIC_CSS_OCTICONS_PATH).join(file)).ok()
|
||||
}
|
||||
#[get("/css/pathfinder.css")]
|
||||
fn static_css_pathfinder_css() -> io::Result<NamedFile> {
|
||||
NamedFile::open(STATIC_CSS_PATHFINDER_PATH)
|
||||
|
@ -509,6 +515,10 @@ fn static_js_popper_js(file: PathBuf) -> Option<NamedFile> {
|
|||
fn static_js_pathfinder(file: PathBuf) -> Option<NamedFile> {
|
||||
NamedFile::open(Path::new(STATIC_JS_PATHFINDER_PATH).join(file)).ok()
|
||||
}
|
||||
#[get("/svg/octicons/<file..>")]
|
||||
fn static_svg_octicons(file: PathBuf) -> Option<NamedFile> {
|
||||
NamedFile::open(Path::new(STATIC_SVG_OCTICONS_PATH).join(file)).ok()
|
||||
}
|
||||
#[get("/glsl/<file..>")]
|
||||
fn static_glsl(file: PathBuf) -> Option<Shader> {
|
||||
Shader::open(Path::new(STATIC_GLSL_PATH).join(file)).ok()
|
||||
|
@ -540,11 +550,13 @@ fn main() {
|
|||
static_svg_demo,
|
||||
static_3d_demo,
|
||||
static_css_bootstrap,
|
||||
static_css_octicons,
|
||||
static_css_pathfinder_css,
|
||||
static_js_bootstrap,
|
||||
static_js_jquery,
|
||||
static_js_popper_js,
|
||||
static_js_pathfinder,
|
||||
static_svg_octicons,
|
||||
static_glsl,
|
||||
]).launch();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue