RGraph V5 Upgrade - error getting context - rgraph

I had a working 3d chart using version 2107-10-1 that used images for the y axis.
I'm now trying to use the version 5 libraries but I'm getting an error:
"Cannot read property 'getContext' of null at new RGraph.Drawing.Image (RGraph.drawing.image.js:64)
Which is:
"context = this.canvas.getContext('2d');"
I change the line in the library to 3d to match the chart variant setting of 3d and the error is resolved. However I then get the following errors:
"Cannot set property 'shadowColor' of null
at Object.RG.noShadow.RG.NoShadow (RGraph.common.core.js:5155)
at RGraph.Drawing.Image.draw.Draw (RGraph.drawing.image.js:490)"
I've been going through the API to try and find any differences to the property names but my skill and understanding is not great.
Any help or advice would be greatly appreciated.
:-)
new RGraph.Bar({
id: 'cvs',
data: [ [0,5,5],[0,5,5],[0,5,5] ],
options: {
/******/
variant: '3d',
variantThreedAngle: 0,
hmarginGrouped: 2,
/*****/
textFont: '"Courier New", Courier, monospace',
titleFont: '"Courier New", Courier, monospace',
labels:['Monday', 'Saturday', 'Sunday'] ,
colors: [ '#3cb44b','#5484ed','#fbd75b' ],
textSize: 11,
title: 'Test Learner1: T1C1 W/B 22nd April 2019',
titleSize: 11,
titleColor:'#338833',
titleX: 50,
titleY: 25,
titleHalign: 'Left',
textAccessible: false,
key: ['LabelOne','LabelTwo','LabelThree'], //['One','Two','Three','Four','Five'],
keyPositionY: 470,
keyPositionX: 0,
gutterBottom: 65,
gutterRight: 10,
gutterTop: 40,
gutterLeft: 70,
keyPosition: 'gutter',
keyTextSize: 9,
numyticks: 2,
ylabelsCount: 2,
ymax: 10,
ymin: 0,
backgroundColor: 'white',
labelsColor: 'green'
// end options
}
}).draw().exec(function (obj)
{
var images = [
'smileyimages/graphimages/smiley5.png','smileyimages/graphimages/smiley10.png','smileyimages/graphimages/smiley1.png',
];
var index = 0;
obj.coordsText.forEach(function (val, key, arr)
{
if (val.tag === 'scale') {
var x = val.x,
y = val.y,
text = val.text;
var img = new RGraph.Drawing.Image({
id: 'cvs',
x: x,
y: y,
src: images[index],
options: {
halign: 'right',
valign: 'center'
}
}).draw();
index++;
}
});
obj.set({
ylabels: true
});
RGraph.redraw();
}).on('beforedraw', function (obj)
{
RGraph.clear(obj.canvas, 'white');
});

I've adjusted your code for the new property names. With this code remember to update the paths to the images.
<script src="/libraries/RGraph.drawing.image.js"></script>
<script src="/libraries/RGraph.common.core.js"></script>
<script src="/libraries/RGraph.common.key.js"></script>
<script src="/libraries/RGraph.bar.js"></script>
And the code that makes the chart:
new RGraph.Bar({
id: 'cvs',
data: [ [1,5,5],[1,5,5],[1,5,5] ],
options: {
variant: '3d',
hmargin: 20,
hmarginGrouped: 2,
textFont: '"Courier New", Courier, monospace',
titleFont: '"Courier New", Courier, monospace',
xaxis: false,
xaxisLabels:['Monday', 'Saturday', 'Sunday'] ,
colors: [ '#3cb44b','#5484ed','#fbd75b' ],
title: 'Test Learner1: T1C1 W/B 22nd April 2019',
titleX: 120,
titleY: 25,
titleHalign: 'Left',
textAccessible: false,
key: ['LabelOne','LabelTwo','LabelThree'], //['One','Two','Three','Four','Five'],
keyPositionY: 435,
keyPositionX: 100,
marginBottom: 95,
marginRight: 10,
marginTop: 40,
marginLeft: 100,
keyPosition: 'margin',
keyLabelsSize: 9,
yaxis: false,
yaxisLabelsCount: 2,
yaxisScaleMax: 10,
yaxisScaleMin: 0,
backgroundColor: 'white',
xaxisLabelsColor: 'green'
}
}).draw().exec(function (obj)
{
var images = [
'/images/alex.png',
'/images/alert.png',
'/images/facebook.png'
];
var index = 0;
obj.coordsText.forEach(function (val, key, arr)
{
if (val.tag === 'scale') {
var x = val.x,
y = val.y,
text = val.text;
var img = new RGraph.Drawing.Image({
id: 'cvs',
x: x,
y: y + 10,
src: images[index++],
options: {
halign: 'right',
valign: 'center'
}
}).draw();
}
});
});

Related

Creating chart overlays with Plotly.js

I have been trying to create overlays with Plotly.js, e.g. Week over Week, Month over Month etc., and I am required to render a similar looking chart as below. I believe the candleStick chart can get me somewhat near to it, but just wanted to explore if anyone has got a better idea.
Year Over Year, chart sample
The candleStick plots are a good option indeed, but they are somewhat limited in Plotly (see below). Another one is to use fill between two curves, something that'd look like this:
Here is the code to produce this:
<html>
<head>
<!-- Plotly.js -->
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
<body>
<div class="item-graph" id="plotly_graph">
</div>
</body>
<script>
// Some random data
const date = ["2022/01/01", "2022/01/07", "2022/01/13", "2022/01/18", "2022/01/25", "2022/02/01", "2022/02/07", "2022/02/13", "2022/02/18", "2022/02/25"]
const new_date = date.map(function (d) { return new Date(d) })
const bluecurve = [450, 550, 460, 450, 530, 440, 340, 345, 290, 270]
const graycurve = [390, 410, 320, 490, 470, 380, 480, 410, 190, 310]
const min = [350, 430, 420, 410, 480, 350, 320, 310, 230, 190]
const max = [500, 600, 520, 490, 540, 500, 450, 390, 350, 360]
// Setting range of Forecast for hoverinfo
var hovertemplate = []
for (let i = 0; i < min.length; i++) {
hovertemplate.push(min[i] + ' - ' + max[i])
}
// Setting up the traces:
traces = [
{
x: new_date,
y: max,
// name: 'Forecast',
yaxis: 'y',
showlegend: false,
line: { width: 1, shape: 'hvh', color: "lightblue" },
hoverinfo: 'skip',
mode: 'lines',
},
{
x: new_date,
y: min,
name: 'Forecast',
yaxis: 'y',
showlegend: false,
line: { width: 1, shape: 'hvh', color: "lightblue" },
// hoverinfo: 'skip',
hovertemplate: hovertemplate,
mode: 'lines',
fillcolor: "lightblue",
fill: 'tonexty',
},
{
x: new_date,
y: bluecurve,
name: "This Year",
yaxis: 'y',
type: 'scatter',
showlegend: false,
mode: 'markers',
marker: {
size: 20,
color: "blue",
line: {
width: 2,
color: 'DarkSlateGrey'
},
},
},
{
x: new_date,
y: graycurve,
name: "Last Year",
yaxis: 'y',
type: 'scatter',
showlegend: false,
mode: 'markers',
marker: {
size: 20,
color: "lightgray",
line: {
width: 2,
color: 'DarkSlateGrey'
},
},
},
]
// Setting up layout
const layout = {
yaxis: {
rangemode: 'nonnegative',
range: [0, 700]
},
hovermode: "x unified",
};
// Creating the plots
Plotly.react("plotly_graph", traces, layout);
</script>
</html>
If you want to use candlesticks, you can change the layout and the first two elements on the traces to, respectively:
const layout= {
xaxis: {
type: 'date',
rangeslider: {
visible: false,
},
},
yaxis: {
rangemode: 'nonnegative',
range: [0,700]
},
hovermode: "x unified",
};
and
{
x: new_date,
low: min,
open: min,
high: max,
close: max,
decreasing: {line: {color: "lightblue" }},
increasing: {line: {color: "lightblue" }},
yaxis: 'y',
type: 'candlestick',
showlegend: false,
// text: hovertemplate,
hoverinfo: 'skip',
},
The hoverinfo of the candlesticks seem to always include high, low, open and close (I couldn't find a way to edit it, as text just adds to those, so I deactivated it). Here is how it looks like:
There's also no control over the width, apart from the number of sticks in the figure.

Why inactive option not working on scatter highcharts

I have try to show inactive setting in my chart. But it's not showing in my project { it's worked on another live editor }
Chart Library: Highcharts
Chart type: scatter
Chart Version:
"highcharts": "^6.1.1",
"highcharts-more": "^0.1.7","highcharts-react-official": "^3.1.0",
``const config = {
chart: {
zoomType: 'x',
type: 'scatter',
height: 400,
spacingLeft: 0,
spacingRight: 0,
spacingTop: 0,
spacingBottom: 0,
margin: [30, 50, 80, 180],
width: null,
style: {
fontFamily: 'Fira Sans'
},
},
title: {
text: '',
},
subtitle: {
text: '',
},
xAxis: {
type: 'datetime',
ordinal: false,
startOnTick: false,
endOnTick: false,
minPadding: 0,
maxPadding: 0,
Date: false,
tickInterval: 3600 * 4000,
minTickInterval: 3600 * 100,
minRange: 1000 * 60 * 60,
dateTimeLabelFormats: {
minute: '%I:%M',
hour: '%I %P',
},
offset: 0,
},
yAxis: [
{
title: {
text: 'Part A',
align: "high",
textAlign: "right",
rotation: 0,
offset: 0,
margin: 0,
y: -10,
x: -15,
style: {
fontWeight: 500,
fontSize: '14px',
lineHeight: 20,
color: "#333333",
},
},
labels: {
style: {
fontWeight: 300,
fontSize: '14px',
lineHeight: 16,
color: "#333333",
letterSpacing: 0,
},
y: 3,
align:'right',
},
categories: ['', 'B1', 'B2', '', 'A1', 'A2', 'A3', ''],
},
{
title: {
text: 'Part B',
align: "middle",
textAlign: "right",
rotation: 0,
offset: 0,
margin: 0,
y: 30,
x: 25,
style: {
fontWeight: 500,
fontSize: '14px',
lineHeight: 20,
color: "#333333",
},
},
},
],
plotOptions: {
column: {
stacking: 'normal',
column: {
pointPadding: 0,
borderWidth: 0,
groupPadding: 0,
grouping: true,
}
},
},
series: [
{
"name": "Poor",
"data": [[1.424304e+12, 1], [1.4243076e+12, 2], [1.4243148e+12, 1], [1.4243301e+12, 1], [1.4243364e+12, 6]],
color: '#FF8A45',
marker: {
symbol: 'square'
},
},
{
"name": "Fair",
"data": [[1.424304e+12, 6], [1.4243112e+12, 1], [1.4243292e+12, 2], [1.4243436e+12, 2], [1.4243616e+12, 2]],
color: '#FFC100',
marker: {
symbol: 'square'
},
},
{
"name": "Moderate",
"data": [[1.4243616e+12, 4], [1.4243436e+12, 4], [1.4243112e+12, 4], [1.424304e+12, 4], [1.4243292e+12, 6]],
color: '#B7DCFD',
marker: {
symbol: 'square'
},
},
{
"name": "Good",
"data": [[1.424304e+12, 5], [1.4243112e+12, 5], [1.4243292e+12, 5], [1.4243436e+12, 5], [1.4243616e+12, 6]],
color: '#00C96A',
marker: {
symbol: 'square'
},
},
],
credits: {
enabled: false
},
};``
Here is my full config of hoghchart
You are using the 6.1.1 version but inactive option is available from 7.1.0 https://www.highcharts.com/blog/changelog/#highcharts-v7.1.0 .
I would recommend to always using the latest highcharts version.
So, all you have to do is set "highcharts": "latest" in your project.
If for some reason you need to use an older version, use mouseOver and mouseOut events to change the series color on hover.
plotOptions: {
series: {
events: {
mouseOver: function() {
let hoveredSeries = this;
let allSeries = this.chart.series;
allSeries.forEach(series => {
if (series === hoveredSeries) {
return true
} else if (series.name === 'A') {
series.update({
color: 'rgba(0, 155, 0, 0.5)',
})
} else if (series.name === 'B') {
series.update({
color: 'rgba(255, 0, 0, 0.5)'
})
}
})
},
mouseOut: function() {
let hoveredSeries = this;
let allSeries = this.chart.series;
allSeries.forEach(series => {
if (series === hoveredSeries) {
return true
} else if (series.name === 'A') {
series.update({
color: 'rgba(0, 155, 0, 1)',
})
} else if (series.name === 'B') {
series.update({
color: 'rgba(255, 0, 0, 1)'
})
}
})
}
}
}
},
Example demo:
https://jsfiddle.net/BlackLabel/zgjsof7L/
API Reference:
https://api.highcharts.com/highcharts/plotOptions.series.events.mouseOver

set different bar width for each bar using ECHARTS

Im using the e-charts libary for creating a bar chart for my data .
like so :
option.series = [
{
name: 'buy',
type: 'bar',
stack: 'one',
data: Object.values(chartData?.data || {}).map(elem => -elem.buy?.total),
color: colors.bought,
label: {
show: true,
position: "bottom",
formatter: (value) => Math.round(Math.abs(value.data))
},
tooltip: {
formatter: (data) => Math.abs(data.value).toString()
},
// barWidth:this.data
},
{
name: 'sell',
type: 'bar',
stack: 'one',
data: Object.values(chartData?.data || {}).map(elem =>elem.sell?.total),
color: colors.sold,
label: {
show: true,
position: "top",
formatter: (value) => Math.round(Math.abs(value.data))
},
tooltip: {
formatter: (data) => Math.abs(data.value).toString()
},
},
{
name: 'profite',
type: 'bar',
stack: 'two',
barGap: '-100%',
z: 100,
data: Object.values(chartData?.data || {}).map(elem => elem.sell?.profit),
color: colors.profit,
label: {
show: true,
position: "insideTop",
textBorderWidth: -1,
offset: [0, -20],
formatter: (value) => Math.round(Math.abs(value.data))
},
tooltip: {
formatter: (data) => Math.abs(data.value).toString()
},
},
]
im trying to set a different width for each bar depending on the value of each bar .
on data property i get a list of numbers rendering .
When i try to add a barWidth property all i can do is change all of the bars in the same chrts like so for example:
barWidth: ${getBarWidth((Object.values(chartData?.data || {}).map((elem) => elem.sell?.amount)))}%
so i returne a different value of my data each time but it didnt changed each bar according to its value (either buy, sell and so on).
Thanks in adavance.
As you pointed out, barWidth sets the width of all the bars of a bar series. And I don't think there is a way to set the width of each bar in the same bar series.
What you should use instead is a custom series.
Custom series have a parameter called renderItem, where you write the render logic of the chart. It's where you'll be able to display custom shapes (custom sized bar in your case), using graphics.
Here is an example I found on their website, doing pretty much what you're looking for.
var container = document.getElementById('main');
var chart = echarts.init(container);
const colorList = [
'#4f81bd',
'#c0504d',
'#9bbb59',
'#604a7b',
'#948a54',
'#e46c0b'
];
const data = [
[10, 16, 3, 'A'],
[16, 18, 15, 'B'],
[18, 26, 12, 'C'],
[26, 32, 22, 'D'],
[32, 56, 7, 'E'],
[56, 62, 17, 'F']
].map(function (item, index) {
return {
value: item,
itemStyle: {
color: colorList[index]
}
};
});
chart.setOption({
title: {
text: 'Profit',
left: 'center'
},
tooltip: {},
xAxis: {
scale: true
},
yAxis: {},
series: [
{
type: 'custom',
renderItem: function (params, api) {
var yValue = api.value(2);
var start = api.coord([api.value(0), yValue]);
var size = api.size([api.value(1) - api.value(0), yValue]);
var style = api.style();
return {
type: 'rect',
shape: {
x: start[0],
y: start[1],
width: size[0],
height: size[1]
},
style: style
};
},
label: {
show: true,
position: 'top'
},
dimensions: ['from', 'to', 'profit'],
encode: {
x: [0, 1],
y: 2,
tooltip: [0, 1, 2],
itemName: 3
},
data: data
}
]
});
#main {
width: 600px;
height: 400px;
}
<html>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.3.2/echarts.min.js"></script>
<div id="main"></div>
</body>
</html>

Multiple Gauge Chart

Is it possible to Draw this type of gauges in the left and right of the circle using Highcharts?
Basically left side gauge is representing the shorts' %age at left, the right side gauge is representing the shorts' %age at right, and the center is one simple round circle with the %age of center shots.
Series variable pie it's looks fit better for this case.
Tooltip we built setting useHTML:true, circle at the center we rendered by SVG renderer.
Highcharts.chart('container', {
chart: {
events: {
render() {
const chart = this;
if (!chart.customCenterCircle) {
chart.customCenterCircle = chart.renderer.circle(
chart.plotLeft + chart.plotSizeX / 2,
chart.plotTop + chart.plotSizeY / 2,
0
).add().toFront();
}
if (!chart.customCenterText) {
chart.customCenterText = chart.renderer.text('50%', 0, 0).css({
fontSize: '24px',
color: '#d4d4d4'
}).add().toFront();
}
chart.customCenterCircle.animate({
x: chart.plotLeft + chart.plotSizeX / 2,
y: chart.plotTop + chart.plotSizeY / 2,
r: chart.series[0].center[3] / 2,
fill: 'rgba(31, 112, 31, 0.5)',
stroke: 'rgba(154, 214, 154, 1)',
'stroke-width': 4
});
chart.customCenterText.attr({
x: chart.plotLeft + chart.plotSizeX / 2 -
chart.customCenterText.getBBox().width / 2,
y: chart.plotTop + chart.plotSizeY / 2 -
chart.customCenterText.getBBox().y -
chart.customCenterText.getBBox().height / 2
});
}
}
},
tooltip: {
backgroundColor: '#ffffff',
borderWidth: 0,
useHTML: true,
formatter: function() {
return `<p><h1 style="color:${this.color};">${this.y}</h1></br>${this.key}</p>`
}
},
series: [{
type: 'variablepie',
minPointSize: 0,
innerSize: '30%',
startAngle: 30,
dataLabels: {
enabled: false
},
borderWidth: 3,
zMin: 0,
data: [{
y: 80,
z: 100,
name: 'other',
color: 'black'
}, {
y: 30,
z: 100,
name: 'missed right',
color: 'red'
}, {
y: 50,
z: 0
}, {
y: 25,
z: 80,
name: 'missed right',
color: 'red'
}, {
y: 75,
z: 80,
name: 'other',
color: 'black'
}, {
y: 60,
z: 0,
name: 'other',
}]
}]
});
Live demo:
https://jsfiddle.net/BlackLabel/sc9vwzjt/2/
API References:
https://www.highcharts.com/docs/chart-and-series-types/variable-radius-pie-chart
https://api.highcharts.com/highcharts/series.variablepie
https://api.highcharts.com/class-reference/Highcharts.SVGRenderer

Custom component not displaying on an Ext.panel.Panel

I have extended a component and I can't get it to render to a panel. Seems like I am missing something pretty basic since the debugger in Chrome actually shows that the panel has the data, it just isn't showing up.
Here is the fiddle and here are parts of the code:
Custom Component:
Ext.define('StoplightControl', {
extend: 'Ext.draw.Component',
alias: 'widget.Stoplight',
constructor: function (config) {
this.initConfig(config);
this.callParent(arguments);
},
initComponent: function () {
var kpiData; // = Ext.data.StoreManager.get('KPIStore').getById(this.model.get('KPI_ID'));
if (typeof (kpiData) === 'undefined' || kpiData == null) {
kpiData = Ext.create('KPIModel', {
ControlBackground: '#000000',
Caution_label: 'On',
Good_label: 'Ahead',
Poor_label: 'Behind',
Good_color: '#00FF00',
Poor_color: '#ff0000',
Caution_color: '#550000',
Header: 'Test'
});
}
this.setGradients(kpiData.get('ControlBackground'));
this.drawItems(this.model, kpiData);
},
setGradients: function (controlColor) {
this.gradients = [{
id: 'middleGradient',
angle: 180,
stops: {
0: {
color: controlColor,
opacity: 1
},
50: {
color: controlColor,
opacity: .6
},
100: {
color: controlColor,
opacity: 1
}
}
}, {
id: 'lightGradient1',
angle: -90,
stops: {
0: {
color: '#ffffff',
opacity: 0.01
},
100: {
color: '#ffffff',
opacity: .8
}
}
}]
},
drawItems: function (model, kpiData) {
var cautionValueX = -22.5 * (model.get('cautionValue').toString().length) + 227.5,
goodValueX = -22.5 * (model.get('goodValue').toString().length) + 227.5,
poorValueX = -22.5 * (model.get('poorValue').toString().length) + 227.5,
maxLineLength = 15,
changeOfY = -50,
cautionLabel = linebreaks(kpiData.get('Caution_label'), maxLineLength),
goodLabel = linebreaks(kpiData.get('Good_label'), maxLineLength),
poorLabel = linebreaks(kpiData.get('Poor_label'), maxLineLength),
cautionChangeY = (cautionLabel.split("\n").length - 1) * changeOfY,
goodChangeY = (goodLabel.split("\n").length - 1) * changeOfY,
poorChangeY = (poorLabel.split("\n").length - 1) * changeOfY,
headerFontSize = '100px arial,sans-serif',
textFontSize = '80px arial,sans-serif';
var drawItems = [{
type: 'rect',
x: 1.6620979,
y: 52.362183,
radius: 90,
width: 448.10959,
height: 1000,
fill: 'url(#middleGradient)',
stroke: 'none'
}, {
type: "circle",
radius: 140,
x: 224,
y: 896,
stroke: "#000000",
'stroke-width': 1,
fill: kpiData.get('Good_color')
}, {
type: "circle",
x: 224,
y: 214,
radius: 140,
stroke: "#000000",
'stroke-width': 1,
fill: kpiData.get('Poor_color')
}, {
type: "circle",
x: 224,
y: 555,
radius: 140,
stroke: "#000000",
'stroke-width': 1,
fill: kpiData.get('Caution_color')
}, {
type: "text",
id: "svg-stoplight-poorValue",
text: model.get('poorValue'),
x: poorValueX,
y: 220,
fill: "Black",
font: textFontSize
}, {
type: "text",
id: "svg-stoplight-cautionValue",
text: model.get('cautionValue'),
x: cautionValueX,
y: 560,
fill: "Black",
font: textFontSize
}, {
type: "text",
id: "svg-stoplight-goodValue",
text: model.get('goodValue'),
x: goodValueX,
y: 900,
fill: "Black",
font: textFontSize
}, {
type: "text",
id: "svg-stoplight-poorLabel",
text: poorLabel,
x: 500,
y: 220 + poorChangeY,
fill: "Black",
font: textFontSize
}, {
type: "text",
id: "svg-stoplight-cautionLabel",
text: cautionLabel,
x: 500,
y: 560 + cautionChangeY,
fill: "Black",
font: textFontSize
}, {
type: "text",
id: "svg-stoplight-goodLabel",
text: goodLabel,
x: 500,
y: 900 + goodChangeY,
fill: "Black",
font: textFontSize
}, {
type: "text",
id: "svg-stoplight-headerLabel",
text: kpiData.get('Header'),
x: 145,
y: -40,
fill: "Black",
font: headerFontSize
}, {
type: "text",
id: "svg-stoplight-totalLabel",
text: "Total = " + model.get('total'),
x: 100,
y: 1250,
fill: "Black",
font: textFontSize
}];
//don't add gradients if IE is > 10 or documentMode is less than 9
if (!(ie > 10 || document.documentMode < 9)) {
drawItems.push({
type: "ellipse",
id: 'test1',
radiusX: 112,
radiusY: 80,
x: 224,
y: 156,
fill: 'url(#lightGradient1)'
}, {
type: "ellipse",
radiusX: 112,
radiusY: 80,
x: 224,
y: 498,
fill: 'url(#lightGradient1)'
}, {
type: "ellipse",
radiusX: 112,
radiusY: 80,
x: 224,
y: 838,
fill: 'url(#lightGradient1)'
});
}
},
width: 210,
height: 250
});
Creation of the Panel and adding the component:
var displayPanel = Ext.create('widget.panel', {
width: 600,
height: 800,
title: 'Cost & Schedule Variance',
renderTo: 'WorkstreamStoplights',
pack: 'center',
shrinkWrap: 3,
layout: {
type: 'table',
column: 2
},
});
stoplightStore.each(function (model, idx) {
var stoplight = Ext.create('StoplightControl', {
model: model
});
displayPanel.add(stoplight);
});
displayPanel.doLayout();
As you'll be able to see from the fiddle, the Title displays properly and I have even added an item to the displayPanel on creation, but doing a .add() doesn't seem to have any effect even with the .doLayout()
Haven't dabbled in ExtJS for a long time, but the 4.2 doc states, for this method:
This method needs to be called whenever you change something on this
component that requires the Component's layout to be recalculated.
Ah, silly me. I needed to add items to my component. I needed to make the assignment in the initComponents of
this.items = drawItems;
Working fiddle

Resources