From b1eed7162783608eb26483ba95a920ea6bac1ee8 Mon Sep 17 00:00:00 2001 From: RincewindWizzard Date: Wed, 1 Nov 2023 20:51:05 +0100 Subject: [PATCH] =?UTF-8?q?aufgera=C3=A4umt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/js/calculator.js | 89 ------------ src/js/histogram.js | 200 -------------------------- src/js/t_shirt_inputs_ui.js | 40 ------ src/js/t_shirt_table.js | 5 - src/script/calculator.ts | 2 +- src/{js => script}/csv_import_hack.js | 0 src/script/t_shirt.ts | 2 +- src/webworker/worker.ts | 2 + 8 files changed, 4 insertions(+), 336 deletions(-) delete mode 100644 src/js/calculator.js delete mode 100644 src/js/histogram.js delete mode 100644 src/js/t_shirt_inputs_ui.js delete mode 100644 src/js/t_shirt_table.js rename src/{js => script}/csv_import_hack.js (100%) diff --git a/src/js/calculator.js b/src/js/calculator.js deleted file mode 100644 index 577ec4b..0000000 --- a/src/js/calculator.js +++ /dev/null @@ -1,89 +0,0 @@ -import "./t_shirt_inputs_ui" -import {t_shirt_sizes} from "./t_shirt_table.js" -import query_string from 'query-string'; -import {update_histogram} from './histogram' - -const default_threshold = 75 - -const t_shirts = t_shirt_sizes - .map((t_shirt) => { - let new_shirt = { - input: document.getElementById(`input-${t_shirt.name}`), - ...t_shirt - } - new_shirt.value = () => parseInt(new_shirt.input.value) || 0 - return new_shirt - }) - - -// capacity and threshold -const input_capacity = document.getElementById("capacity"); -const input_threshold = document.getElementById("threshold"); - -// result displays -const output_minimum = document.getElementById("minimum"); -const output_maximum = document.getElementById("maximum"); -const output_min_capacity = document.getElementById("min_capacity"); -const output_success_probability = document.getElementById("success_probability"); - -function update_results() { - const interval = { - min: t_shirts - .map((t_shirt) => t_shirt.value() * t_shirt.min) - .reduce((accumulator, currentValue) => accumulator + currentValue, 0), - max: t_shirts - .map((t_shirt) => t_shirt.value() * t_shirt.max) - .reduce((accumulator, currentValue) => accumulator + currentValue, 0) - } - const width = interval.max - interval.min - const min_capacity = Math.floor((parseInt(input_threshold.value) / 100 * width) + interval.min) || 0 - - output_minimum.innerHTML = interval.min; - output_maximum.innerHTML = interval.max; - - output_min_capacity.innerHTML = min_capacity - - if (parseInt(input_capacity.value) >= min_capacity) { - output_min_capacity.classList.add("has-text-success") - output_min_capacity.classList.remove("has-text-danger") - } else { - output_min_capacity.classList.add("has-text-danger") - output_min_capacity.classList.remove("has-text-success") - } - - let state = get_state() - update_histogram(state) - - history.replaceState(null, '', '?' + query_string.stringify(state)); -} - -function get_state() { - const state = t_shirts.map((t_shirt) => ({ - [t_shirt.name]: t_shirt.value() - })).reduce((acc, curr) => Object.assign(acc, curr), {}); - state.capacity = parseInt(input_capacity.value) || 0 - state.threshold = parseInt(input_threshold.value) || 0 - return state -} - -function set_state(state) { - for (let tshirt of t_shirts) { - tshirt.input.value = state[tshirt.name] || 0 - } - input_capacity.value = state.capacity || 0 - input_threshold.value = state.threshold || default_threshold -} - -window.addEventListener('DOMContentLoaded', (event) => { - t_shirts.forEach((t_shirt) => { - t_shirt.input.addEventListener('input', update_results) - }) - input_capacity.addEventListener('input', update_results) - input_threshold.addEventListener('input', update_results) - update_results() -}); - -// set the current state from URL params -const url = new URL(window.location.href); -const searchParams = url.searchParams; -set_state(Object.fromEntries(searchParams)) diff --git a/src/js/histogram.js b/src/js/histogram.js deleted file mode 100644 index f1c8b08..0000000 --- a/src/js/histogram.js +++ /dev/null @@ -1,200 +0,0 @@ -import * as d3 from 'd3'; - -import {t_shirt_sizes} from "./t_shirt_table.js" - -const success_probability_input = document.getElementById("success_probability"); -const capacity_input = document.getElementById("capacity"); - -function efficient_count(t_shirts) { - //console.log(t_shirts) - let min_x = t_shirts.reduce((sum, t_shirt) => sum + t_shirt.min, 0); - let max_x = t_shirts.reduce((sum, t_shirt) => sum + t_shirt.max, 0); - - function count_combinations(current_index, current_sum) { - if (current_index === t_shirts.length) { - return current_sum === 0 ? 1 : 0 - } - - if (memo[current_index] && memo[current_index][current_sum] !== undefined) { - return memo[current_index][current_sum]; - } - - let t_shirt = t_shirts[current_index] - let possibilities = 0 - for (let size = t_shirt.min; size <= t_shirt.max; size++) { - possibilities += count_combinations(current_index + 1, current_sum - size) - } - memo[(current_index, current_sum)] = possibilities - return possibilities - } - - let memo = {} - let possibilities = {} - - for (let i = min_x; i <= max_x; i++) { - possibilities[i] = count_combinations(0, i) - } - - return Object.entries(possibilities) - .map((x) => [parseInt(x[0]), x[1]]) -} - -/* -* -* def efficient_count(t_shirts): - min_x = sum(t_shirt.min for t_shirt in t_shirts) - max_x = sum(t_shirt.max for t_shirt in t_shirts) - - def count_combinations(current_index, current_sum): - if current_index == len(t_shirts): - return 1 if current_sum == 0 else 0 - - if (current_index, current_sum) in memo: - return memo[(current_index, current_sum)] - - t_shirt = t_shirts[current_index] - possibilities = 0 - for size in range(t_shirt.min, t_shirt.max + 1): - possibilities += count_combinations(current_index + 1, current_sum - size) - - memo[(current_index, current_sum)] = possibilities - return possibilities - - memo = {} - possibilities = defaultdict(int) - - for i in range(min_x, max_x + 1): - possibilities[i] = count_combinations(0, i) - - result = list(possibilities.items()) - return result -* */ - -function plot_histogram(data) { - const container = document.getElementById("histogram"); - - const width = container.clientWidth - const height = container.clientHeight - const margin = {top: 20, right: 20, bottom: 30, left: 40}; - - - // Skalierungsfunktionen für die Achsen - const xScale = d3.scaleLinear() - .domain([0, d3.max(data, d => d[0])]) - .range([margin.left, width - margin.right]); - - const yScale = d3.scaleLinear() - .domain([0, d3.max(data, d => d[1])]) - .nice() - .range([height - margin.bottom, margin.top]); - - // Linie erstellen - const line = d3.line() - .x(d => xScale(d[0])) - .y(d => yScale(d[1])); - - // SVG-Element erstellen - const svg = d3.create("svg") - .attr("width", width) // Breite des SVG-Containers - .attr("height", height); // Höhe des SVG-Containers - - // Linie zeichnen - svg.append("path") - .datum(data) - .attr("d", line) - .attr("fill", "lightsteelblue") - .attr("stroke", "blue") - .attr("stroke-width", 2); - - // X-Achse erstellen - const xAxis = g => g - .attr("transform", `translate(0,${height - margin.bottom})`) - .call(d3.axisBottom(xScale).ticks(5)); - - svg.append("g") - .call(xAxis); - - // Y-Achse erstellen - const yAxis = g => g - .attr("transform", `translate(${margin.left},0)`) - .call(d3.axisLeft(yScale)); - - svg.append("g") - .call(yAxis); - - container.replaceChildren(svg.node()); -} - -const cache = new Map(); - -export function update_histogram(state) { - const div = document.querySelector("#histogram"); - - //console.log(t_shirt_sizes) - const t_shirt_by_name = t_shirt_sizes.reduce((acc, t_shirt) => { - acc[t_shirt.name] = t_shirt; - return acc; - }, {}); - - const only_shirts_state = {} - for (const name in state) { - if (t_shirt_by_name[name]) { - only_shirts_state[name] = state[name] - } - } - //console.log(only_shirts_state) - - const t_shirts = [] - - for (const name in state) { - if (t_shirt_by_name[name]) { - for (let i = 0; i < state[name]; i++) { - t_shirts.push(t_shirt_by_name[name]) - } - } - } - - //console.log(cache) - let cache_key = JSON.stringify(only_shirts_state) - let result = [] - if (cache.has(cache_key)) { - result = cache.get(cache_key) - console.log('cache') - } else { - console.log("generating") - result = efficient_count(t_shirts) - .sort((a, b) => a[0] > b[0]) - - result = [ - [Math.max(result[0][0] - 1, 0), 0], - ...result, - [result[result.length - 1][0] + 1, 0] - ] - - cache.set(cache_key, result) - } - - //div.innerHTML = JSON.stringify(result, null, 2) - //console.log(result) - - update_success_probability(result) - - plot_histogram(result) - - -} - -function update_success_probability(result) { - let capacity = parseInt(capacity_input.value) - let full = result - .map((t) => t[1]) - .reduce((sum, x) => sum + x, 0) - - let reachable = result - .filter((t) => t[0] <= capacity) - .map((t) => t[1]) - .reduce((sum, x) => sum + x, 0) - - let success_probability = reachable / full - success_probability_input.innerText = `${(success_probability * 100).toFixed(2)} %` -} \ No newline at end of file diff --git a/src/js/t_shirt_inputs_ui.js b/src/js/t_shirt_inputs_ui.js deleted file mode 100644 index 56e0f33..0000000 --- a/src/js/t_shirt_inputs_ui.js +++ /dev/null @@ -1,40 +0,0 @@ -import {t_shirt_sizes} from "./t_shirt_table.js" - -function attach_listeners(name) { - const input = document.getElementById(`input-${name}`); - const dec_btn = document.getElementById(`btn-${name}-dec`); - const inc_btn = document.getElementById(`btn-${name}-inc`); - - - if (inc_btn) { - inc_btn.addEventListener('click', () => { - const current_value = parseInt(input.value); - if (current_value) { - input.value = current_value + 1 - } else { - input.value = 1 - } - input.dispatchEvent(new Event("input", { - bubbles: true, cancelable: true, - })); - }) - } - if (dec_btn) { - dec_btn.addEventListener('click', () => { - const current_value = parseInt(input.value); - if (current_value && current_value > 0) { - input.value = current_value - 1 - } else { - input.value = 0 - } - input.dispatchEvent(new Event("input", { - bubbles: true, cancelable: true, - })); - }) - } -} -window.addEventListener('DOMContentLoaded', (event) => { - for (let t_shirt of t_shirt_sizes) { - attach_listeners(t_shirt.name) - } -}); diff --git a/src/js/t_shirt_table.js b/src/js/t_shirt_table.js deleted file mode 100644 index 807ee6e..0000000 --- a/src/js/t_shirt_table.js +++ /dev/null @@ -1,5 +0,0 @@ -import t_shirt_size_csv from '../data/t_shirt_sizes.csv'; - -export const t_shirt_sizes = t_shirt_size_csv - .map((x) => ({'name': x[0], 'min': parseInt(x[1]), 'max': parseInt(x[2])})) - diff --git a/src/script/calculator.ts b/src/script/calculator.ts index 6d4645c..b721bd9 100644 --- a/src/script/calculator.ts +++ b/src/script/calculator.ts @@ -51,7 +51,7 @@ function calculateMinimumCapacity(histogram: Histogram, confidenceLevel: number) } - return NaN + return histogram[histogram.length - 1][0] } function calculateSuccessProbability(histogram: Histogram, capacity: number): number { diff --git a/src/js/csv_import_hack.js b/src/script/csv_import_hack.js similarity index 100% rename from src/js/csv_import_hack.js rename to src/script/csv_import_hack.js diff --git a/src/script/t_shirt.ts b/src/script/t_shirt.ts index e83ed99..8dda517 100644 --- a/src/script/t_shirt.ts +++ b/src/script/t_shirt.ts @@ -1,5 +1,5 @@ // @ts-ignore -import {t_shirt_sizes} from '../js/csv_import_hack.js' +import {t_shirt_sizes} from './csv_import_hack.js' export class TShirt { diff --git a/src/webworker/worker.ts b/src/webworker/worker.ts index 2c77720..da12421 100644 --- a/src/webworker/worker.ts +++ b/src/webworker/worker.ts @@ -1,3 +1,5 @@ +// TODO: part of the heavy weight calculations of calculator.ts schon be done in a web worker + self.onmessage = (event) => { const message = event.data if (message.type === 'request') {