Make the demo UI less cluttered

This commit is contained in:
Patrick Walton 2017-08-30 17:01:28 -07:00
parent d7b606987a
commit 58b558de64
11 changed files with 222 additions and 53 deletions

View File

@ -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;
}

View File

@ -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&times;SSAA</option>
<option data-pf-type="ssaa" data-pf-level="4">4&times;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">&times;</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&times;SSAA</option>
<option value="ssaa-4">4&times;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>

View File

@ -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>

View File

@ -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&hellip;
<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&times;SSAA</option>
<option data-pf-type="ssaa" data-pf-level="4">4&times;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">&times;</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&hellip;</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&times;SSAA</option>
<option value="ssaa-4">4&times;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>

View File

@ -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&hellip;
<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&times;SSAA</option>
<option data-pf-type="ssaa" data-pf-level="4">4&times;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">&times;</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&hellip;</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&times;SSAA</option>
<option value="ssaa-4">4&times;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>

View File

@ -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"

View File

@ -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;
}

View File

@ -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() {

View File

@ -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,

View File

@ -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: [

View File

@ -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();
}