From a6d4bdd7f93f3b7c7db2d6f295e56fedaf73de7d Mon Sep 17 00:00:00 2001 From: Tom Schindler <tom.schindler@student.uni-halle.de> Date: Wed, 14 Aug 2024 20:42:05 +0200 Subject: [PATCH] Interaktion Parallel und ScatterPlot, Fehler behoben bei Scatterplot mit Attribut sichtbarkeit in select, Filter Optionen Tree umgesetzt --- public/main.js | 919 ++++++++++++++++++++++-------------- src/Main.elm | 156 +++++- src/Model.elm | 11 + src/ParallelCoordinates.elm | 20 +- src/Scatterplot.elm | 65 ++- src/TreeView.elm | 190 +++++++- 6 files changed, 953 insertions(+), 408 deletions(-) diff --git a/public/main.js b/public/main.js index 6acaafd..111df25 100644 --- a/public/main.js +++ b/public/main.js @@ -6307,6 +6307,9 @@ var $author$project$Main$init = function (_v0) { ]) }, { + dropCount: 0, + inputDropCount: '', + selectedFilter: {brand: 'all', g5: 'false', ir_blaster: 'false', nfc: 'false'}, zoomOption: A2( $gampleman$elm_visualization$Zoom$translateExtent, _Utils_Tuple2( @@ -7008,7 +7011,7 @@ var $author$project$Main$createAttList = F2( function ($) { return $.num_cores; }, - model.data) : ((att === 'ProcessorSpeed') ? A2( + model.data) : ((att === 'Processor Speed') ? A2( $elm$core$List$map, function ($) { return $.processor_speed; @@ -7018,7 +7021,7 @@ var $author$project$Main$createAttList = F2( function ($) { return $.battery; }, - model.data) : ((att === 'FastCharging') ? A2( + model.data) : ((att === 'Fast Charging') ? A2( $elm$core$List$map, function ($) { return $.fast_charging; @@ -7033,12 +7036,12 @@ var $author$project$Main$createAttList = F2( function ($) { return $.ram; }, - model.data) : ((att === 'ScreenSize') ? A2( + model.data) : ((att === 'Screen Size') ? A2( $elm$core$List$map, function ($) { return $.screen_size; }, - model.data) : ((att === 'RefreshRate') ? A2( + model.data) : ((att === 'Refresh Rate') ? A2( $elm$core$List$map, function ($) { return $.refresh_rate; @@ -9194,7 +9197,7 @@ var $author$project$Main$update = F2( model, { scatterplotOptions: { - att1List: _List_Nil, + att1List: model.scatterplotOptions.att1List, att2List: A2($author$project$Main$createAttList, model, value), attribute1: model.scatterplotOptions.attribute1, attribute2: value @@ -9219,19 +9222,38 @@ var $author$project$Main$update = F2( $elm$core$Platform$Cmd$none); } case 'ParallelCoordinatesMsg': - var _v2 = msg.a; - var pos1 = _v2.a; - var pos2 = _v2.b; - return _Utils_Tuple2( - _Utils_update( - model, - { - parallelPlotOption: { - orderedLabels: A3($elm_community$list_extra$List$Extra$swapAt, pos1, pos2, model.parallelPlotOption.orderedLabels), - orderedList: A3($elm_community$list_extra$List$Extra$swapAt, pos1, pos2, model.parallelPlotOption.orderedList) - } - }), - $elm$core$Platform$Cmd$none); + if (msg.a.$ === 'ChangeOrder') { + var _v2 = msg.a; + var pos1 = _v2.a; + var pos2 = _v2.b; + return _Utils_Tuple2( + _Utils_update( + model, + { + parallelPlotOption: { + orderedLabels: A3($elm_community$list_extra$List$Extra$swapAt, pos1, pos2, model.parallelPlotOption.orderedLabels), + orderedList: A3($elm_community$list_extra$List$Extra$swapAt, pos1, pos2, model.parallelPlotOption.orderedList) + } + }), + $elm$core$Platform$Cmd$none); + } else { + var _v3 = msg.a; + var att1 = _v3.a; + var att2 = _v3.b; + return _Utils_Tuple2( + _Utils_update( + model, + { + plotVisible: {parallelCoordinatesPlot: false, scatterPlot: true, starPlot: false, treeView: false}, + scatterplotOptions: { + att1List: A2($author$project$Main$createAttList, model, att1), + att2List: A2($author$project$Main$createAttList, model, att2), + attribute1: att1, + attribute2: att2 + } + }), + $elm$core$Platform$Cmd$none); + } case 'TreeViewMsg': switch (msg.a.$) { case 'ZoomMsg': @@ -9241,6 +9263,9 @@ var $author$project$Main$update = F2( model, { treeOption: { + dropCount: model.treeOption.dropCount, + inputDropCount: model.treeOption.inputDropCount, + selectedFilter: model.treeOption.selectedFilter, zoomOption: A2($gampleman$elm_visualization$Zoom$update, m, model.treeOption.zoomOption) } }), @@ -9252,11 +9277,14 @@ var $author$project$Main$update = F2( model, { treeOption: { + dropCount: model.treeOption.dropCount, + inputDropCount: model.treeOption.inputDropCount, + selectedFilter: model.treeOption.selectedFilter, zoomOption: A2($author$project$TreeView$performZoom, t, model.treeOption.zoomOption) } }), $elm$core$Platform$Cmd$none); - default: + case 'SetStarPlotFromTree': var id = msg.a.a; return _Utils_Tuple2( _Utils_update( @@ -9272,6 +9300,88 @@ var $author$project$Main$update = F2( } }), $elm$core$Platform$Cmd$none); + case 'SetDropCountInput': + var value = msg.a.a; + return _Utils_Tuple2( + _Utils_update( + model, + { + treeOption: {dropCount: model.treeOption.dropCount, inputDropCount: value, selectedFilter: model.treeOption.selectedFilter, zoomOption: model.treeOption.zoomOption} + }), + $elm$core$Platform$Cmd$none); + case 'SetDropCount': + var _v4 = msg.a; + return _Utils_Tuple2( + _Utils_update( + model, + { + treeOption: { + dropCount: A2( + $elm$core$Maybe$withDefault, + 0, + $elm$core$String$toInt(model.treeOption.inputDropCount)), + inputDropCount: model.treeOption.inputDropCount, + selectedFilter: model.treeOption.selectedFilter, + zoomOption: model.treeOption.zoomOption + } + }), + $elm$core$Platform$Cmd$none); + case 'SetBrandTree': + var value = msg.a.a; + return _Utils_Tuple2( + _Utils_update( + model, + { + treeOption: { + dropCount: model.treeOption.dropCount, + inputDropCount: model.treeOption.inputDropCount, + selectedFilter: {brand: value, g5: model.treeOption.selectedFilter.g5, ir_blaster: model.treeOption.selectedFilter.ir_blaster, nfc: model.treeOption.selectedFilter.nfc}, + zoomOption: model.treeOption.zoomOption + } + }), + $elm$core$Platform$Cmd$none); + case 'Set5GTree': + var value = msg.a.a; + return _Utils_Tuple2( + _Utils_update( + model, + { + treeOption: { + dropCount: model.treeOption.dropCount, + inputDropCount: model.treeOption.inputDropCount, + selectedFilter: {brand: model.treeOption.selectedFilter.brand, g5: value, ir_blaster: model.treeOption.selectedFilter.ir_blaster, nfc: model.treeOption.selectedFilter.nfc}, + zoomOption: model.treeOption.zoomOption + } + }), + $elm$core$Platform$Cmd$none); + case 'SetNFCTree': + var value = msg.a.a; + return _Utils_Tuple2( + _Utils_update( + model, + { + treeOption: { + dropCount: model.treeOption.dropCount, + inputDropCount: model.treeOption.inputDropCount, + selectedFilter: {brand: model.treeOption.selectedFilter.brand, g5: model.treeOption.selectedFilter.g5, ir_blaster: model.treeOption.selectedFilter.ir_blaster, nfc: value}, + zoomOption: model.treeOption.zoomOption + } + }), + $elm$core$Platform$Cmd$none); + default: + var value = msg.a.a; + return _Utils_Tuple2( + _Utils_update( + model, + { + treeOption: { + dropCount: model.treeOption.dropCount, + inputDropCount: model.treeOption.inputDropCount, + selectedFilter: {brand: model.treeOption.selectedFilter.brand, g5: model.treeOption.selectedFilter.g5, ir_blaster: value, nfc: model.treeOption.selectedFilter.nfc}, + zoomOption: model.treeOption.zoomOption + } + }), + $elm$core$Platform$Cmd$none); } case 'ZooomMsg': var m = msg.a; @@ -9280,6 +9390,9 @@ var $author$project$Main$update = F2( model, { treeOption: { + dropCount: model.treeOption.dropCount, + inputDropCount: model.treeOption.inputDropCount, + selectedFilter: model.treeOption.selectedFilter, zoomOption: A2($gampleman$elm_visualization$Zoom$update, m, model.treeOption.zoomOption) } }), @@ -9287,7 +9400,7 @@ var $author$project$Main$update = F2( case 'StarplotMsg': switch (msg.a.$) { case 'Nothing1': - var _v3 = msg.a; + var _v5 = msg.a; return _Utils_Tuple2(model, $elm$core$Platform$Cmd$none); case 'InputChange1': var id = msg.a.a; @@ -9308,7 +9421,7 @@ var $author$project$Main$update = F2( }), $elm$core$Platform$Cmd$none); case 'SubmitNumber1': - var _v4 = msg.a; + var _v6 = msg.a; return _Utils_Tuple2( _Utils_update( model, @@ -9323,7 +9436,7 @@ var $author$project$Main$update = F2( }), $elm$core$Platform$Cmd$none); default: - var _v5 = msg.a; + var _v7 = msg.a; return _Utils_Tuple2( _Utils_update( model, @@ -10340,6 +10453,10 @@ var $author$project$ParallelCoordinates$ChangeOrder = F2( function (a, b) { return {$: 'ChangeOrder', a: a, b: b}; }); +var $author$project$ParallelCoordinates$SetScatterPlotFromParallelPlot = F2( + function (a, b) { + return {$: 'SetScatterPlotFromParallelPlot', a: a, b: b}; + }); var $elm_community$typed_svg$TypedSvg$Types$Translate = F2( function (a, b) { return {$: 'Translate', a: a, b: b}; @@ -10678,12 +10795,22 @@ var $gampleman$elm_visualization$Axis$left = A4($gampleman$elm_visualization$Axi var $author$project$ParallelCoordinates$yAxis = function (scale) { return A2($gampleman$elm_visualization$Axis$left, _List_Nil, scale); }; -var $author$project$ParallelCoordinates$createYAxis = F3( - function (scaleX, scaleY, text) { +var $author$project$ParallelCoordinates$createYAxis = F4( + function (scaleX, model, scaleY, text) { var index = scaleY.a; var indexF = index; var indexafter = (index === 9) ? 0 : (index + 1); var indexbefore = (!index) ? 9 : (index - 1); + var att2 = A2( + $elm$core$Maybe$withDefault, + 'Price', + $elm$core$List$head( + A2($elm$core$List$drop, indexafter, model.parallelPlotOption.orderedLabels))); + var att1 = A2( + $elm$core$Maybe$withDefault, + 'Price', + $elm$core$List$head( + A2($elm$core$List$drop, index, model.parallelPlotOption.orderedLabels))); return A2( $elm_community$typed_svg$TypedSvg$g, _List_fromArray( @@ -10748,7 +10875,9 @@ var $author$project$ParallelCoordinates$createYAxis = F3( $elm_community$typed_svg$TypedSvg$Attributes$InPx$y(-10), $elm_community$typed_svg$TypedSvg$Attributes$textAnchor($elm_community$typed_svg$TypedSvg$Types$AnchorMiddle), $elm_community$typed_svg$TypedSvg$Attributes$fontSize( - $elm_community$typed_svg$TypedSvg$Types$Px(14)) + $elm_community$typed_svg$TypedSvg$Types$Px(14)), + $elm$html$Html$Events$onClick( + A2($author$project$ParallelCoordinates$SetScatterPlotFromParallelPlot, att1, att2)) ]), _List_fromArray( [ @@ -11490,7 +11619,7 @@ var $author$project$ParallelCoordinates$parallelCoordinatesPlot = F2( A2($elm$core$List$map, $author$project$ParallelCoordinates$yScale, yValues)); var yaxis = A3( $elm$core$List$map2, - $author$project$ParallelCoordinates$createYAxis(xScaleLocal), + A2($author$project$ParallelCoordinates$createYAxis, xScaleLocal, model), yScaleLocalsWithIndex, multidimStrings); var yValue1 = A2( @@ -11584,6 +11713,48 @@ var $author$project$Scatterplot$ChangeAttribute1 = function (a) { var $author$project$Scatterplot$ChangeAttribute2 = function (a) { return {$: 'ChangeAttribute2', a: a}; }; +var $elm$html$Html$option = _VirtualDom_node('option'); +var $elm$json$Json$Encode$bool = _Json_wrap; +var $elm$html$Html$Attributes$boolProperty = F2( + function (key, bool) { + return A2( + _VirtualDom_property, + key, + $elm$json$Json$Encode$bool(bool)); + }); +var $elm$html$Html$Attributes$selected = $elm$html$Html$Attributes$boolProperty('selected'); +var $elm$json$Json$Encode$string = _Json_wrap; +var $elm$html$Html$Attributes$stringProperty = F2( + function (key, string) { + return A2( + _VirtualDom_property, + key, + $elm$json$Json$Encode$string(string)); + }); +var $elm$html$Html$Attributes$value = $elm$html$Html$Attributes$stringProperty('value'); +var $author$project$Scatterplot$createSelectorOptions = F2( + function (select, att) { + return _Utils_eq(select, att) ? A2( + $elm$html$Html$option, + _List_fromArray( + [ + $elm$html$Html$Attributes$value(att), + $elm$html$Html$Attributes$selected(true) + ]), + _List_fromArray( + [ + $elm$html$Html$text(att) + ])) : A2( + $elm$html$Html$option, + _List_fromArray( + [ + $elm$html$Html$Attributes$value(att) + ]), + _List_fromArray( + [ + $elm$html$Html$text(att) + ])); + }); var $elm$html$Html$Events$alwaysStop = function (x) { return _Utils_Tuple2(x, true); }; @@ -11616,155 +11787,28 @@ var $elm$html$Html$Events$onInput = function (tagger) { $elm$html$Html$Events$alwaysStop, A2($elm$json$Json$Decode$map, tagger, $elm$html$Html$Events$targetValue))); }; -var $elm$html$Html$option = _VirtualDom_node('option'); var $elm$html$Html$select = _VirtualDom_node('select'); -var $elm$json$Json$Encode$string = _Json_wrap; -var $elm$html$Html$Attributes$stringProperty = F2( - function (key, string) { +var $author$project$Scatterplot$attributeSelector = F2( + function (attNr, model) { + var attributes = _List_fromArray( + ['Price', 'Rating', 'NumCores', 'Processor Speed', 'Battery', 'Fast Charging', 'Memory', 'RAM', 'Screen Size', 'Refresh Rate']); + var att2 = model.scatterplotOptions.attribute2; + var att1 = model.scatterplotOptions.attribute1; return A2( - _VirtualDom_property, - key, - $elm$json$Json$Encode$string(string)); - }); -var $elm$html$Html$Attributes$value = $elm$html$Html$Attributes$stringProperty('value'); -var $author$project$Scatterplot$attributeSelector = function (attNr) { - return A2( - $elm$html$Html$select, - _List_fromArray( - [ - $elm$html$Html$Events$onInput( - (attNr === 1) ? $author$project$Scatterplot$ChangeAttribute1 : $author$project$Scatterplot$ChangeAttribute2) - ]), - _Utils_ap( - (attNr === 1) ? _List_fromArray( - [ - A2( - $elm$html$Html$option, - _List_fromArray( - [ - $elm$html$Html$Attributes$value('Price') - ]), - _List_fromArray( - [ - $elm$html$Html$text('Price') - ])), - A2( - $elm$html$Html$option, - _List_fromArray( - [ - $elm$html$Html$Attributes$value('Rating') - ]), - _List_fromArray( - [ - $elm$html$Html$text('Rating') - ])) - ]) : _List_fromArray( - [ - A2( - $elm$html$Html$option, - _List_fromArray( - [ - $elm$html$Html$Attributes$value('Rating') - ]), - _List_fromArray( - [ - $elm$html$Html$text('Rating') - ])), - A2( - $elm$html$Html$option, - _List_fromArray( - [ - $elm$html$Html$Attributes$value('Price') - ]), - _List_fromArray( - [ - $elm$html$Html$text('Price') - ])) - ]), + $elm$html$Html$select, _List_fromArray( [ - A2( - $elm$html$Html$option, - _List_fromArray( - [ - $elm$html$Html$Attributes$value('NumCores') - ]), - _List_fromArray( - [ - $elm$html$Html$text('NumCores') - ])), - A2( - $elm$html$Html$option, - _List_fromArray( - [ - $elm$html$Html$Attributes$value('ProcessorSpeed') - ]), - _List_fromArray( - [ - $elm$html$Html$text('ProcessorSpeed') - ])), - A2( - $elm$html$Html$option, - _List_fromArray( - [ - $elm$html$Html$Attributes$value('Battery') - ]), - _List_fromArray( - [ - $elm$html$Html$text('Battery') - ])), - A2( - $elm$html$Html$option, - _List_fromArray( - [ - $elm$html$Html$Attributes$value('FastCharging') - ]), - _List_fromArray( - [ - $elm$html$Html$text('FastCharging') - ])), - A2( - $elm$html$Html$option, - _List_fromArray( - [ - $elm$html$Html$Attributes$value('Memory') - ]), - _List_fromArray( - [ - $elm$html$Html$text('Memory') - ])), - A2( - $elm$html$Html$option, - _List_fromArray( - [ - $elm$html$Html$Attributes$value('Ram') - ]), - _List_fromArray( - [ - $elm$html$Html$text('Ram') - ])), - A2( - $elm$html$Html$option, - _List_fromArray( - [ - $elm$html$Html$Attributes$value('ScreenSize') - ]), - _List_fromArray( - [ - $elm$html$Html$text('ScreenSize') - ])), - A2( - $elm$html$Html$option, - _List_fromArray( - [ - $elm$html$Html$Attributes$value('RefreshRate') - ]), - _List_fromArray( - [ - $elm$html$Html$text('RefreshRate') - ])) - ]))); -}; + $elm$html$Html$Events$onInput( + (attNr === 1) ? $author$project$Scatterplot$ChangeAttribute1 : $author$project$Scatterplot$ChangeAttribute2) + ]), + (attNr === 1) ? A2( + $elm$core$List$map, + $author$project$Scatterplot$createSelectorOptions(att1), + attributes) : A2( + $elm$core$List$map, + $author$project$Scatterplot$createSelectorOptions(att2), + attributes)); + }); var $elm$html$Html$b = _VirtualDom_node('b'); var $author$project$Scatterplot$XyData = F3( function (xDescription, yDescription, data) { @@ -12128,17 +12172,17 @@ var $author$project$Scatterplot$viewScatterplot = function (model) { _List_Nil, _List_fromArray( [ - $elm$html$Html$text('Attribut 1: ') + $elm$html$Html$text('x-Achse: ') ])), - $author$project$Scatterplot$attributeSelector(1), + A2($author$project$Scatterplot$attributeSelector, 1, model), A2( $elm$html$Html$b, _List_Nil, _List_fromArray( [ - $elm$html$Html$text(' Attribut 2: ') + $elm$html$Html$text(' y-Achse: ') ])), - $author$project$Scatterplot$attributeSelector(2), + A2($author$project$Scatterplot$attributeSelector, 2, model), $author$project$Scatterplot$scatterplot(filteredSmartphoneData) ])); }; @@ -12574,7 +12618,7 @@ var $author$project$Starplot$viewStarplot = function (model) { [ $elm$html$Html$text('Submit for SP1') ])), - $elm$html$Html$text(' ID2 auswaehlen: '), + $elm$html$Html$text(' ID2 auswaehlen: '), A2( $elm$html$Html$input, _List_fromArray( @@ -12682,6 +12726,45 @@ var $author$project$Starplot$viewStarplot = function (model) { }() ])); }; +var $author$project$TreeView$Set5GTree = function (a) { + return {$: 'Set5GTree', a: a}; +}; +var $author$project$TreeView$SetBrandTree = function (a) { + return {$: 'SetBrandTree', a: a}; +}; +var $author$project$TreeView$SetDropCount = {$: 'SetDropCount'}; +var $author$project$TreeView$SetDropCountInput = function (a) { + return {$: 'SetDropCountInput', a: a}; +}; +var $author$project$TreeView$SetIRBlasterTree = function (a) { + return {$: 'SetIRBlasterTree', a: a}; +}; +var $author$project$TreeView$SetNFCTree = function (a) { + return {$: 'SetNFCTree', a: a}; +}; +var $author$project$TreeView$createSelectorOptions = F2( + function (select, valueOption) { + return _Utils_eq(select, valueOption) ? A2( + $elm$html$Html$option, + _List_fromArray( + [ + $elm$html$Html$Attributes$value(valueOption), + $elm$html$Html$Attributes$selected(true) + ]), + _List_fromArray( + [ + $elm$html$Html$text(valueOption) + ])) : A2( + $elm$html$Html$option, + _List_fromArray( + [ + $elm$html$Html$Attributes$value(valueOption) + ]), + _List_fromArray( + [ + $elm$html$Html$text(valueOption) + ])); + }); var $author$project$TreeView$ZoomMsg = function (a) { return {$: 'ZoomMsg', a: a}; }; @@ -14917,6 +15000,25 @@ var $gampleman$elm_visualization$Hierarchy$tidy = F2( }); var $author$project$TreeView$Leaf = {$: 'Leaf'}; var $author$project$TreeView$Node = {$: 'Node'}; +var $author$project$TreeView$fromBrand = F2( + function (model, smartphone) { + return (_Utils_eq( + model.treeOption.selectedFilter.brand, + A2($elm$core$Maybe$withDefault, '', smartphone.brand)) || (model.treeOption.selectedFilter.brand === 'all')) ? true : false; + }); +var $elm$core$Basics$not = _Basics_not; +var $author$project$TreeView$has5G = F2( + function (model, smartphone) { + return (((model.treeOption.selectedFilter.g5 === 'true') && A2($elm$core$Maybe$withDefault, false, smartphone.g5)) || (model.treeOption.selectedFilter.g5 === 'all')) ? true : (((model.treeOption.selectedFilter.g5 === 'false') && (!A2($elm$core$Maybe$withDefault, true, smartphone.g5))) ? true : false); + }); +var $author$project$TreeView$hasIRBlaster = F2( + function (model, smartphone) { + return (((model.treeOption.selectedFilter.ir_blaster === 'true') && A2($elm$core$Maybe$withDefault, false, smartphone.ir_blaster)) || (model.treeOption.selectedFilter.ir_blaster === 'all')) ? true : (((model.treeOption.selectedFilter.ir_blaster === 'false') && (!A2($elm$core$Maybe$withDefault, true, smartphone.ir_blaster))) ? true : false); + }); +var $author$project$TreeView$hasNFC = F2( + function (model, smartphone) { + return (((model.treeOption.selectedFilter.nfc === 'true') && A2($elm$core$Maybe$withDefault, false, smartphone.nfc)) || (model.treeOption.selectedFilter.nfc === 'all')) ? true : (((model.treeOption.selectedFilter.nfc === 'false') && (!A2($elm$core$Maybe$withDefault, true, smartphone.nfc))) ? true : false); + }); var $author$project$TreeView$mapToSPData = function (smartphone) { return $author$project$ExtendedFunctions$map10( function (brand) { @@ -14964,10 +15066,23 @@ var $author$project$TreeView$mapToSPData = function (smartphone) { }; })(smartphone.brand)(smartphone.model)(smartphone.price)(smartphone.rating)(smartphone.battery)(smartphone.processor_name)(smartphone.memory)(smartphone.ram)(smartphone.screen_size)(smartphone.refresh_rate); }; -var $author$project$TreeView$filterSPData = function (smartphone) { - var smartphoneList = A2($elm$core$List$filterMap, $author$project$TreeView$mapToSPData, smartphone); - return smartphoneList; -}; +var $author$project$TreeView$filterSPData = F2( + function (model, smartphone) { + var smartphoneList = A2( + $elm$core$List$filter, + $author$project$TreeView$hasIRBlaster(model), + A2( + $elm$core$List$filter, + $author$project$TreeView$hasNFC(model), + A2( + $elm$core$List$filter, + $author$project$TreeView$has5G(model), + A2( + $elm$core$List$filter, + $author$project$TreeView$fromBrand(model), + A2($elm$core$List$filterMap, $author$project$TreeView$mapToSPData, smartphone))))); + return smartphoneList; + }); var $author$project$TreeView$getTreeString = function (smartphone) { return { id: A2($elm$core$Maybe$withDefault, '-1', smartphone.id), @@ -15329,110 +15444,119 @@ var $elm$core$Result$withDefault = F2( } }); var $author$project$TreeView$tree = function (model) { - var filteredSmartphoneData = $author$project$TreeView$filterSPData(model.data); - var limitedfilteredSmartphones = A2($elm$core$List$drop, 500, filteredSmartphoneData); - return A2( - $gampleman$elm_rosetree$Tree$sortBy, + var notfilteredSmartphoneNodeCount = $elm$core$List$length(model.data); + var filteredSmartphoneData = A2($author$project$TreeView$filterSPData, model, model.data); + var filteredSmartphoneNodeCount = $elm$core$List$length(filteredSmartphoneData); + var limitedfilteredSmartphones = A2($elm$core$List$drop, model.treeOption.dropCount, filteredSmartphoneData); + return _Utils_Tuple2( A2( - $elm$core$Basics$composeR, - $gampleman$elm_rosetree$Tree$label, - function ($) { - return $.name; - }), - A3( - $gampleman$elm_rosetree$Tree$sumUp, - function (n) { - return {id: n.id, kind: $author$project$TreeView$Leaf, name: n.name, size: n.size}; - }, - F2( - function (node, children) { - return { - id: node.id, - kind: $author$project$TreeView$Node, - name: node.name, - size: $elm$core$List$sum( - A2( - $elm$core$List$map, - function ($) { - return $.size; - }, - children)) - }; - }), + $gampleman$elm_rosetree$Tree$sortBy, A2( - $elm$core$Result$withDefault, - $gampleman$elm_rosetree$Tree$singleton( - {id: '-1', name: 'Smartphone', size: 0}), + $elm$core$Basics$composeR, + $gampleman$elm_rosetree$Tree$label, + function ($) { + return $.name; + }), + A3( + $gampleman$elm_rosetree$Tree$sumUp, + function (n) { + return {id: n.id, kind: $author$project$TreeView$Leaf, name: n.name, size: n.size}; + }, + F2( + function (node, children) { + return { + id: node.id, + kind: $author$project$TreeView$Node, + name: node.name, + size: $elm$core$List$sum( + A2( + $elm$core$List$map, + function ($) { + return $.size; + }, + children)) + }; + }), A2( - $gampleman$elm_rosetree$Tree$stratifyWithPath, - { - createMissingNode: function (path) { - return { - id: '-1', - name: A2($elm$core$String$join, '.', path), - size: 0 - }; + $elm$core$Result$withDefault, + $gampleman$elm_rosetree$Tree$singleton( + {id: '-1', name: 'Smartphone', size: 0}), + A2( + $gampleman$elm_rosetree$Tree$stratifyWithPath, + { + createMissingNode: function (path) { + return { + id: '-1', + name: A2($elm$core$String$join, '.', path), + size: 0 + }; + }, + path: function (item) { + return A2($elm$core$String$split, '.', item.name); + } }, - path: function (item) { - return A2($elm$core$String$split, '.', item.name); - } - }, - $author$project$TreeView$getTreeData(limitedfilteredSmartphones))))); + $author$project$TreeView$getTreeData(limitedfilteredSmartphones))))), + _Utils_Tuple2(notfilteredSmartphoneNodeCount, filteredSmartphoneNodeCount)); }; var $author$project$TreeView$layedOut = function (model) { - return A3( - $gampleman$elm_rosetree$Tree$sumUp, - function (n) { - return { - bbox: {height: n.height, width: n.width, x: n.x, y: n.y}, - height: n.height, - node: n.node, - width: n.width, - x: n.x, - y: n.y - }; - }, - F2( - function (n, c) { + var treeModelInfo = $author$project$TreeView$tree(model); + var treeNodeCounts = treeModelInfo.b; + var treeModel = treeModelInfo.a; + return _Utils_Tuple2( + A3( + $gampleman$elm_rosetree$Tree$sumUp, + function (n) { return { - bbox: A3( - $elm$core$List$foldl, - F2( - function (item, t) { - return A2($author$project$TreeView$maxBBoxes, item.bbox, t); - }), - {height: n.height, width: n.width, x: n.x, y: n.y}, - c), + bbox: {height: n.height, width: n.width, x: n.x, y: n.y}, height: n.height, node: n.node, width: n.width, x: n.x, y: n.y }; - }), - A2( - $gampleman$elm_visualization$Hierarchy$tidy, - _List_fromArray( - [ - $gampleman$elm_visualization$Hierarchy$nodeSize( - function (_v0) { - var kind = _v0.kind; - var size = _v0.size; - if (kind.$ === 'Leaf') { - return _Utils_Tuple2( - $elm$core$Basics$sqrt(size) / 1.1, - $elm$core$Basics$sqrt(size) * 1.1); - } else { - return _Utils_Tuple2( - $elm$core$Basics$sqrt(size) * 1.05, - $elm$core$Basics$sqrt(size) / 1.05); - } - }), - $gampleman$elm_visualization$Hierarchy$parentChildMargin(900), - $gampleman$elm_visualization$Hierarchy$peerMargin(60), - A2($gampleman$elm_visualization$Hierarchy$size, $author$project$TreeView$w - ($author$project$TreeView$padding * 2), $author$project$TreeView$h - ($author$project$TreeView$padding * 2)) - ]), - $author$project$TreeView$tree(model))); + }, + F2( + function (n, c) { + return { + bbox: A3( + $elm$core$List$foldl, + F2( + function (item, t) { + return A2($author$project$TreeView$maxBBoxes, item.bbox, t); + }), + {height: n.height, width: n.width, x: n.x, y: n.y}, + c), + height: n.height, + node: n.node, + width: n.width, + x: n.x, + y: n.y + }; + }), + A2( + $gampleman$elm_visualization$Hierarchy$tidy, + _List_fromArray( + [ + $gampleman$elm_visualization$Hierarchy$nodeSize( + function (_v0) { + var kind = _v0.kind; + var size = _v0.size; + if (kind.$ === 'Leaf') { + return _Utils_Tuple2( + $elm$core$Basics$sqrt(size) / 1.1, + $elm$core$Basics$sqrt(size) * 1.1); + } else { + return _Utils_Tuple2( + $elm$core$Basics$sqrt(size) * 1.05, + $elm$core$Basics$sqrt(size) / 1.05); + } + }), + $gampleman$elm_visualization$Hierarchy$parentChildMargin(900), + $gampleman$elm_visualization$Hierarchy$peerMargin(60), + A2($gampleman$elm_visualization$Hierarchy$size, $author$project$TreeView$w - ($author$project$TreeView$padding * 2), $author$project$TreeView$h - ($author$project$TreeView$padding * 2)) + ]), + treeModel)), + treeNodeCounts); }; var $gampleman$elm_rosetree$Tree$breadthFirstFoldHelp = F5( function (f, acc, parents, trees, nextSets) { @@ -15566,99 +15690,196 @@ var $elm_community$typed_svg$TypedSvg$Attributes$InPx$width = function (value) { return $elm_community$typed_svg$TypedSvg$Attributes$width( $elm_community$typed_svg$TypedSvg$Types$px(value)); }; -var $author$project$TreeView$viewTree = function (model) { - return A2( - $elm_community$typed_svg$TypedSvg$svg, - _List_fromArray( - [ - A4($elm_community$typed_svg$TypedSvg$Attributes$viewBox, 0, 0, $author$project$TreeView$w, $author$project$TreeView$h), - $elm_community$typed_svg$TypedSvg$Attributes$width( - $elm_community$typed_svg$TypedSvg$Types$Percent(100)), - $elm_community$typed_svg$TypedSvg$Attributes$height( - $elm_community$typed_svg$TypedSvg$Types$Percent(100)) - ]), - _List_fromArray( - [ - A2( - $elm_community$typed_svg$TypedSvg$rect, - A2( - $elm$core$List$cons, - $elm_community$typed_svg$TypedSvg$Attributes$InPx$width($author$project$TreeView$w), +var $author$project$TreeView$createViewTree = function (model) { + var layoutTreeInfo = $author$project$TreeView$layedOut(model); + var nodeCounts = layoutTreeInfo.b; + var layoutTree = layoutTreeInfo.a; + return _Utils_Tuple2( + A2( + $elm_community$typed_svg$TypedSvg$svg, + _List_fromArray( + [ + A4($elm_community$typed_svg$TypedSvg$Attributes$viewBox, 0, 0, $author$project$TreeView$w, $author$project$TreeView$h), + $elm_community$typed_svg$TypedSvg$Attributes$width( + $elm_community$typed_svg$TypedSvg$Types$Percent(100)), + $elm_community$typed_svg$TypedSvg$Attributes$height( + $elm_community$typed_svg$TypedSvg$Types$Percent(100)) + ]), + _List_fromArray( + [ + A2( + $elm_community$typed_svg$TypedSvg$rect, A2( $elm$core$List$cons, - $elm_community$typed_svg$TypedSvg$Attributes$InPx$height($author$project$TreeView$h), + $elm_community$typed_svg$TypedSvg$Attributes$InPx$width($author$project$TreeView$w), A2( $elm$core$List$cons, - $elm_community$typed_svg$TypedSvg$Attributes$fill( - $elm_community$typed_svg$TypedSvg$Types$Paint( - A4($avh4$elm_color$Color$rgba, 0, 0, 0, 0))), + $elm_community$typed_svg$TypedSvg$Attributes$InPx$height($author$project$TreeView$h), A2( $elm$core$List$cons, - $elm_community$typed_svg$TypedSvg$Attributes$stroke( - $elm_community$typed_svg$TypedSvg$Types$Paint($avh4$elm_color$Color$black)), + $elm_community$typed_svg$TypedSvg$Attributes$fill( + $elm_community$typed_svg$TypedSvg$Types$Paint( + A4($avh4$elm_color$Color$rgba, 0, 0, 0, 0))), A2( $elm$core$List$cons, - $elm_community$typed_svg$TypedSvg$Attributes$InPx$strokeWidth(2), - A2($gampleman$elm_visualization$Zoom$events, model.treeOption.zoomOption, $author$project$TreeView$ZoomMsg)))))), + $elm_community$typed_svg$TypedSvg$Attributes$stroke( + $elm_community$typed_svg$TypedSvg$Types$Paint($avh4$elm_color$Color$black)), + A2( + $elm$core$List$cons, + $elm_community$typed_svg$TypedSvg$Attributes$InPx$strokeWidth(2), + A2($gampleman$elm_visualization$Zoom$events, model.treeOption.zoomOption, $author$project$TreeView$ZoomMsg)))))), + _List_Nil), + A2( + $elm_community$typed_svg$TypedSvg$g, + _List_fromArray( + [ + $gampleman$elm_visualization$Zoom$transform(model.treeOption.zoomOption) + ]), + _List_fromArray( + [ + A2( + $elm_community$typed_svg$TypedSvg$g, + _List_fromArray( + [ + $elm_community$typed_svg$TypedSvg$Attributes$transform( + _List_fromArray( + [ + A2($elm_community$typed_svg$TypedSvg$Types$Translate, $author$project$TreeView$padding, $author$project$TreeView$padding) + ])) + ]), + _List_fromArray( + [ + function (p) { + return A2( + $folkertdev$one_true_path_experiment$Path$element, + p, + _List_fromArray( + [ + $elm_community$typed_svg$TypedSvg$Attributes$fill($elm_community$typed_svg$TypedSvg$Types$PaintNone), + $elm_community$typed_svg$TypedSvg$Attributes$stroke( + $elm_community$typed_svg$TypedSvg$Types$Paint( + A3($avh4$elm_color$Color$rgb, 0.3, 0.3, 0.3))), + $elm_community$typed_svg$TypedSvg$Attributes$style('vector-effect: non-scaling-stroke'), + $elm_community$typed_svg$TypedSvg$Attributes$pointerEvents('none') + ])); + }( + A2( + $elm$core$List$map, + function (_v0) { + var from = _v0.a; + var to = _v0.b; + return $gampleman$elm_visualization$Shape$bumpYCurve( + _List_fromArray( + [ + _Utils_Tuple2(from.x + (from.width / 2), from.y + from.height), + _Utils_Tuple2(to.x + (to.width / 2), to.y + (to.height * 0.1)) + ])); + }, + $gampleman$elm_rosetree$Tree$links(layoutTree))), + A2( + $elm_community$typed_svg$TypedSvg$g, + _List_Nil, + A2( + $elm$core$List$map, + $author$project$TreeView$label, + $gampleman$elm_rosetree$Tree$toList(layoutTree))) + ])) + ])) + ])), + nodeCounts); +}; +var $elm$core$Set$fromList = function (list) { + return A3($elm$core$List$foldl, $elm$core$Set$insert, $elm$core$Set$empty, list); +}; +var $author$project$TreeView$viewTree = function (model) { + var treeViewInfo = $author$project$TreeView$createViewTree(model); + var treeView = treeViewInfo.a; + var otherFilterValues = _List_fromArray( + ['all', 'true', 'false']); + var nodeCounts = treeViewInfo.b; + var brandList = $elm$core$Set$toList( + $elm$core$Set$fromList( + A2( + $elm$core$List$filterMap, + function ($) { + return $.brand; + }, + model.data))); + var brandFilterValues = A2($elm$core$List$cons, 'all', brandList); + return A2( + $elm$html$Html$div, + _List_Nil, + _List_fromArray( + [ + $elm$html$Html$text( + 'Knoten im Baum: ' + ($elm$core$Debug$toString(nodeCounts.b) + (' | Knoten gesamt: ' + $elm$core$Debug$toString(nodeCounts.a)))), + A2($elm$html$Html$br, _List_Nil, _List_Nil), + $elm$html$Html$text( + 'manuelle entfernte Knoten: ' + $elm$core$Debug$toString(model.treeOption.dropCount)), + A2($elm$html$Html$br, _List_Nil, _List_Nil), + $elm$html$Html$text('Anzahl zu entfernender Knoten: '), + A2( + $elm$html$Html$input, + _List_fromArray( + [ + $elm$html$Html$Events$onInput($author$project$TreeView$SetDropCountInput) + ]), _List_Nil), A2( - $elm_community$typed_svg$TypedSvg$g, + $elm$html$Html$button, _List_fromArray( [ - $gampleman$elm_visualization$Zoom$transform(model.treeOption.zoomOption) + $elm$html$Html$Events$onClick($author$project$TreeView$SetDropCount) ]), _List_fromArray( [ - A2( - $elm_community$typed_svg$TypedSvg$g, - _List_fromArray( - [ - $elm_community$typed_svg$TypedSvg$Attributes$transform( - _List_fromArray( - [ - A2($elm_community$typed_svg$TypedSvg$Types$Translate, $author$project$TreeView$padding, $author$project$TreeView$padding) - ])) - ]), - _List_fromArray( - [ - function (p) { - return A2( - $folkertdev$one_true_path_experiment$Path$element, - p, - _List_fromArray( - [ - $elm_community$typed_svg$TypedSvg$Attributes$fill($elm_community$typed_svg$TypedSvg$Types$PaintNone), - $elm_community$typed_svg$TypedSvg$Attributes$stroke( - $elm_community$typed_svg$TypedSvg$Types$Paint( - A3($avh4$elm_color$Color$rgb, 0.3, 0.3, 0.3))), - $elm_community$typed_svg$TypedSvg$Attributes$style('vector-effect: non-scaling-stroke'), - $elm_community$typed_svg$TypedSvg$Attributes$pointerEvents('none') - ])); - }( - A2( - $elm$core$List$map, - function (_v0) { - var from = _v0.a; - var to = _v0.b; - return $gampleman$elm_visualization$Shape$bumpYCurve( - _List_fromArray( - [ - _Utils_Tuple2(from.x + (from.width / 2), from.y + from.height), - _Utils_Tuple2(to.x + (to.width / 2), to.y + (to.height * 0.1)) - ])); - }, - $gampleman$elm_rosetree$Tree$links( - $author$project$TreeView$layedOut(model)))), - A2( - $elm_community$typed_svg$TypedSvg$g, - _List_Nil, - A2( - $elm$core$List$map, - $author$project$TreeView$label, - $gampleman$elm_rosetree$Tree$toList( - $author$project$TreeView$layedOut(model)))) - ])) - ])) + $elm$html$Html$text('Entferne Knoten') + ])), + $elm$html$Html$text(' Brand: '), + A2( + $elm$html$Html$select, + _List_fromArray( + [ + $elm$html$Html$Events$onInput($author$project$TreeView$SetBrandTree) + ]), + A2( + $elm$core$List$map, + $author$project$TreeView$createSelectorOptions(model.treeOption.selectedFilter.brand), + brandFilterValues)), + $elm$html$Html$text(' 5G: '), + A2( + $elm$html$Html$select, + _List_fromArray( + [ + $elm$html$Html$Events$onInput($author$project$TreeView$Set5GTree) + ]), + A2( + $elm$core$List$map, + $author$project$TreeView$createSelectorOptions(model.treeOption.selectedFilter.g5), + otherFilterValues)), + $elm$html$Html$text(' NFC: '), + A2( + $elm$html$Html$select, + _List_fromArray( + [ + $elm$html$Html$Events$onInput($author$project$TreeView$SetNFCTree) + ]), + A2( + $elm$core$List$map, + $author$project$TreeView$createSelectorOptions(model.treeOption.selectedFilter.nfc), + otherFilterValues)), + $elm$html$Html$text(' IR-Blaster: '), + A2( + $elm$html$Html$select, + _List_fromArray( + [ + $elm$html$Html$Events$onInput($author$project$TreeView$SetIRBlasterTree) + ]), + A2( + $elm$core$List$map, + $author$project$TreeView$createSelectorOptions(model.treeOption.selectedFilter.ir_blaster), + otherFilterValues)), + treeView ])); }; var $author$project$Main$view = function (model) { diff --git a/src/Main.elm b/src/Main.elm index 5502ff6..38995cd 100644 --- a/src/Main.elm +++ b/src/Main.elm @@ -59,6 +59,14 @@ init _ = Zoom.init { width = TreeView.w, height = TreeView.h } |> Zoom.scaleExtent 1 100 |> Zoom.translateExtent ( ( 0, 0 ), ( TreeView.w, TreeView.h ) ) + , dropCount = 0 + , inputDropCount = "" + , selectedFilter = + { brand = "all" + , g5 = "false" + , nfc = "false" + , ir_blaster = "false" + } } { modelID1 = "0" , modelID2 = "1019" @@ -131,7 +139,7 @@ update msg model = | scatterplotOptions = { attribute1 = model.scatterplotOptions.attribute1 , attribute2 = value - , att1List = [] + , att1List = model.scatterplotOptions.att1List , att2List = createAttList model value } } @@ -177,11 +185,42 @@ update msg model = , Cmd.none ) + ParallelCoordinatesMsg (SetScatterPlotFromParallelPlot att1 att2) -> + ( { model + | scatterplotOptions = + { attribute1 = att1 + , attribute2 = att2 + , att1List = createAttList model att1 + , att2List = createAttList model att2 + } + , plotVisible = { scatterPlot = True, parallelCoordinatesPlot = False, treeView = False, starPlot = False } + } + , Cmd.none + ) + TreeViewMsg (ZoomMsg m) -> - ( { model | treeOption = { zoomOption = Zoom.update m model.treeOption.zoomOption } }, Cmd.none ) + ( { model + | treeOption = + { zoomOption = Zoom.update m model.treeOption.zoomOption + , dropCount = model.treeOption.dropCount + , inputDropCount = model.treeOption.inputDropCount + , selectedFilter = model.treeOption.selectedFilter + } + } + , Cmd.none + ) TreeViewMsg (Click t) -> - ( { model | treeOption = { zoomOption = TreeView.performZoom t model.treeOption.zoomOption } }, Cmd.none ) + ( { model + | treeOption = + { zoomOption = TreeView.performZoom t model.treeOption.zoomOption + , dropCount = model.treeOption.dropCount + , inputDropCount = model.treeOption.inputDropCount + , selectedFilter = model.treeOption.selectedFilter + } + } + , Cmd.none + ) TreeViewMsg (SetStarPlotFromTree id) -> ( { model @@ -212,8 +251,109 @@ update msg model = , Cmd.none ) + TreeViewMsg (SetDropCountInput value) -> + ( { model + | treeOption = + { zoomOption = model.treeOption.zoomOption + , dropCount = model.treeOption.dropCount + , inputDropCount = value + , selectedFilter = model.treeOption.selectedFilter + } + } + , Cmd.none + ) + + TreeViewMsg SetDropCount -> + ( { model + | treeOption = + { zoomOption = model.treeOption.zoomOption + , dropCount = Maybe.withDefault 0 (String.toInt model.treeOption.inputDropCount) + , inputDropCount = model.treeOption.inputDropCount + , selectedFilter = model.treeOption.selectedFilter + } + } + , Cmd.none + ) + + TreeViewMsg (SetBrandTree value) -> + ( { model + | treeOption = + { zoomOption = model.treeOption.zoomOption + , dropCount = model.treeOption.dropCount + , inputDropCount = model.treeOption.inputDropCount + , selectedFilter = + { brand = value + , g5 = model.treeOption.selectedFilter.g5 + , nfc = model.treeOption.selectedFilter.nfc + , ir_blaster = model.treeOption.selectedFilter.ir_blaster + } + } + } + , Cmd.none + ) + + TreeViewMsg (Set5GTree value) -> + ( { model + | treeOption = + { zoomOption = model.treeOption.zoomOption + , dropCount = model.treeOption.dropCount + , inputDropCount = model.treeOption.inputDropCount + , selectedFilter = + { brand = model.treeOption.selectedFilter.brand + , g5 = value + , nfc = model.treeOption.selectedFilter.nfc + , ir_blaster = model.treeOption.selectedFilter.ir_blaster + } + } + } + , Cmd.none + ) + + TreeViewMsg (SetNFCTree value) -> + ( { model + | treeOption = + { zoomOption = model.treeOption.zoomOption + , dropCount = model.treeOption.dropCount + , inputDropCount = model.treeOption.inputDropCount + , selectedFilter = + { brand = model.treeOption.selectedFilter.brand + , g5 = model.treeOption.selectedFilter.g5 + , nfc = value + , ir_blaster = model.treeOption.selectedFilter.ir_blaster + } + } + } + , Cmd.none + ) + + TreeViewMsg (SetIRBlasterTree value) -> + ( { model + | treeOption = + { zoomOption = model.treeOption.zoomOption + , dropCount = model.treeOption.dropCount + , inputDropCount = model.treeOption.inputDropCount + , selectedFilter = + { brand = model.treeOption.selectedFilter.brand + , g5 = model.treeOption.selectedFilter.g5 + , nfc = model.treeOption.selectedFilter.nfc + , ir_blaster = value + } + } + } + , Cmd.none + ) + ZooomMsg m -> - ( { model | treeOption = { zoomOption = Zoom.update m model.treeOption.zoomOption } }, Cmd.none ) + ( { model + | treeOption = + { zoomOption = Zoom.update m model.treeOption.zoomOption + , dropCount = model.treeOption.dropCount + , inputDropCount = model.treeOption.inputDropCount + , selectedFilter = model.treeOption.selectedFilter + } + } + , Cmd.none + ) StarplotMsg Nothing1 -> ( model @@ -306,13 +446,13 @@ createAttList model att = else if att == "NumCores" then List.map .num_cores model.data - else if att == "ProcessorSpeed" then + else if att == "Processor Speed" then List.map .processor_speed model.data else if att == "Battery" then List.map .battery model.data - else if att == "FastCharging" then + else if att == "Fast Charging" then List.map .fast_charging model.data else if att == "Memory" then @@ -321,10 +461,10 @@ createAttList model att = else if att == "Ram" then List.map .ram model.data - else if att == "ScreenSize" then + else if att == "Screen Size" then List.map .screen_size model.data - else if att == "RefreshRate" then + else if att == "Refresh Rate" then List.map .refresh_rate model.data else diff --git a/src/Model.elm b/src/Model.elm index 6018ef5..548dac2 100644 --- a/src/Model.elm +++ b/src/Model.elm @@ -37,6 +37,17 @@ type alias ParallelPlotOption = type alias TreeOption = { zoomOption : Zoom + , dropCount : Int + , inputDropCount : String + , selectedFilter : FilterOptions + } + + +type alias FilterOptions = + { brand : String + , g5 : String + , nfc : String + , ir_blaster : String } diff --git a/src/ParallelCoordinates.elm b/src/ParallelCoordinates.elm index 33d3acb..2bd2c2d 100644 --- a/src/ParallelCoordinates.elm +++ b/src/ParallelCoordinates.elm @@ -87,7 +87,7 @@ parallelCoordinatesPlot model smartphonesList = xScale (List.map toFloat (List.range 0 dimLen)) yaxis = - List.map2 (createYAxis xScaleLocal) yScaleLocalsWithIndex multidimStrings + List.map2 (createYAxis xScaleLocal model) yScaleLocalsWithIndex multidimStrings yValue1 = Maybe.withDefault [] <| List.head yValues @@ -166,8 +166,8 @@ createLine path = ] -createYAxis : ContinuousScale Float -> ( Int, ContinuousScale Float ) -> String -> Svg Msg -createYAxis scaleX scaleY text = +createYAxis : ContinuousScale Float -> Model -> ( Int, ContinuousScale Float ) -> String -> Svg Msg +createYAxis scaleX model scaleY text = let index = Tuple.first scaleY @@ -188,6 +188,12 @@ createYAxis scaleX scaleY text = else index + 1 + + att1 = + Maybe.withDefault "Price" <| List.head <| List.drop index model.parallelPlotOption.orderedLabels + + att2 = + Maybe.withDefault "Price" <| List.head <| List.drop indexafter model.parallelPlotOption.orderedLabels in g [ transform [ Translate (Scale.convert scaleX indexF) axisPaddig ], class [ "axis" ] ] [ g [] [ yAxis (Tuple.second scaleY) ] @@ -198,7 +204,7 @@ createYAxis scaleX scaleY text = [ x 10, y -30, textAnchor AnchorStart, fontSize <| Px 10, onClick (ChangeOrder index indexafter) ] [ Html.text ">>>" ] , text_ - [ y -10, textAnchor AnchorMiddle, fontSize <| Px 14 ] + [ y -10, textAnchor AnchorMiddle, fontSize <| Px 14, onClick (SetScatterPlotFromParallelPlot att1 att2) ] [ Html.text text ] ] @@ -231,9 +237,8 @@ filterSPData smartphone = smartphoneList = List.filterMap mapToSPData smartphone - {- carsInType = - List.filter (carInCarType carType) carDataList - -} + -- smartphoneFromBrand = + -- List.filter (isSmartphoneFromBrand brand) smartphoneList in smartphoneList @@ -350,3 +355,4 @@ type alias MultiDimData = type Msg = ChangeOrder Int Int + | SetScatterPlotFromParallelPlot String String diff --git a/src/Scatterplot.elm b/src/Scatterplot.elm index 8619830..84c4639 100644 --- a/src/Scatterplot.elm +++ b/src/Scatterplot.elm @@ -2,7 +2,7 @@ module Scatterplot exposing (..) import Axis exposing (..) import Html exposing (Html, option) -import Html.Attributes exposing (value) +import Html.Attributes exposing (selected, value) import Html.Events exposing (onClick, onInput) import Model exposing (Model) import Scale exposing (ContinuousScale) @@ -238,16 +238,36 @@ viewScatterplot model = filterSmartphonesXY model att1List att2List in Html.div [] - [ Html.b [] [ Html.text "Attribut 1: " ] - , attributeSelector 1 - , Html.b [] [ Html.text " Attribut 2: " ] - , attributeSelector 2 + [ Html.b [] [ Html.text "x-Achse: " ] + , attributeSelector 1 model + , Html.b [] [ Html.text " y-Achse: " ] + , attributeSelector 2 model , scatterplot filteredSmartphoneData ] -attributeSelector : Int -> Html Msg -attributeSelector attNr = +attributeSelector : Int -> Model -> Html Msg +attributeSelector attNr model = + let + attributes = + [ "Price" + , "Rating" + , "NumCores" + , "Processor Speed" + , "Battery" + , "Fast Charging" + , "Memory" + , "RAM" + , "Screen Size" + , "Refresh Rate" + ] + + att1 = + model.scatterplotOptions.attribute1 + + att2 = + model.scatterplotOptions.attribute2 + in Html.select [ onInput (if attNr == 1 then @@ -257,28 +277,23 @@ attributeSelector attNr = ChangeAttribute2 ) ] - ((if attNr == 1 then - [ option [ value "Price" ] [ Html.text "Price" ] - , option [ value "Rating" ] [ Html.text "Rating" ] - ] + (if attNr == 1 then + List.map (createSelectorOptions att1) attributes - else - [ option [ value "Rating" ] [ Html.text "Rating" ] - , option [ value "Price" ] [ Html.text "Price" ] - ] - ) - ++ [ option [ value "NumCores" ] [ Html.text "NumCores" ] - , option [ value "ProcessorSpeed" ] [ Html.text "ProcessorSpeed" ] - , option [ value "Battery" ] [ Html.text "Battery" ] - , option [ value "FastCharging" ] [ Html.text "FastCharging" ] - , option [ value "Memory" ] [ Html.text "Memory" ] - , option [ value "Ram" ] [ Html.text "Ram" ] - , option [ value "ScreenSize" ] [ Html.text "ScreenSize" ] - , option [ value "RefreshRate" ] [ Html.text "RefreshRate" ] - ] + else + List.map (createSelectorOptions att2) attributes ) +createSelectorOptions : String -> String -> Html Msg +createSelectorOptions select att = + if select == att then + option [ value att, selected True ] [ Html.text att ] + + else + option [ value att ] [ Html.text att ] + + type Msg = ChangeAttribute1 String | ChangeAttribute2 String diff --git a/src/TreeView.elm b/src/TreeView.elm index 8d1f4a3..b9f8eb8 100644 --- a/src/TreeView.elm +++ b/src/TreeView.elm @@ -2,12 +2,16 @@ module TreeView exposing (..) import Color import Curve +import Debug exposing (toString) import ExtendedFunctions exposing (map10) import Hierarchy -import Html.Events exposing (onClick) +import Html exposing (Html, br, button, div, input, option, select, text) +import Html.Attributes exposing (selected, value) +import Html.Events exposing (onClick, onInput) import List.Extra import Model exposing (Model) import Path +import Set import Shape import SmartPhoneType exposing (Smartphone) import Tree exposing (Tree) @@ -35,9 +39,19 @@ padding = 30 -layedOut : Model -> Tree Datum +layedOut : Model -> ( Tree Datum, ( Int, Int ) ) layedOut model = - Hierarchy.tidy + let + treeModelInfo = + tree model + + treeModel = + Tuple.first treeModelInfo + + treeNodeCounts = + Tuple.second treeModelInfo + in + ( Hierarchy.tidy [ Hierarchy.nodeSize (\{ kind, size } -> case kind of @@ -51,7 +65,7 @@ layedOut model = , Hierarchy.peerMargin 60 , Hierarchy.size (w - padding * 2) (h - padding * 2) ] - (tree model) + treeModel |> Tree.sumUp (\n -> { x = n.x @@ -71,6 +85,8 @@ layedOut model = , bbox = List.foldl (\item t -> maxBBoxes item.bbox t) { x = n.x, y = n.y, width = n.width, height = n.height } c } ) + , treeNodeCounts + ) maxBBoxes : @@ -106,6 +122,12 @@ type Msg = ZoomMsg Zoom.OnZoom | Click Datum | SetStarPlotFromTree String + | SetDropCountInput String + | SetDropCount + | SetBrandTree String + | Set5GTree String + | SetNFCTree String + | SetIRBlasterTree String performZoom : Datum -> Zoom -> Zoom @@ -139,9 +161,72 @@ performZoom t = Zoom.setTransform (Zoom.animatedAround p) { scale = scale, translate = translate } -viewTree : Model -> Svg Msg +viewTree : Model -> Html Msg viewTree model = - svg + let + brandList = + Set.toList <| Set.fromList <| List.filterMap .brand model.data + + brandFilterValues = + "all" :: brandList + + otherFilterValues = + [ "all", "true", "false" ] + + treeViewInfo = + createViewTree model + + treeView = + Tuple.first treeViewInfo + + nodeCounts = + Tuple.second treeViewInfo + in + div [] + [ text ("Knoten im Baum: " ++ (toString <| Tuple.second nodeCounts) ++ " | Knoten gesamt: " ++ (toString <| Tuple.first nodeCounts)) + , br [] [] + , text ("manuelle entfernte Knoten: " ++ toString model.treeOption.dropCount) + , br [] [] + , text "Anzahl zu entfernender Knoten: " + , input [ onInput SetDropCountInput ] [] + , button [ onClick SetDropCount ] [ text "Entferne Knoten" ] + , text " Brand: " + , select [ onInput SetBrandTree ] (List.map (createSelectorOptions model.treeOption.selectedFilter.brand) brandFilterValues) + , text " 5G: " + , select [ onInput Set5GTree ] + (List.map (createSelectorOptions model.treeOption.selectedFilter.g5) otherFilterValues) + , text " NFC: " + , select [ onInput SetNFCTree ] + (List.map (createSelectorOptions model.treeOption.selectedFilter.nfc) otherFilterValues) + , text " IR-Blaster: " + , select [ onInput SetIRBlasterTree ] + (List.map (createSelectorOptions model.treeOption.selectedFilter.ir_blaster) otherFilterValues) + , treeView + ] + + +createSelectorOptions : String -> String -> Html Msg +createSelectorOptions select valueOption = + if select == valueOption then + option [ value valueOption, selected True ] [ Html.text valueOption ] + + else + option [ value valueOption ] [ Html.text valueOption ] + + +createViewTree : Model -> ( Svg Msg, ( Int, Int ) ) +createViewTree model = + let + layoutTreeInfo = + layedOut model + + layoutTree = + Tuple.first layoutTreeInfo + + nodeCounts = + Tuple.second layoutTreeInfo + in + ( svg [ viewBox 0 0 w h , TypedSvg.Attributes.width <| TypedSvg.Types.Percent 100 , TypedSvg.Attributes.height <| TypedSvg.Types.Percent 100 @@ -157,7 +242,7 @@ viewTree model = [] , g [ Zoom.transform model.treeOption.zoomOption ] [ g [ transform [ Translate padding padding ] ] - [ layedOut model + [ layoutTree |> Tree.links |> List.map (\( from, to ) -> @@ -174,13 +259,15 @@ viewTree model = , pointerEvents "none" ] ) - , layedOut model + , layoutTree |> Tree.toList |> List.map label |> g [] ] ] ] + , nodeCounts + ) label : Datum -> Svg Msg @@ -293,20 +380,22 @@ type Kind | Node -tree : Model -> Tree { name : String, id : String, kind : Kind, size : Float } +tree : Model -> ( Tree { name : String, id : String, kind : Kind, size : Float }, ( Int, Int ) ) tree model = let filteredSmartphoneData = - filterSPData model.data + filterSPData model model.data - -- lengthFSP = - -- List.length filteredSmartphoneData - limitedfilteredSmartphones = - List.drop 500 filteredSmartphoneData + notfilteredSmartphoneNodeCount = + List.length model.data + + filteredSmartphoneNodeCount = + List.length filteredSmartphoneData - -- drop 500 Smartphones später auswählen Attribute + limitedfilteredSmartphones = + List.drop model.treeOption.dropCount filteredSmartphoneData in - Tree.stratifyWithPath + ( Tree.stratifyWithPath { path = \item -> String.split "." item.name , createMissingNode = \path -> { name = String.join "." path, id = "-1", size = 0 } } @@ -317,6 +406,8 @@ tree model = { name = node.name, id = node.id, size = List.sum (List.map .size children), kind = Node } ) |> Tree.sortBy (Tree.label >> .name) + , ( notfilteredSmartphoneNodeCount, filteredSmartphoneNodeCount ) + ) getTreeData : List Smartphone -> List { name : String, id : String, size : Float } @@ -332,15 +423,76 @@ getTreeString smartphone = } -filterSPData : List Smartphone -> List Smartphone -filterSPData smartphone = +filterSPData : Model -> List Smartphone -> List Smartphone +filterSPData model smartphone = let smartphoneList = - List.filterMap mapToSPData smartphone + List.filter (hasIRBlaster model) <| + List.filter (hasNFC model) <| + List.filter (has5G model) <| + List.filter (fromBrand model) <| + List.filterMap mapToSPData smartphone in smartphoneList +fromBrand : Model -> Smartphone -> Bool +fromBrand model smartphone = + if model.treeOption.selectedFilter.brand == Maybe.withDefault "" smartphone.brand || model.treeOption.selectedFilter.brand == "all" then + True + + else + False + + +has5G : Model -> Smartphone -> Bool +has5G model smartphone = + if + (model.treeOption.selectedFilter.g5 == "true" && Maybe.withDefault False smartphone.g5) + || model.treeOption.selectedFilter.g5 + == "all" + then + True + + else if model.treeOption.selectedFilter.g5 == "false" && not (Maybe.withDefault True smartphone.g5) then + True + + else + False + + +hasNFC : Model -> Smartphone -> Bool +hasNFC model smartphone = + if + (model.treeOption.selectedFilter.nfc == "true" && Maybe.withDefault False smartphone.nfc) + || model.treeOption.selectedFilter.nfc + == "all" + then + True + + else if model.treeOption.selectedFilter.nfc == "false" && not (Maybe.withDefault True smartphone.nfc) then + True + + else + False + + +hasIRBlaster : Model -> Smartphone -> Bool +hasIRBlaster model smartphone = + if + (model.treeOption.selectedFilter.ir_blaster == "true" && Maybe.withDefault False smartphone.ir_blaster) + || model.treeOption.selectedFilter.ir_blaster + == "all" + then + True + + else if model.treeOption.selectedFilter.ir_blaster == "false" && not (Maybe.withDefault True smartphone.ir_blaster) then + True + + else + False + + mapToSPData : Smartphone -> Maybe Smartphone mapToSPData smartphone = map10 -- GitLab