mirror of
https://github.com/apache/superset.git
synced 2026-05-21 15:55:10 +00:00
Compare commits
4 Commits
docs/dashb
...
pr-34524
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
acf3635500 | ||
|
|
1926212f0e | ||
|
|
86d5d4b4a8 | ||
|
|
2029fd0131 |
@@ -59,3 +59,29 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
stroke: #eee;
|
stroke: #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.superset-legacy-chart-country-map .tooltip {
|
||||||
|
position: absolute;
|
||||||
|
text-align: left;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
background: rgba(0, 0, 0, 0.8);
|
||||||
|
color: white;
|
||||||
|
border-radius: 4px;
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.superset-legacy-chart-country-map .tooltip.show {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.superset-legacy-chart-country-map .tooltip .tooltip-title {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.superset-legacy-chart-country-map .tooltip .tooltip-value {
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|||||||
@@ -100,6 +100,12 @@ function CountryMap(element, props) {
|
|||||||
.classed('result-text', true)
|
.classed('result-text', true)
|
||||||
.attr('dy', '1em');
|
.attr('dy', '1em');
|
||||||
|
|
||||||
|
// Create tooltip
|
||||||
|
const tooltip = div
|
||||||
|
.append('div')
|
||||||
|
.attr('class', 'tooltip')
|
||||||
|
.style('opacity', 0);
|
||||||
|
|
||||||
let centered;
|
let centered;
|
||||||
|
|
||||||
const clicked = function clicked(d) {
|
const clicked = function clicked(d) {
|
||||||
@@ -181,12 +187,38 @@ function CountryMap(element, props) {
|
|||||||
region => region.country_id === d.properties.ISO,
|
region => region.country_id === d.properties.ISO,
|
||||||
);
|
);
|
||||||
updateMetrics(result);
|
updateMetrics(result);
|
||||||
|
|
||||||
|
// Show tooltip
|
||||||
|
let name = '';
|
||||||
|
if (d && d.properties) {
|
||||||
|
if (d.properties.ID_2) {
|
||||||
|
name = d.properties.NAME_2;
|
||||||
|
} else {
|
||||||
|
name = d.properties.NAME_1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = result.length > 0 ? format(result[0].metric) : 'No data';
|
||||||
|
|
||||||
|
tooltip
|
||||||
|
.classed('show', true)
|
||||||
|
.html(
|
||||||
|
`<div class="tooltip-title">${name}</div>` +
|
||||||
|
`<div class="tooltip-value">${value}</div>`,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const mousemove = function mousemove() {
|
||||||
|
tooltip
|
||||||
|
.style('left', `${d3.event.pageX + 15}px`)
|
||||||
|
.style('top', `${d3.event.pageY - 28}px`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const mouseout = function mouseout() {
|
const mouseout = function mouseout() {
|
||||||
d3.select(this).style('fill', colorFn);
|
d3.select(this).style('fill', colorFn);
|
||||||
bigText.text('');
|
bigText.text('');
|
||||||
resultText.text('');
|
resultText.text('');
|
||||||
|
tooltip.classed('show', false);
|
||||||
};
|
};
|
||||||
|
|
||||||
function drawMap(mapData) {
|
function drawMap(mapData) {
|
||||||
@@ -225,6 +257,7 @@ function CountryMap(element, props) {
|
|||||||
.attr('vector-effect', 'non-scaling-stroke')
|
.attr('vector-effect', 'non-scaling-stroke')
|
||||||
.style('fill', colorFn)
|
.style('fill', colorFn)
|
||||||
.on('mouseenter', mouseenter)
|
.on('mouseenter', mouseenter)
|
||||||
|
.on('mousemove', mousemove)
|
||||||
.on('mouseout', mouseout)
|
.on('mouseout', mouseout)
|
||||||
.on('click', clicked);
|
.on('click', clicked);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import '@testing-library/jest-dom';
|
||||||
|
import CountryMap from '../src/CountryMap';
|
||||||
|
import '../src/CountryMap.css';
|
||||||
|
|
||||||
|
describe('CountryMap', () => {
|
||||||
|
let container;
|
||||||
|
let mockProps;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
container = document.createElement('div');
|
||||||
|
container.style.width = '800px';
|
||||||
|
container.style.height = '600px';
|
||||||
|
document.body.appendChild(container);
|
||||||
|
|
||||||
|
mockProps = {
|
||||||
|
data: [
|
||||||
|
{ country_id: 'USA', metric: 100 },
|
||||||
|
{ country_id: 'CAN', metric: 50 },
|
||||||
|
],
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
country: 'usa',
|
||||||
|
linearColorScheme: 'greenBlue',
|
||||||
|
numberFormat: '.3s',
|
||||||
|
colorScheme: null,
|
||||||
|
sliceId: 1,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
document.body.removeChild(container);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create the necessary DOM elements', () => {
|
||||||
|
CountryMap(container, mockProps);
|
||||||
|
|
||||||
|
// Check if main container has the correct class
|
||||||
|
expect(container).toHaveClass('superset-legacy-chart-country-map');
|
||||||
|
|
||||||
|
// Check if SVG is created
|
||||||
|
const svg = container.querySelector('svg');
|
||||||
|
expect(svg).toBeTruthy();
|
||||||
|
expect(svg).toHaveAttribute('width', '800');
|
||||||
|
expect(svg).toHaveAttribute('height', '600');
|
||||||
|
|
||||||
|
// Check if tooltip div is created
|
||||||
|
const tooltip = container.querySelector('.tooltip');
|
||||||
|
expect(tooltip).toBeTruthy();
|
||||||
|
expect(tooltip).toHaveStyle({ opacity: '0' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create map layers', () => {
|
||||||
|
CountryMap(container, mockProps);
|
||||||
|
|
||||||
|
// Check if map layer exists
|
||||||
|
const mapLayer = container.querySelector('.map-layer');
|
||||||
|
expect(mapLayer).toBeTruthy();
|
||||||
|
|
||||||
|
// Check if text layer exists
|
||||||
|
const textLayer = container.querySelector('.text-layer');
|
||||||
|
expect(textLayer).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should apply tooltip styles', () => {
|
||||||
|
CountryMap(container, mockProps);
|
||||||
|
|
||||||
|
const tooltip = container.querySelector('.tooltip');
|
||||||
|
expect(tooltip).toBeTruthy();
|
||||||
|
|
||||||
|
// Check if tooltip has the correct class
|
||||||
|
expect(tooltip).toHaveClass('tooltip');
|
||||||
|
|
||||||
|
// Check if tooltip has opacity 0 initially
|
||||||
|
expect(tooltip).toHaveStyle({ opacity: '0' });
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -673,16 +673,6 @@ const config: ControlPanelConfig = {
|
|||||||
type: 'ConditionalFormattingControl',
|
type: 'ConditionalFormattingControl',
|
||||||
renderTrigger: true,
|
renderTrigger: true,
|
||||||
label: t('Custom conditional formatting'),
|
label: t('Custom conditional formatting'),
|
||||||
extraColorChoices: [
|
|
||||||
{
|
|
||||||
value: ColorSchemeEnum.Green,
|
|
||||||
label: t('Green for increase, red for decrease'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: ColorSchemeEnum.Red,
|
|
||||||
label: t('Red for increase, green for decrease'),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
description: t(
|
description: t(
|
||||||
'Apply conditional color formatting to numeric columns',
|
'Apply conditional color formatting to numeric columns',
|
||||||
),
|
),
|
||||||
@@ -695,6 +685,23 @@ const config: ControlPanelConfig = {
|
|||||||
)
|
)
|
||||||
? (explore?.datasource as Dataset)?.verbose_map
|
? (explore?.datasource as Dataset)?.verbose_map
|
||||||
: (explore?.datasource?.columns ?? {});
|
: (explore?.datasource?.columns ?? {});
|
||||||
|
|
||||||
|
// Only show increase/decrease color options when time comparison is active
|
||||||
|
const hasTimeComparison = !isEmpty(
|
||||||
|
explore?.form_data?.time_compare,
|
||||||
|
);
|
||||||
|
const extraColorChoices = hasTimeComparison
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
value: ColorSchemeEnum.Green,
|
||||||
|
label: t('Green for increase, red for decrease'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: ColorSchemeEnum.Red,
|
||||||
|
label: t('Red for increase, green for decrease'),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [];
|
||||||
const chartStatus = chart?.chartStatus;
|
const chartStatus = chart?.chartStatus;
|
||||||
const { colnames, coltypes } =
|
const { colnames, coltypes } =
|
||||||
chart?.queriesResponse?.[0] ?? {};
|
chart?.queriesResponse?.[0] ?? {};
|
||||||
@@ -725,6 +732,7 @@ const config: ControlPanelConfig = {
|
|||||||
removeIrrelevantConditions: chartStatus === 'success',
|
removeIrrelevantConditions: chartStatus === 'success',
|
||||||
columnOptions,
|
columnOptions,
|
||||||
verboseMap,
|
verboseMap,
|
||||||
|
extraColorChoices,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -730,16 +730,6 @@ const config: ControlPanelConfig = {
|
|||||||
type: 'ConditionalFormattingControl',
|
type: 'ConditionalFormattingControl',
|
||||||
renderTrigger: true,
|
renderTrigger: true,
|
||||||
label: t('Custom conditional formatting'),
|
label: t('Custom conditional formatting'),
|
||||||
extraColorChoices: [
|
|
||||||
{
|
|
||||||
value: ColorSchemeEnum.Green,
|
|
||||||
label: t('Green for increase, red for decrease'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: ColorSchemeEnum.Red,
|
|
||||||
label: t('Red for increase, green for decrease'),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
description: t(
|
description: t(
|
||||||
'Apply conditional color formatting to numeric columns',
|
'Apply conditional color formatting to numeric columns',
|
||||||
),
|
),
|
||||||
@@ -752,6 +742,23 @@ const config: ControlPanelConfig = {
|
|||||||
)
|
)
|
||||||
? (explore?.datasource as Dataset)?.verbose_map
|
? (explore?.datasource as Dataset)?.verbose_map
|
||||||
: (explore?.datasource?.columns ?? {});
|
: (explore?.datasource?.columns ?? {});
|
||||||
|
|
||||||
|
// Only show increase/decrease color options when time comparison is active
|
||||||
|
const hasTimeComparison = !isEmpty(
|
||||||
|
explore?.form_data?.time_compare,
|
||||||
|
);
|
||||||
|
const extraColorChoices = hasTimeComparison
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
value: ColorSchemeEnum.Green,
|
||||||
|
label: t('Green for increase, red for decrease'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: ColorSchemeEnum.Red,
|
||||||
|
label: t('Red for increase, green for decrease'),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [];
|
||||||
const chartStatus = chart?.chartStatus;
|
const chartStatus = chart?.chartStatus;
|
||||||
const { colnames, coltypes } =
|
const { colnames, coltypes } =
|
||||||
chart?.queriesResponse?.[0] ?? {};
|
chart?.queriesResponse?.[0] ?? {};
|
||||||
@@ -782,6 +789,7 @@ const config: ControlPanelConfig = {
|
|||||||
removeIrrelevantConditions: chartStatus === 'success',
|
removeIrrelevantConditions: chartStatus === 'success',
|
||||||
columnOptions,
|
columnOptions,
|
||||||
verboseMap,
|
verboseMap,
|
||||||
|
extraColorChoices,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user