feat: add DimensionFilter widget with h_data_url, v_measure_url, show_data_url support
New Bricks widget that provides:
- Search input bar with configurable placeholder
- Horizontally scrollable dimension buttons with left/right arrows
- Vertically scrollable measure buttons on the left side
- Display area on the right side loading show_data_url with params
- Single-selection for both horizontal and vertical dimensions
- '全部' (All) option default selected for both axes
- filter_changed event on every selection/search change
- Registered via bricks.Factory.register('DimensionFilter', ...)
This commit is contained in:
parent
bc3c4525fd
commit
850d44ddb5
@ -7,6 +7,7 @@ SOURCES=" page_data_loader.js factory.js uitypesdef.js utils.js uitype.js \
|
|||||||
tree.js multiple_state_image.js dynamiccolumn.js form.js message.js conform.js \
|
tree.js multiple_state_image.js dynamiccolumn.js form.js message.js conform.js \
|
||||||
paging.js datagrid.js iframe.js cols.js echartsext.js \
|
paging.js datagrid.js iframe.js cols.js echartsext.js \
|
||||||
floaticonbar.js miniform.js wterm.js dynamicaccordion.js \
|
floaticonbar.js miniform.js wterm.js dynamicaccordion.js \
|
||||||
|
dimension_filter.js \
|
||||||
binstreaming.js streaming_audio.js vadtext.js rtc.js docxviewer.js \
|
binstreaming.js streaming_audio.js vadtext.js rtc.js docxviewer.js \
|
||||||
llm.js websocket.js datarow.js tabular.js continueaudio.js \
|
llm.js websocket.js datarow.js tabular.js continueaudio.js \
|
||||||
line.js pie.js bar.js gobang.js period.js iconbarpage.js \
|
line.js pie.js bar.js gobang.js period.js iconbarpage.js \
|
||||||
|
|||||||
245
bricks/dimension_filter.js
Normal file
245
bricks/dimension_filter.js
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
var bricks = window.bricks || {};
|
||||||
|
|
||||||
|
bricks.DimensionFilter = class extends bricks.VBox {
|
||||||
|
/*
|
||||||
|
options:
|
||||||
|
{
|
||||||
|
h_data_url: URL to fetch horizontal dimension labels/values,
|
||||||
|
v_measure_url: URL to fetch vertical dimension labels/values,
|
||||||
|
show_data_url: base URL to fetch display data,
|
||||||
|
search_placeholder: placeholder text for search input
|
||||||
|
}
|
||||||
|
events:
|
||||||
|
filter_changed: {h_id: string, v_id: string, keyword: string}
|
||||||
|
*/
|
||||||
|
constructor(opts){
|
||||||
|
opts.width = '100%';
|
||||||
|
opts.height = '100%';
|
||||||
|
opts.overflow = 'hidden';
|
||||||
|
super(opts);
|
||||||
|
this.selected_h_id = 'all';
|
||||||
|
this.selected_v_id = 'all';
|
||||||
|
this.search_keyword = '';
|
||||||
|
this.h_buttons = [];
|
||||||
|
this.v_buttons = [];
|
||||||
|
this.h_data = [];
|
||||||
|
this.v_data = [];
|
||||||
|
schedule_once(this.build_all.bind(this), 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
async build_all(){
|
||||||
|
this.build_search_bar();
|
||||||
|
this.build_horizontal_bar();
|
||||||
|
this.build_content_area();
|
||||||
|
await this.load_dimensions_data();
|
||||||
|
}
|
||||||
|
|
||||||
|
build_search_bar(){
|
||||||
|
this.searchbar = new bricks.SearchBar({
|
||||||
|
placeholder: this.opts.search_placeholder || '搜索...',
|
||||||
|
width: '100%',
|
||||||
|
search_label: this.opts.search_label || '搜索',
|
||||||
|
clear_label: this.opts.clear_label || '清除'
|
||||||
|
});
|
||||||
|
this.searchbar.bind('search', this.search_handle.bind(this));
|
||||||
|
this.add_widget(this.searchbar);
|
||||||
|
}
|
||||||
|
|
||||||
|
build_horizontal_bar(){
|
||||||
|
var bar = new bricks.HBox({width: '100%', height: 'auto', flexShrink: 0});
|
||||||
|
bar.set_style('alignItems', 'center');
|
||||||
|
|
||||||
|
this.left_arrow = new bricks.Button({
|
||||||
|
label: '◀',
|
||||||
|
width: 'auto',
|
||||||
|
height: 'auto',
|
||||||
|
flexShrink: 0,
|
||||||
|
nonepack: true
|
||||||
|
});
|
||||||
|
this.left_arrow.bind('click', this.scroll_left.bind(this));
|
||||||
|
bar.add_widget(this.left_arrow);
|
||||||
|
|
||||||
|
this.h_scroll = new bricks.HBox({
|
||||||
|
width: '100%',
|
||||||
|
flexGrow: 1,
|
||||||
|
overflow: 'hidden'
|
||||||
|
});
|
||||||
|
bar.add_widget(this.h_scroll);
|
||||||
|
|
||||||
|
this.right_arrow = new bricks.Button({
|
||||||
|
label: '▶',
|
||||||
|
width: 'auto',
|
||||||
|
height: 'auto',
|
||||||
|
flexShrink: 0,
|
||||||
|
nonepack: true
|
||||||
|
});
|
||||||
|
this.right_arrow.bind('click', this.scroll_right.bind(this));
|
||||||
|
bar.add_widget(this.right_arrow);
|
||||||
|
|
||||||
|
this.add_widget(bar);
|
||||||
|
}
|
||||||
|
|
||||||
|
build_content_area(){
|
||||||
|
var content = new bricks.HBox({width: '100%', height: '100%'});
|
||||||
|
|
||||||
|
/* Left: vertical measure buttons in a scroll panel */
|
||||||
|
this.v_scroll = new bricks.VScrollPanel({width: 'auto', height: '100%'});
|
||||||
|
this.v_scroll.set_style('maxWidth', '200px');
|
||||||
|
this.v_scroll.set_style('minWidth', '80px');
|
||||||
|
content.add_widget(this.v_scroll);
|
||||||
|
|
||||||
|
/* Right: display area for show_data_url results */
|
||||||
|
this.display_filler = new bricks.Filler({flexGrow: 1});
|
||||||
|
this.display_w = new bricks.VBox({width: '100%', height: '100%'});
|
||||||
|
this.display_filler.add_widget(this.display_w);
|
||||||
|
content.add_widget(this.display_filler);
|
||||||
|
|
||||||
|
this.add_widget(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
scroll_left(){
|
||||||
|
var el = this.h_scroll.dom_element;
|
||||||
|
el.scrollLeft -= 150;
|
||||||
|
}
|
||||||
|
|
||||||
|
scroll_right(){
|
||||||
|
var el = this.h_scroll.dom_element;
|
||||||
|
el.scrollLeft += 150;
|
||||||
|
}
|
||||||
|
|
||||||
|
async load_dimensions_data(){
|
||||||
|
var jc = new bricks.HttpJson();
|
||||||
|
try {
|
||||||
|
var hd = await jc.get(this.opts.h_data_url);
|
||||||
|
this.h_data = (hd && hd.rows) ? hd.rows : [];
|
||||||
|
} catch(e) {
|
||||||
|
console.error('DimensionFilter: failed to load h_data_url', e);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
var vd = await jc.get(this.opts.v_measure_url);
|
||||||
|
this.v_data = (vd && vd.rows) ? vd.rows : [];
|
||||||
|
} catch(e) {
|
||||||
|
console.error('DimensionFilter: failed to load v_measure_url', e);
|
||||||
|
}
|
||||||
|
this.build_horizontal_buttons();
|
||||||
|
this.build_vertical_buttons();
|
||||||
|
}
|
||||||
|
|
||||||
|
build_horizontal_buttons(){
|
||||||
|
this.h_scroll.clear_widgets();
|
||||||
|
this.h_buttons = [];
|
||||||
|
|
||||||
|
var all_btn = this._make_dim_btn('全部', 'all', true);
|
||||||
|
all_btn._is_h = true;
|
||||||
|
this.h_scroll.add_widget(all_btn);
|
||||||
|
this.h_buttons.push(all_btn);
|
||||||
|
|
||||||
|
for (var i = 0; i < this.h_data.length; i++){
|
||||||
|
var dim = this.h_data[i];
|
||||||
|
var label = dim.name || dim.label || dim.id || String(dim);
|
||||||
|
var id = dim.id || dim.name || label;
|
||||||
|
var btn = this._make_dim_btn(label, id, false);
|
||||||
|
btn._is_h = true;
|
||||||
|
this.h_scroll.add_widget(btn);
|
||||||
|
this.h_buttons.push(btn);
|
||||||
|
if (this.selected_h_id == id){
|
||||||
|
this.select_h_button(btn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
build_vertical_buttons(){
|
||||||
|
this.v_scroll.clear_widgets();
|
||||||
|
this.v_buttons = [];
|
||||||
|
|
||||||
|
var all_btn = this._make_dim_btn('全部', 'all', true);
|
||||||
|
all_btn._is_h = false;
|
||||||
|
this.v_scroll.add_widget(all_btn);
|
||||||
|
this.v_buttons.push(all_btn);
|
||||||
|
|
||||||
|
for (var i = 0; i < this.v_data.length; i++){
|
||||||
|
var dim = this.v_data[i];
|
||||||
|
var label = dim.name || dim.label || dim.id || String(dim);
|
||||||
|
var id = dim.id || dim.name || label;
|
||||||
|
var btn = this._make_dim_btn(label, id, false);
|
||||||
|
btn._is_h = false;
|
||||||
|
this.v_scroll.add_widget(btn);
|
||||||
|
this.v_buttons.push(btn);
|
||||||
|
if (this.selected_v_id == id){
|
||||||
|
this.select_v_button(btn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_make_dim_btn(label, id, is_selected){
|
||||||
|
var btn = new bricks.Button({
|
||||||
|
label: label,
|
||||||
|
width: 'auto',
|
||||||
|
height: 'auto',
|
||||||
|
flexShrink: 0
|
||||||
|
});
|
||||||
|
btn.dim_id = id;
|
||||||
|
if (is_selected){
|
||||||
|
btn.set_css('dimension-btn-active');
|
||||||
|
}
|
||||||
|
btn.bind('click', this.dim_button_clicked.bind(this, btn));
|
||||||
|
return btn;
|
||||||
|
}
|
||||||
|
|
||||||
|
dim_button_clicked(btn){
|
||||||
|
if (btn._is_h){
|
||||||
|
this.selected_h_id = btn.dim_id;
|
||||||
|
this.select_h_button(btn);
|
||||||
|
} else {
|
||||||
|
this.selected_v_id = btn.dim_id;
|
||||||
|
this.select_v_button(btn);
|
||||||
|
}
|
||||||
|
this.refresh_display();
|
||||||
|
}
|
||||||
|
|
||||||
|
select_h_button(btn){
|
||||||
|
for (var i = 0; i < this.h_buttons.length; i++){
|
||||||
|
this.h_buttons[i].set_css('dimension-btn-active', true);
|
||||||
|
}
|
||||||
|
btn.set_css('dimension-btn-active');
|
||||||
|
}
|
||||||
|
|
||||||
|
select_v_button(btn){
|
||||||
|
for (var i = 0; i < this.v_buttons.length; i++){
|
||||||
|
this.v_buttons[i].set_css('dimension-btn-active', true);
|
||||||
|
}
|
||||||
|
btn.set_css('dimension-btn-active');
|
||||||
|
}
|
||||||
|
|
||||||
|
search_handle(event){
|
||||||
|
var d = event.params || {};
|
||||||
|
this.search_keyword = d.keyword || '';
|
||||||
|
this.refresh_display();
|
||||||
|
}
|
||||||
|
|
||||||
|
async refresh_display(){
|
||||||
|
this.display_w.clear_widgets();
|
||||||
|
var params = {
|
||||||
|
h_id: this.selected_h_id,
|
||||||
|
v_id: this.selected_v_id
|
||||||
|
};
|
||||||
|
if (this.search_keyword){
|
||||||
|
params.keyword = this.search_keyword;
|
||||||
|
}
|
||||||
|
var desc = {
|
||||||
|
widgettype: 'urlwidget',
|
||||||
|
options: {
|
||||||
|
url: this.opts.show_data_url,
|
||||||
|
params: params,
|
||||||
|
method: this.opts.show_data_method || 'GET'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var w = await bricks.widgetBuild(desc, this);
|
||||||
|
if (w){
|
||||||
|
this.display_w.add_widget(w);
|
||||||
|
}
|
||||||
|
this.dispatch('filter_changed', params);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bricks.Factory.register('DimensionFilter', bricks.DimensionFilter);
|
||||||
Loading…
x
Reference in New Issue
Block a user