From 5a6f387a1265e32826a49119e0beaa71e29eac1c Mon Sep 17 00:00:00 2001 From: Roald Christesen Date: Mon, 2 Oct 2023 17:56:23 +0200 Subject: [PATCH] first draft using @sndcds/mvc --- index.js | 13 ++ package.json | 2 +- pnpm-lock.yaml | 8 +- src/app.js | 71 ++++++++- src/appModel.js | 3 +- src/components/button.js | 40 +++++ .../demoComponent.js} | 18 ++- .../districtSelect.js} | 19 ++- src/components/grid.js | 19 +++ src/components/numPercentView.js | 102 ++++++++++++ src/components/vBarsView.js | 41 +++++ src/index.html | 17 +- src/index.js | 20 ++- src/main.css | 147 ++++++++++++++---- src/main.js | 106 ++++++++++--- src/popComponent.js | 96 ------------ src/stateController.js | 122 --------------- 17 files changed, 535 insertions(+), 309 deletions(-) create mode 100644 index.js create mode 100644 src/components/button.js rename src/{testcomponent.js => components/demoComponent.js} (63%) rename src/{districtSelectComponent.js => components/districtSelect.js} (74%) create mode 100644 src/components/grid.js create mode 100644 src/components/numPercentView.js create mode 100644 src/components/vBarsView.js delete mode 100644 src/popComponent.js delete mode 100644 src/stateController.js diff --git a/index.js b/index.js new file mode 100644 index 0000000..96feca2 --- /dev/null +++ b/index.js @@ -0,0 +1,13 @@ +import Model from './lib/model.js' +import View from './lib/view.js' +import Router from './lib/router.js' +import Controller from './lib/controller.js' +import Component from './lib/component.js' + +export { + Model, + View, + Router, + Controller, + Component +} \ No newline at end of file diff --git a/package.json b/package.json index 5f3436f..e99b864 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "staticPath": "static" }, "dependencies": { - "@sndcds/mvc": "^0.0.8" + "@sndcds/mvc": "^0.0.31" }, "devDependencies": { "@parcel/config-default": "^2.9.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 50c5284..58425ad 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,8 +6,8 @@ settings: dependencies: '@sndcds/mvc': - specifier: ^0.0.8 - version: 0.0.8 + specifier: ^0.0.31 + version: 0.0.31 devDependencies: '@parcel/config-default': @@ -1141,8 +1141,8 @@ packages: nullthrows: 1.1.1 dev: true - /@sndcds/mvc@0.0.8: - resolution: {integrity: sha512-qhpL+3DvvBZbmDGvWdBsbXFV2F8djsr+6k4I8yJwLPTEyjFNBXG0vZt0ARHrgZ+RiGOjSZZZOJZ72vAM/yhIjg==} + /@sndcds/mvc@0.0.31: + resolution: {integrity: sha512-m5XM+8ECMgGYlwLuTemELDHWs9t0o0XF+CQEbcQGTrzrwudewm0fz/OQxRd2gAbQdH7UHczYerQv0mHh3wHhuw==} dev: false /@swc/core-darwin-arm64@1.3.91: diff --git a/src/app.js b/src/app.js index fab2a6b..ceb5a20 100644 --- a/src/app.js +++ b/src/app.js @@ -1,9 +1,12 @@ -import { View, Controller, Component, Router } from '@sndcds/mvc' +import { View, Controller } from '@sndcds/mvc' + export default class App extends Controller { /* eslint no-useless-constructor: 0 */ constructor(model, view) { super(model, view) + + this.onDistrictChanged = this.onDistrictChanged.bind(this) // TODO: Description! } initApp(url, id) { @@ -17,12 +20,74 @@ export default class App extends Controller { this.model.setDistrictId(this.districtId) } - // test if data was found in local storage if (this.data === null) { this.fetchData(url) } else { - // this.state.onDataChanged(this.data) + this.onDataChanged(this.data) } } + + renderAgeSection() { + const items = [ + { 'id': 'age-view-1', 'path': ['district_detail', '2021', 'age_groups', 'age_to_under_18'] }, + { 'id': 'age-view-2', 'path': ['district_detail', '2021', 'age_groups', 'age_18_to_under_30'] }, + { 'id': 'age-view-3', 'path': ['district_detail', '2021', 'age_groups', 'age_30_to_under_45'] }, + { 'id': 'age-view-4', 'path': ['district_detail', '2021', 'age_groups', 'age_45_to_under_65'] }, + { 'id': 'age-view-5', 'path': ['district_detail', '2021', 'age_groups', 'age_65_to_under_80'] }, + { 'id': 'age-view-6', 'path': ['district_detail', '2021', 'age_groups', 'age_80_and_above'] }, + { 'id': 'age-view-7', 'path': ['district_detail', '2021', 'age_groups', 'age_0_to_under_7'] }, + { 'id': 'age-view-8', 'path': ['district_detail', '2021', 'age_groups', 'age_60_and_above'] } + ] + + let sum = 0 + items.forEach((item) => { + sum += this.getNestedValue(this.model.districtObject, item.path) + }) + + let barOffset = 0 + items.forEach((item) => { + const c = this.componentById(item.id) + const d = this.getNestedValue(this.model.districtObject, item.path) + const percentage = d / sum * 100 + c.setProperties( + { + 'value': this.formatNumber(d), + 'percentage': this.formatNumber(percentage), + barOffset + }) + barOffset += percentage + }) + } + + onDataChanged(data) { + this.model.setDataObject(data) + this.model.setDistrictObject(this.model.districtId) + + const d = { 'data': this.model.data, 'districtId': this.model.districtId } + const c = this.componentById('district-select') + c.setWithData(d) + c.bindDistrictChanged(this.onDistrictChanged) + + this.renderAgeSection() + } + + onDistrictChanged(id) { + this.model.setDistrictId(id + 1) + this.model.setDistrictObject(id + 1) + + this.renderAgeSection() + } + + /** + * Generates a random RGB color. + * + * @returns {string} A random RGB color string. + */ + static randomColor() { + const red = Math.floor(Math.random() * 256) + const green = Math.floor(Math.random() * 256) + const blue = Math.floor(Math.random() * 256) + return `rgb(${red}, ${green}, ${blue})` + } } \ No newline at end of file diff --git a/src/appModel.js b/src/appModel.js index 884250a..e3fff83 100644 --- a/src/appModel.js +++ b/src/appModel.js @@ -1,10 +1,9 @@ import { Model } from '@sndcds/mvc' + export default class AppModel extends Model { constructor() { super() - - // override library defaults this.data = null this.districtNames = null this.districtObject = null diff --git a/src/components/button.js b/src/components/button.js new file mode 100644 index 0000000..dd535ed --- /dev/null +++ b/src/components/button.js @@ -0,0 +1,40 @@ +import { Component } from '@sndcds/mvc' + + +export default class Button extends Component { + constructor(parent, id, setupData) { + super(parent, id, setupData) + + this.label = 'Button' + this.onClick = undefined + + this.setProperties(setupData) + } + + defaultClass() { + return 'custom-button' + } + + propertyNames() { + const names = [ + 'label', 'onClick' + ] + return super.propertyNames(names) + } + + propertiesChanged() { + if (this.e !== null) { + this.e.innerText = this.label + } + } + + build() { + this.e = this.addDomElement('button') + this.e.innerText = this.label + + this.buildChilds() + + this.e.addEventListener('click', () => this.onClick(this)) + // this.e.addEventListener('click', this.onClick) + } +} \ No newline at end of file diff --git a/src/testcomponent.js b/src/components/demoComponent.js similarity index 63% rename from src/testcomponent.js rename to src/components/demoComponent.js index ea12e2c..4d8ab93 100644 --- a/src/testcomponent.js +++ b/src/components/demoComponent.js @@ -1,9 +1,20 @@ import { Component } from '@sndcds/mvc' -export default class TestComponent extends Component { - /* eslint no-useless-constructor: 0 */ + +export default class DemoComponent extends Component { constructor(parent, id, setupData) { super(parent, id, setupData) + this.demoProperty = 0 + + this.setProperties(setupData) + } + + defaultClass() { + return 'custom-demo-component' + } + + propertyNames() { + return super.propertyNames(['demoProperty']) } setMessage(message) { @@ -20,10 +31,9 @@ export default class TestComponent extends Component { } build() { - this.e = this.domCreateElement('p') + this.e = this.addDomElement('p') this.e.innerText = 'Hello' this.e.style.backgroundColor = '#999' - this.parent.e.appendChild(this.e) this.buildChilds() } } \ No newline at end of file diff --git a/src/districtSelectComponent.js b/src/components/districtSelect.js similarity index 74% rename from src/districtSelectComponent.js rename to src/components/districtSelect.js index b4b3a86..809f7dc 100644 --- a/src/districtSelectComponent.js +++ b/src/components/districtSelect.js @@ -1,18 +1,25 @@ import { Component } from '@sndcds/mvc' -export default class DistrictSelectComponent extends Component { - /* eslint no-useless-constructor: 0 */ + +export default class DistrictSelect extends Component { constructor(parent, id, setupData) { super(parent, id, setupData) + this.setProperties(setupData) + } + + defaultClass() { + return 'custom-district-select' + } + + propertyNames() { + return super.propertyNames() } build() { - this.e = this.domCreateElement('div') - this.parent.e.appendChild(this.e) + this.e = this.addDomElement('div') } - setProperties(data) { - console.trace() + setWithData(data) { const selectElement = this.domCreateElement('select') data.data.forEach((item) => { diff --git a/src/components/grid.js b/src/components/grid.js new file mode 100644 index 0000000..a4c0e1e --- /dev/null +++ b/src/components/grid.js @@ -0,0 +1,19 @@ +import { Component } from '@sndcds/mvc' + + +export default class Grid extends Component { + constructor(parent, id, setupData) { + super(parent, id, setupData) + this.setProperties(setupData) + } + + defaultClass() { + return 'sc-grid' + } + + build() { + this.e = this.addDomElement('div') + this.e.style.display = 'grid' + this.buildChilds() + } +} \ No newline at end of file diff --git a/src/components/numPercentView.js b/src/components/numPercentView.js new file mode 100644 index 0000000..24ab3f2 --- /dev/null +++ b/src/components/numPercentView.js @@ -0,0 +1,102 @@ +import { Component } from '@sndcds/mvc' + + +/** + * Component for displaying a label, value, bar and percentage. + * Can be used for displaying numeric information, i. e. of statistics and other number related contexts. + * + * @since 20.9.2023 + */ +export default class NumPercentView extends Component { + /** + * Create a NumPercentView. + * + * @param {Component} parent - The parent component. + * @param {String} id - The id of the new Component. + * @param {any} setupData - Optional set up data. + */ + constructor(parent, id, setupData) { + super(parent, id, setupData) + this.label = 'Label' + this.value = 100 + this.percentage = 10 + this.barOffset = 0 + this.barColor1 = '#999' + this.barColor2 = '#333' + + this.setProperties(setupData) + } + + defaultClass() { + return 'custom-num-percent' + } + + /** + * Build the DOM Elements for HTML rendering og the component. + * + * This method mus be overridden in derived classes. + * + * Styling: + * One solution is to assign classes to the emelemts. + */ + build() { + this.e = this.addDomElement('div') + + let a = this.e.appendChild(this.domCreateElement('div')) + a.style.textAlign = 'center' + a.innerText = this.label + a.className = this.prefixedClassName('label') + + a = this.e.appendChild(this.domCreateElement('div')) + a.style.textAlign = 'center' + a.innerText = this.value + a.className = this.prefixedClassName('value') + + const gradient = this.gradient() + + a = this.e.appendChild(this.domCreateElement('div')) + a.style.textAlign = 'left' + a.style.background = gradient + a.className = this.prefixedClassName('bar') + + a = this.e.appendChild(this.domCreateElement('div')) + a.style.textAlign = 'center' + a.innerText = `${this.percentage} %` + a.className = this.prefixedClassName('percentage') + + this.buildChilds() + } + + propertyNames() { + const names = [ + 'label', + 'value', + 'percentage', + 'barOffset', + 'barColor1', + 'barColor2' + ] + + return super.propertyNames(names) + } + + propertiesChanged() { + if (this.e !== null) { + this.e.children.item(1).innerText = this.value + this.e.children.item(2).style.background = this.gradient() + this.e.children.item(3).innerText = `${this.percentage} %` + } + } + + + gradient() { + const p = parseFloat(this.percentage) + const color1 = this.barColor1 + const color2 = this.barColor2 + const spot1 = `${this.barOffset}%` + const spot2 = `${this.barOffset + 0.1}%` + const spot3 = `${this.barOffset + p - 0.1}%` + const spot4 = `${this.barOffset + p}%` + return `linear-gradient(90deg, ${color1} 0%, ${color1} ${spot1}, ${color2} ${spot2}, ${color2} ${spot3}, ${color1} ${spot4})` + } +} \ No newline at end of file diff --git a/src/components/vBarsView.js b/src/components/vBarsView.js new file mode 100644 index 0000000..3381d3b --- /dev/null +++ b/src/components/vBarsView.js @@ -0,0 +1,41 @@ +import { Component } from '@sndcds/mvc' + + +/** + * Component for displaying a label, value, bar and percentage. + * Can be used for displaying numeric information, i. e. of statistics and other number related contexts. + * + * @since 20.9.2023 + */ +export default class VBarsView extends Component { + constructor(parent, id, setupData) { + super(parent, id, setupData) + this.heights = [10, 20, 100, 30, 2, 10, 60, 50, 10, 39, 54, 12, 30] + this.setProperties(setupData) + } + + defaultClass() { + return 'custom-vbars' + } + + propertyNames() { + return super.propertyNames() + } + + build() { + this.e = this.addDomElement('div') + this.e.style.display = 'grid' + this.e.style.gridTemplateColumns = 'repeat(13, 1fr)' + + this.heights.forEach((height) => { + height = Math.floor(Math.random() * 90 + 10) + const a = this.e.appendChild(this.domCreateElement('div')) + a.style.height = `${height}%` + a.style.position = 'relative' + a.style.top = `${100 - height}%` + }) + + + this.buildChilds() + } +} \ No newline at end of file diff --git a/src/index.html b/src/index.html index ec3cc38..2b3b23a 100644 --- a/src/index.html +++ b/src/index.html @@ -1,17 +1,22 @@ - + Sozialatlas Dashboard - Stadt Flensburg + - + + - -
+ + +
+
- - \ No newline at end of file + + + diff --git a/src/index.js b/src/index.js index 7522e2b..8e5ef40 100644 --- a/src/index.js +++ b/src/index.js @@ -1,15 +1,19 @@ import App from './app.js' import AppModel from './appModel.js' -import TestComponent from './testcomponent.js' -import DistrictSelectComponent from './districtSelectComponent.js' -import PopComponent from './popComponent.js' -import StateController from './stateController.js' +import Grid from './components/grid.js' +import DemoComponent from './components/demoComponent.js' +import Button from './components/button.js' +import DistrictSelect from './components/districtSelect.js' +import NumPercentView from './components/numPercentView.js' +import VBarsView from './components/vBarsView.js' export { App, AppModel, - TestComponent, - DistrictSelectComponent, - PopComponent, - StateController + Grid, + DemoComponent, + Button, + DistrictSelect, + NumPercentView, + VBarsView } \ No newline at end of file diff --git a/src/main.css b/src/main.css index 8dbc324..1ec7680 100644 --- a/src/main.css +++ b/src/main.css @@ -6,68 +6,149 @@ body { color: #333; } +:root { + --primary-color: #0069f6; + --primary-light-color: #d1e4fd; + --background-color: #fff; +} + +button { + color: var(--primary-color); + background-color: var(--background-color); + border: 1px solid var(--primary-color); +} + +button:hover { + color: var(--background-color); + background-color: var(--primary-color); +} + .grid { padding: 20px; } -.pop { +.sm-vpb { display: grid; grid-template-rows: 1fr 1fr 1fr 1fr; } -.popLabel { - font-size: 0.8em; +.num-percent .custom-num-percent { + color: #999; +} + +.num-percent::after { + /* TODO */ + content: ""; + position: absolute; + top: 0; + right: 0; + bottom: 0; + width: 10px; /* Adjust the width of the separator as needed */ + background-color: #ccc; /* Adjust the color of the separator as needed */ + z-index: 1; +} + +.num-percent .label, +.custom-num-percent .label { + font-size: 1em; padding: 8px 0; } -.popValue { - font-size: 1.4em; +.num-percent .value, +.custom-num-percent .value { + color: #000; + font-size: 1.6em; font-weight: bold; padding: 8px 0; } -.popBar { - height: 100%; - border-radius: 4px; +.num-percent .bar, +.custom-num-percent .bar { + height: 10px; + border-radius: 2px; } -.popPercentage { +.custom-num-percent .bar { + height: 20px; + border-radius: 10px; +} + +.num-percent .percentage, +.custom-num-percent .percentage { font-size: 0.8em; padding: 8px 0; } -.xyz_pop { - display: grid; - grid-template-rows: 1fr 1fr 0.3fr 0.6fr; - color: #333; - padding: 4px; - border-radius: 8px; - border: 1px solid rgba(0 0 0 0); - transition: 0.2s; +.custom-vbar { + padding: 40px; + background-color: #fff; + grid-column-gap: 3px; + min-height: 160px; + max-width: 600px; } -.xyz_pop:hover { - color: #000; - border: 1px solid #999; +.custom-vbar div { + background-color: var(--primary-color); + border-radius: 2px; } -.xyz_popLabel { - font-size: 0.8em; - padding: 8px 0; +.sm-grid2 { + grid-template-columns: 3fr 1fr; + grid-gap: 20px; } -.xyz_popValue { - font-size: 1.2em; - font-weight: bold; - padding: 8px 0; +.abc-sm-grid2 { + grid-template-columns: 8fr 4fr; + grid-gap: 0; } -.xyz_popBar { - height: 100%; - border-radius: 4px; +.section { + grid-gap: 10px; + grid-template-columns: repeat(8, 1fr); } -.xyz_popPercentage { - font-size: 0.8em; - padding: 8px 0; +.apple { + grid-template-columns: repeat(8, 1fr); +} + +.banana { + grid-template-columns: 3fr 1fr; +} + +.ibm { + grid-template-columns: repeat(1, 1fr); +} + +.lenovo { + grid-template-columns: repeat(8, 1fr); +} + +.sgi { + grid-template-columns: repeat(1, 1fr); +} + +.arena { + grid-template-columns: repeat(20, 1fr); +} + +.padding-10 { + padding: 10px; +} + +@media (width <= 900px) { + .lenovo { + grid-template-columns: repeat(4, 1fr); + } +} + +@media (width <= 1200px) { + .banana { + grid-template-columns: 1fr; + } + + .custom-vbar { + justify-self: center; + min-width: 400px; + padding: 0; + } } \ No newline at end of file diff --git a/src/main.js b/src/main.js index b49c284..341e4d0 100644 --- a/src/main.js +++ b/src/main.js @@ -1,47 +1,105 @@ import { Model, View, - Router, Controller, - Component, - GridComponent + Component } from '@sndcds/mvc' + import { App, AppModel, - TestComponent, - DistrictSelectComponent, - PopComponent, - StateController + Grid, + DemoComponent, + Button, + DistrictSelect, + NumPercentView, + VBarsView } from './index.js' -// Create an instance of AppModel + +// Sozialatlas + +// Create model const model = new AppModel() -// Create an instance of View +// Create view const view = new View() -// Create an instance of App with the model and view -const app = new App(model, view) +// Create Components +const section1 = new Grid(view, 'section-1', { 'classList': 'section apple padding-10' }) +new Button(section1, 'button-1', { 'onClick': button1OnClick }) +new Button(section1, 'button-2', { 'label': 'District 1', 'tag': 1, 'onClick': button2OnClick }) +new Button(section1, 'button-3', { 'label': 'District 2', 'tag': 2, 'onClick': button2OnClick }) +new DistrictSelect(section1, 'district-select') -// Define routes object with path and name -const routes = [{ path: '/', controller: 'demoController1' }] +const section2 = new Grid(view, 'section-2', { 'classList': 'section banana padding-10' }) +const subView2_1 = new Grid(section2, 'subview-2-1', { 'classList': 'section ibm' }) +const subView2_1_1 = new Grid(subView2_1, 'subview-2-1-1', { 'classList': 'section lenovo' }) +for (let i = 1; i <= 3; i++) { + const labels = ['Alpha', 'Beta', 'Gamma'] + new NumPercentView(subView2_1_1, `value-display-${i}`, { 'label': labels[i - 1], 'value': 123, 'percentage': 87.3, 'barOffset': 13.2, 'barColor1': '#d1e4fd', 'barColor2': '#0069f6' }) +} -const demoController1 = () => { - const a = new StateController(app) +const subView2_1_2 = new Grid(subView2_1, 'subview-2-1', { 'classList': 'section lenovo' }) +for (let i = 1; i <= 8; i++) { + const labels = ['0 - 18', '18 - 30', '30 - 45', '45 - 65', '65 - 80', '80+', '0 - 8', '60+'] + new NumPercentView(subView2_1_2, `age-view-${i}`, { 'classList': 'num-percent', 'label': labels[i - 1], 'value': 123, 'percentage': 87.3, 'barOffset': 13.2, 'barColor1': '#d1e4fd', 'barColor2': '#0069f6' }) } -// Create an object that maps controller names to controller functions. -const controllers = { - demoController1 +const subView2_2 = new Grid(section2, 'subview-2-2', { 'classList': 'section sgi' }) +new VBarsView(subView2_2, 'vbar-1', { 'classList': 'custom-vbar' }) + +const section3 = new Grid(view, 'section-3', { 'classList': 'section arena padding-10' }) +for (let i = 1; i <= 13; i++) { + new Button(section3, `district-button-${i}`, { 'classList': '', 'label': i, 'tag': i - 1, 'onClick': button2OnClick }) } -// Create an instance of Router -const router = new Router(app, routes, controllers) -router.start() -// Build the view in the HTML and append view to element with id `root` + +/* +for (let i = 4; i <= 2; i++) { + const labels = ['SUN', 'DEC', 'Apple', 'NeXT', 'HP', 'Compaq', 'Lenovo', 'sgi', 'Atari', 'Commodore', 'IBM'] + const randomIndex = Math.floor(Math.random() * labels.length) + const label = labels[randomIndex] + + const percentage = Math.floor(Math.random() * 80) + const barOffset = Math.floor(Math.random() * (100 - percentage)) + const setupData = { + label, + value: Math.floor(Math.random() * 1000), + percentage, + barOffset, + barColor1: App.randomColor(), + barColor2: App.randomColor() + } + + new NumPercentView(container2, `pop-${i}`, setupData) +} +*/ +// Create app +const app = new App(model, view) +app.configurate({ 'locale': 'de-DE' }) app.buildView('root') -// Initialize the application with url and district id -app.initApp('./details.json', 13) \ No newline at end of file +// Init app, must be called after configurate and buildView +app.initApp('./details.json', 13) + + +// Handlers +function button1OnClick(component) { + component.e.innerText = 'clicked!' + const c = app.componentById('value-display-1') + c.setProperties({ 'value': 987, 'barColor1': 'red', 'barColor2': 'yellow' }) + const s = app.componentById('section-2') + s.e.style.display = 'none' +// s.e.style.visibility = 'hidden' +} + + +function button2OnClick(component) { + app.onDistrictChanged(component.tag) + const n = app.view.countDescendants() + const s = app.componentById('section-2') + s.e.style.display = 'grid' +// s.e.style.visibility = 'visible' +} \ No newline at end of file diff --git a/src/popComponent.js b/src/popComponent.js deleted file mode 100644 index f91380b..0000000 --- a/src/popComponent.js +++ /dev/null @@ -1,96 +0,0 @@ -import { Component } from '@sndcds/mvc' - -export default class PopComponent extends Component { - /** - * Component for displaying a label, value, bar an percentage. - * - * Can be used for displaying numeric information, i. e. of statistics and other number related contexts. - * - * @since 20.9.2023 - * - * @param {Component} parent The parent component. - * @param {String} id The id of the new Component. - * @param {any} setupData Optional set up data. - */ - constructor(parent, id, setupData) { - super(parent, id, setupData) - this.label = 'Label' - this.value = 0 - this.percentage = 100 - this.barOffset = 20 - this.barSize = 30 - this.barColor1 = '#999' - this.barColor2 = '#333' - - if (setupData !== undefined) { - if (setupData.label !== undefined) { - this.label = setupData.label - } - if (setupData.value !== undefined) { - this.value = setupData.value - } - if (setupData.percentage !== undefined) { - this.percentage = setupData.percentage - } - if (setupData.barOffset !== undefined) { - this.barOffset = setupData.barOffset - } - if (setupData.barSize !== undefined) { - this.barSize = setupData.barSize - } - if (setupData.barColor1 !== undefined) { - this.barColor1 = setupData.barColor1 - } - if (setupData.barColor2 !== undefined) { - this.barColor2 = setupData.barColor2 - } - } - } - - /** - * Build the DOM Elements for HTML rendering og the component. - * - * This method mus be overridden in derived classes. - * - * Styling: - * One solotion is to assign classes to the emelemts. - */ - build() { - this.e = this.domCreateElement('div') - this.parent.e.appendChild(this.e) - this.e.className = this.prefixedClassName('pop') - - let a = this.e.appendChild(this.domCreateElement('div')) - a.style.textAlign = 'center' - a.innerText = this.label - a.className = this.prefixedClassName('popLabel') - - a = this.e.appendChild(this.domCreateElement('div')) - a.style.textAlign = 'center' - a.innerText = this.value - a.className = this.prefixedClassName('popValue') - - const color1 = this.barColor1 - const color2 = this.barColor2 - const spot1 = `${this.barOffset}%` - const spot2 = `${this.barOffset + 0.1}%` - const spot3 = `${this.barOffset + this.barSize - 0.1}%` - const spot4 = `${this.barOffset + this.barSize}%` - const gradient = `linear-gradient(90deg, ${color1} 0%, ${color1} ${spot1}, ${color2} ${spot2}, ${color2} ${spot3}, ${color1} ${spot4})` - - a = this.e.appendChild(this.domCreateElement('div')) - a.style.textAlign = 'left' - a.style.background = gradient - a.className = this.prefixedClassName('popBar') - a = this.e.appendChild(this.domCreateElement('div')) - a.style.textAlign = 'center' - a.innerText = `${this.percentage} %` - a.className = this.prefixedClassName('popPercentage') - - this.buildChilds() - } - - setProperties(data) { - this.e.children.item(1).innerText = data.value - } -} \ No newline at end of file diff --git a/src/stateController.js b/src/stateController.js deleted file mode 100644 index c85c6a7..0000000 --- a/src/stateController.js +++ /dev/null @@ -1,122 +0,0 @@ -import { Component, GridComponent } from '@sndcds/mvc' -import { DistrictSelectComponent, PopComponent } from './index.js' - -export default class StateController { - constructor(app) { - this.app = app - app.state = this - - this.buildView() - if (app.model.data === null) { - app.fetchData('./details.json') - } - } - - onDataChanged(data) { - this.app.model.setDataObject(data) - this.app.model.setDistrictObject(this.app.model.districtId) - - if (this.app.state !== null) { - this.app.state.onDistrictChanged = - this.app.state.onDistrictChanged.bind(this) // TODO: Description! - } - - const d = { - data: this.app.model.data, - districtId: this.app.model.districtId - } - this.app.setProperties('districtSelect', d) - const c = this.app.componentById('districtSelect') - c.bindDistrictChanged(this.app.onDistrictChanged) - // this.renderAgeSection() - } - - onDistrictChanged(id) { - this.app.model.setDistrictId(id + 1) - this.app.model.setDistrictObject(id + 1) - // this.renderAgeSection() - } - - buildView() { - // Create a GridComponent called 'container1' within the view - const container1 = new GridComponent(this.app.view, 'container1') - const subView = new Component(container1, 'subView') - const c = new DistrictSelectComponent(subView, 'districtSelect') - // new TestComponent(subView, 'test1') - - const container2 = new GridComponent(this.app.view, 'container2') - - // Create a series of 'PopComponent' instances within 'container2' - for (let i = 1; i <= 8; i++) { - const labels = [ - '0 - 18', - '18 - 30', - '30 - 45', - '45 - 65', - '65 - 80', - '80+', - '0 - 8', - '60+' - ] - new PopComponent(container2, `ageView${i}`, { - classPrefix: 'xyz', - label: labels[i - 1], - value: 123, - percentage: 87.3, - barOffset: 13.2, - barColor1: '#d1e4fd', - barColor2: '#0069f6' - }) - } - } - - renderAgeSection() { - const items = [ - { - id: 'ageView1', - path: ['district_detail', '2021', 'age_groups', 'age_to_under_18'] - }, - { - id: 'ageView2', - path: ['district_detail', '2021', 'age_groups', 'age_18_to_under_30'] - }, - { - id: 'ageView3', - path: ['district_detail', '2021', 'age_groups', 'age_30_to_under_45'] - }, - { - id: 'ageView4', - path: ['district_detail', '2021', 'age_groups', 'age_45_to_under_65'] - }, - { - id: 'ageView5', - path: ['district_detail', '2021', 'age_groups', 'age_65_to_under_80'] - }, - { - id: 'ageView6', - path: ['district_detail', '2021', 'age_groups', 'age_80_and_above'] - }, - { - id: 'ageView7', - path: ['district_detail', '2021', 'age_groups', 'age_0_to_under_7'] - }, - { - id: 'ageView8', - path: ['district_detail', '2021', 'age_groups', 'age_60_and_above'] - } - ] - - items.forEach((item) => { - const c = this.app.componentById(item.id) - const d = this.app.getNestedValue( - this.app.model.districtObject, - item.path - ) - c.setProperties({ value: this.app.formatNumberWithDot(d) }) - }) - } - - renderDistrictSelect() { - new DistrictSelectComponent() - } -} \ No newline at end of file