SlideShare ist ein Scribd-Unternehmen logo
1 von 59
Add Magic to Your ExtJS Apps with D3
Visualizations
Vitaly Kravchenko
D3 and Charts
we can have both
• Complements charts
• Offers unique components
• Has no feature overlap
VS
D3 Components
visualized by themselves
Hierarchy Components
for tree store visualizations
d3-pack d3-tree d3-treemap d3-sunburst
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
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
items: {
xtype: 'd3-treemap',
}
viewModel: vm,
bind: {
store: '{letters}'
}
Config
...
{
name: 'D',
},
{
name: 'E'
},
...
Data Result
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
• 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
Data
Binding
viewModel: 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' }
]
Live
Demo
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
}
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
With a bit more tweaking…
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
}
}
Live
Demo
Interactions
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
}
}
Heatmap
Represent matrix values with colors
Sales per Employee per Day
{
"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
Heatmap definition
{
xtype: 'd3-heatmap',
store: {
type: 'salesperemployee'
},
...
}
Component & Store
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
Heatmap definition
colorAxis: {
field: 'sales',
scale: {
type: 'linear',
range: [
'green’,
'yellow',
'red'
]
}
}
Colors
tiles: {
attr: {
'stroke': 'darkblue',
'stroke-width': 2
}
}
Styles
Heatmap definition
legend: {
docked: 'right',
padding: 50,
items: {
count: 7,
reverse: true,
size: {
x: 60,
y: 30
}
}
}
Legend
A Heatmap with Discrete X- and Y-axes
Name, Category, Index, etc.
Sales per Employee per Day
Discrete Color Axis
is supported too
Axis and Legend configuration
colorAxis: {
scale: {
type: 'ordinal',
range: 'd3.schemeCategory20c'
},
field: 'category'
}
legend: {
docked: 'right',
padding: 50,
items: {
size: {
x: 60,
y: 30
}
}
}
Heatmaps with Continuous Axes
Quantity, 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
}
Purchases by Day
Heatmap definition
{
xtype: 'd3-heatmap',
store: {
type: 'purchasesbyday'
},
...
}
Component & Store
Heatmap definition
yAxis: {
axis: {
orient: 'left',
tickFormat: "d3.format('$d')"
},
scale: {
type: 'linear'
},
title: {
text: 'Total'
},
field: 'bucket',
step: 100
}
y-Axis
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
Heatmap definition
colorAxis: {
field: 'count',
scale: {
type: 'linear',
range: ['white', 'green']
},
minimum: 0
}
Colors
tiles: {
attr: {
'stroke': 'green',
'stroke-width': 1
}
}
Styles
Heatmap definition
legend: {
docked: 'bottom',
padding: 60,
items: {
count: 7,
slice: [1],
reverse: true,
size: {
x: 60,
y: 30
}
}
}
Legend
Purchases by Day
Heatmap Tooltips
they 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);
}
Live
Demo
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
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());
{
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
}
}
Subclassing
let’s create an org chart
Ext.define('Ext.d3.sencha.Tree', {
extend: 'Ext.d3.hierarchy.tree.HorizontalTree',
xtype: 'sencha-tree',
...
});
Extending the tree
setupScene: function () {
this.callParent(arguments);
this.getDefs().append('clipPath')
.attr('id', 'node-clip')
.append('circle')
.attr('r', 45);
}
Creating a clip path
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
updateNodes: function (update, enter) {
var selection = update.merge(enter);
selection
.transition(this.layoutTransition)
.attr('opacity', 1)
.call(this.getNodeTransform());
}
Taking care of layout updates
{
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
Live
Demo
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
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!
Some Breaking Changes
not our fault*
version 3 version 4
Some Breaking Changes
for 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
Live
Demothe last one
Thanks!
Vitaly Kravchenko
@vitalyx
vitaly.kravchenko@sencha.com
SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko

Weitere ähnliche Inhalte

Was ist angesagt?

JavaScript para Graficos y Visualizacion de Datos - BogotaJS
JavaScript para Graficos y Visualizacion de Datos - BogotaJSJavaScript para Graficos y Visualizacion de Datos - BogotaJS
JavaScript para Graficos y Visualizacion de Datos - BogotaJS
philogb
 
GWT.create 2013: Introduction to GXT
GWT.create 2013: Introduction to GXTGWT.create 2013: Introduction to GXT
GWT.create 2013: Introduction to GXT
niloc132
 
Mongo db washington dc 2014
Mongo db washington dc 2014Mongo db washington dc 2014
Mongo db washington dc 2014
ikanow
 
Database madness with_mongoengine_and_sql_alchemy
Database madness with_mongoengine_and_sql_alchemyDatabase madness with_mongoengine_and_sql_alchemy
Database madness with_mongoengine_and_sql_alchemy
Jaime Buelta
 

Was ist angesagt? (20)

SVG, CSS3, and D3 for Beginners
SVG, CSS3, and D3 for BeginnersSVG, CSS3, and D3 for Beginners
SVG, CSS3, and D3 for Beginners
 
Dig Deeper into WordPress - WD Meetup Cairo
Dig Deeper into WordPress - WD Meetup CairoDig Deeper into WordPress - WD Meetup Cairo
Dig Deeper into WordPress - WD Meetup Cairo
 
MongoDB .local Paris 2020: La puissance du Pipeline d'Agrégation de MongoDB
MongoDB .local Paris 2020: La puissance du Pipeline d'Agrégation de MongoDBMongoDB .local Paris 2020: La puissance du Pipeline d'Agrégation de MongoDB
MongoDB .local Paris 2020: La puissance du Pipeline d'Agrégation de MongoDB
 
Thunderstruck
ThunderstruckThunderstruck
Thunderstruck
 
JavaScript para Graficos y Visualizacion de Datos - BogotaJS
JavaScript para Graficos y Visualizacion de Datos - BogotaJSJavaScript para Graficos y Visualizacion de Datos - BogotaJS
JavaScript para Graficos y Visualizacion de Datos - BogotaJS
 
Webinar: Applikationsentwicklung mit MongoDB : Teil 5: Reporting & Aggregation
Webinar: Applikationsentwicklung mit MongoDB: Teil 5: Reporting & AggregationWebinar: Applikationsentwicklung mit MongoDB: Teil 5: Reporting & Aggregation
Webinar: Applikationsentwicklung mit MongoDB : Teil 5: Reporting & Aggregation
 
Introduction to d3js (and SVG)
Introduction to d3js (and SVG)Introduction to d3js (and SVG)
Introduction to d3js (and SVG)
 
MongoDB .local Toronto 2019: Tips and Tricks for Effective Indexing
MongoDB .local Toronto 2019: Tips and Tricks for Effective IndexingMongoDB .local Toronto 2019: Tips and Tricks for Effective Indexing
MongoDB .local Toronto 2019: Tips and Tricks for Effective Indexing
 
Single page webapps & javascript-testing
Single page webapps & javascript-testingSingle page webapps & javascript-testing
Single page webapps & javascript-testing
 
Drupal content-migration
Drupal content-migrationDrupal content-migration
Drupal content-migration
 
Migrate
MigrateMigrate
Migrate
 
GWT.create 2013: Introduction to GXT
GWT.create 2013: Introduction to GXTGWT.create 2013: Introduction to GXT
GWT.create 2013: Introduction to GXT
 
Django - sql alchemy - jquery
Django - sql alchemy - jqueryDjango - sql alchemy - jquery
Django - sql alchemy - jquery
 
Learn D3.js in 90 minutes
Learn D3.js in 90 minutesLearn D3.js in 90 minutes
Learn D3.js in 90 minutes
 
Entities in drupal 7
Entities in drupal 7Entities in drupal 7
Entities in drupal 7
 
Mongo db washington dc 2014
Mongo db washington dc 2014Mongo db washington dc 2014
Mongo db washington dc 2014
 
Green dao
Green daoGreen dao
Green dao
 
GreenDao Introduction
GreenDao IntroductionGreenDao Introduction
GreenDao Introduction
 
Database madness with_mongoengine_and_sql_alchemy
Database madness with_mongoengine_and_sql_alchemyDatabase madness with_mongoengine_and_sql_alchemy
Database madness with_mongoengine_and_sql_alchemy
 
4Developers 2018: Structuring React components (Bartłomiej Witczak)
4Developers 2018: Structuring React components (Bartłomiej Witczak)4Developers 2018: Structuring React components (Bartłomiej Witczak)
4Developers 2018: Structuring React components (Bartłomiej Witczak)
 

Andere mochten auch

Andere mochten auch (18)

Sencha Roadshow 2017: Best Practices for Implementing Continuous Web App Testing
Sencha Roadshow 2017: Best Practices for Implementing Continuous Web App TestingSencha Roadshow 2017: Best Practices for Implementing Continuous Web App Testing
Sencha Roadshow 2017: Best Practices for Implementing Continuous Web App Testing
 
Sencha Roadshow 2017: What's New in Sencha Test
Sencha Roadshow 2017: What's New in Sencha TestSencha Roadshow 2017: What's New in Sencha Test
Sencha Roadshow 2017: What's New in Sencha Test
 
Ext JS Architecture Best Practices - Mitchell Simeons
Ext JS Architecture Best Practices - Mitchell SimeonsExt JS Architecture Best Practices - Mitchell Simeons
Ext JS Architecture Best Practices - Mitchell Simeons
 
SenchaCon 2016: Keynote Presentation - Art Landro, Gautam Agrawal, Mark Brocato
SenchaCon 2016: Keynote Presentation - Art Landro, Gautam Agrawal, Mark BrocatoSenchaCon 2016: Keynote Presentation - Art Landro, Gautam Agrawal, Mark Brocato
SenchaCon 2016: Keynote Presentation - Art Landro, Gautam Agrawal, Mark Brocato
 
SenchaCon 2016: Mobile First? Desktop First? Or Should you Think Universal Ap...
SenchaCon 2016: Mobile First? Desktop First? Or Should you Think Universal Ap...SenchaCon 2016: Mobile First? Desktop First? Or Should you Think Universal Ap...
SenchaCon 2016: Mobile First? Desktop First? Or Should you Think Universal Ap...
 
Sencha Roadshow 2017: Build Progressive Web Apps with Ext JS and Cmd
Sencha Roadshow 2017: Build Progressive Web Apps with Ext JS and Cmd Sencha Roadshow 2017: Build Progressive Web Apps with Ext JS and Cmd
Sencha Roadshow 2017: Build Progressive Web Apps with Ext JS and Cmd
 
Sencha Roadshow 2017: Sencha Upgrades - The Good. The Bad. The Ugly - Eva Luc...
Sencha Roadshow 2017: Sencha Upgrades - The Good. The Bad. The Ugly - Eva Luc...Sencha Roadshow 2017: Sencha Upgrades - The Good. The Bad. The Ugly - Eva Luc...
Sencha Roadshow 2017: Sencha Upgrades - The Good. The Bad. The Ugly - Eva Luc...
 
Sencha Roadshow 2017: Innovations in Ext JS 6.5 and Beyond
Sencha Roadshow 2017: Innovations in Ext JS 6.5 and BeyondSencha Roadshow 2017: Innovations in Ext JS 6.5 and Beyond
Sencha Roadshow 2017: Innovations in Ext JS 6.5 and Beyond
 
Sencha Roadshow 2017: Modernizing the Ext JS Class System and Tooling
Sencha Roadshow 2017: Modernizing the Ext JS Class System and ToolingSencha Roadshow 2017: Modernizing the Ext JS Class System and Tooling
Sencha Roadshow 2017: Modernizing the Ext JS Class System and Tooling
 
Learn Key Insights from The State of Web Application Testing Research Report
Learn Key Insights from The State of Web Application Testing Research ReportLearn Key Insights from The State of Web Application Testing Research Report
Learn Key Insights from The State of Web Application Testing Research Report
 
Introducing ExtReact: Adding Powerful Sencha Components to React Apps
Introducing ExtReact: Adding Powerful Sencha Components to React AppsIntroducing ExtReact: Adding Powerful Sencha Components to React Apps
Introducing ExtReact: Adding Powerful Sencha Components to React Apps
 
SenchaCon 2016: Expect the Unexpected - Dealing with Errors in Web Apps
SenchaCon 2016: Expect the Unexpected - Dealing with Errors in Web AppsSenchaCon 2016: Expect the Unexpected - Dealing with Errors in Web Apps
SenchaCon 2016: Expect the Unexpected - Dealing with Errors in Web Apps
 
SenchaCon 2016: LinkRest - Modern RESTful API Framework for Ext JS Apps - Rou...
SenchaCon 2016: LinkRest - Modern RESTful API Framework for Ext JS Apps - Rou...SenchaCon 2016: LinkRest - Modern RESTful API Framework for Ext JS Apps - Rou...
SenchaCon 2016: LinkRest - Modern RESTful API Framework for Ext JS Apps - Rou...
 
Sencha Roadshow 2017: BufferedStore Internals featuring eyeworkers interactiv...
Sencha Roadshow 2017: BufferedStore Internals featuring eyeworkers interactiv...Sencha Roadshow 2017: BufferedStore Internals featuring eyeworkers interactiv...
Sencha Roadshow 2017: BufferedStore Internals featuring eyeworkers interactiv...
 
Sencha Roadshow 2017: Sencha Best Practices: Coworkee App
Sencha Roadshow 2017: Sencha Best Practices: Coworkee App Sencha Roadshow 2017: Sencha Best Practices: Coworkee App
Sencha Roadshow 2017: Sencha Best Practices: Coworkee App
 
Building Ext JS Using HATEOAS - Jeff Stano
Building Ext JS Using HATEOAS - Jeff StanoBuilding Ext JS Using HATEOAS - Jeff Stano
Building Ext JS Using HATEOAS - Jeff Stano
 
Sencha Roadshow 2017: Mobile First or Desktop First
Sencha Roadshow 2017: Mobile First or Desktop FirstSencha Roadshow 2017: Mobile First or Desktop First
Sencha Roadshow 2017: Mobile First or Desktop First
 
Leveraging React and GraphQL to Create a Performant, Scalable Data Grid
Leveraging React and GraphQL to Create a Performant, Scalable Data GridLeveraging React and GraphQL to Create a Performant, Scalable Data Grid
Leveraging React and GraphQL to Create a Performant, Scalable Data Grid
 

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

circ.db.dbcircleserver(1).py#!usrlocalbinpython3im.docx
circ.db.dbcircleserver(1).py#!usrlocalbinpython3im.docxcirc.db.dbcircleserver(1).py#!usrlocalbinpython3im.docx
circ.db.dbcircleserver(1).py#!usrlocalbinpython3im.docx
christinemaritza
 

Ähnlich wie SenchaCon 2016: Add Magic to Your Ext JS Apps with D3 Visualizations - Vitaly Kravchenko (20)

Better d3 charts with tdd
Better d3 charts with tddBetter d3 charts with tdd
Better d3 charts with tdd
 
D3 data visualization
D3 data visualizationD3 data visualization
D3 data visualization
 
Having fun with graphs, a short introduction to D3.js
Having fun with graphs, a short introduction to D3.jsHaving fun with graphs, a short introduction to D3.js
Having fun with graphs, a short introduction to D3.js
 
Visualization of Big Data in Web Apps
Visualization of Big Data in Web AppsVisualization of Big Data in Web Apps
Visualization of Big Data in Web Apps
 
Fun with D3.js: Data Visualization Eye Candy with Streaming JSON
Fun with D3.js: Data Visualization Eye Candy with Streaming JSONFun with D3.js: Data Visualization Eye Candy with Streaming JSON
Fun with D3.js: Data Visualization Eye Candy with Streaming JSON
 
D3
D3D3
D3
 
D3.js - A picture is worth a thousand words
D3.js - A picture is worth a thousand wordsD3.js - A picture is worth a thousand words
D3.js - A picture is worth a thousand words
 
D3.js 30-minute intro
D3.js   30-minute introD3.js   30-minute intro
D3.js 30-minute intro
 
Ember.js Tokyo event 2014/09/22 (English)
Ember.js Tokyo event 2014/09/22 (English)Ember.js Tokyo event 2014/09/22 (English)
Ember.js Tokyo event 2014/09/22 (English)
 
WebXR if X = how?
WebXR if X = how?WebXR if X = how?
WebXR if X = how?
 
Dynamic Data Visualization With Chartkick
Dynamic Data Visualization With ChartkickDynamic Data Visualization With Chartkick
Dynamic Data Visualization With Chartkick
 
React + Redux + d3.js
React + Redux + d3.jsReact + Redux + d3.js
React + Redux + d3.js
 
d3sparql.js demo at SWAT4LS 2014 in Berlin
d3sparql.js demo at SWAT4LS 2014 in Berlind3sparql.js demo at SWAT4LS 2014 in Berlin
d3sparql.js demo at SWAT4LS 2014 in Berlin
 
d4 and friendly charting DSL for D3
d4 and friendly charting DSL for D3d4 and friendly charting DSL for D3
d4 and friendly charting DSL for D3
 
SVGD3Angular2React
SVGD3Angular2ReactSVGD3Angular2React
SVGD3Angular2React
 
The Web map stack on Django
The Web map stack on DjangoThe Web map stack on Django
The Web map stack on Django
 
circ.db.dbcircleserver(1).py#!usrlocalbinpython3im.docx
circ.db.dbcircleserver(1).py#!usrlocalbinpython3im.docxcirc.db.dbcircleserver(1).py#!usrlocalbinpython3im.docx
circ.db.dbcircleserver(1).py#!usrlocalbinpython3im.docx
 
ELK Stack - Turn boring logfiles into sexy dashboard
ELK Stack - Turn boring logfiles into sexy dashboardELK Stack - Turn boring logfiles into sexy dashboard
ELK Stack - Turn boring logfiles into sexy dashboard
 
Interactively Search and Visualize Your Data: Presented by Romain Rigaux, Clo...
Interactively Search and Visualize Your Data: Presented by Romain Rigaux, Clo...Interactively Search and Visualize Your Data: Presented by Romain Rigaux, Clo...
Interactively Search and Visualize Your Data: Presented by Romain Rigaux, Clo...
 
Interactively Search and Visualize Your Big Data
Interactively Search and Visualize Your Big DataInteractively Search and Visualize Your Big Data
Interactively Search and Visualize Your Big Data
 

Mehr von Sencha

Mehr von Sencha (11)

Breathe New Life into Your Existing JavaScript Applications with Web Components
Breathe New Life into Your Existing JavaScript Applications with Web ComponentsBreathe New Life into Your Existing JavaScript Applications with Web Components
Breathe New Life into Your Existing JavaScript Applications with Web Components
 
Ext JS 6.6 Highlights
Ext JS 6.6 HighlightsExt JS 6.6 Highlights
Ext JS 6.6 Highlights
 
SenchaCon 2016: Developing and Delivering Quality Code, Frequently - Neil Manvar
SenchaCon 2016: Developing and Delivering Quality Code, Frequently - Neil ManvarSenchaCon 2016: Developing and Delivering Quality Code, Frequently - Neil Manvar
SenchaCon 2016: Developing and Delivering Quality Code, Frequently - Neil Manvar
 
SenchaCon 2016: Creating a Flexible and Usable Industry Specific Solution - D...
SenchaCon 2016: Creating a Flexible and Usable Industry Specific Solution - D...SenchaCon 2016: Creating a Flexible and Usable Industry Specific Solution - D...
SenchaCon 2016: Creating a Flexible and Usable Industry Specific Solution - D...
 
SenchaCon 2016: JavaScript is Great but Stop Writing It - Rory Hardy
SenchaCon 2016: JavaScript is Great but Stop Writing It - Rory HardySenchaCon 2016: JavaScript is Great but Stop Writing It - Rory Hardy
SenchaCon 2016: JavaScript is Great but Stop Writing It - Rory Hardy
 
SenchaCon 2016: Accessibility, Teamwork & Ext JS: A Customer Success Story - ...
SenchaCon 2016: Accessibility, Teamwork & Ext JS: A Customer Success Story - ...SenchaCon 2016: Accessibility, Teamwork & Ext JS: A Customer Success Story - ...
SenchaCon 2016: Accessibility, Teamwork & Ext JS: A Customer Success Story - ...
 
SenchaCon 2016: Using Ext JS 6 for Cross-Platform Development on Mobile - And...
SenchaCon 2016: Using Ext JS 6 for Cross-Platform Development on Mobile - And...SenchaCon 2016: Using Ext JS 6 for Cross-Platform Development on Mobile - And...
SenchaCon 2016: Using Ext JS 6 for Cross-Platform Development on Mobile - And...
 
SenchaCon 2016: Handling Undo-Redo in Sencha Applications - Nickolay Platonov
SenchaCon 2016: Handling Undo-Redo in Sencha Applications - Nickolay PlatonovSenchaCon 2016: Handling Undo-Redo in Sencha Applications - Nickolay Platonov
SenchaCon 2016: Handling Undo-Redo in Sencha Applications - Nickolay Platonov
 
SenchaCon 2016: How to Auto Generate a Back-end in Minutes - Per Minborg, Emi...
SenchaCon 2016: How to Auto Generate a Back-end in Minutes - Per Minborg, Emi...SenchaCon 2016: How to Auto Generate a Back-end in Minutes - Per Minborg, Emi...
SenchaCon 2016: How to Auto Generate a Back-end in Minutes - Per Minborg, Emi...
 
SenchaCon 2016: Turbocharge your Ext JS App - Per Minborg, Anselm McClain, Jo...
SenchaCon 2016: Turbocharge your Ext JS App - Per Minborg, Anselm McClain, Jo...SenchaCon 2016: Turbocharge your Ext JS App - Per Minborg, Anselm McClain, Jo...
SenchaCon 2016: Turbocharge your Ext JS App - Per Minborg, Anselm McClain, Jo...
 
SenchaCon 2016: Integrating Geospatial Maps & Big Data Using CartoDB via Ext ...
SenchaCon 2016: Integrating Geospatial Maps & Big Data Using CartoDB via Ext ...SenchaCon 2016: Integrating Geospatial Maps & Big Data Using CartoDB via Ext ...
SenchaCon 2016: Integrating Geospatial Maps & Big Data Using CartoDB via Ext ...
 

Kürzlich hochgeladen

Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

Kürzlich hochgeladen (20)

Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
Apidays New York 2024 - Passkeys: Developing APIs to enable passwordless auth...
 
Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..Understanding the FAA Part 107 License ..
Understanding the FAA Part 107 License ..
 
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
Vector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptxVector Search -An Introduction in Oracle Database 23ai.pptx
Vector Search -An Introduction in Oracle Database 23ai.pptx
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 

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

  • 1. Add Magic to Your ExtJS Apps with D3 Visualizations Vitaly Kravchenko
  • 2. D3 and Charts we can have both • Complements charts • Offers unique components • Has no feature overlap VS
  • 4. Hierarchy Components for tree store visualizations d3-pack d3-tree d3-treemap d3-sunburst
  • 5. 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
  • 6. 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
  • 7. items: { xtype: 'd3-treemap', } viewModel: vm, bind: { store: '{letters}' } Config ... { name: 'D', }, { name: 'E' }, ... Data Result
  • 8. 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
  • 9. • 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
  • 10. Data Binding viewModel: 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' } ]
  • 12. 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 }
  • 13. 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
  • 14. With a bit more tweaking…
  • 15. 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 } }
  • 17.
  • 18.
  • 20. 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 } }
  • 21. Heatmap Represent matrix values with colors Sales per Employee per Day
  • 22. { "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
  • 23. Heatmap definition { xtype: 'd3-heatmap', store: { type: 'salesperemployee' }, ... } Component & Store
  • 24. 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
  • 25. Heatmap definition colorAxis: { field: 'sales', scale: { type: 'linear', range: [ 'green’, 'yellow', 'red' ] } } Colors tiles: { attr: { 'stroke': 'darkblue', 'stroke-width': 2 } } Styles
  • 26. Heatmap definition legend: { docked: 'right', padding: 50, items: { count: 7, reverse: true, size: { x: 60, y: 30 } } } Legend
  • 27. A Heatmap with Discrete X- and Y-axes Name, Category, Index, etc. Sales per Employee per Day
  • 28. Discrete Color Axis is supported too
  • 29. Axis and Legend configuration colorAxis: { scale: { type: 'ordinal', range: 'd3.schemeCategory20c' }, field: 'category' } legend: { docked: 'right', padding: 50, items: { size: { x: 60, y: 30 } } }
  • 30. Heatmaps with Continuous Axes Quantity, 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 }
  • 32. Heatmap definition { xtype: 'd3-heatmap', store: { type: 'purchasesbyday' }, ... } Component & Store
  • 33. Heatmap definition yAxis: { axis: { orient: 'left', tickFormat: "d3.format('$d')" }, scale: { type: 'linear' }, title: { text: 'Total' }, field: 'bucket', step: 100 } y-Axis
  • 34. 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
  • 35. Heatmap definition colorAxis: { field: 'count', scale: { type: 'linear', range: ['white', 'green'] }, minimum: 0 } Colors tiles: { attr: { 'stroke': 'green', 'stroke-width': 1 } } Styles
  • 36. Heatmap definition legend: { docked: 'bottom', padding: 60, items: { count: 7, slice: [1], reverse: true, size: { x: 60, y: 30 } } } Legend
  • 38. Heatmap Tooltips they 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); }
  • 40. 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
  • 41. 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());
  • 42. { 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 } } Subclassing let’s create an org chart
  • 43.
  • 45. setupScene: function () { this.callParent(arguments); this.getDefs().append('clipPath') .attr('id', 'node-clip') .append('circle') .attr('r', 45); } Creating a clip path
  • 46. 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
  • 47. updateNodes: function (update, enter) { var selection = update.merge(enter); selection .transition(this.layoutTransition) .attr('opacity', 1) .call(this.getNodeTransform()); } Taking care of layout updates
  • 48. { 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
  • 50.
  • 51. 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
  • 52.
  • 53.
  • 54. 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!
  • 55. Some Breaking Changes not our fault* version 3 version 4
  • 56. Some Breaking Changes for 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

Hinweis der Redaktion

  1. Sample code: https://github.com/yay/SenchaCon2016