Commit 0e9c3790 authored by Pietro Saccardi's avatar Pietro Saccardi

Added customizable konami background

parent e4b60c4a
<div id="knWrapper">
<h4 class="d-konami m-2">Multidirectional Dijkstra background by Spak</h4>
<button type="button" class="btn btn-light m-2 d-konami" data-toggle="modal" data-target="#knCustomizeModal">
Customize
</button>
<button type="button" class="btn btn-light m-2 d-konami" data-kn-fn="redraw">
Redraw
</button>
<svg class="w-100 h-100 position-fixed z-lowest" id="graph"></svg>
</div>
\ No newline at end of file
......@@ -6,11 +6,12 @@
{% block title %}{{ this.title }}{% endblock %}
{% block body %}
<body>
{% include 'konami.html' %}
<div class="container-fluid h-md-100 px-0">
<div class="row h-md-100 mx-0">
<div class="col-md-6 col-lg-5 order-md-2 inner-shadow px-0 h-100">
<div class="scrollable-md">
<svg class="w-100 h-100 position-fixed z-lowest" id="graph"></svg>
{% include 'bg_graph.html' %}
<header class="my-3 mx-3">
<h1><img src="{{ '/images/logo.svg' | url}}" alt="Mittelab" class="logo d-block mx-auto"></h1>
<p class="text-monospace text-center lead">
......
<div class="modal fade" id="knCustomizeModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content bg-dark border-secondary outer-shadow">
<div class="modal-header border-secondary">
<h5 class="modal-title">Customize multi-directional Dijkstra</h5>
<button type="button" class="close text-white" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form>
<div class="form-group form-row mb-1">
<label for="knNSources" class="col text-right col-form-label col-form-label-sm">Num. of terminals</label>
<div class="col-5">
<input type="number" class="form-control-sm form-control" id="knNSources" value="10" min="2">
</div>
</div>
<div class="form-group form-row mb-1">
<label for="knGridUnit" class="col text-right col-form-label col-form-label-sm">Grid unit</label>
<div class="input-group input-group-sm col-5">
<input id="knGridUnit" type="number" class="form-control-sm form-control" aria-describedby="knPx" min="5" value="30">
<div class="input-group-append">
<span class="input-group-text" id="knPx">px</span>
</div>
</div>
</div>
<div class="form-group form-row mb-1">
<label for="knCostNodeW" class="col text-right col-form-label col-form-label-sm">Edge cost node weight</label>
<div class="col-5">
<input type="number" class="form-control-sm form-control" id="knCostNodeW" value="5" min="0" step="0.1">
</div>
</div>
<div class="form-group form-row mb-1">
<label for="knCostRndFrac" class="col text-right col-form-label col-form-label-sm">Edge cost random fraction</label>
<div class="col-5">
<input type="range" class="form-control-sm form-control-range" id="knCostRndFrac" value="0.6" min="0.0" max="1.0" step="0.01">
</div>
</div>
<div class="form-group form-row mb-1">
<label for="knFeasCenterX" class="col text-right col-form-label col-form-label-sm">Node clearance center X</label>
<div class="col-5">
<input type="number" class="form-control-sm form-control" id="knFeasCenterX" value="0.5" step="0.01">
</div>
</div>
<div class="form-group form-row mb-1">
<label for="knFeasCenterY" class="col text-right col-form-label col-form-label-sm">Node clearance center Y</label>
<div class="col-5">
<input type="number" class="form-control-sm form-control" id="knFeasCenterY" value="0.3" step="0.01">
</div>
</div>
<div class="form-group form-row mb-1">
<label for="knFeasRad" class="col text-right col-form-label col-form-label-sm">Node clearance radius</label>
<div class="col-5">
<input type="number" class="form-control-sm form-control" id="knFeasRad" value="0.2" min="0" step="0.01">
</div>
</div>
<div class="form-group form-row mb-1">
<label for="knFeasFalloff" class="col text-right col-form-label col-form-label-sm">Node clearance falloff radius</label>
<div class="col-5">
<input type="number" class="form-control-sm form-control" id="knFeasFalloff" value="0.3" min="0" step="0.01">
</div>
</div>
<div class="form-group form-row mb-1">
<label for="knFeasFalloffExp" class="col text-right col-form-label col-form-label-sm">Node clearance falloff exponent</label>
<div class="col-5">
<input type="number" class="form-control-sm form-control" id="knFeasFalloffExp" value="0.8" step="0.01">
</div>
</div>
<div class="form-group form-row mb-1">
<label for="knFeasRndFrac" class="col text-right col-form-label col-form-label-sm">Node clearance random fraction</label>
<div class="col-5">
<input type="range" class="form-control-sm form-control-range" id="knFeasRndFrac" value="0.3" min="0.0" max="1.0" step="0.01">
</div>
</div>
<div class="form-group form-row mb-1">
<label for="knLblPcPerFrame" class="col text-right col-form-label col-form-label-sm">Max grid fraction labeled per frame</label>
<div class="col-5">
<input type="number" class="form-control-sm form-control" id="knLblPcPerFrame" min="0.0" max="1.0" value="0.004" step="0.0001">
</div>
</div>
<div class="form-group form-row mb-1">
<label for="knOpacity" class="col text-right col-form-label col-form-label-sm">Opacity</label>
<div class="col-5">
<input type="range" class="form-control-sm form-control-range" id="knOpacity" value="0.45" min="0.0" max="1.0" step="0.01">
</div>
</div>
<div class="form-group form-row mb-1">
<label for="knOpacityTempLbl" class="col text-right col-form-label col-form-label-sm">Temporary label opacity</label>
<div class="col-5">
<input type="range" class="form-control-sm form-control-range" id="knOpacityTempLbl" value="0.23" min="0.0" max="1.0" step="0.01">
</div>
</div>
<div class="form-group form-row mb-1">
<label for="knOpacityShortestPath" class="col text-right col-form-label col-form-label-sm">Shortest path opacity</label>
<div class="col-5">
<input type="range" class="form-control-sm form-control-range" id="knOpacityShortestPath" value="0.36" min="0.0" max="1.0" step="0.01">
</div>
</div>
<div class="form-group form-row mb-1">
<label for="knStrokeWShortestPath" class="col text-right col-form-label col-form-label-sm">Shortest path stroke width</label>
<div class="col-5">
<input type="number" class="form-control-sm form-control" id="knStrokeWShortestPath" min="0.0" value="5" step="0.1">
</div>
</div>
<div class="form-group form-row mb-1">
<label for="knTrunkCol" class="col text-right col-form-label col-form-label-sm">Steiner tree path color</label>
<div class="col-5">
<input type="text" class="form-control-sm form-control" id="knTrunkCol" value="#444">
</div>
</div>
<div class="form-group form-row mb-1">
<label for="knRayCol" class="col text-right col-form-label col-form-label-sm">Secondary path color</label>
<div class="col-5">
<input type="text" class="form-control-sm form-control" id="knRayCol" value="#fff">
</div>
</div>
<div class="form-group form-row mb-1">
<label for="knRootRad" class="col text-right col-form-label col-form-label-sm">Terminal radius</label>
<div class="col-5">
<input type="number" class="form-control-sm form-control" id="knRootRad" min="0.0" value="6" step="0.1">
</div>
</div>
<div class="form-group form-row mb-1">
<label for="knRootCol" class="col text-right col-form-label col-form-label-sm">Terminal color</label>
<div class="col-5">
<input type="text" class="form-control-sm form-control" id="knRootCol" value="#444">
</div>
</div>
</form>
</div>
<div class="modal-footer border-secondary">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-light" data-kn-fn="redraw">Redraw</button>
</div>
</div>
</div>
</div>
\ No newline at end of file
......@@ -2,7 +2,8 @@
{% block title %}{{ this.title }}{% endblock %}
{% block body %}
<body class="inner-shadow">
<svg class="w-100 h-100 position-fixed z-lowest" id="graph"></svg>
{% include 'bg_graph.html' %}
{% include 'konami.html' %}
<div class="container-fluid h-md-100">
<div class="row h-100">
<div class="col-md-5 col-lg-4 col-xl-3 col-xxl-2 px-0">
......
......@@ -6,21 +6,43 @@ require('typeface-ubuntu');
import Konami from 'konami';
new Konami(function () {
alert('Konami Code!')
});
const Snap = require( "imports-loader?this=>window,fix=>module.exports=0!snapsvg/dist/snap.svg.js" );
import {Dijkstra, GridGraph} from "./grid";
import $ from 'jquery';
function paintTree() {
const GRID_UNIT = 30
const N_SOURCES = 10
const OPACITY = 0.45
const TRUNK_COL = '#444' //'#7fc0c2'
const RAY_COL = '#fff' //'#fff'
const ROOT_COL = '#444' //'#222'
function getSetting(camelId, defaultVal) {
let settingInput = $(`#kn${camelId}`)
let value = defaultVal
if (settingInput.length == 1) {
value = settingInput.val()
}
console.log(`Graph setting ${camelId}: ${value}`)
return value
}
const GRID_UNIT = getSetting('GridUnit', 30)
const N_SOURCES = getSetting('NSources', 10)
const COST_NODE_W = getSetting('CostNodeW', 5.)
const COST_RND_FRAC = getSetting('CostRndFrac', 0.6)
const FEAS_CENTER = [getSetting('FeasCenterX', 0.5), getSetting('FeasCenterY', 0.3)]
const FEAS_RAD = getSetting('FeasRad', 0.2)
const FEAS_FALLOFF = getSetting('FeasFalloff', 0.3)
const FEAS_FALLOFF_EXP = getSetting('FeasFalloffExp', 0.8)
const FEAS_RND_FRAC = getSetting('FeasRndFrac', 0.3)
const LBL_PC_PER_FRAME = getSetting('LblPcPerFrame', 1. / 250.)
const OPACITY = getSetting('Opacity', 0.45)
const OPACITY_TEMP_LBL = getSetting('OpacityTempLbl', 0.23)
const OPACITY_SHORTEST_PATH = getSetting('OpacityShortestPath', 0.36)
const STROKEW_SHORTEST_PATH = getSetting('StrokeWShortestPath', 5)
const ROOT_RAD = getSetting('RootRad', 6)
const TRUNK_COL = getSetting('TrunkCol', '#444')
const RAY_COL = getSetting('RayCol', '#fff')
const ROOT_COL = getSetting('RootCol', '#444')
const graph = $('#graph')
const W = graph.width()
......@@ -30,7 +52,7 @@ function paintTree() {
console.log(`Grid graph: ${N_X}×${N_Y}`)
const LBLS_PER_FRAME = N_X * N_Y / 250
const LBLS_PER_FRAME = N_X * N_Y * LBL_PC_PER_FRAME
const embed = pos => [(W - N_X * GRID_UNIT) / 2 + pos[0] * GRID_UNIT, (H - N_Y * GRID_UNIT) / 2 + pos[1] * GRID_UNIT]
......@@ -46,18 +68,13 @@ function paintTree() {
let pos = grid.getNodeXY(node)
pos[0] /= N_X
pos[1] /= N_Y
const center = [0.5, 0.3]
const radius = 0.2
const falloff = 0.3
const exp = 0.8
const rand_fraction = 0.3
// Actual math:
const dx = center[0] - pos[0]
const dy = center[1] - pos[1]
const dx = FEAS_CENTER[0] - pos[0]
const dy = FEAS_CENTER[1] - pos[1]
const l2 = Math.sqrt(dx * dx + dy * dy)
const unit_l2 = Math.max(Math.min((l2 - radius) / falloff, 1.), 0.)
const l2_pow_law = Math.pow(unit_l2, exp)
const rand_lerp = l2_pow_law * (1. - rand_fraction) + rand_fraction * Math.random()
const unit_l2 = Math.max(Math.min((l2 - FEAS_RAD) / FEAS_FALLOFF, 1.), 0.)
const l2_pow_law = Math.pow(unit_l2, FEAS_FALLOFF_EXP)
const rand_lerp = l2_pow_law * (1. - FEAS_RND_FRAC) + FEAS_RND_FRAC * Math.random()
return rand_lerp
}
......@@ -85,17 +102,15 @@ function paintTree() {
const dir = grid.getEdgeDirection(edge)
// base l2 cost
const l2 = dir_l2_len[dir2idx(dir)]
const node_weight = 5.
const rand_fraction = 0.6
// Add a random component
const artificial_cost = (1. + (Math.random() - 1.) * rand_fraction) * node_weight * (1. - node_feasibility(node))
const artificial_cost = (1. + (Math.random() - 1.) * COST_RND_FRAC) * COST_NODE_W * (1. - node_feasibility(node))
return l2 + artificial_cost
}
let algo = new Dijkstra(grid, edge_cost, {
found_candidate: function (node, edge, other_node) {
ensure_edge(edge)
edges[edge].attr('opacity', 0.5 * OPACITY)
edges[edge].attr('opacity', OPACITY_TEMP_LBL)
},
remove_candidate: function (node, edge, other_node) {
edges[edge].attr('opacity', 0.)
......@@ -105,16 +120,16 @@ function paintTree() {
if (algo.labels[other_node].backlink != null) {
edges[algo.labels[other_node].backlink].attr('opacity', 0.)
}
edges[edge].attr('opacity', 0.5 * OPACITY)
edges[edge].attr('opacity', OPACITY_TEMP_LBL)
},
add_source: function(node, owner) {
if (owner < N_SOURCES) {
node_group.circle(...embed(grid.getNodeXY(node)), 6)
node_group.circle(...embed(grid.getNodeXY(node)), ROOT_RAD)
.attr('stroke', TRUNK_COL)
.attr('strokeOpacity', 0.8 * OPACITY)
.attr('strokeWidth', 5)
.attr('strokeOpacity', OPACITY_SHORTEST_PATH)
.attr('strokeWidth', STROKEW_SHORTEST_PATH)
.attr('fill', ROOT_COL)
.attr('fillOpacity', 0.8 * OPACITY)
.attr('fillOpacity', OPACITY_SHORTEST_PATH)
}
}
})
......@@ -141,8 +156,8 @@ function paintTree() {
edges[edge]
.attr('opacity', 1.)
.attr('stroke', TRUNK_COL)
.attr('strokeOpacity', 0.8 * OPACITY)
.attr('strokeWidth', 5)
.attr('strokeOpacity', OPACITY_SHORTEST_PATH)
.attr('strokeWidth', STROKEW_SHORTEST_PATH)
})
if (algo.isRouted()) {
clearInterval(anim)
......@@ -153,7 +168,21 @@ function paintTree() {
}
document.addEventListener('DOMContentLoaded', () => {
$('[data-kn-fn="redraw"]').click(paintTree)
paintTree()
new Konami(function () {
$('#knWrapper')
.prependTo('body')
.addClass('fixed-fill')
.addClass('z-konami')
.addClass('inner-shadow')
.addClass('bg-dark')
$('#graph')
.removeClass('position-fixed')
.addClass('fixed-fill')
$('.d-konami').removeClass('d-konami')
});
});
let resizeTimer = null
......@@ -177,3 +206,5 @@ window.addEventListener('resize', () => {
}
}, 250)
});
......@@ -9,7 +9,11 @@ html, body {
}
.z-overlay {
z-index: 1055;
z-index: $zindex-fixed;
}
.z-konami {
z-index: $zindex-modal-backdrop + 5;
}
.z-lowest {
......@@ -28,6 +32,10 @@ html, body {
box-shadow: inset 0 0 5rem rgba($black, .5);
}
.outer-shadow {
box-shadow: 0 0 5rem $black;
}
@mixin _pos-top-left {
top: 0;
left: 0;
......@@ -37,6 +45,14 @@ html, body {
@include _pos-absolute-fill;
}
.fixed-fill {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.scrollable {
@include _pos-absolute-fill;
overflow: auto;
......@@ -118,4 +134,8 @@ html, body {
footer {
clear: both;
}
\ No newline at end of file
}
.d-konami {
display: none !important;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment