问题
I have a dimension with the values A,B,C,D.
I would like to create a selectMenu with dc.js, where
the value A is selected by default
only one value can be selected (no mulit-selection)
always one value has to be selected
a) I used .multiple(false)
and expected that a single value is selected by default.
However, the default state of the menu is to select all available options (=no filtering).
b) I also tried to set the promptTitle
and promptValue
to my wanted initial value A.
Also see doc at https://dc-js.github.io/dc.js/docs/html/SelectMenu.html
However, then the option A is displayed twice (and applying the initial value does not work either):
let typeSelection = dc.selectMenu('#type');
typeSelection.dimension(typeDim)
.multiple(false)
.group(typeGroupCount)
.title(d => d.key)
.promptText('A')
.promptValue('A')
.controlsUseVisibility(true);
c) I also tried to use the method filterDisplayed
. However, only the single options are passed as arguments and there does not seem to be a way to disable the 'Select all' option here.
回答1:
A. Here is a manual implementation of a single selection combo box:
<div>
<label>Type</label>
<select id='type' style='padding:5px;'>
<option>A</option>
<option>B</option>
<option>C</option>
<option>D</option>
</select>
</div>
-
dc.renderAll();
d3.select('#type')
.on('change', applyTypeSelection);
applyTypeSelection();
function applyTypeSelection(){
let selectedType = d3.select('#type').node().value;
typeDim.filter(type => {
return type === selectedType;
});
dc.redrawAll();
}
B. Here is a full example for another approach. It is based on the pretransition
event that is used in the answer of the old duplicate question
Change text and remove Select All from dc.selectMenu
dc.selectMenu('#type')
.dimension(typeDim)
.multiple(false)
.group(typeGroupCount)
.title(d => d.key)
.on('pretransition', event => {
typeSelection.select('option[value=""]')
.remove();
})
.filter('A');
<html>
<head>
<title>dc demo</title>
<meta http-equiv='content-type' content='text/html; charset=UTF8'>
<!-- this demo is based on following tuturials:
https://www.tutorialspoint.com/dcjs/dcjs_introduction_to_d3js.htm
https://www.codeproject.com/articles/693841/making-dashboards-with-dc-js-part-1-using-crossfil
-->
<script src='https://d3js.org/d3.v4.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/crossfilter2/1.5.2/crossfilter.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/dc/3.1.8/dc.min.js'></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/dc/3.1.8/dc.css" />
</head>
<body>
<div style="font-family:arial;">
<div style="float:left;padding:10px;">
<div >
<label>Number of colors:</label>
<div id='color-chart-count'></div>
</div>
<div>
<label>Value sum for colors:</label>
<div id='color-chart-value-sum'></div>
</div>
</div>
<div style="float:left;padding:10px;">
<div>
<label>Number of ages:</label>
<div id='age-chart-count'></div>
</div>
<div>
<label>Value sum for ages:</label>
<div id='age-chart-value-sum'></div>
</div>
</div>
<div style="float:left;padding:10px;">
<div>
<label>Type</label>
<div id="type"></div>
<!--
<select id='type' style='padding:5px;'>
<option>A</option>
<option>B</option>
<option>C</option>
<option>D</option>
</select>
-->
</div>
</div>
</div>
<div style="font-family:arial; float:left">
<label for='value-chart'>Values:</label>
<div id='value-chart'></div>
</div>
<script>
let data = [
{color: 'red', age: 1, type: 'A', value: 10},
{color: 'red', age: 1, type: 'B', value: 11},
{color: 'red', age: 1, type: 'C', value: 12},
{color: 'red', age: 1, type: 'D', value: 13},
{color: 'red', age: 2, type: 'A', value: 20},
{color: 'red', age: 2, type: 'B', value: 21},
{color: 'red', age: 2, type: 'C', value: 22},
{color: 'red', age: 2, type: 'D', value: 23},
{color: 'red', age: 3, type: 'A', value: 30},
{color: 'red', age: 3, type: 'B', value: 31},
{color: 'red', age: 3, type: 'C', value: 32},
{color: 'red', age: 3, type: 'D', value: 33},
{color: 'green', age: 1, type: 'A', value: 100},
{color: 'green', age: 1, type: 'B', value: 105},
{color: 'green', age: 1, type: 'C', value: 110},
{color: 'green', age: 1, type: 'D', value: 115},
{color: 'green', age: 2, type: 'A', value: 120},
{color: 'green', age: 2, type: 'B', value: 125},
{color: 'green', age: 2, type: 'C', value: 130},
{color: 'green', age: 2, type: 'D', value: 135},
{color: 'green', age: 3, type: 'A', value: 140},
{color: 'green', age: 3, type: 'B', value: 145},
{color: 'green', age: 3, type: 'C', value: 150},
{color: 'green', age: 3, type: 'D', value: 155},
{color: 'blue', age: 1, type: 'A', value: 300},
{color: 'blue', age: 1, type: 'B', value: 305},
{color: 'blue', age: 1, type: 'C', value: 310},
{color: 'blue', age: 1, type: 'D', value: 315},
{color: 'blue', age: 2, type: 'A', value: 320},
{color: 'blue', age: 2, type: 'B', value: 325},
{color: 'blue', age: 2, type: 'C', value: 330},
{color: 'blue', age: 2, type: 'D', value: 335},
{color: 'blue', age: 3, type: 'A', value: 340},
{color: 'blue', age: 3, type: 'B', value: 345},
{color: 'blue', age: 3, type: 'C', value: 350},
{color: 'blue', age: 3, type: 'D', value: 355},
];
//create instance of cross filter
let cf = crossfilter(data);
//define dimensions and groups
let colorDim = cf.dimension(d=> d.color);
let colorGroupCount = colorDim.group().reduceCount();
let colorGroupValueSum = colorDim.group().reduceSum(d => d.value);
let ageDim = cf.dimension(d=> d.age);
let ageGroupCount = ageDim.group().reduceCount();
let ageGroupValueSum = ageDim.group().reduceSum(d => d.value);
let typeDim = cf.dimension(d=> d.type);
let typeGroupCount = typeDim.group().reduceCount();
let typeGroupValueSum = typeDim.group().reduceSum(d => d.value);
let colorAgeDim = cf.dimension(d => [d.color, d.age]);
function reduceAdd(previous, current) {
if(current){
if(current.value !== null){
if(previous.sum === null){
previous.sum = current.value;
previous.count = 1;
} else {
previous.sum += current.value;
previous.count += 1;
}
}
}
return previous;
}
function reduceRemove(previous, current) {
if(current){
if(current.value !== null){
if(previous.sum !== null){
previous.sum -= current.value;
previous.count -= 1;
if(previous.count === 0){
previous.sum = null;
}
}
}
}
return previous;
}
function reduceInit(previous) {
return {
sum: null,
count: 0
};
}
let colorAgeGroup = colorAgeDim.group()
.reduce(reduceAdd, reduceRemove, reduceInit);
let filteredColorAgeGroup = removeMissingEntries(colorAgeGroup);
function removeMissingEntries(sourceGroup) {
return {
all:function () {
return sourceGroup.all().filter(function(d) {
return d.value.sum !== null;
});
}
};
}
let ordinalColors = ['red','green','blue'];
let ordinalAgeColors = ['lightgray','grey','#666666'];
let ordinalTypeColors = ['#ffff0020','#ffff0050','#ffff0090', '#ffff00'];
//color charts
let rgbColorScale = d3.scaleOrdinal().domain(ordinalColors).range(ordinalColors);
let colorChartCount = barChart('#color-chart-count')
.xAxisLabel('Color')
.x(d3.scaleBand().domain(ordinalColors))
.dimension(colorDim)
.yAxisLabel('Count')
.group(colorGroupCount)
.defineColors(rgbColorScale);
colorChartCount.yAxis().ticks(4);
barChart('#color-chart-value-sum')
.xAxisLabel('Color')
.x(d3.scaleBand().domain(ordinalColors))
.dimension(colorDim)
.yAxisLabel('Value sum')
.group(colorGroupValueSum)
.defineColors(rgbColorScale);
//age charts
let ageColorScale = d3.scaleOrdinal().domain([1,2,3]).range(ordinalAgeColors);
let ageChartCount = barChart('#age-chart-count')
.xAxisLabel('Age')
.x(d3.scaleLinear().domain([1,2,3]))
.dimension(ageDim)
.yAxisLabel('Count')
.group(ageGroupCount)
.defineColors(ageColorScale);
ageChartCount.yAxis().ticks(4);
barChart('#age-chart-value-sum')
.xAxisLabel('Age')
.x(d3.scaleLinear().domain([1,2,3]))
.dimension(colorDim)
.yAxisLabel('Value sum')
.group(ageGroupValueSum)
.defineColors(ageColorScale);
//type selection
//dc selection menu
//also see https://dc-js.github.io/dc.js/docs/html/SelectMenu.html#undefined
//and https://stackoverflow.com/questions/51746692/change-text-and-remove-select-all-from-dc-selectmenu
dc.selectMenu('#type')
.dimension(typeDim)
.multiple(false)
.group(typeGroupCount)
.title(d => d.key)
.on('pretransition', event => {
typeSelection.select('option[value=""]')
.remove();
})
.filter('A');
//helper functions
function barChart(elementSelector){
let barChart = dc.barChart(elementSelector)
.width(200)
.height(200)
.xUnits(dc.units.ordinal)
.margins({top:10,left:40,right:5,bottom:35})
.barPadding(0.1)
.outerPadding(0.1)
.transitionDuration(500);
barChart.defineColors = function(colorScale){
this.renderlet(chart=>{
chart.selectAll('rect.bar')
.each(function(d){
let isSelected = this.classList.contains('selected');
if(isSelected){
d3.select(this).attr('style', 'fill: ' + colorScale(d.x) + ';stroke-width:2;stroke:#39ff14');
} else {
d3.select(this).attr('style', 'fill: ' + colorScale(d.x));
}
});
});
return this;
}
return barChart;
}
//value chart
let chart = dc.seriesChart('#value-chart');
chart
.width(500)
.height(500)
.chart( c =>
dc.lineChart(c)
.renderDataPoints(true)
)
.xAxisLabel('Age')
.x(d3.scaleLinear().domain([1,3]))
.dimension(colorAgeDim)
.yAxisLabel('Value')
.elasticY(true)
.group(filteredColorAgeGroup)
.brushOn(false)
.clipPadding(10)
.mouseZoomable(true)
.seriesAccessor(d => d.key[0])
.keyAccessor(d => d.key[1])
.valueAccessor(d => {
return d.value.sum;
})
.ordinalColors(['blue','green','red'])
.legend(dc.legend().x(430).y(350));
dc.renderAll();
//dimensions can also be used for filtering:
//let color_red = colorDim.filter('red');
//let filterResult = JSON.stringify(color_red.top(Infinity)).replace('[','[\n\t').replace(/}\,/g,'},\n\t').replace(']','\n]');
//console.log(filterResult);
//let functionFilter = ageDim.filter(age => age === 2);
//let functionFilterResult = JSON.stringify(functionFilter.top(Infinity)).replace('[','[\n\t').replace(/}\,/g,'},\n\t').replace(']','\n]');
//console.log(functionFilterResult);
</script>
</body>
</html>
来源:https://stackoverflow.com/questions/59826057/how-to-remove-additional-prompt-option-select-all-from-dc-js-selectmenu