Creating sites with modular Typescript, JQuery, requireJS and D3js (v4)

Standard Approach for a page is to setup div with an ID that will become the SVG Canvas

  • The SVG Canvas object (implements ISvgCanvas)
    • maitains identity with the page via div:id, fetching attribute data for canvas dimensions
    • Creates a Defines child object with stores filters, markers that can be used by any of the child objects
    • Creates a d3v4 selection object that other controls will use for appended graphics
    • The SVG Canvas object is passed to all child controls so they can
      • Figure out the extents of the window
      • Access the Defs (or create additional ones at the correct level)
      • Append to the main SVG node

Note – the modular (AMD/EC5) approach uses the following imports from a d3 modular typings:

import * as d3_selection from “d3-selection”;
import * as $ from “jquery”;

export type d3v4Selection = d3_selection.Selection<d3_selection.BaseType, any, any, any>;

ISvgCanvas

export interface ISvgCanvas{
 id:String;
 defines:ICanvasDefines; 
 svgCanvas:d3v4Selection;
 width:number;
 height:number;
}

ICanvasDefines – for addding gradients, filters, markers to the <defs> child of the canvas

export interface ICanvasDefines{
 AddLinearGradient(gradientId: string): d3v4Selection;
 AddGaussianBlurFilter(filterID: string): d3v4Selection;
 //stop1:string='70%',stop1color:string='lightgrey', stop2:string= '100%', stop2color:string= 'gray'
 AddRadialGradiantWithTwoStops(gradientID:string, stop1?:string,stop1color?:string, stop2?:string, stop2color?:string): d3v4Selection;
 AddArrow(markerID:string,markerWidth?:number,markerHeight?:number,refX?:number,refY?:number): d3v4Selection
}

Canvas Object (SvgD3Canvas implements ISvgCanvas)

export class SvgD3Canvas implements ISvgCanvas{

 private _container:JQuery;
 private _d3SVG:d3v4Selection;
 private _width:number;
 private _height:number;
 private _defines:ICanvasDefines;


 constructor(divID:string){

 this._container = $(divID);
 let itemHeight = this._container.attr("item-height");
 if(!itemHeight){
   itemHeight = this._container.css("height").replace(/[^-\d\.]/g, '');;
 }
 if(!itemHeight){
   itemHeight = "2000";
 }

 let itemwidth = this._container.attr("item-width");
 if(!itemwidth){
   itemwidth = this._container.css("width").replace(/[^-\d\.]/g, '');
 }
 if(!itemwidth){
   itemwidth = "2000";
 }


 this._height = Math.round(Number(itemHeight));
 this._width =Math.round(Number(itemwidth));
 this._d3SVG = d3_selection.select(divID).append("svg").attr("width",this._width).attr("height", this._height);
 this._defines= new SVGdefsHelper(this._d3SVG);
 
 }

 public get width():number{
 return this._width;
 }
 public get height():number{
 return this._height;
 }
 public get svgCanvas():d3v4Selection{
 return this._d3SVG;
 }

 public get defines():ICanvasDefines{
 return this._defines;
 }
}

Defines Object


export class SVGdefsHelper implements ICanvasDefines {

 _svgDefsSection: d3v4Selection;

 constructor(svgDefs: d3v4Selection) {
 this._svgDefsSection = svgDefs;
 }


 public AddRadialGradiantWithTwoStops(gradientID:string, stop1:string='70%',stop1color:string='lightgrey', stop2:string= '100%', stop2color:string= 'gray'): d3v4Selection{
 let gradient = this._svgDefsSection.append('radialGradient')
 .attr("id", gradientID);

 gradient.append("stop").attr("offset", stop1).attr("stop-color", stop1color);
 gradient.append("stop").attr("offset", stop2).attr("stop-color", stop2color);

 return gradient;
 }

 public AddArrow(markerID:string,markerWidth:number=10,markerHeight:number=10,refX:number=6,refY:number=3): d3v4Selection{
 let marker = this._svgDefsSection.append('marker').attr("class","def-marker-arrow").attr("id", markerID)
 .attr("markerWidth", markerWidth)
 .attr("markerHeight",markerHeight)
 .attr("refX",refX)
 .attr("refY",refY)
 .attr("orient","auto")
 .attr("markerUnits", "strokeWidth");

 let path = marker.append("path").attr("d","M0,0 L0,6 L9,3 z").attr("class","def-marker-arrow");
 
 return marker;

 
// <marker id="arrow" markerWidth="10" markerHeight="10" refX="0" refY="3" orient="auto" markerUnits="strokeWidth">
// <path d="M0,0 L0,6 L9,3 z" fill="#f00" />
// </marker>
 }
 public AddRadialGradient(gradiantParams: IGradientStop2): d3v4Selection {
 // <radialGradient id="exampleGradient">
 // <stop offset="70%" stop-color="lightgrey"/>
 // <stop offset="100%" stop-color="gray"/>
 //</radialGradient>
 var grayCircularRadialGrad = { id: 'grayRadial', stop1: '70%', stop1color: 'lightgrey', stop2: '100%', stop2color: 'gray' };
 var gradient = this._svgDefsSection.append('radialGradient')
 .attr("id", gradiantParams.id);

 gradient.append("stop").attr("offset", gradiantParams.stop1).attr("stop-color", gradiantParams.stop1color);
 gradient.append("stop").attr("offset", gradiantParams.stop2).attr("stop-color", gradiantParams.stop2color);

 return gradient;

 }

 public AddLinearGradient(gradientId: string): d3v4Selection {

 //<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
 // <stop offset="0%" style="stop-color:rgb(255,255,0);stop-opacity:1" />
 // <stop offset="100%" style="stop-color:rgb(255,0,0);stop-opacity:1" />
 // </linearGradient>

 var mainGradient = this._svgDefsSection.append('linearGradient')
 .attr("id", gradientId)
 .attr("x1", "0%")
 .attr("y1", "0%")
 .attr("x2", "100%")
 .attr("y2", "0%")

 mainGradient.append('stop')
 .attr('class', 'stop-left')
 .attr('offset', '0%')
 .attr('style', 'stop-color:rgb(255,255,0);stop-opacity:1');

 mainGradient.append('stop')
 .attr('class', 'stop-left')
 .attr('offset', '100%')
 .attr('style', 'stop-color:rgb(255,0,0);stop-opacity:1');

 return mainGradient;


 }

 public AddGaussianBlurFilter(filterID: string): d3v4Selection {
 //<filter id="f3" x="0" y="0" width="200%" height="200%">
 // <feOffset result="offOut" in="SourceAlpha" dx="20" dy="20" />
 // <feGaussianBlur result="blurOut" in="offOut" stdDeviation="10" />
 // <feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
 // </filter>
 var mainFilter = this._svgDefsSection.append('filter')
 .attr("id", filterID)
 .attr("x", "0")
 .attr("y", "0")
 .attr("width", "200%")
 .attr("height", "200%");

 mainFilter.append("feOffset")
 .attr("result", "offOut")
 .attr("in", "SourceAlpha")
 .attr("dx", "20")
 .attr("dy", "20");

 mainFilter.append("feGaussianBlur")
 .attr("result", "blurOut")
 .attr("in", "offOut")
 .attr("stdDeviation", "10");

 mainFilter.append("feBlend")
 .attr("in", "SourceGraphic")
 .attr("in2", "blurOut")
 .attr("mode", "normal");

 return mainFilter;


 }
 public AddFilterToDefs(filterID: string): d3v4Selection {
 //<filter id="f3" x="0" y="0" width="200%" height="200%">
 // <feOffset result="offOut" in="SourceAlpha" dx="20" dy="20" />
 // <feGaussianBlur result="blurOut" in="offOut" stdDeviation="10" />
 // <feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
 // </filter>
 var mainFilter = this._svgDefsSection.append('filter')
 .attr("id", filterID)
 .attr("x", "0")
 .attr("y", "0")
 .attr("width", "200%")
 .attr("height", "200%");

 mainFilter.append("feOffset")
 .attr("result", "offOut")
 .attr("in", "SourceAlpha")
 .attr("dx", "20")
 .attr("dy", "20");

 mainFilter.append("feGaussianBlur")
 .attr("result", "blurOut")
 .attr("in", "offOut")
 .attr("stdDeviation", "10");

 mainFilter.append("feBlend")
 .attr("in", "SourceGraphic")
 .attr("in2", "blurOut")
 .attr("mode", "normal");

 return mainFilter;


 }
 public AddWhiteToColorGradient(gradientID: string, color: string): d3v4Selection {
 //<linearGradient id="gradientOrange" x1="0%" y1="0%" x2="0%" y2="100%" spreadMethod="pad">
 // <stop offset="000%" stop-color="#FF9600" stop-opacity="1"/>
 // <stop offset="050%" stop-color="#FFFFFF" stop-opacity="1"/>
 // <stop offset="100%" stop-color="#000000" stop-opacity="1"/>
 //</linearGradient>

 //<linearGradient id="gradientGreen" x1="0%" y1="0%" x2="0%" y2="100%" spreadMethod="pad">
 // <stop offset="000%" stop-color="#22DD00" stop-opacity="1"/>
 // <stop offset="050%" stop-color="#FFFFFF" stop-opacity="1"/>
 // <stop offset="100%" stop-color="#000000" stop-opacity="1"/>
 //</linearGradient>

 var gradient = this._svgDefsSection.append('linearGradient')
 .attr("id", gradientID)
 .attr("x1", "0%")
 .attr("y1", "0%")
 .attr("x2", "0%")
 .attr("y2", "100%")

 gradient.append('stop')
 .attr('offset', '0%')
 .attr('stop-color', color)
 .attr('stop-opacity', 1);


 gradient.append('stop')
 .attr('offset', '50%')
 .attr('stop-color', "#FFFFFF")
 .attr('stop-opacity', 1);

 gradient.append('stop')
 .attr('offset', '100%')
 .attr('stop-color', "#000000")
 .attr('stop-opacity', 1);

 return gradient;

 }
}

Leave a Reply

Your email address will not be published. Required fields are marked *