-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(shadow): specify the shadow filter units as userSpaceOnUse
.
#792
base: master
Are you sure you want to change the base?
Conversation
Do we need to change x, y, width, and height after using userSpaceOnUse Also, this seems to be a bug in chrome. The shadow filter should have no reason to affect the display of the original graphic. I tested it on safari and the line won't disappear. |
Seems so. It also works in Firefox. |
Just one more thing, the shadow seems buggy when hovering. Two series will use the same shadow filter id when hovering. That is not expected. option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [{
data: [0, 0, 10, 0, 0, 0, 0],
type: 'line',
stack: true,
color: '#7f64ff',
symbol: 'none',
smooth: true,
lineStyle: {
shadowColor: 'red',
shadowBlur: 5,
shadowOffsetX: 0,
shadowOffsetY: 0
}
}, {
data: [0, 80, 0, 50, 0, 0, 0],
type: 'line',
stack: true,
color: '#7f64ff',
symbol: 'none',
smooth: true,
lineStyle: {
shadowColor: 'blue',
shadowBlur: 5,
shadowOffsetX: 0,
shadowOffsetY: 0
}
}]
}; |
I opened #822 before seeing this PR... Perhaps it's better to add this attribute in
https://bugs.chromium.org/p/chromium/issues/detail?id=1247310#c3 |
Let's keep the discussion in this PR. The major concern from me is calculating |
Merged the test case from #822 |
Get this updated slightly. Here are two strategies I can think out. 1. Add a tiny offset to make it not entirely straight. (Ref) It can make the line displayed but the result is strange and unexpected. 2. Specify especially It seems to be working for me. But it needs some extra logic to check. export function getShadowKey(displayable: Displayable) {
const style = displayable.style;
const globalScale = displayable.getGlobalScale();
let isHorizontalVerticalStraightLine = 0;
// FIXME Use `userSpaceOnUse` as the unit when applying filters on a horizontal or vertical straight line
if (displayable.type === 'line') {
const shape = (displayable as Line).shape;
const rad = Math.atan2(shape.y2 - shape.y1, shape.x2 - shape.x1);
isHorizontalVerticalStraightLine = +!(rad % (Math.PI / 2));
}
return [
[
style.shadowColor,
(style.shadowBlur || 0).toFixed(2), // Reduce the precision
(style.shadowOffsetX || 0).toFixed(2),
(style.shadowOffsetY || 0).toFixed(2),
globalScale[0],
globalScale[1],
isHorizontalVerticalStraightLine
].join(','),
isHorizontalVerticalStraightLine
];
}
function setShadow(
el: Displayable,
attrs: SVGVNodeAttrs,
scope: BrushScope
) {
const style = el.style;
if (hasShadow(style)) {
const [shadowKey, isHorizontalVerticalStraightLine] = getShadowKey(el);
const shadowCache = scope.shadowCache;
let shadowId = shadowCache[shadowKey];
if (!shadowId) {
const globalScale = el.getGlobalScale();
const scaleX = globalScale[0];
const scaleY = globalScale[1];
if (!scaleX || !scaleY) {
return;
}
const offsetX = style.shadowOffsetX || 0;
const offsetY = style.shadowOffsetY || 0;
const blur = style.shadowBlur;
const {opacity, color} = normalizeColor(style.shadowColor);
const stdDx = blur / 2 / scaleX;
const stdDy = blur / 2 / scaleY;
const stdDeviation = stdDx + ' ' + stdDy;
// Use a simple prefix to reduce the size
shadowId = scope.zrId + '-s' + scope.shadowIdx++;
const filterAttrs: SVGVNodeAttrs = {
'id': shadowId,
'x': '-100%',
'y': '-100%',
'width': '300%',
'height': '300%'
};
//
isHorizontalVerticalStraightLine && (filterAttrs.filterUnits = 'userSpaceOnUse');
scope.defs[shadowId] = createVNode(
'filter', shadowId, filterAttrs,
[
createVNode('feDropShadow', '', {
'dx': offsetX / scaleX,
'dy': offsetY / scaleY,
'stdDeviation': stdDeviation,
'flood-color': color,
'flood-opacity': opacity
})
]
);
shadowCache[shadowKey] = shadowId;
}
attrs.filter = getIdURL(shadowId);
}
}
Here is another article that states the same issue: |
In your second solution. Checking zero area bounding rect without lineWidth will be more accurate than checking type because line chart use an extended path. If we use I'm not sure but is it possible to use |
I think the fix also needs to apply to the diff --git a/src/svg/graphic.ts b/src/svg/graphic.ts
index 096014967613dcc0bfecd8e9215c5ee900abf79a..f4b41016e301240dd060aae8368172ca01a29d84 100644
--- a/src/svg/graphic.ts
+++ b/src/svg/graphic.ts
@@ -393,7 +393,8 @@ function setShadow(
'x': '-100%',
'y': '-100%',
'width': '300%',
- 'height': '300%'
+ 'height': '300%',
+ 'filterUnits': 'userSpaceOnUse'
},
[
createVNode('feDropShadow', '', {
diff --git a/src/svg-legacy/helper/ShadowManager.ts b/src/svg-legacy/helper/ShadowManager.ts
index cc2c76e891e821becfb40d3efebada921efe3102..c27219fe8a59a907266abb67ef63918b10668d9a 100644
--- a/src/svg-legacy/helper/ShadowManager.ts
+++ b/src/svg-legacy/helper/ShadowManager.ts
@@ -36,6 +36,7 @@ export default class ShadowManager extends Definable {
if (!shadowDom) {
shadowDom = createElement('filter') as SVGFilterElement;
shadowDom.setAttribute('id', 'zr' + this._zrId + '-shadow-' + this.nextId++);
+ shadowDom.setAttribute('filterUnits', 'userSpaceOnUse');
const domChild = createElement('feDropShadow');
shadowDom.appendChild(domChild);
this.addDom(shadowDom);
@@ -118,6 +119,7 @@ export default class ShadowManager extends Definable {
shadowDom.setAttribute('y', '-100%');
shadowDom.setAttribute('width', '300%');
shadowDom.setAttribute('height', '300%');
+ shadowDom.setAttribute('filterUnits', 'userSpaceOnUse');
// Store dom element in shadow, to avoid creating multiple
// dom instances for the same shadow element
|
Before
After
A simple demo