59
Add Magic to Your ExtJS Apps with D3 Visualizations Vitaly Kravchenko

SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

  • Upload
    sencha

  • View
    178

  • Download
    1

Embed Size (px)

Citation preview

Page 1: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Add Magic to Your ExtJS Apps with D3 Visualizations

Vitaly Kravchenko

Page 2: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

D3 and Chartswe can have both

• Complements charts

• Offers unique components• Has no feature overlap

VS

Page 3: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

D3 Componentsvisualized by themselves

Page 4: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Hierarchy Componentsfor tree store visualizations

d3-pack d3-tree d3-treemap d3-sunburst

Page 5: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

So how did we create these charts?

That’s it!

then cycle through other x-types

items: {

xtype: 'd3-treemap',

}

•define the x-type of the D3 component

viewModel: vm,• define a view model

bind: { store: '{letters}' }

• bind component’s store to the store from a view model

Page 6: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

The data is a tree of objects with

• the name field

•the children array

{ name: 'A', expanded: true, children: [ { name: 'B', expanded: true, children: [ { name: 'D' }, { name: 'E' } ] }, { name: 'C' } ]}

Data

Page 7: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

items: {

xtype: 'd3-treemap',

}

viewModel: vm,

bind: { store: '{letters}' }

Config

...

{ name: 'D',},{ name: 'E'},

...

Data Result

Page 8: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

How do we know to fetch the name?

• name and text are the defaults nodeText: ['name', 'text']

nodeText: 'foo'• but it can be anything

nodeText: function (component, node) { var record = node.data;

return record.get('firstName') + ' ' + record.get('lastName');}

• including a calculated value

Page 9: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

• use the tooltip config

tooltip: {

}

When you can’t show everything

• it’s just a Ext.tip.ToolTip

• with the extra renderer property

renderer: function (cmp, tooltip, node) { tooltip.setHtml(node.data.get('hint')); }

showDelay: 500,

trackMouse: false

Page 10: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Data BindingviewModel: vm,

defaults: { bind: { store: '{letters}', selection: '{selection}', }, tooltip: { renderer: function (component, tooltip, node, element) { tooltip.setHtml(node.data.get('hint')); } }},

items: [ { xtype: 'd3-tree' }, { xtype: 'd3-pack' }, { xtype: 'd3-treemap' }, { xtype: 'd3-sunburst' }]

Page 11: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Live Demo

Page 12: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Make the size matter! { xtype: 'd3-treemap',

bind: { store: '{letters}' },

rootVisible: false,

nodeValue: 'frequency'}

[{ name: 'A', frequency: 8.167}, { name: 'B', frequency: 1.492}, { name: 'C', frequency: 2.782}, { name: 'D', frequency: 4.253}, { name: 'E', frequency: 12.702}]

{ xtype: 'd3-treemap',

bind: { store: '{letters}' },

rootVisible: false,

nodeValue: 1 // default}

Page 13: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Change the colors!

• use the colorAxis config

colorAxis: {

}

range

• field - what values to colorize

field: 'name',

• scale - how to do it

scale: { type: 'ordinal', range: 'd3.schemeCategory20c' }

domain

Page 14: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

With a bit more tweaking…

Page 15: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Flexible coloring options

• custom scales (e.g. polylinear)

• custom logic

colorAxis: {

field: 'change',

scale: { type: 'linear',

domain: [ -5, 0, 5 ],

range: ['red', 'lightgray', 'green'] },

processor: function (axis, scale, node, field) {

var record = node.data;

return record.isLeaf()

? scale(record.get(field))

: 'lightgray'; // sector color }

}

Page 16: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Live Demo

Page 17: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko
Page 18: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko
Page 19: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Interactions

Page 20: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

panzoom interaction

• it’s like zoom behavior with extras

• plays nice with Ext event/gesture system

• kinetic scrolling

• constraints, elastic borders

• scroll indicators

interactions: { type: 'panzoom'}

pan: { gesture: 'drag', constrain: true, momentum: { friction: 1, spring: 0.2 } },

zoom: { gesture: 'pinch', extent: [1, 3], uniform: true, mouseWheel: { factor: 1.02 }, doubleTap: { factor: 1.1 } }

Page 21: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

HeatmapRepresent matrix values with colors

Sales per Employee per Day

Page 22: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

{ "employee": "Alex", "day": "Monday", "sales": 67 }, { "employee": "Alex", "day": "Tuesday", "sales": 69 }, { "employee": "Alex", "day": "Wednesday", "sales": 187 }, { "employee": "Alex", "day": "Thursday", "sales": 62 }, { "employee": "Alex", "day": "Friday", "sales": 91 },

{ "employee": "Nige", "day": "Monday", "sales": 31 }, { "employee": "Nige", "day": "Tuesday", "sales": 164 }, { "employee": "Nige", "day": "Wednesday", "sales": 120 }, { "employee": "Nige", "day": "Thursday", "sales": 43 }, { "employee": "Nige", "day": "Friday", "sales": 32 },

Data

Heatmap

Page 23: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Heatmap definition

{ xtype: 'd3-heatmap',

store: { type: 'salesperemployee' },

...}

Component & Store

Page 24: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Heatmap definition

xAxis: { axis: { orient: 'bottom' }, scale: { type: 'band' }, title: { text: 'Employee', attr: { 'font-size': '14px' } }, field: 'employee' }

yAxis: { axis: { orient: 'left' }, scale: { type: 'band' }, title: { text: 'Day', attr: { 'font-size': '14px' } }, field: 'day' }

Axes

Page 25: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Heatmap definition

colorAxis: {

field: 'sales',

scale: { type: 'linear',

range: [ 'green’, 'yellow', 'red' ] } }

Colors

tiles: {

attr: { 'stroke': 'darkblue', 'stroke-width': 2 }

}

Styles

Page 26: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Heatmap definition

legend: {

docked: 'right', padding: 50,

items: { count: 7,

reverse: true,

size: { x: 60, y: 30 } }}

Legend

Page 27: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

A Heatmap with Discrete X- and Y-axesName, Category, Index, etc.

Sales per Employee per Day

Page 28: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Discrete Color Axisis supported too

Page 29: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Axis and Legend configuration

colorAxis: {

scale: { type: 'ordinal', range: 'd3.schemeCategory20c' },

field: 'category'

}

legend: { docked: 'right', padding: 50,

items: { size: { x: 60, y: 30 } }}

Page 30: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Heatmaps with Continuous AxesQuantity, Time, etc.

Data

Heatmap

{ "date": "2012-07-20", "bucket": 800, "count": 89},{ "date": "2012-07-20", "bucket": 900, "count": 90},{ "date": "2012-07-20", "bucket": 1000, "count": 134}

{ "date": "2012-07-21", "bucket": 800, "count": 90},{ "date": "2012-07-21", "bucket": 900, "count": 129},{ "date": "2012-07-21", "bucket": 1000, "count": 192}

Page 31: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Purchases by Day

Page 32: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Heatmap definition

{ xtype: 'd3-heatmap',

store: { type: 'purchasesbyday' },

...}

Component & Store

Page 33: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Heatmap definition

yAxis: { axis: { orient: 'left', tickFormat: "d3.format('$d')" },

scale: { type: 'linear' }, title: { text: 'Total' }, field: 'bucket', step: 100}

y-Axis

Page 34: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Heatmap definition

xAxis: { axis: { orient: 'bottom', ticks: 'd3.timeDay', tickFormat: "d3.timeFormat('%b %d')" }, scale: { type: 'time' }, title: { text: 'Date' }, field: 'date', step: 24 * 60 * 60 * 1000}

x-Axis

Page 35: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Heatmap definition

colorAxis: {

field: 'count',

scale: { type: 'linear', range: ['white', 'green'] },

minimum: 0}

Colors

tiles: { attr: { 'stroke': 'green', 'stroke-width': 1 }}

Styles

Page 36: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Heatmap definition

legend: { docked: 'bottom', padding: 60, items: { count: 7, slice: [1], reverse: true, size: { x: 60, y: 30 } }}

Legend

Page 37: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Purchases by Day

Page 38: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Heatmap Tooltipsthey are just the same

tooltip: { renderer: 'onTooltip'}

onTooltip: function (component, tooltip, record, element, event) {

var xField = component.getXAxis().getField(), yField = component.getYAxis().getField(), colorField = component.getColorAxis().getField(),

date = record.get(xField), bucket = record.get(yField), count = record.get(colorField),

dateStr = Ext.Date.format(date, 'F j');

tooltip.setHtml(count + ' customers purchased a total of $' + bucket + ' to $' + (bucket + 100) + '<br> of goods on ' + dateStr);}

Page 39: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Live Demo

Page 40: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

How D3 selections work?a quick aside

d3.select('body') // a selection (a transient object that holds the 'body' element)

d3.select('body').selectAll('div') // a selection of all 'div' elements in the body

// joining data with selected 'div' elements:var update = d3.select('body').selectAll('div').data([0, 1, 2, 3, 4])

// existing DOM elements in the selection// for which no new datum was found:update.exit()

// a selection of successfully updated DOM elements:update

// a selection with placeholder nodes// for data that has no corresponding DOM elements:update.enter()

update.enter().append('div')

<div>.__data__ = 0<div>.__data__ = 1

...<div>.__data__ = 4

Page 41: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

How ExtJS Hierarchy components work?

var layout = d3.tree();

var layoutRoot = layout(d3.hierarchy(storeRoot));

var nodes = layoutRoot.descendants();

var update = scene.selectAll(‘.x-d3-node').data(nodes);

this.addNodes(update.enter());

this.updateNodes(update);

this.removeNodes(update.exit());

Page 42: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

{ name: 'Art Landro’, url: '1.jpg',

children: [

{ name: 'Craig Gering', url: '4.jpg', },

...

{ xtype: 'd3-tree',

nodeSize: [200, 100], interactions: { type: 'panzoom', zoom: { doubleTap: false } },

store: { root: data }}

Subclassinglet’s create an org chart

Page 43: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko
Page 44: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Ext.define('Ext.d3.sencha.Tree', { extend: 'Ext.d3.hierarchy.tree.HorizontalTree',

xtype: 'sencha-tree',

...

});

Extending the tree

Page 45: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

setupScene: function () { this.callParent(arguments);

this.getDefs().append('clipPath') .attr('id', 'node-clip') .append('circle') .attr('r', 45); }

Creating a clip path

Page 46: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

addNodes: function (selection) { selection .attr('opacity', 0) .append('image') .attr('xlink:href', node => 'img/' + node.data.get('url')) .attr('x', '-45px') .attr('y', '-45px') .attr('width', '90px') .attr('height', '90px') .attr('clip-path', 'url(#node-clip)'); }

Populating entering nodes

Page 47: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

updateNodes: function (update, enter) {

var selection = update.merge(enter);

selection .transition(this.layoutTransition) .attr('opacity', 1) .call(this.getNodeTransform());

}

Taking care of layout updates

Page 48: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

{ name: 'Art Landro', url: '1.jpg',

children: [

{ name: 'Craig Gering', url: '4.jpg', },

...

{ xtype: 'sencha-tree',

nodeSize: [200, 100], interactions: { type: 'panzoom', zoom: { doubleTap: false } },

store: { root: data }}

Swapping the xtype

Page 49: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Live Demo

Page 50: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko
Page 51: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Custom visualizations

• d3-svg (aliased as d3)- creates an SVG document for you

- takes care about the size

- responds to store changes

- has a life cycle of a component

onSceneSetup: function (component, scene) { var data = ['A', 'B', 'C', 'D', ‘E', 'F', 'G', 'H', 'I', ‘J'],

color = d3.scaleOrdinal(d3.schemeCategory20c), selection = scene.selectAll().data(data).enter(), position = (d, i) => i * 30;

selection.append('circle') .attr('fill', d => color(d)) .attr('cx', position) .attr('r', 10);

selection.append('text') .text((d, i) => i < 5 ? d : '') .attr('x', position) .attr('y', 30) .attr('text-anchor', 'middle') .attr('font-weight', 'bold');}

{ xtype: 'd3',

listeners: { scenesetup: 'onSceneSetup' }}

• d3-canvas - same as d3, but for Canvas- resolution independence

Page 52: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko
Page 53: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko
Page 54: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

What’s New?• D3 version 4.x based

- future proof

• Immutable selections- less unexpected side effects

• Immutable data- store data is not polluted by layout data,

due to separation between layout nodes and data

• New and Improved APIs- on both the Ext package and D3 library levels

• Better animations- FTW!

Page 55: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Some Breaking Changesnot our fault*

version 3 version 4

Page 56: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Some Breaking Changesfor example…

axis: { orient: 'bottom', ticks: 'd3.time.days', tickFormat: "d3.time.format('%b %d')"}

axis: { orient: 'bottom', ticks: 'd3.timeDay', tickFormat: "d3.timeFormat('%b %d')"}

Ext configs

d3.svg.axis() .orient('left') .ticks(d3.time.days) .tickFormat(d3.time.format('%b %d'));

d3.axisLeft()

.ticks(d3.timeDay) .tickFormat(d3.timeFormat('%b %d'));

D3 code

D3 v3.x D3 v4.x

Page 57: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Live Demothe last one

Page 58: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Thanks!

Vitaly [email protected]@sencha.com

Page 59: SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko