Chart Line Shadow

Posted by: tfoster on 29 April 2019, 10:41 am EST

  • Posted 29 April 2019, 10:41 am EST

    I’m trying to figure out if there is any possible way to add drop shadows to chart series lines. Creating SVG drop shadow effects is unfortunately a bit convoluted, requiring a ‘defs’ child element on the SVG where one can define a filter to describe the drop shadow effect and which can then be referenced by a polyline element. My initial attempt to dynamically add a ‘defs’ element to the chart SVG in response to a ‘rendered’ event did not seem to pay off. Any suggestions?

  • Posted 29 April 2019, 2:48 pm EST

    Well, I finally figured out a way to pull it off, though more hacky than I’d prefer:

    	public flexChartInitialized(flexChart: wijmo.chart.FlexChart) {
    		this.flexChart = flexChart;
    		this.flexChart.rendered.addHandler(() => {
    
    			// Add a 'defs' element to the SVG in order to define the drop shadow affect we want for some elements
    			var svgNS = 'http://www.w3.org/2000/svg';
    			var svg = this.flexChart._currentRenderEngine.element;
    			var defs = <SVGDefsElement>document.createElementNS(svgNS, 'defs');
    			var filter = <SVGFilterElement>document.createElementNS(svgNS, 'filter');
    			var feOffset = <SVGFEOffsetElement>document.createElementNS(svgNS, 'feOffset');
    			var feGaussianBlur = <SVGFEGaussianBlurElement>document.createElementNS(svgNS, 'feGaussianBlur');
    			var feBlend = <SVGFEBlendElement>document.createElementNS(svgNS, 'feBlend');
    
    			svg.insertBefore(defs, svg.firstChild);
    
    			defs.appendChild(filter);
    			filter.setAttribute('id', 'f1');
    			filter.setAttribute('filterUnits', 'userSpaceOnUse'); // the default is 'objectBoundingBox' - without this, horizontal/vertical lines won't render at all
    
    			filter.appendChild(feOffset);
    			feOffset.setAttribute('result', 'offOut');
    			feOffset.setAttribute('in', 'SourceAlpha');
    			feOffset.setAttribute('dx', '2');
    			feOffset.setAttribute('dy', '2');
    
    			filter.appendChild(feGaussianBlur);
    			feGaussianBlur.setAttribute('result', 'blurOut');
    			feGaussianBlur.setAttribute('in', 'offOut');
    			feGaussianBlur.setAttribute('stdDeviation', '2');
    
    			filter.appendChild(feBlend);
    			feBlend.setAttribute('in', 'SourceGraphic');
    			feBlend.setAttribute('in2', 'blurOut');
    			feBlend.setAttribute('mode', 'normal');
    
    			// Add filter attribute to the lines that need a shadow
    			$("polyline[stroke-width='3']").attr('filter', 'url(#f1)')
    		})
    	}
    

    Please do let me know if there is perhaps a better/cleaner way to pull it off.

    Thanks,

    Terry

  • Posted 30 April 2019, 3:21 am EST

    Instead of creating the filter element using javascript inside the rendered event, you can directly create an element with the filter function as you want and provide an “id” to this filter.

    Here, we have provided “f1” as id to the filter element. We can use this id to reference this filter to render the chart using CSS:

    .wj-series-group g polyline {

    filter: url(#f1);

    }

    Please refer to the sample below:

    https://stackblitz.com/edit/angular-iw5qzp

Need extra support?

Upgrade your support plan and get personal unlimited phone support with our customer engagement team

Learn More

Forum Channels